void blowfish_key_setup(const BYTE user_key[], BLOWFISH_KEY *keystruct, size_t len) { BYTE block[8]; int idx,idx2; // Copy over the constant init array vals (so the originals aren't destroyed). memcpy(keystruct->p,p_perm,sizeof(WORD) * 18); memcpy(keystruct->s,s_perm,sizeof(WORD) * 1024); // Combine the key with the P box. Assume key is standard 448 bits (56 bytes) or less. for (idx = 0, idx2 = 0; idx < 18; ++idx, idx2 += 4) keystruct->p[idx] ^= (user_key[idx2 % len] << 24) | (user_key[(idx2+1) % len] << 16) | (user_key[(idx2+2) % len] << 8) | (user_key[(idx2+3) % len]); // Re-calculate the P box. memset(block, 0, 8); for (idx = 0; idx < 18; idx += 2) { blowfish_encrypt(block,block,keystruct); keystruct->p[idx] = (block[0] << 24) | (block[1] << 16) | (block[2] << 8) | block[3]; keystruct->p[idx+1]=(block[4] << 24) | (block[5] << 16) | (block[6] << 8) | block[7]; } // Recalculate the S-boxes. for (idx = 0; idx < 4; ++idx) { for (idx2 = 0; idx2 < 256; idx2 += 2) { blowfish_encrypt(block,block,keystruct); keystruct->s[idx][idx2] = (block[0] << 24) | (block[1] << 16) | (block[2] << 8) | block[3]; keystruct->s[idx][idx2+1] = (block[4] << 24) | (block[5] << 16) | (block[6] << 8) | block[7]; } } }
static void blowfish_setkey(BlowfishContext * ctx, const unsigned char *key, short keybytes) { word32 *S0 = ctx->S0; word32 *S1 = ctx->S1; word32 *S2 = ctx->S2; word32 *S3 = ctx->S3; word32 *P = ctx->P; word32 str[2]; int i; for (i = 0; i < 18; i++) { P[i] = parray[i]; P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 0) % keybytes])) << 24; P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 1) % keybytes])) << 16; P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 2) % keybytes])) << 8; P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 3) % keybytes])); } for (i = 0; i < 256; i++) { S0[i] = sbox0[i]; S1[i] = sbox1[i]; S2[i] = sbox2[i]; S3[i] = sbox3[i]; } str[0] = str[1] = 0; for (i = 0; i < 18; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); P[i] = str[0]; P[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); S0[i] = str[0]; S0[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); S1[i] = str[0]; S1[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); S2[i] = str[0]; S2[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); S3[i] = str[0]; S3[i + 1] = str[1]; } }
static void blowfish_lsb_encrypt_cbc(unsigned char *blk, int len, BlowfishContext * ctx) { word32 xL, xR, out[2], iv0, iv1; assert((len & 7) == 0); iv0 = ctx->iv0; iv1 = ctx->iv1; while (len > 0) { xL = GET_32BIT_LSB_FIRST(blk); xR = GET_32BIT_LSB_FIRST(blk + 4); iv0 ^= xL; iv1 ^= xR; blowfish_encrypt(iv0, iv1, out, ctx); iv0 = out[0]; iv1 = out[1]; PUT_32BIT_LSB_FIRST(blk, iv0); PUT_32BIT_LSB_FIRST(blk + 4, iv1); blk += 8; len -= 8; } ctx->iv0 = iv0; ctx->iv1 = iv1; }
void blowfish_encrypt_cbc(uint8 *blk, int len, BlowfishContext *ctx) { uint32 xL, xR, out[2], iv0, iv1; Assert((len & 7) == 0); iv0 = ctx->iv0; iv1 = ctx->iv1; while (len > 0) { xL = GET_32BIT_MSB_FIRST(blk); xR = GET_32BIT_MSB_FIRST(blk + 4); iv0 ^= xL; iv1 ^= xR; blowfish_encrypt(iv0, iv1, out, ctx); iv0 = out[0]; iv1 = out[1]; PUT_32BIT_MSB_FIRST(blk, iv0); PUT_32BIT_MSB_FIRST(blk + 4, iv1); blk += 8; len -= 8; } ctx->iv0 = iv0; ctx->iv1 = iv1; }
static void blowfish_msb_sdctr(unsigned char *blk, int len, BlowfishContext * ctx) { word32 b[2], iv0, iv1, tmp; assert((len & 7) == 0); iv0 = ctx->iv0; iv1 = ctx->iv1; while (len > 0) { blowfish_encrypt(iv0, iv1, b, ctx); tmp = GET_32BIT_MSB_FIRST(blk); PUT_32BIT_MSB_FIRST(blk, tmp ^ b[0]); tmp = GET_32BIT_MSB_FIRST(blk + 4); PUT_32BIT_MSB_FIRST(blk + 4, tmp ^ b[1]); if ((iv1 = (iv1 + 1) & 0xffffffff) == 0) iv0 = (iv0 + 1) & 0xffffffff; blk += 8; len -= 8; } ctx->iv0 = iv0; ctx->iv1 = iv1; }
DECLARE_TEST(blowfish, random_data) { uint64_t plaintext[2][1024]; uint64_t keytext[32]; unsigned int i, j; blowfish_t* blowfish; uint64_t init_vector; blowfish = blowfish_allocate(); for (i = 0; i < 1024; ++i) { for (j = 0; j < 32; ++j) keytext[j] = random64(); for (j = 0; j < 1024; ++j) { plaintext[0][j] = random64(); plaintext[1][j] = plaintext[0][j]; } init_vector = random64(); blowfish_initialize(blowfish, keytext, random32_range(1, 32 * 8)); blowfish_encrypt(blowfish, plaintext[0], 1024 * 8, BLOCKCIPHER_ECB, init_vector); blowfish_decrypt(blowfish, plaintext[0], 1024 * 8, BLOCKCIPHER_ECB, init_vector); EXPECT_EQ(memcmp(plaintext[0], plaintext[1], 1024 * 8), 0); blowfish_encrypt(blowfish, plaintext[0], 1024 * 8, BLOCKCIPHER_CBC, init_vector); blowfish_decrypt(blowfish, plaintext[0], 1024 * 8, BLOCKCIPHER_CBC, init_vector); EXPECT_EQ(memcmp(plaintext[0], plaintext[1], 1024 * 8), 0); blowfish_encrypt(blowfish, plaintext[0], 1024 * 8, BLOCKCIPHER_CFB, init_vector); blowfish_decrypt(blowfish, plaintext[0], 1024 * 8, BLOCKCIPHER_CFB, init_vector); EXPECT_EQ(memcmp(plaintext[0], plaintext[1], 1024 * 8), 0); blowfish_encrypt(blowfish, plaintext[0], 1024 * 8, BLOCKCIPHER_OFB, init_vector); blowfish_decrypt(blowfish, plaintext[0], 1024 * 8, BLOCKCIPHER_OFB, init_vector); EXPECT_EQ(memcmp(plaintext[0], plaintext[1], 1024 * 8), 0); } blowfish_deallocate(blowfish); return 0; }
DECLARE_TEST(blowfish, known_data) { unsigned char plaintext[2][NUM_VARIABLEKEYTESTS * 8]; unsigned int i; blowfish_t* blowfish; uint64_t init_vector = 0x54A23F87BE3147C3; blowfish = blowfish_allocate(); for (i = 0; i < NUM_VARIABLEKEYTESTS; ++i) { memcpy(&plaintext[0][(8 * i) + 0 ], &_test_plaintext_left[i], 4); memcpy(&plaintext[0][(8 * i) + 4 ], &_test_plaintext_right[i], 4); } memcpy(plaintext[1], plaintext[0], NUM_VARIABLEKEYTESTS * 8); for (i = 0; i < NUM_VARIABLEKEYTESTS; ++i) { blowfish_initialize(blowfish, _test_key_variable[i], 8); //Add some unalignment to size of buffer to test re-alignment in implementation blowfish_encrypt(blowfish, plaintext[0], 1 + NUM_VARIABLEKEYTESTS * 8, BLOCKCIPHER_ECB, init_vector); blowfish_decrypt(blowfish, plaintext[0], 2 + NUM_VARIABLEKEYTESTS * 8, BLOCKCIPHER_ECB, init_vector); EXPECT_EQ(memcmp(plaintext[0], plaintext[1], NUM_VARIABLEKEYTESTS * 8), 0); blowfish_encrypt(blowfish, plaintext[0], 3 + NUM_VARIABLEKEYTESTS * 8, BLOCKCIPHER_CBC, init_vector); blowfish_decrypt(blowfish, plaintext[0], 4 + NUM_VARIABLEKEYTESTS * 8, BLOCKCIPHER_CBC, init_vector); EXPECT_EQ(memcmp(plaintext[0], plaintext[1], NUM_VARIABLEKEYTESTS * 8), 0); blowfish_encrypt(blowfish, plaintext[0], 5 + NUM_VARIABLEKEYTESTS * 8, BLOCKCIPHER_CFB, init_vector); blowfish_decrypt(blowfish, plaintext[0], 6 + NUM_VARIABLEKEYTESTS * 8, BLOCKCIPHER_CFB, init_vector); EXPECT_EQ(memcmp(plaintext[0], plaintext[1], NUM_VARIABLEKEYTESTS * 8), 0); blowfish_encrypt(blowfish, plaintext[0], 7 + NUM_VARIABLEKEYTESTS * 8, BLOCKCIPHER_OFB, init_vector); blowfish_decrypt(blowfish, plaintext[0], NUM_VARIABLEKEYTESTS * 8, BLOCKCIPHER_OFB, init_vector); EXPECT_EQ(memcmp(plaintext[0], plaintext[1], NUM_VARIABLEKEYTESTS * 8), 0); init_vector *= (uintptr_t)blowfish; } blowfish_deallocate(blowfish); return 0; }
/*********************** FUNCTION DEFINITIONS ***********************/ int blowfish_test(void) { BYTE key1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; BYTE key2[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; BYTE key3[24] = {0xF0,0xE1,0xD2,0xC3,0xB4,0xA5,0x96,0x87, 0x78,0x69,0x5A,0x4B,0x3C,0x2D,0x1E,0x0F, 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}; BYTE p1[BLOWFISH_BLOCK_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; BYTE p2[BLOWFISH_BLOCK_SIZE] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; BYTE p3[BLOWFISH_BLOCK_SIZE] = {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10}; BYTE c1[BLOWFISH_BLOCK_SIZE] = {0x4e,0xf9,0x97,0x45,0x61,0x98,0xdd,0x78}; BYTE c2[BLOWFISH_BLOCK_SIZE] = {0x51,0x86,0x6f,0xd5,0xb8,0x5e,0xcb,0x8a}; BYTE c3[BLOWFISH_BLOCK_SIZE] = {0x05,0x04,0x4b,0x62,0xfa,0x52,0xd0,0x80}; BYTE enc_buf[BLOWFISH_BLOCK_SIZE]; BLOWFISH_KEY key; int pass = 1; // Test vector 1. blowfish_key_setup(key1, &key, BLOWFISH_BLOCK_SIZE); blowfish_encrypt(p1, enc_buf, &key); pass = pass && !memcmp(c1, enc_buf, BLOWFISH_BLOCK_SIZE); blowfish_decrypt(c1, enc_buf, &key); pass = pass && !memcmp(p1, enc_buf, BLOWFISH_BLOCK_SIZE); // Test vector 2. blowfish_key_setup(key2, &key, BLOWFISH_BLOCK_SIZE); blowfish_encrypt(p2, enc_buf, &key); pass = pass && !memcmp(c2, enc_buf, BLOWFISH_BLOCK_SIZE); blowfish_decrypt(c2, enc_buf, &key); pass = pass && !memcmp(p2, enc_buf, BLOWFISH_BLOCK_SIZE); // Test vector 3. blowfish_key_setup(key3, &key, 24); blowfish_encrypt(p3, enc_buf, &key); pass = pass && !memcmp(c3, enc_buf, BLOWFISH_BLOCK_SIZE); blowfish_decrypt(c3, enc_buf, &key); pass = pass && !memcmp(p3, enc_buf, BLOWFISH_BLOCK_SIZE); return(pass); }
void BLOWFISH_Base::generatePAndSBoxes(const unsigned char* key, size_t keySize, uint32_t* p, uint32_t* sboxes) { for (size_t i = 0 ; i < 4 * 256; ++i) sboxes[i] = Init_SBoxes[i]; for (size_t i = 0, j = 0; i < 18; ++i) { uint32_t data = 0x00000000; for (size_t k = 0; k < 4; ++k) { data = (data << 8) | (uint32_t)key[j]; ++j; if (j >= keySize) j = 0; } p[i] = Init_P[i] ^ data; } uint32_t l = 0x00000000; uint32_t r = 0x00000000; for (size_t i = 0 ; i < 18 ; i += 2) { blowfish_encrypt(l, r, p, sboxes); p[i] = l; p[i + 1] = r; } for (size_t i = 0 ; i < 4 ; ++i) { for (size_t j = 0 ; j < 256; j += 2) { blowfish_encrypt(l, r, p, sboxes); sboxes[i * 256 + j] = l; sboxes[i * 256 + j + 1] = r; } } }
// Perform the key schedule for BlowFish32. This is esentially the encryption of // a zero-block and using the result for successive values of the P and S // subkeys until all subkeys have been filled out. The initial P keys are seeded // with the key obtained from the user. void blowfish_keygen() { size_t idx; // Initial block to encrypt int32_t block = 0x00000000; // XOR the key with the P subkey to get the first permutation for (idx = 0; idx < 18; idx++) { arr_p[idx] = arr_p[idx] ^ arr_key[idx]; } // Complete the generation of the P subkey for (idx = 0; idx < 18; idx += 2) { block = blowfish_encrypt(block); arr_p[idx+0] = BIT16_HI(block); arr_p[idx+1] = BIT16_LO(block); } // Complete the generation of the S subkeys size_t sidx; for (sidx = 0; sidx < 4; sidx++) { uint16_t* arr_sx = NULL; switch (sidx) { case 0: arr_sx = arr_s1; break; case 1: arr_sx = arr_s2; break; case 2: arr_sx = arr_s3; break; case 3: arr_sx = arr_s4; break; } for (idx = 0; idx < 16; idx += 2) { block = blowfish_encrypt(block); arr_sx[idx+0] = BIT16_HI(block); arr_sx[idx+1] = BIT16_LO(block); } } }
void blowfish_lsb_encrypt_ecb(unsigned char *blk, int len, BlowfishContext * ctx) { word32 xL, xR, out[2]; assert((len & 7) == 0); while (len > 0) { xL = GET_32BIT_LSB_FIRST(blk); xR = GET_32BIT_LSB_FIRST(blk + 4); blowfish_encrypt(xL, xR, out, ctx); PUT_32BIT_LSB_FIRST(blk, out[0]); PUT_32BIT_LSB_FIRST(blk + 4, out[1]); blk += 8; len -= 8; } }
void blowfish_encrypt_ecb(uint8 *blk, int len, BlowfishContext *ctx) { uint32 xL, xR, out[2]; Assert((len & 7) == 0); while (len > 0) { xL = GET_32BIT_MSB_FIRST(blk); xR = GET_32BIT_MSB_FIRST(blk + 4); blowfish_encrypt(xL, xR, out, ctx); PUT_32BIT_MSB_FIRST(blk, out[0]); PUT_32BIT_MSB_FIRST(blk + 4, out[1]); blk += 8; len -= 8; } }
int main(int argc, char *argv[]) { int i; struct blowfish_context *ctx; uint32_t tmp[2]; ctx = blowfish_context_new(); blowfish_set_p(ctx, newP); blowfish_set_key(ctx, (unsigned char*) "TESTKEY", 7); printf("\nbefore encr = "); for (i = 0; i < 8; i++) printf("%x.",((unsigned char*) var)[i]); memcpy(tmp, var, sizeof(var)); blowfish_encrypt(ctx, (uint32_t*) var); printf("\nafter encr = "); for (i = 0; i < 8; i++) printf("%x.",((unsigned char*) var)[i]); blowfish_decrypt(ctx,(uint32_t*) var); printf("\nafter decr = "); for (i = 0; i < 8; i++) printf("%x.",((unsigned char*) var)[i]); printf("\n"); if (strncmp((char*)tmp, (char*)var, sizeof(var))) printf("%s%s", "\n===================================", "\ntest failed!!!!!!!!!!\n\n===================================\n"); else printf("%s%s", "\n===================================", "\nTEST PASSED\n\n===================================\n"); return 0; }
IoObject *IoBlowfish_process(IoBlowfish *self, IoObject *locals, IoMessage *m) { /*doc Blowfish process Process the inputBuffer and appends the result to the outputBuffer. The processed inputBuffer is empties except for the spare bytes at the end which don't fit into a cipher block. */ blowfish_ctx *context = &(DATA(self)->context); int isEncrypting = DATA(self)->isEncrypting; UArray *input = IoObject_rawGetMutableUArraySlot(self, locals, m, IOSYMBOL("inputBuffer")); UArray *output = IoObject_rawGetMutableUArraySlot(self, locals, m, IOSYMBOL("outputBuffer")); const unsigned char *inputBytes = (uint8_t *)UArray_bytes(input); size_t inputSize = UArray_sizeInBytes(input); unsigned long lr[2]; size_t i, runs = inputSize / sizeof(lr); for (i = 0; i < runs; i ++) { memcpy(lr, inputBytes, sizeof(lr)); inputBytes += sizeof(lr); if (isEncrypting) { blowfish_encrypt(context, &lr[0], &lr[1]); } else { blowfish_decrypt(context, &lr[0], &lr[1]); } UArray_appendBytes_size_(output, (unsigned char *)&lr, sizeof(lr)); } UArray_removeRange(input, 0, runs * sizeof(lr)); return self; }
IoObject *IoBlowfish_endProcessing(IoBlowfish *self, IoObject *locals, IoMessage *m) { /*doc Blowfish endProcessing Finish processing remaining bytes of inputBuffer. */ blowfish_ctx *context = &(DATA(self)->context); unsigned long lr[2]; IoBlowfish_process(self, locals, m); // process the full blocks first { int isEncrypting = DATA(self)->isEncrypting; UArray *input = IoObject_rawGetMutableUArraySlot(self, locals, m, IOSYMBOL("inputBuffer")); UArray *output = IoObject_rawGetMutableUArraySlot(self, locals, m, IOSYMBOL("outputBuffer")); IOASSERT(UArray_sizeInBytes(input) < sizeof(lr), "internal error - too many bytes left in inputBuffer"); memset(lr, 0, sizeof(lr)); memcpy(lr, (uint8_t *)UArray_bytes(input), UArray_sizeInBytes(input)); if (isEncrypting) { blowfish_encrypt(context, &lr[0], &lr[1]); } else { blowfish_decrypt(context, &lr[0], &lr[1]); } UArray_appendBytes_size_(output, (unsigned char *)&lr, sizeof(lr)); UArray_setSize_(input, 0); } return self; }
void blowfish_setkey(BlowfishContext *ctx, const uint8 *key, short keybytes) { uint32 *S0 = ctx->S0; uint32 *S1 = ctx->S1; uint32 *S2 = ctx->S2; uint32 *S3 = ctx->S3; uint32 *P = ctx->P; uint32 str[2]; int i; Assert(keybytes > 0 && keybytes <= (448 / 8)); for (i = 0; i < 18; i++) { P[i] = parray[i]; P[i] ^= ((uint32) key[(i * 4 + 0) % keybytes]) << 24; P[i] ^= ((uint32) key[(i * 4 + 1) % keybytes]) << 16; P[i] ^= ((uint32) key[(i * 4 + 2) % keybytes]) << 8; P[i] ^= ((uint32) key[(i * 4 + 3) % keybytes]); } for (i = 0; i < 256; i++) { S0[i] = sbox0[i]; S1[i] = sbox1[i]; S2[i] = sbox2[i]; S3[i] = sbox3[i]; } str[0] = str[1] = 0; for (i = 0; i < 18; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); P[i] = str[0]; P[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); S0[i] = str[0]; S0[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); S1[i] = str[0]; S1[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); S2[i] = str[0]; S2[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { blowfish_encrypt(str[0], str[1], str, ctx); S3[i] = str[0]; S3[i + 1] = str[1]; } }
void blowfish_expandkey(BlowfishContext * ctx, const unsigned char *key, short keybytes, const unsigned char *salt, short saltbytes) { word32 *S0 = ctx->S0; word32 *S1 = ctx->S1; word32 *S2 = ctx->S2; word32 *S3 = ctx->S3; word32 *P = ctx->P; word32 str[2]; int i, j; int saltpos; unsigned char dummysalt[1]; saltpos = 0; if (!salt) { saltbytes = 1; salt = dummysalt; dummysalt[0] = 0; } for (i = 0; i < 18; i++) { P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 0) % keybytes])) << 24; P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 1) % keybytes])) << 16; P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 2) % keybytes])) << 8; P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 3) % keybytes])); } str[0] = str[1] = 0; for (i = 0; i < 18; i += 2) { for (j = 0; j < 8; j++) str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); P[i] = str[0]; P[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { for (j = 0; j < 8; j++) str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); S0[i] = str[0]; S0[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { for (j = 0; j < 8; j++) str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); S1[i] = str[0]; S1[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { for (j = 0; j < 8; j++) str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); S2[i] = str[0]; S2[i + 1] = str[1]; } for (i = 0; i < 256; i += 2) { for (j = 0; j < 8; j++) str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4)); blowfish_encrypt(str[0], str[1], str, ctx); S3[i] = str[0]; S3[i + 1] = str[1]; } }