Crypt-Twofish2

 view release on metacpan or  search on metacpan

twofish.c  view on Meta::CPAN

*
* Function Name:    makeKey
*
* Function:         Initialize the Twofish key schedule
*
* Arguments:        key         =   ptr to keyInstance to be initialized
*                   direction   =   DIR_ENCRYPT or DIR_DECRYPT
*                   keyLen      =   # bits of key text at *keyMaterial
*                   keyMaterial =   ptr to hex ASCII chars representing key bits
*
* Return:           TRUE on success
*                   else error code (e.g., BAD_KEY_DIR)
*
* Notes:    This parses the key bits from keyMaterial.  Zeroes out unused key bits
*
-****************************************************************************/
static int makeKey(keyInstance *key, BYTE direction, int keyLen,CONST char *keyMaterial)
    {
    int i;

#if VALIDATE_PARMS              /* first, sanity check on parameters */
    if (key == NULL)
        return BAD_KEY_INSTANCE;/* must have a keyInstance to initialize */
    if ((direction != DIR_ENCRYPT) && (direction != DIR_DECRYPT))
        return BAD_KEY_DIR;     /* must have valid direction */
    if ((keyLen > MAX_KEY_BITS) || (keyLen < 8) || (keyLen & 0x3F))
        return BAD_KEY_MAT;     /* length must be valid */
    key->keySig = VALID_SIG;    /* show that we are initialized */
  #if ALIGN32
    if ((((int)key) & 3) || (((int)key->key32) & 3))
        return BAD_ALIGN32;
  #endif
#endif

    key->direction  = direction;/* set our cipher direction */
    key->keyLen     = (keyLen+63) & ~63;        /* round up to multiple of 64 */
    key->numRounds  = numRounds[(keyLen-1)/64];
    memset(key->key32,0,sizeof(key->key32));    /* zero unused bits */

    if (keyMaterial == NULL)
        return TRUE;            /* allow a "dummy" call */

    for (i=0;i<keyLen/32;i++)   /* make byte-oriented copy for CFB1 */
        key->key32[i] = (((unsigned char *)keyMaterial)[i*4+0] <<  0)
                      | (((unsigned char *)keyMaterial)[i*4+1] <<  8)
                      | (((unsigned char *)keyMaterial)[i*4+2] << 16)
                      | (((unsigned char *)keyMaterial)[i*4+3] << 24);

    return reKey(key);          /* generate round subkeys */
    }


/*
+*****************************************************************************
*
* Function Name:    cipherInit
*
* Function:         Initialize the Twofish cipher in a given mode
*
* Arguments:        cipher      =   ptr to cipherInstance to be initialized
*                   mode        =   MODE_ECB, MODE_CBC, or MODE_CFB1
*                   IV          =   ptr to hex ASCII test representing IV bytes
*
* Return:           TRUE on success
*                   else error code (e.g., BAD_CIPHER_MODE)
*
-****************************************************************************/
static int cipherInit(cipherInstance *cipher, BYTE mode,CONST char *IV)
    {
    int i;
#if VALIDATE_PARMS              /* first, sanity check on parameters */
    if (cipher == NULL)
        return BAD_PARAMS;      /* must have a cipherInstance to initialize */
    if ((mode != MODE_ECB) && (mode != MODE_CBC) && (mode != MODE_CFB1))
        return BAD_CIPHER_MODE; /* must have valid cipher mode */
    cipher->cipherSig   =   VALID_SIG;
  #if ALIGN32
    if ((((int)cipher) & 3) || (((int)cipher->IV) & 3) || (((int)cipher->iv32) & 3))
        return BAD_ALIGN32;
  #endif
#endif

    if ((mode != MODE_ECB) && (IV)) /* parse the IV */
        {
            memcpy (cipher->iv32, IV, BLOCK_SIZE/32);
            for (i=0;i<BLOCK_SIZE/32;i++)   /* make byte-oriented copy for CFB1 */
                ((DWORD *)cipher->IV)[i] = Bswap(cipher->iv32[i]);
        }

    cipher->mode        =   mode;

    return TRUE;
    }

/*
+*****************************************************************************
*
* Function Name:    blockEncrypt
*
* Function:         Encrypt block(s) of data using Twofish
*
* Arguments:        cipher      =   ptr to already initialized cipherInstance
*                   key         =   ptr to already initialized keyInstance
*                   input       =   ptr to data blocks to be encrypted
*                   inputLen    =   # bits to encrypt (multiple of blockSize)
*                   outBuffer   =   ptr to where to put encrypted blocks
*
* Return:           # bits ciphered (>= 0)
*                   else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL)
*
* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits.
*        If inputLen is not a multiple of BLOCK_SIZE bits in those modes,
*        an error BAD_INPUT_LEN is returned.  In CFB1 mode, all block
*        sizes can be supported.
*
-****************************************************************************/
static int blockEncrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input,
                int inputLen, BYTE *outBuffer)
    {
    int   i,n;                      /* loop counters */
    DWORD x[BLOCK_SIZE/32];         /* block being encrypted */
    DWORD t0,t1;                    /* temp variables */
    int   rounds=key->numRounds;    /* number of rounds */
    BYTE  bit,bit0,ctBit,carry;     /* temps for CFB */

    /* make local copies of things for faster access */
    int   mode = cipher->mode;
    DWORD sk[TOTAL_SUBKEYS];
    DWORD IV[BLOCK_SIZE/32];

    GetSboxKey;

#if VALIDATE_PARMS
    if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG))
        return BAD_CIPHER_STATE;
    if ((key == NULL) || (key->keySig != VALID_SIG))
        return BAD_KEY_INSTANCE;
    if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1))
        return BAD_KEY_INSTANCE;
    if ((mode != MODE_CFB1) && (inputLen % BLOCK_SIZE))
        return BAD_INPUT_LEN;
  #if ALIGN32
    if ( (((int)cipher) & 3) || (((int)key      ) & 3) ||
         (((int)input ) & 3) || (((int)outBuffer) & 3))
        return BAD_ALIGN32;
  #endif
#endif

    if (mode == MODE_CFB1)
        {   /* use recursion here to handle CFB, one block at a time */
        cipher->mode = MODE_ECB;    /* do encryption in ECB */
        for (n=0;n<inputLen;n++)
            {
            blockEncrypt(cipher,key,cipher->IV,BLOCK_SIZE,(BYTE *)x);
            bit0  = 0x80 >> (n & 7);/* which bit position in byte */
            ctBit = (input[n/8] & bit0) ^ ((((BYTE *) x)[0] & 0x80) >> (n&7));
            outBuffer[n/8] = (outBuffer[n/8] & ~ bit0) | ctBit;
            carry = ctBit >> (7 - (n&7));
            for (i=BLOCK_SIZE/8-1;i>=0;i--)
                {
                bit = cipher->IV[i] >> 7;   /* save next "carry" from shift */
                cipher->IV[i] = (cipher->IV[i] << 1) ^ carry;
                carry = bit;
                }
            }
        cipher->mode = MODE_CFB1;   /* restore mode for next time */
        return inputLen;
        }

    /* here for ECB, CBC modes */
    if (key->direction != DIR_ENCRYPT)
        ReverseRoundSubkeys(key,DIR_ENCRYPT);   /* reverse the round subkey order */

#ifdef USE_ASM
    if ((useAsm & 1) && (inputLen))
  #ifdef COMPILE_KEY
        if (key->keySig == VALID_SIG)
            return ((CipherProc *)(key->encryptFuncPtr))(cipher,key,input,inputLen,outBuffer);
  #else
        return (*blockEncrypt_86)(cipher,key,input,inputLen,outBuffer);
  #endif
#endif
    /* make local copy of subkeys for speed */
    memcpy(sk,key->subKeys,sizeof(DWORD)*(ROUND_SUBKEYS+2*rounds));
    if (mode == MODE_CBC)
        BlockCopy(IV,cipher->iv32)
    else
        IV[0]=IV[1]=IV[2]=IV[3]=0;

    for (n=0;n<inputLen;n+=BLOCK_SIZE,input+=BLOCK_SIZE/8,outBuffer+=BLOCK_SIZE/8)
        {
#define LoadBlockE(N)  x[N]=Bswap(((DWORD *)input)[N]) ^ sk[INPUT_WHITEN+N] ^ IV[N]
        LoadBlockE(0);  LoadBlockE(1);  LoadBlockE(2);  LoadBlockE(3);
#define EncryptRound(K,R,id)    \
            t0     = Fe32##id(x[K  ],0);                    \
            t1     = Fe32##id(x[K^1],3);                    \
            x[K^3] = ROL(x[K^3],1);                         \
            x[K^2]^= t0 +   t1 + sk[ROUND_SUBKEYS+2*(R)  ]; \
            x[K^3]^= t0 + 2*t1 + sk[ROUND_SUBKEYS+2*(R)+1]; \
            x[K^2] = ROR(x[K^2],1);
#define     Encrypt2(R,id)  { EncryptRound(0,R+1,id); EncryptRound(2,R,id); }

#if defined(ZERO_KEY)
        switch (key->keyLen)
            {
            case 128:
                for (i=rounds-2;i>=0;i-=2)
                    Encrypt2(i,_128);
                break;
            case 192:
                for (i=rounds-2;i>=0;i-=2)
                    Encrypt2(i,_192);
                break;
            case 256:
                for (i=rounds-2;i>=0;i-=2)
                    Encrypt2(i,_256);
                break;
            }
#else
        Encrypt2(14,_);
        Encrypt2(12,_);
        Encrypt2(10,_);
        Encrypt2( 8,_);
        Encrypt2( 6,_);
        Encrypt2( 4,_);
        Encrypt2( 2,_);
        Encrypt2( 0,_);
#endif

        /* need to do (or undo, depending on your point of view) final swap */
#if LittleEndian
#define StoreBlockE(N)  ((DWORD *)outBuffer)[N]=x[N^2] ^ sk[OUTPUT_WHITEN+N]
#else
#define StoreBlockE(N)  { t0=x[N^2] ^ sk[OUTPUT_WHITEN+N]; ((DWORD *)outBuffer)[N]=Bswap(t0); }
#endif
        StoreBlockE(0); StoreBlockE(1); StoreBlockE(2); StoreBlockE(3);
        if (mode == MODE_CBC)
            {
            IV[0]=Bswap(((DWORD *)outBuffer)[0]);
            IV[1]=Bswap(((DWORD *)outBuffer)[1]);
            IV[2]=Bswap(((DWORD *)outBuffer)[2]);
            IV[3]=Bswap(((DWORD *)outBuffer)[3]);
            }
        }

    if (mode == MODE_CBC)
        BlockCopy(cipher->iv32,IV);

    return inputLen;
    }

/*
+*****************************************************************************
*
* Function Name:    blockDecrypt
*
* Function:         Decrypt block(s) of data using Twofish
*
* Arguments:        cipher      =   ptr to already initialized cipherInstance
*                   key         =   ptr to already initialized keyInstance
*                   input       =   ptr to data blocks to be decrypted
*                   inputLen    =   # bits to encrypt (multiple of blockSize)
*                   outBuffer   =   ptr to where to put decrypted blocks
*
* Return:           # bits ciphered (>= 0)
*                   else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL)
*
* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits.
*        If inputLen is not a multiple of BLOCK_SIZE bits in those modes,
*        an error BAD_INPUT_LEN is returned.  In CFB1 mode, all block
*        sizes can be supported.
*
-****************************************************************************/
static int blockDecrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input,
                int inputLen, BYTE *outBuffer)
    {
    int   i,n;                      /* loop counters */
    DWORD x[BLOCK_SIZE/32];         /* block being encrypted */
    DWORD t0,t1;                    /* temp variables */
    int   rounds=key->numRounds;    /* number of rounds */
    BYTE  bit,bit0,ctBit,carry;     /* temps for CFB */

    /* make local copies of things for faster access */
    int   mode = cipher->mode;
    DWORD sk[TOTAL_SUBKEYS];
    DWORD IV[BLOCK_SIZE/32];

    GetSboxKey;

#if VALIDATE_PARMS
    if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG))
        return BAD_CIPHER_STATE;
    if ((key == NULL) || (key->keySig != VALID_SIG))
        return BAD_KEY_INSTANCE;
    if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1))
        return BAD_KEY_INSTANCE;
    if ((cipher->mode != MODE_CFB1) && (inputLen % BLOCK_SIZE))
        return BAD_INPUT_LEN;
  #if ALIGN32
    if ( (((int)cipher) & 3) || (((int)key      ) & 3) ||
         (((int)input)  & 3) || (((int)outBuffer) & 3))
        return BAD_ALIGN32;
  #endif
#endif

    if (cipher->mode == MODE_CFB1)
        {   /* use blockEncrypt here to handle CFB, one block at a time */
        cipher->mode = MODE_ECB;    /* do encryption in ECB */
        for (n=0;n<inputLen;n++)
            {
            blockEncrypt(cipher,key,cipher->IV,BLOCK_SIZE,(BYTE *)x);
            bit0  = 0x80 >> (n & 7);
            ctBit = input[n/8] & bit0;
            outBuffer[n/8] = (outBuffer[n/8] & ~ bit0) |
                             (ctBit ^ ((((BYTE *) x)[0] & 0x80) >> (n&7)));
            carry = ctBit >> (7 - (n&7));
            for (i=BLOCK_SIZE/8-1;i>=0;i--)
                {
                bit = cipher->IV[i] >> 7;   /* save next "carry" from shift */
                cipher->IV[i] = (cipher->IV[i] << 1) ^ carry;
                carry = bit;
                }
            }
        cipher->mode = MODE_CFB1;   /* restore mode for next time */
        return inputLen;
        }

    /* here for ECB, CBC modes */
    if (key->direction != DIR_DECRYPT)
        ReverseRoundSubkeys(key,DIR_DECRYPT);   /* reverse the round subkey order */
#ifdef USE_ASM
    if ((useAsm & 2) && (inputLen))
  #ifdef COMPILE_KEY
        if (key->keySig == VALID_SIG)
            return ((CipherProc *)(key->decryptFuncPtr))(cipher,key,input,inputLen,outBuffer);
  #else
        return (*blockDecrypt_86)(cipher,key,input,inputLen,outBuffer);
  #endif
#endif
    /* make local copy of subkeys for speed */
    memcpy(sk,key->subKeys,sizeof(DWORD)*(ROUND_SUBKEYS+2*rounds));
    if (mode == MODE_CBC)
        BlockCopy(IV,cipher->iv32)
    else
        IV[0]=IV[1]=IV[2]=IV[3]=0;

    for (n=0;n<inputLen;n+=BLOCK_SIZE,input+=BLOCK_SIZE/8,outBuffer+=BLOCK_SIZE/8)
        {
#define LoadBlockD(N) x[N^2]=Bswap(((DWORD *)input)[N]) ^ sk[OUTPUT_WHITEN+N]
        LoadBlockD(0);  LoadBlockD(1);  LoadBlockD(2);  LoadBlockD(3);

#define DecryptRound(K,R,id)                                \
            t0     = Fe32##id(x[K  ],0);                    \
            t1     = Fe32##id(x[K^1],3);                    \
            x[K^2] = ROL (x[K^2],1);                        \
            x[K^2]^= t0 +   t1 + sk[ROUND_SUBKEYS+2*(R)  ]; \
            x[K^3]^= t0 + 2*t1 + sk[ROUND_SUBKEYS+2*(R)+1]; \
            x[K^3] = ROR (x[K^3],1);

#define     Decrypt2(R,id)  { DecryptRound(2,R+1,id); DecryptRound(0,R,id); }

#if defined(ZERO_KEY)
        switch (key->keyLen)
            {
            case 128:
                for (i=rounds-2;i>=0;i-=2)
                    Decrypt2(i,_128);
                break;
            case 192:
                for (i=rounds-2;i>=0;i-=2)
                    Decrypt2(i,_192);
                break;
            case 256:
                for (i=rounds-2;i>=0;i-=2)
                    Decrypt2(i,_256);
                break;
            }
#else
        {
        Decrypt2(14,_);
        Decrypt2(12,_);
        Decrypt2(10,_);
        Decrypt2( 8,_);
        Decrypt2( 6,_);
        Decrypt2( 4,_);
        Decrypt2( 2,_);
        Decrypt2( 0,_);
        }
#endif
        if (cipher->mode == MODE_ECB)
            {
#if LittleEndian
#define StoreBlockD(N)  ((DWORD *)outBuffer)[N] = x[N] ^ sk[INPUT_WHITEN+N]
#else
#define StoreBlockD(N)  { t0=x[N]^sk[INPUT_WHITEN+N]; ((DWORD *)outBuffer)[N] = Bswap(t0); }
#endif
            StoreBlockD(0); StoreBlockD(1); StoreBlockD(2); StoreBlockD(3);
#undef  StoreBlockD
            continue;
            }
        else
            {
#define StoreBlockD(N)  x[N]   ^= sk[INPUT_WHITEN+N] ^ IV[N];   \
                        IV[N]   = Bswap(((DWORD *)input)[N]);   \
                        ((DWORD *)outBuffer)[N] = Bswap(x[N]);
            StoreBlockD(0); StoreBlockD(1); StoreBlockD(2); StoreBlockD(3);
#undef  StoreBlockD
            }
        }
    if (mode == MODE_CBC)   /* restore iv32 to cipher */
        BlockCopy(cipher->iv32,IV)

    return inputLen;
    }

#ifdef GetCodeSize
static DWORD TwofishCodeSize(void)
    {
    DWORD x= Here(0);
#ifdef USE_ASM
    if (useAsm & 3)
        return TwofishAsmCodeSize();
#endif
    return x - TwofishCodeStart();
    };
#endif



( run in 0.590 second using v1.01-cache-2.11-cpan-e1769b4cff6 )