int pgp_cfb_create(PGP_CFB **ctx_p, int algo, const uint8 *key, int key_len, int resync, uint8 *iv) { int res; PX_Cipher *ciph; PGP_CFB *ctx; res = pgp_load_cipher(algo, &ciph); if (res < 0) return res; res = px_cipher_init(ciph, key, key_len, NULL); if (res < 0) { px_cipher_free(ciph); return res; } ctx = px_alloc(sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx)); ctx->ciph = ciph; ctx->block_size = px_cipher_block_size(ciph); ctx->resync = resync; if (iv) memcpy(ctx->fr, iv, ctx->block_size); *ctx_p = ctx; return 0; }
static int combo_decrypt(PX_Combo *cx, const uint8 *data, unsigned dlen, uint8 *res, unsigned *rlen) { unsigned bs, i, pad; unsigned pad_ok; PX_Cipher *c = cx->cipher; /* decide whether zero-length input is allowed */ if (dlen == 0) { /* with padding, empty ciphertext is not allowed */ if (cx->padding) return PXE_DECRYPT_FAILED; /* without padding, report empty result */ *rlen = 0; return 0; } bs = px_cipher_block_size(c); if (bs > 1 && (dlen % bs) != 0) goto block_error; /* decrypt */ *rlen = dlen; px_cipher_decrypt(c, data, dlen, res); /* unpad */ if (bs > 1 && cx->padding) { pad = res[*rlen - 1]; pad_ok = 0; if (pad > 0 && pad <= bs && pad <= *rlen) { pad_ok = 1; for (i = *rlen - pad; i < *rlen; i++) if (res[i] != pad) { pad_ok = 0; break; } } if (pad_ok) *rlen -= pad; } return 0; block_error: return PXE_NOTBLOCKSIZE; }
static int combo_init(PX_Combo *cx, const uint8 *key, unsigned klen, const uint8 *iv, unsigned ivlen) { int err; unsigned bs, ks, ivs; PX_Cipher *c = cx->cipher; uint8 *ivbuf = NULL; uint8 *keybuf; bs = px_cipher_block_size(c); ks = px_cipher_key_size(c); ivs = px_cipher_iv_size(c); if (ivs > 0) { ivbuf = px_alloc(ivs); memset(ivbuf, 0, ivs); if (ivlen > ivs) memcpy(ivbuf, iv, ivs); else memcpy(ivbuf, iv, ivlen); } if (klen > ks) klen = ks; keybuf = px_alloc(ks); memset(keybuf, 0, ks); memcpy(keybuf, key, klen); err = px_cipher_init(c, keybuf, klen, ivbuf); if (ivbuf) px_free(ivbuf); px_free(keybuf); return err; }
static int combo_encrypt(PX_Combo *cx, const uint8 *data, unsigned dlen, uint8 *res, unsigned *rlen) { int err = 0; uint8 *bbuf; unsigned bs, bpos, i, pad; PX_Cipher *c = cx->cipher; bbuf = NULL; bs = px_cipher_block_size(c); /* encrypt */ if (bs > 1) { bbuf = px_alloc(bs * 4); bpos = dlen % bs; *rlen = dlen - bpos; memcpy(bbuf, data + *rlen, bpos); /* encrypt full-block data */ if (*rlen) { err = px_cipher_encrypt(c, data, *rlen, res); if (err) goto out; } /* bbuf has now bpos bytes of stuff */ if (cx->padding) { pad = bs - (bpos % bs); for (i = 0; i < pad; i++) bbuf[bpos++] = pad; } else if (bpos % bs) { /* ERROR? */ pad = bs - (bpos % bs); for (i = 0; i < pad; i++) bbuf[bpos++] = 0; } /* encrypt the rest - pad */ if (bpos) { err = px_cipher_encrypt(c, bbuf, bpos, res + *rlen); *rlen += bpos; } } else { /* stream cipher/mode - no pad needed */ err = px_cipher_encrypt(c, data, dlen, res); if (err) goto out; *rlen = dlen; } out: if (bbuf) px_free(bbuf); return err; }