static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg, const char *key, char *buf) { int bs = alg->iv_size; char iv[bs], iv_old[bs]; struct crypt_cipher *cipher = NULL; int i, j, r; assert(bs == 2*sizeof(uint32_t)); r = crypt_cipher_init(&cipher, "blowfish", "ecb", &key[alg->key_offset], alg->key_size); if (r < 0) return r; memcpy(iv, &key[alg->iv_offset], alg->iv_size); for (i = 0; i < TCRYPT_HDR_LEN; i += bs) { memcpy(iv_old, &buf[i], bs); TCRYPT_swab_le(&buf[i]); r = crypt_cipher_decrypt(cipher, &buf[i], &buf[i], bs, NULL, 0); TCRYPT_swab_le(&buf[i]); if (r < 0) break; for (j = 0; j < bs; j++) buf[i + j] ^= iv[j]; memcpy(iv, iv_old, bs); } crypt_cipher_destroy(cipher); crypt_memzero(iv, bs); crypt_memzero(iv_old, bs); return r; }
/* * For chanined ciphers and CBC mode we need "outer" decryption. * Backend doesn't provide this, so implement it here directly using ECB. */ static int TCRYPT_decrypt_cbci(struct tcrypt_algs *ciphers, const char *key, struct tcrypt_phdr *hdr) { struct crypt_cipher *cipher[ciphers->chain_count]; unsigned int bs = ciphers->cipher[0].iv_size; char *buf = (char*)&hdr->e, iv[bs], iv_old[bs]; unsigned int i, j; int r = -EINVAL; TCRYPT_remove_whitening(buf, &key[8]); memcpy(iv, &key[ciphers->cipher[0].iv_offset], bs); /* Initialize all ciphers in chain in ECB mode */ for (j = 0; j < ciphers->chain_count; j++) cipher[j] = NULL; for (j = 0; j < ciphers->chain_count; j++) { r = crypt_cipher_init(&cipher[j], ciphers->cipher[j].name, "ecb", &key[ciphers->cipher[j].key_offset], ciphers->cipher[j].key_size); if (r < 0) goto out; } /* Implements CBC with chained ciphers in loop inside */ for (i = 0; i < TCRYPT_HDR_LEN; i += bs) { memcpy(iv_old, &buf[i], bs); for (j = ciphers->chain_count; j > 0; j--) { r = crypt_cipher_decrypt(cipher[j - 1], &buf[i], &buf[i], bs, NULL, 0); if (r < 0) goto out; } for (j = 0; j < bs; j++) buf[i + j] ^= iv[j]; memcpy(iv, iv_old, bs); } out: for (j = 0; j < ciphers->chain_count; j++) if (cipher[j]) crypt_cipher_destroy(cipher[j]); crypt_memzero(iv, bs); crypt_memzero(iv_old, bs); return r; }
static int TCRYPT_decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode, const char *key,struct tcrypt_phdr *hdr) { char backend_key[TCRYPT_HDR_KEY_LEN]; char iv[TCRYPT_HDR_IV_LEN] = {}; char mode_name[MAX_CIPHER_LEN]; struct crypt_cipher *cipher; char *c, *buf = (char*)&hdr->e; int r; /* Remove IV if present */ strncpy(mode_name, mode, MAX_CIPHER_LEN); c = strchr(mode_name, '-'); if (c) *c = '\0'; if (!strncmp(mode, "lrw", 3)) iv[alg->iv_size - 1] = 1; else if (!strncmp(mode, "cbc", 3)) { TCRYPT_remove_whitening(buf, &key[8]); if (!strcmp(alg->name, "blowfish_le")) return decrypt_blowfish_le_cbc(alg, key, buf); memcpy(iv, &key[alg->iv_offset], alg->iv_size); } TCRYPT_copy_key(alg, mode, backend_key, key); r = crypt_cipher_init(&cipher, alg->name, mode_name, backend_key, alg->key_size); if (!r) { r = crypt_cipher_decrypt(cipher, buf, buf, TCRYPT_HDR_LEN, iv, alg->iv_size); crypt_cipher_destroy(cipher); } crypt_memzero(backend_key, sizeof(backend_key)); crypt_memzero(iv, TCRYPT_HDR_IV_LEN); return r; }
static int cipher_perf_one(struct cipher_perf *cp, char *buf, size_t buf_size, int enc) { struct crypt_cipher *cipher = NULL; size_t done = 0, block = CIPHER_BLOCK_BYTES; int r; if (buf_size < block) block = buf_size; r = crypt_cipher_init(&cipher, cp->name, cp->mode, cp->key, cp->key_length); if (r < 0) { log_dbg("Cannot initialise cipher %s, mode %s.", cp->name, cp->mode); return r; } while (done < buf_size) { if ((done + block) > buf_size) block = buf_size - done; if (enc) r = crypt_cipher_encrypt(cipher, &buf[done], &buf[done], block, cp->iv, cp->iv_length); else r = crypt_cipher_decrypt(cipher, &buf[done], &buf[done], block, cp->iv, cp->iv_length); if (r < 0) break; done += block; } crypt_cipher_destroy(cipher); return r; }