cilj mi je da u C-u uradim MAC CBC, i treba mi pomoć oko razumevanja kako se to radi.
Proučavao sam kod iz openssl-a, ali rezultat se ne podudara sa rezultatom dobijenim u javi
Java kod koji radi:
Code (java):
public class MacCBC {
private Mac mac = null;
public MacCBC(){
BouncyCastleProvider prov = new BouncyCastleProvider();
Security.addProvider(prov);
BlockCipher cipher = new DESedeEngine();
mac = new CBCBlockCipherMac(cipher);
}
public byte[] hashIt(byte data[], byte key[], byte iv[]) {
KeyParameter keyP = new KeyParameter(key);
ParametersWithIV param = new ParametersWithIV(keyP, iv);
mac.init(param);
mac.update(data, 0, data.length);
byte out[] = new byte[4];
mac.doFinal(out, 0);
return out;
}
}
public class MacCBC {
private Mac mac = null;
public MacCBC(){
BouncyCastleProvider prov = new BouncyCastleProvider();
Security.addProvider(prov);
BlockCipher cipher = new DESedeEngine();
mac = new CBCBlockCipherMac(cipher);
}
public byte[] hashIt(byte data[], byte key[], byte iv[]) {
KeyParameter keyP = new KeyParameter(key);
ParametersWithIV param = new ParametersWithIV(keyP, iv);
mac.init(param);
mac.update(data, 0, data.length);
byte out[] = new byte[4];
mac.doFinal(out, 0);
return out;
}
}
Kod iz openssl-a:
Code (c):
#define DES_LONG unsigned long
#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
*((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
*((c)++)=(unsigned char)(((l)>>16L)&0xff), \
*((c)++)=(unsigned char)(((l)>>24L)&0xff))
#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \
l|=((DES_LONG)(*((c)++)))<< 8L, \
l|=((DES_LONG)(*((c)++)))<<16L, \
l|=((DES_LONG)(*((c)++)))<<24L)
#define c2ln(c,l1,l2,n) { c+=n; l1=l2=0; \
switch (n) { \
case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \
case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \
case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \
case 5: l2|=((DES_LONG)(*(--(c)))); \
case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \
case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \
case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \
case 1: l1|=((DES_LONG)(*(--(c)))); \
} \
}
typedef unsigned char DES_cblock[8];
typedef /* const */ unsigned char const_DES_cblock[8];
typedef struct DES_ks
{
union
{
DES_cblock cblock;
/* make sure things are correct size on machines with
* 8 byte longs */
DES_LONG deslong[2];
} ks[16];
} DES_key_schedule;
long DES_cbc_cksum(const unsigned char *in, DES_cblock *output,
long length, DES_key_schedule *schedule,
const_DES_cblock *ivec) {
register long tout0,tout1,tin0,tin1;
register long l=length;
long tin[2];
unsigned char *out = &(*output)[0];
const unsigned char *iv = &(*ivec)[0];
c2l(iv,tout0); c2l(iv,tout1);
for (; l>0; l-=8) {
if (l >= 8) {
c2l(in,tin0); c2l(in,tin1);
} else
c2ln(in,tin0,tin1,l);
tin0^=tout0; tin[0]=tin0;
tin1^=tout1; tin[1]=tin1;
DES_encrypt1((long *)tin,schedule,DES_ENCRYPT); /////// OVDE?????
/* fix 15/10/91 eay - thanks to [email protected] */
tout0=tin[0]; tout1=tin[1];
}
if (out != NULL) {
l2c(tout0,out); l2c(tout1,out);
}
tout0=tin0=tin1=tin[0]=tin[1]=0;
/* Transform the data in tout1 so that it will
match the return value that the MIT Kerberos
mit_des_cbc_cksum API returns.
*/
tout1 = ((tout1 >> 24L) & 0x000000FF) | ((tout1 >> 8L) & 0x0000FF00)
| ((tout1 << 8L) & 0x00FF0000) | ((tout1 << 24L) & 0xFF000000);
return(tout1);
}
#define DES_LONG unsigned long
#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
*((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
*((c)++)=(unsigned char)(((l)>>16L)&0xff), \
*((c)++)=(unsigned char)(((l)>>24L)&0xff))
#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \
l|=((DES_LONG)(*((c)++)))<< 8L, \
l|=((DES_LONG)(*((c)++)))<<16L, \
l|=((DES_LONG)(*((c)++)))<<24L)
#define c2ln(c,l1,l2,n) { c+=n; l1=l2=0; \
switch (n) { \
case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \
case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \
case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \
case 5: l2|=((DES_LONG)(*(--(c)))); \
case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \
case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \
case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \
case 1: l1|=((DES_LONG)(*(--(c)))); \
} \
}
typedef unsigned char DES_cblock[8];
typedef /* const */ unsigned char const_DES_cblock[8];
typedef struct DES_ks
{
union
{
DES_cblock cblock;
/* make sure things are correct size on machines with
* 8 byte longs */
DES_LONG deslong[2];
} ks[16];
} DES_key_schedule;
long DES_cbc_cksum(const unsigned char *in, DES_cblock *output,
long length, DES_key_schedule *schedule,
const_DES_cblock *ivec) {
register long tout0,tout1,tin0,tin1;
register long l=length;
long tin[2];
unsigned char *out = &(*output)[0];
const unsigned char *iv = &(*ivec)[0];
c2l(iv,tout0); c2l(iv,tout1);
for (; l>0; l-=8) {
if (l >= 8) {
c2l(in,tin0); c2l(in,tin1);
} else
c2ln(in,tin0,tin1,l);
tin0^=tout0; tin[0]=tin0;
tin1^=tout1; tin[1]=tin1;
DES_encrypt1((long *)tin,schedule,DES_ENCRYPT); /////// OVDE?????
/* fix 15/10/91 eay - thanks to [email protected] */
tout0=tin[0]; tout1=tin[1];
}
if (out != NULL) {
l2c(tout0,out); l2c(tout1,out);
}
tout0=tin0=tin1=tin[0]=tin[1]=0;
/* Transform the data in tout1 so that it will
match the return value that the MIT Kerberos
mit_des_cbc_cksum API returns.
*/
tout1 = ((tout1 >> 24L) & 0x000000FF) | ((tout1 >> 8L) & 0x0000FF00)
| ((tout1 << 8L) & 0x00FF0000) | ((tout1 << 24L) & 0xFF000000);
return(tout1);
}
Dakle ono što sam do sad shvatio:
- poruka se deli na po 8 bajta, delovi se obrađuju i kriptuju
- pošto je krajnji rezultat 8 bajta, za rezultat se uzimaju poslednja 4 bajta
Ono što ne znam je, da li umesto DES_encrypt1 (nisam siguran ni koji je to tačno algoritam) treba da stavim 3des cbc i da IV koji dobijem tokom obrade treba da iskoristim za sledeću obradu, tj. da ne resetujem na nulu.
Ili je možda ovaj C kod potpuno pogrešan....