#include "crptkPCH.h" //----------------------------------------------------------------------------- // // File: CBC64WS4.cpp // // Microsoft Digital Rights Management // Copyright (C) 1998-1999 Microsoft Corporation, All Rights Reserved // // Description: // //----------------------------------------------------------------------------- /* chain-sum MAC scheme 4.5: multiply-&-swap rounds plus sum (reversible -- reversal code included) 6/15/98 mj 8/22/98 mj 8/31/98 mj 9/21/98 mj 2/4/99 mj */ #include "cbckey.h" #ifndef SHCLASS #define SHCLASS #endif // // C version // #define WORDSWAP(d) \ ((d >> 16) + (d << 16)) // pairwise independent function and summing step #define C_STEP(L1, L2, L3, L4, L5, L6) \ t += *Data++; \ t *= L1; \ t = WORDSWAP(t); \ t *= L2; \ t = WORDSWAP(t); \ t *= L3; \ t = WORDSWAP(t); \ t *= L4; \ t = WORDSWAP(t); \ t *= L5; \ t += L6; \ sum += t; // MAC function // returns half of 64-bit MAC, and places other half in *pKey2 UINT32 CBC64WS4_asm( UINT32 *Data, unsigned NumDWORDBlocks, UINT32 *pKey2, CBCKey key) { UINT32 sum = 0, t = 0; while (NumDWORDBlocks > 0) { C_STEP(key.a1, key.b1, key.c1, key.d1, key.e1, key.f1); C_STEP(key.a2, key.b2, key.c2, key.d2, key.e2, key.f2); NumDWORDBlocks -= 2; } *pKey2 = t; return sum; } // // inverse MAC // // compute gcd(a, b) = x*a + y*b static void egcd(UINT64 a, UINT64 b, __int64 &gcd, __int64 &x, __int64 &y) { if (b == 0) { gcd = a; x = 1; y = 1; } else { egcd(b, a % b, gcd, x, y); __int64 t = y; y = x - y*(a/b); x = t; } } // invert n mod 2^32 UINT32 inv32(UINT32 n) { __int64 gcd, in, x; __int64 modulus = (__int64)1<<32; egcd(modulus, n, gcd, x, in); while (in < 0) in += modulus; return (UINT32) in; } // step to reverse action of multiply-&-swap rounds #define INV_STEP_C(iL1, iL2, iL3, iL4, iL5) \ tmp *= iL5; \ tmp = WORDSWAP(tmp); \ tmp *= iL4; \ tmp = WORDSWAP(tmp); \ tmp *= iL3; \ tmp = WORDSWAP(tmp); \ tmp *= iL2; \ tmp = WORDSWAP(tmp); \ tmp *= iL1; // inverse MAC function // decrypts last two blocks of Data // (replaces 64-bit ciphertext Data[NumDWORDBlocks - 1] and Data[NumDWORDBlocks - 2] with // plaintext, and returns the plaintext in the return value and *pKey2 -- change as required) UINT32 InvCBC64WS4_asm( UINT32 *Data, unsigned NumDWORDBlocks, UINT32 *pKey2, CBCKey key, CBCKey ikey ) { UINT32 yn, yn1, yn2, xn, xn1; UINT32 sum32, tmp; // Invert last two blocks (sum and 32-bit MAC). This requires the encrypted last two // blocks and the (NumDWORDBlocks-2) plaintext blocks. sum32 = CBC64WS4_asm(Data, NumDWORDBlocks - 2, &yn2, key) + Data[NumDWORDBlocks - 1]; yn = Data[NumDWORDBlocks - 1]; yn1 = Data[NumDWORDBlocks - 2] - sum32; // last word tmp = yn - key.f2; INV_STEP_C(ikey.a2, ikey.b2, ikey.c2, ikey.d2, ikey.e2); xn = tmp - yn1; // next-to-last word tmp = yn1 - key.f1; INV_STEP_C(ikey.a1, ikey.b1, ikey.c1, ikey.d1, ikey.e1); xn1 = tmp - yn2; Data[NumDWORDBlocks - 2] = *pKey2 = (UINT32) xn1; Data[NumDWORDBlocks - 1] = (UINT32) xn; return (UINT32) xn; } void CBC64InitState( CBCState *cbcstate ) { cbcstate->sum = 0; cbcstate->t = 0; cbcstate->dwBufLen = 0; } void CBC64Init( CBCKey *cbckey, CBCState *cbcstate, BYTE *pKey ) { UINT32 *p; cbcstate->sum = 0; cbcstate->t = 0; cbcstate->dwBufLen = 0; p = (UINT32 *)pKey; cbckey->a1 = *p++ | 0x00000001; cbckey->b1 = *p++ | 0x00000001; cbckey->c1 = *p++ | 0x00000001; cbckey->d1 = *p++ | 0x00000001; cbckey->e1 = *p++ | 0x00000001; cbckey->f1 = *p++ | 0x00000001; cbckey->a2 = *p++ | 0x00000001; cbckey->b2 = *p++ | 0x00000001; cbckey->c2 = *p++ | 0x00000001; cbckey->d2 = *p++ | 0x00000001; cbckey->e2 = *p++ | 0x00000001; cbckey->f2 = *p++ | 0x00000001; } void CBC64InvKey( CBCKey *cbckey, CBCKey *cbcInvKey ) { cbcInvKey->a1 = inv32( cbckey->a1 ); cbcInvKey->a2 = inv32( cbckey->a2 ); cbcInvKey->b1 = inv32( cbckey->b1 ); cbcInvKey->b2 = inv32( cbckey->b2 ); cbcInvKey->c1 = inv32( cbckey->c1 ); cbcInvKey->c2 = inv32( cbckey->c2 ); cbcInvKey->d1 = inv32( cbckey->d1 ); cbcInvKey->d2 = inv32( cbckey->d2 ); cbcInvKey->e1 = inv32( cbckey->e1 ); cbcInvKey->e2 = inv32( cbckey->e2 ); cbcInvKey->f1 = inv32( cbckey->f1 ); cbcInvKey->f2 = inv32( cbckey->f2 ); } // pairwise independent function and summing step #define MP_C_STEP(Data,L1, L2, L3, L4, L5, L6) \ t += *Data++; \ t *= L1; \ t = WORDSWAP(t); \ t *= L2; \ t = WORDSWAP(t); \ t *= L3; \ t = WORDSWAP(t); \ t *= L4; \ t = WORDSWAP(t); \ t *= L5; \ t += L6; \ sum += t; void CBC64Update( CBCKey *key, CBCState *cbcstate,DWORD dwLen, BYTE *pData ) { DWORD i, copylen=0, tmp; DWORD *p; UINT32 sum,t; sum = cbcstate->sum; t = cbcstate->t; if ( cbcstate->dwBufLen > 0 ) { copylen = min( dwLen, 8 - cbcstate->dwBufLen ); for ( i=0; ibuf[ cbcstate->dwBufLen + i ] = pData[i]; cbcstate->dwBufLen += copylen; if ( cbcstate->dwBufLen == 8 ) { p = (DWORD *)cbcstate->buf; MP_C_STEP( p, key->a1, key->b1, key->c1, key->d1, key->e1, key->f1 ); MP_C_STEP( p, key->a2, key->b2, key->c2, key->d2, key->e2, key->f2 ); cbcstate->dwBufLen = 0; } } tmp = (dwLen - copylen) / 8; p = (DWORD *)(pData + copylen); #ifndef WIN32 #define ARMBUG #endif #ifndef ARMBUG while (tmp > 0) { MP_C_STEP( p, key->a1, key->b1, key->c1, key->d1, key->e1, key->f1); MP_C_STEP( p, key->a2, key->b2, key->c2, key->d2, key->e2, key->f2); tmp--; } #else DWORD AllignedDWORD( DWORD * ); DWORD *q; while (tmp > 0) { q = (DWORD *)cbcstate->buf; *q = AllignedDWORD( p++ ); MP_C_STEP( q, key->a1, key->b1, key->c1, key->d1, key->e1, key->f1); *q = AllignedDWORD( p++ ); MP_C_STEP( q, key->a2, key->b2, key->c2, key->d2, key->e2, key->f2); tmp--; } #endif tmp = copylen + ((dwLen-copylen) / 8) * 8; if ( tmp < dwLen ) { for ( i=tmp; ibuf[ i - tmp ] = pData[i]; cbcstate->dwBufLen = dwLen - tmp; } cbcstate->sum = sum; cbcstate->t = t; } UINT32 CBC64Finalize( CBCKey *key, CBCState *cbcstate, UINT32 *pKey2 ) { DWORD i, *p; UINT32 sum,t; if ( cbcstate->dwBufLen > 0 ) { for ( i=cbcstate->dwBufLen; i<8; i++ ) cbcstate->buf[ i ] = 0; sum = cbcstate->sum; t = cbcstate->t; p = (DWORD *)cbcstate->buf; MP_C_STEP( p, key->a1, key->b1, key->c1, key->d1, key->e1, key->f1 ); MP_C_STEP( p, key->a2, key->b2, key->c2, key->d2, key->e2, key->f2 ); cbcstate->dwBufLen = 0; cbcstate->sum = sum; cbcstate->t = t; } *pKey2 = cbcstate->t; return cbcstate->sum; } UINT32 CBC64Invert( CBCKey *key, CBCKey *ikey, UINT32 MacA1, UINT32 MacA2, UINT32 MacB1, UINT32 MacB2, UINT32 *pInvKey2 ) { UINT32 tmp; UINT32 yn, yn1, xn, xn1; MacA1 += MacB2; yn = MacB2; yn1 = MacB1 - MacA1; // last word tmp = yn - key->f2; INV_STEP_C(ikey->a2, ikey->b2, ikey->c2, ikey->d2, ikey->e2); xn = tmp - yn1; // next-to-last word tmp = yn1 - key->f1; INV_STEP_C(ikey->a1, ikey->b1, ikey->c1, ikey->d1, ikey->e1); xn1 = tmp - MacA2; *pInvKey2 = (UINT32) xn1; return (UINT32) xn; }