You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
7.3 KiB
325 lines
7.3 KiB
#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; i<copylen; i++ )
|
|
cbcstate->buf[ 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; i<dwLen; i++ )
|
|
cbcstate->buf[ 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;
|
|
}
|