int ocb_decrypt_verify_memory(int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *nonce, const unsigned char *ct, unsigned long ctlen, unsigned char *pt, const unsigned char *tag, unsigned long taglen, int *res) { int err; ocb_state ocb; _ARGCHK(key != NULL); _ARGCHK(nonce != NULL); _ARGCHK(pt != NULL); _ARGCHK(ct != NULL); _ARGCHK(tag != NULL); _ARGCHK(res != NULL); if ((err = ocb_init(&ocb, cipher, key, keylen, nonce)) != CRYPT_OK) { return err; } while (ctlen > (unsigned long)ocb.block_len) { if ((err = ocb_decrypt(&ocb, ct, pt)) != CRYPT_OK) { return err; } ctlen -= ocb.block_len; pt += ocb.block_len; ct += ocb.block_len; } return ocb_done_decrypt(&ocb, ct, ctlen, pt, tag, taglen, res); }
/** Decrypt and compare the tag with OCB. @param cipher The index of the cipher desired @param key The secret key @param keylen The length of the secret key (octets) @param nonce The session nonce (length of the block size of the block cipher) @param ct The ciphertext @param ctlen The length of the ciphertext (octets) @param pt [out] The plaintext @param tag The tag to compare against @param taglen The length of the tag (octets) @param stat [out] The result of the tag comparison (1==valid, 0==invalid) @return CRYPT_OK if successful regardless of the tag comparison */ int ocb_decrypt_verify_memory(int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *nonce, const unsigned char *ct, unsigned long ctlen, unsigned char *pt, const unsigned char *tag, unsigned long taglen, int *stat) { int err; ocb_state *ocb; LTC_ARGCHK(key != NULL); LTC_ARGCHK(nonce != NULL); LTC_ARGCHK(pt != NULL); LTC_ARGCHK(ct != NULL); LTC_ARGCHK(tag != NULL); LTC_ARGCHK(stat != NULL); /* allocate memory */ ocb = XMALLOC(sizeof(ocb_state)); if (ocb == NULL) { return CRYPT_MEM; } if ((err = ocb_init(ocb, cipher, key, keylen, nonce)) != CRYPT_OK) { goto LBL_ERR; } while (ctlen > (unsigned long)ocb->block_len) { if ((err = ocb_decrypt(ocb, ct, pt)) != CRYPT_OK) { goto LBL_ERR; } ctlen -= ocb->block_len; pt += ocb->block_len; ct += ocb->block_len; } err = ocb_done_decrypt(ocb, ct, ctlen, pt, tag, taglen, stat); LBL_ERR: #ifdef LTC_CLEAN_STACK zeromem(ocb, sizeof(ocb_state)); #endif XFREE(ocb); return err; }
bool CryptState::decrypt(const unsigned char *source, unsigned char *dst, unsigned int crypted_length) { if (crypted_length < 4) return false; unsigned int plain_length = crypted_length - 4; unsigned char saveiv[AES_BLOCK_SIZE]; unsigned char ivbyte = source[0]; bool restore = false; unsigned char tag[AES_BLOCK_SIZE]; int lost = 0; int late = 0; memcpy(saveiv, decrypt_iv, AES_BLOCK_SIZE); if (((decrypt_iv[0] + 1) & 0xFF) == ivbyte) { // In order as expected. if (ivbyte > decrypt_iv[0]) { decrypt_iv[0] = ivbyte; } else if (ivbyte < decrypt_iv[0]) { decrypt_iv[0] = ivbyte; for (int i=1;i<AES_BLOCK_SIZE;i++) if (++decrypt_iv[i]) break; } else { return false; } } else { // This is either out of order or a repeat. int diff = ivbyte - decrypt_iv[0]; if (diff > 128) diff = diff-256; else if (diff < -128) diff = diff+256; if ((ivbyte < decrypt_iv[0]) && (diff > -30) && (diff < 0)) { // Late packet, but no wraparound. late = 1; lost = -1; decrypt_iv[0] = ivbyte; restore = true; } else if ((ivbyte > decrypt_iv[0]) && (diff > -30) && (diff < 0)) { // Last was 0x02, here comes 0xff from last round late = 1; lost = -1; decrypt_iv[0] = ivbyte; for (int i=1;i<AES_BLOCK_SIZE;i++) if (decrypt_iv[i]--) break; restore = true; } else if ((ivbyte > decrypt_iv[0]) && (diff > 0)) { // Lost a few packets, but beyond that we're good. lost = ivbyte - decrypt_iv[0] - 1; decrypt_iv[0] = ivbyte; } else if ((ivbyte < decrypt_iv[0]) && (diff > 0)) { // Lost a few packets, and wrapped around lost = 256 - decrypt_iv[0] + ivbyte - 1; decrypt_iv[0] = ivbyte; for (int i=1;i<AES_BLOCK_SIZE;i++) if (++decrypt_iv[i]) break; } else { return false; } if (decrypt_history[decrypt_iv[0]] == decrypt_iv[1]) { memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE); return false; } } ocb_decrypt(source+4, dst, plain_length, decrypt_iv, tag); if (memcmp(tag, source+1, 3) != 0) { memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE); return false; } decrypt_history[decrypt_iv[0]] = decrypt_iv[1]; if (restore) memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE); uiGood++; uiLate += late; uiLost += lost; tLastGood.restart(); return true; }