/******************************************************************************* * * VERIFY_BAD_DECRYPTION * * Handles block type 2: This is the third of the three routines, called by * VERIFY_GCM, which reads the "gcm_test_vectors.bin" file block by block. * It invokes the AES-GCM library "gcm_auth_decrypt" function to decrypt the * provided ciphertext, then verifies a AUTHENTICATION FAILURE caused by a * deliberate mismatch in the ciphertext and/or authentication data which was * provided by the NIST file(s). */ int verify_bad_decryption( const uchar *key, // pointer to the cipher key size_t key_len, // byte length of the key const uchar *iv, // pointer to the initialization vector size_t iv_len, // byte length of the initialization vector const uchar *aad, // pointer to the non-ciphered additional data size_t aad_len, // byte length of the additional AEAD data const uchar *ct, // pointer to the CORRECT cipher data size_t ct_len, // byte length of the cipher data const uchar *tag, // pointer to the CORRECT tag to be generated size_t tag_len ) // byte length of the tag to be generated { int ret = 0; // our return value gcm_context ctx; // includes the AES context structure uchar pt_buf[256]; // plaintext results for comparison gcm_setkey( &ctx, key, (const uint)key_len ); // setup our AES-GCM key // decrypt the NIST-provided ciphertext and auth tag into the local pt_buf ret = gcm_auth_decrypt( &ctx, iv, iv_len, aad, aad_len, ct, pt_buf, ct_len, tag, tag_len); ret ^= GCM_AUTH_FAILURE; // the fucntion SHOULD FAIL and return the // GCM_AUTH_FAILURE. We XOR it to verify gcm_zero_ctx( &ctx ); return ( ret ); // return any error 'XOR' generated above }
/* * Packet-oriented decryption for AEAD modes */ int cipher_auth_decrypt( cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, const unsigned char *tag, size_t tag_len ) { #if defined(POLARSSL_GCM_C) if( POLARSSL_MODE_GCM == ctx->cipher_info->mode ) { int ret; *olen = ilen; ret = gcm_auth_decrypt( ctx->cipher_ctx, ilen, iv, iv_len, ad, ad_len, tag, tag_len, input, output ); if( ret == POLARSSL_ERR_GCM_AUTH_FAILED ) ret = POLARSSL_ERR_CIPHER_AUTH_FAILED; return( ret ); } #endif /* POLARSSL_GCM_C */ #if defined(POLARSSL_CCM_C) if( POLARSSL_MODE_CCM == ctx->cipher_info->mode ) { int ret; *olen = ilen; ret = ccm_auth_decrypt( ctx->cipher_ctx, ilen, iv, iv_len, ad, ad_len, input, output, tag, tag_len ); if( ret == POLARSSL_ERR_CCM_AUTH_FAILED ) ret = POLARSSL_ERR_CIPHER_AUTH_FAILED; return( ret ); } #endif /* POLARSSL_CCM_C */ return( POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE ); }
/** * @Brief AES-GCM decrypt, compute authentication tag and compare it to the one provided * * @param[in] key Encryption key * @param[in] keyLength Key buffer length, in bytes, must be 16,24 or 32 * @param[in] cipherText Buffer to be decrypted * @param[in] cipherTextLength Length in bytes of buffer to be decrypted * @param[in] authenticatedData Buffer holding additional data to be used in auth tag computation * @param[in] authenticatedDataLength Additional data length in bytes * @param[in] initializationVector Buffer holding the initialisation vector * @param[in] initializationVectorLength Initialisation vector length in bytes * @param[in] tag Buffer holding the authentication tag * @param[in] tagLength Length in bytes for the authentication tag * @param[out] output Buffer holding the output, shall be at least the length of cipherText buffer * * @return 0 on succes, BCTBX_ERROR_AUTHENTICATION_FAILED if tag doesn't match or polarssl error code */ int32_t bctbx_aes_gcm_decrypt_and_auth(const uint8_t *key, size_t keyLength, const uint8_t *cipherText, size_t cipherTextLength, const uint8_t *authenticatedData, size_t authenticatedDataLength, const uint8_t *initializationVector, size_t initializationVectorLength, const uint8_t *tag, size_t tagLength, uint8_t *output) { gcm_context gcmContext; int ret; ret = gcm_init(&gcmContext, key, keyLength*8); if (ret != 0) return ret; ret = gcm_auth_decrypt(&gcmContext, cipherTextLength, initializationVector, initializationVectorLength, authenticatedData, authenticatedDataLength, tag, tagLength, cipherText, output); if (ret == POLARSSL_ERR_GCM_AUTH_FAILED) { return BCTBX_ERROR_AUTHENTICATION_FAILED; } return ret; }
struct item *symmetric_decryption(struct item *key, struct item *item) /*@ requires [?f]world(?pub, ?key_clsfy) &*& item(item, ?enc, pub) &*& enc == symmetric_encrypted_item(?principal1, ?count1, ?pay, ?ent) &*& item(key, ?k, pub) &*& k == symmetric_key_item(?principal2, ?count2); @*/ /*@ ensures [f]world(pub, key_clsfy) &*& item(item, enc, pub) &*& item(key, k, pub) &*& item(result, ?dec, pub) &*& col ? [_]pub(dec) : switch(pay) { case some(dec2): return principal1 == principal2 && count1 == count2 && dec == dec2; case none: return false; }; @*/ { debug_print("DECRYPTING:\n"); print_item(item); check_is_symmetric_encrypted(item); //@ open [f]world(pub, key_clsfy); struct item* result; result = malloc(sizeof(struct item)); if (result == 0) abort_crypto_lib("Malloc failed"); { gcm_context gcm_context; char *iv; char iv_buffer[GCM_IV_SIZE]; char *encrypted; //@ open item(key, k, pub); //@ assert key->content |-> ?k_cont &*& key->size |-> ?k_size; check_valid_symmetric_key_item_size(key->size); //@ open [_]item_constraints(k, ?k_cs0, pub); //@ assert [_]ic_parts(k)(?k_tag, ?k_cs); //@ crypto_chars_limits(k_cont); //@ crypto_chars_split(k_cont, TAG_LENGTH); //@ WELL_FORMED(k_tag, k_cs, TAG_SYMMETRIC_KEY) //@ assert crypto_chars(secret, k_cont, TAG_LENGTH, k_tag); //@ assert crypto_chars(secret, k_cont + TAG_LENGTH, GCM_KEY_SIZE, k_cs); //@ cryptogram k_cg = cg_symmetric_key(principal2, count2); //@ if (col) k_cg = chars_for_cg_sur(k_cs, tag_symmetric_key); //@ if (col) crypto_chars_to_chars(k_cont + TAG_LENGTH, GCM_KEY_SIZE); //@ if (col) public_chars_extract(k_cont + TAG_LENGTH, k_cg); //@ if (col) chars_to_secret_crypto_chars(k_cont + TAG_LENGTH, GCM_KEY_SIZE); //@ close cryptogram(k_cont + TAG_LENGTH, GCM_KEY_SIZE, k_cs, k_cg); //@ close gcm_context(&gcm_context); if (gcm_init(&gcm_context, POLARSSL_CIPHER_ID_AES, (key->content + TAG_LENGTH), (unsigned int) GCM_KEY_SIZE * 8) != 0) abort_crypto_lib("Init gcm failed"); //@ assert gcm_context_initialized(&gcm_context, ?p, ?c); //@ assert col || (p == principal2 && c == count2); //@ open cryptogram(k_cont + TAG_LENGTH, GCM_KEY_SIZE, k_cs, k_cg); //@ crypto_chars_join(k_cont); //@ close item(key, k, pub); //@ open item(item, enc, pub); //@ assert item->content |-> ?i_cont &*& item->size |-> ?i_size; //@ open [_]item_constraints(enc, ?cs, pub); //@ open [_]ic_parts(enc)(?enc_tag, ?enc_cont); //@ open [_]ic_cg(enc)(_, ?enc_cg); //@ take_append(TAG_LENGTH, enc_tag, enc_cont); //@ drop_append(TAG_LENGTH, enc_tag, enc_cont); //@ open [_]ic_sym_enc(enc)(?enc_iv, ?cg_cs); //@ assert true == well_formed(cs, nat_length(cs)); //@ close [1/2]hide_crypto_chars(_, i_cont, i_size, cs); check_valid_symmetric_encrypted_item_size(item->size); //@ assert length(cs) > TAG_LENGTH + GCM_IV_SIZE; int size = item->size - TAG_LENGTH - GCM_IV_SIZE - GCM_MAC_SIZE; if (size <= MINIMAL_STRING_SIZE) abort_crypto_lib("Gcm decryption failed"); //@ crypto_chars_limits(i_cont); //@ crypto_chars_split(i_cont, TAG_LENGTH); iv = item->content + TAG_LENGTH; //@ crypto_chars_split(iv, GCM_IV_SIZE); //@ assert [1/2]crypto_chars(secret, iv, GCM_IV_SIZE, ?iv_cs); memcpy(iv_buffer, iv, GCM_IV_SIZE); //@ assert cs == append(enc_tag, enc_cont); //@ assert enc_cont == append(iv_cs, cg_cs); //@ public_crypto_chars(iv, GCM_IV_SIZE); //@ chars_to_secret_crypto_chars(iv, GCM_IV_SIZE); encrypted = iv + GCM_IV_SIZE; //@ crypto_chars_limits(encrypted); //@ crypto_chars_split(encrypted, GCM_MAC_SIZE); //@ assert [1/2]crypto_chars(secret, encrypted, GCM_MAC_SIZE, ?mac_cs); /*@ assert [1/2]crypto_chars(secret, encrypted + GCM_MAC_SIZE, size, ?enc_cs); @*/ //@ assert cg_cs == append(mac_cs, enc_cs); result->size = size; result->content = malloc(size); if (result->content == 0) abort_crypto_lib("Malloc failed"); //@ assert result->content |-> ?r_cont &*& result->size |-> size; //@ if (col) enc_cg = chars_for_cg_sur(cg_cs, tag_auth_encrypted); //@ close exists(enc_cg); if (gcm_auth_decrypt(&gcm_context, (unsigned int) size, iv_buffer, GCM_IV_SIZE, NULL, 0, encrypted, GCM_MAC_SIZE, encrypted + GCM_MAC_SIZE, result->content) != 0) abort_crypto_lib("Gcm decryption failed"); //@ assert crypto_chars(secret, r_cont, size, ?dec_cs); //@ assert col || enc_cg == cg_auth_encrypted(principal1, count1, dec_cs, iv_cs); //@ crypto_chars_join(encrypted); //@ crypto_chars_join(iv); //@ crypto_chars_join(i_cont); //@ open [1/2]hide_crypto_chars(_, i_cont, i_size, cs); //@ close item(item, enc, pub); gcm_free(&gcm_context); //@ open gcm_context(&gcm_context); zeroize(iv_buffer, GCM_IV_SIZE); //@ close [f]world(pub, key_clsfy); /*@ if (col) { crypto_chars_to_chars(r_cont, size); chars_to_crypto_chars(r_cont, size); } else { assert enc == symmetric_encrypted_item(principal1, count1, pay, ent); assert enc_cg == cg_auth_encrypted(principal1, count1, dec_cs, enc_iv); switch(pay) { case some(pay1): assert [_]item_constraints(pay1, dec_cs, pub); case none: open [_]ill_formed_item_chars(enc)(dec_cs); assert [_]public_generated(polarssl_pub(pub))(dec_cs); public_crypto_chars(r_cont, size); chars_to_crypto_chars(r_cont, size); } } @*/ parse_item(result->content, size); /*@ if (col) { public_chars(r_cont, size); chars_to_secret_crypto_chars(r_cont, size); retreive_proof_obligations(); deserialize_item(dec_cs, pub); leak proof_obligations(pub); } @*/ //@ assert crypto_chars(secret, r_cont, size, dec_cs); //@ assert [_]item_constraints(?r, dec_cs, pub); //@ close item(result, r, pub); } debug_print("DECRYPTING RESULT:\n"); print_item(result); return result; }
int app_receive(char *key, char **message) /*@ requires [?f0]polarssl_world(sc_auth_polarssl_pub) &*& [?f1]polarssl_cryptogram(key, KEY_BYTE_SIZE, ?key_cs, ?key_cg) &*& key_cg == polarssl_symmetric_key(?creator, ?key_id) &*& pointer(message, _); @*/ /*@ ensures [f0]polarssl_world(sc_auth_polarssl_pub) &*& [f1]polarssl_cryptogram(key, KEY_BYTE_SIZE, key_cs, key_cg) &*& pointer(message, ?message_p) &*& malloc_block(message_p, result) &*& chars(message_p, result, ?m_cs) &*& bad(creator) ? [_]polarssl_public_generated_chars(sc_auth_polarssl_pub)(m_cs) : true == app_send_event(creator, m_cs); @*/ { int socket1; int socket2; int size; int result_size; char buffer[POLARSSL_MAX_MESSAGE_BYTE_SIZE]; char iv[16]; char tag[16]; char* encrypted; char* decrypted; // Receive message if(net_bind(&socket1, NULL, APP_RECEIVE_PORT) != 0) abort(); if(net_accept(socket1, &socket2, NULL) != 0) abort(); if(net_set_block(socket2) != 0) abort(); size = net_recv(&socket2, buffer, POLARSSL_MAX_MESSAGE_BYTE_SIZE); if (size < 16 + POLARSSL_MIN_ENCRYPTED_BYTE_SIZE + 16) abort(); //@ open polarssl_public_message(sc_auth_polarssl_pub)(buffer, size, ?cs); //@ close [1/2]hide_chars(buffer, size, cs); result_size = size - 16 - 16; encrypted = malloc(result_size); if (encrypted == 0) abort(); decrypted = malloc(result_size); if (decrypted == 0) abort(); // Extract parts of message memcpy(iv, buffer, 16); memcpy(encrypted, (void*) buffer + 16, (unsigned int) result_size); memcpy(tag, (void*) buffer + 16 + result_size, 16); //@ assert chars(iv, 16, ?iv_cs); //@ assert chars(encrypted, result_size, ?e_cs); //@ assert chars(tag, 16, ?t_cs); //@ chars_join(buffer); //@ chars_join(buffer); //@ open [1/2]hide_chars(buffer, size, cs); //@ close [1/2]hide_chars(buffer, size, cs); //@ assert cs == append(iv_cs, append(e_cs, t_cs)); // Decrypt message { gcm_context gcm_context; //@ close gcm_context(&gcm_context); //@ open [f1]polarssl_cryptogram(key, KEY_BYTE_SIZE, key_cs, key_cg); //@ close polarssl_key_id(creator, key_id); if (gcm_init(&gcm_context, POLARSSL_AES_CIPHER_ID, key, (unsigned int) KEY_BYTE_SIZE * 8) != 0) abort(); /*@ assert gcm_context_initialized(&gcm_context, some(pair(creator, key_id))); @*/ //@ close [f1]polarssl_cryptogram(key, KEY_BYTE_SIZE, key_cs, key_cg); //@ polarssl_public_generated_chars_split(sc_auth_polarssl_pub, cs, 16); /*@ polarssl_public_generated_chars_split( sc_auth_polarssl_pub, append(e_cs, t_cs), result_size); @*/ //@ assert chars(encrypted, result_size, e_cs); if (gcm_auth_decrypt(&gcm_context, (unsigned int) result_size, iv, 16, NULL, 0, tag, 16, encrypted, decrypted) != 0) abort(); gcm_free(&gcm_context); //@ open gcm_context(&gcm_context); } //@ assert chars(decrypted, result_size, ?dec_cs); //@ chars_join(buffer); //@ open [1/2]hide_chars(buffer, size, cs); /*@ polarssl_cryptogram e_cg = polarssl_auth_encrypted( creator, key_id, t_cs, dec_cs, iv_cs); @*/ //@ assert e_cs == polarssl_chars_for_cryptogram(e_cg); //@ polarssl_cryptogram_constraints(e_cs, e_cg); /*@ polarssl_public_generated_chars_extract( sc_auth_polarssl_pub, e_cs, e_cg); @*/ //@ open [_]sc_auth_polarssl_pub(e_cg); /*@ if (!bad(creator)) { assert true == app_send_event(creator, dec_cs); } else { assert [_]polarssl_public_generated_chars(sc_auth_polarssl_pub)(dec_cs); } @*/ net_close(socket1); net_close(socket2); free(encrypted); *message = decrypted; return result_size; }
void attacker_send_auth_decrypted(havege_state *havege_state, void* socket) //@ requires attacker_invariant(?pub, ?pred, ?kc, havege_state, socket, ?attacker); //@ ensures attacker_invariant(pub, pred, kc, havege_state, socket, attacker); { int temp; int size1; int size2; char buffer1[MAX_MESSAGE_SIZE]; char buffer2[MAX_MESSAGE_SIZE]; char buffer3[MAX_MESSAGE_SIZE]; gcm_context gcm_context; char iv[16]; //@ open attacker_invariant(pub, pred, kc, havege_state, socket, attacker); size1 = net_recv(socket, buffer1, MAX_MESSAGE_SIZE); size2 = net_recv(socket, buffer2, MAX_MESSAGE_SIZE); if (size1 <= 16 || size2 <= 16 || (size1 != 16 && size1 != 24 && size1 != 32)) { //@ close attacker_invariant(pub, pred, kc, havege_state, socket, attacker); return; } //@ close gcm_context(&gcm_context); //@ interpret_symmetric_key(buffer1, size1); //@ assert cryptogram(buffer1, size1, ?ccs1, ?cg_key); //@ assert cg_key == cg_symmetric_key(?p, ?c); if (gcm_init(&gcm_context, POLARSSL_CIPHER_ID_AES, buffer1, (unsigned int) size1 * 8) == 0) { if (get_iv(havege_state, iv) == 0) { //@ assert crypto_chars(normal, iv, 16, ?ccs_iv); //@ assert chars(buffer2, size2, ?cs2); //@ interpret_auth_encrypted(buffer2, size2); //@ open cryptogram(buffer2, size2, ?ccs2, ?cg_enc); //@ cs_to_ccs_crypto_chars(buffer2, cs2); //@ chars_to_crypto_chars(buffer2, size2); //@ close exists(cg_enc); //@ assert cg_enc == cg_auth_encrypted(?p2, ?c2, ?ccs_output2, ?ccs_iv2); //@ crypto_chars_split(buffer2, 16); if (gcm_auth_decrypt(&gcm_context, (unsigned int) size2 - 16, iv, 16, NULL, 0, buffer2, 16, (void*) buffer2 + 16, buffer3) == 0) { /*@ if (!col) { assert crypto_chars(secret, buffer3, size2 - 16, ?ccs_output); ccs_output == ccs_output2; ccs_iv == ccs_iv2; assert ccs2 == ccs_for_cg(cg_enc); assert [_]pub(cg_enc); assert is_public_auth_decryption_is_public(?proof3, pub, pred); proof3(cg_key, cg_enc); public_crypto_chars(buffer3, size2 - 16); chars_to_crypto_chars(buffer3, size2 - 16); } @*/ zeroize(iv, 16); //@ chars_to_crypto_chars(iv, 16); } //@ crypto_chars_to_chars(buffer3, size2 - 16); net_send(socket, buffer3, (unsigned int) size2 - 16); //@ crypto_chars_to_chars(buffer2, 16); //@ crypto_chars_to_chars((void*) buffer2 + 16, size2 - 16); //@ chars_join(buffer2); } //@ crypto_chars_to_chars(iv, 16); gcm_free(&gcm_context); } //@ open gcm_context(&gcm_context); //@ close attacker_invariant(pub, pred, kc, havege_state, socket, attacker); //@ public_cryptogram(buffer1, cg_key); }