[ GORSHTAK @ 08.06.2013. 01:08 ] @
Zdravo,
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;
    }
}
 


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 keithr@sco.COM */
          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....