static SECStatus aes_encrypt_buf( const unsigned char *key, unsigned int keysize, const unsigned char *iv, unsigned int ivsize, unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, const unsigned char *input, unsigned int inputlen, const unsigned char *aad, unsigned int aadlen, unsigned int tagsize) { SECStatus rv = SECFailure; SECItem key_item; PK11SlotInfo* slot = NULL; PK11SymKey *symKey = NULL; CK_GCM_PARAMS gcm_params; SECItem param; /* Import key into NSS. */ key_item.type = siBuffer; key_item.data = (unsigned char *) key; /* const cast */ key_item.len = keysize; slot = PK11_GetInternalSlot(); symKey = PK11_ImportSymKey(slot, CKM_AES_GCM, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL); PK11_FreeSlot(slot); slot = NULL; if (!symKey) { fprintf(stderr, "PK11_ImportSymKey failed\n"); goto loser; } gcm_params.pIv = (unsigned char *) iv; /* const cast */ gcm_params.ulIvLen = ivsize; gcm_params.pAAD = (unsigned char *) aad; /* const cast */ gcm_params.ulAADLen = aadlen; gcm_params.ulTagBits = tagsize * 8; param.type = siBuffer; param.data = (unsigned char *) &gcm_params; param.len = sizeof(gcm_params); if (PK11_Encrypt(symKey, CKM_AES_GCM, ¶m, output, outputlen, maxoutputlen, input, inputlen) != SECSuccess) { fprintf(stderr, "PK11_Encrypt failed\n"); goto loser; } rv = SECSuccess; loser: if (symKey != NULL) { PK11_FreeSymKey(symKey); } return rv; }
static bool ike_alg_nss_gcm(const struct encrypt_desc *alg, u_int8_t *salt, size_t salt_size, u_int8_t *wire_iv, size_t wire_iv_size, u_int8_t *aad, size_t aad_size, u_int8_t *text_and_tag, size_t text_size, size_t tag_size, PK11SymKey *sym_key, bool enc) { /* See pk11gcmtest.c */ bool ok = TRUE; chunk_t salt_chunk = { .ptr = salt, .len = salt_size, }; chunk_t wire_iv_chunk = { .ptr = wire_iv, .len = wire_iv_size, }; chunk_t iv = concat_chunk_chunk("IV", salt_chunk, wire_iv_chunk); CK_GCM_PARAMS gcm_params; gcm_params.pIv = iv.ptr; gcm_params.ulIvLen = iv.len; gcm_params.pAAD = aad; gcm_params.ulAADLen = aad_size; gcm_params.ulTagBits = tag_size * 8; SECItem param; param.type = siBuffer; param.data = (void*)&gcm_params; param.len = sizeof gcm_params; /* Output buffer for transformed data. */ size_t text_and_tag_size = text_size + tag_size; u_int8_t *out_buf = PR_Malloc(text_and_tag_size); unsigned int out_len = 0; if (enc) { SECStatus rv = PK11_Encrypt(sym_key, alg->common.nss_mechanism, ¶m, out_buf, &out_len, text_and_tag_size, text_and_tag, text_size); if (rv != SECSuccess) { loglog(RC_LOG_SERIOUS, "do_aes_gcm: PK11_Encrypt failure (err %d)", PR_GetError()); ok = FALSE; } else if (out_len != text_and_tag_size) { loglog(RC_LOG_SERIOUS, "do_aes_gcm: PK11_Encrypt output length of %u not the expected %zd", out_len, text_and_tag_size); ok = FALSE; } } else { SECStatus rv = PK11_Decrypt(sym_key, CKM_AES_GCM, ¶m, out_buf, &out_len, text_and_tag_size, text_and_tag, text_and_tag_size); if (rv != SECSuccess) { loglog(RC_LOG_SERIOUS, "do_aes_gcm: PK11_Decrypt failure (err %d)", PR_GetError()); ok = FALSE; } else if (out_len != text_size) { loglog(RC_LOG_SERIOUS, "do_aes_gcm: PK11_Decrypt output length of %u not the expected %zd", out_len, text_size); ok = FALSE; } } memcpy(text_and_tag, out_buf, out_len); PR_Free(out_buf); freeanychunk(iv); return ok; }
/* * Structure is. * * struct { * opaque keyName[16]; * opaque iv[16]; * opaque ciphertext<16..2^16-1>; * opaque mac[32]; * } SelfEncrypted; * * We are using AES-CBC + HMAC-SHA256 in Encrypt-then-MAC mode for * two reasons: * * 1. It's what we already used for tickets. * 2. We don't have to worry about nonce collisions as much * (the chance is lower because we have a random 128-bit nonce * and they are less serious than with AES-GCM). */ SECStatus ssl_SelfEncryptProtectInt( PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, const PRUint8 *in, unsigned int inLen, PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) { unsigned int len; unsigned int lenOffset; unsigned char iv[AES_BLOCK_SIZE]; SECItem ivItem = { siBuffer, iv, sizeof(iv) }; /* Write directly to out. */ sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen); SECStatus rv; /* Generate a random IV */ rv = PK11_GenerateRandom(iv, sizeof(iv)); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } /* Add header. */ rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN); if (rv != SECSuccess) { return SECFailure; } rv = sslBuffer_Append(&buf, iv, sizeof(iv)); if (rv != SECSuccess) { return SECFailure; } /* Leave space for the length of the ciphertext. */ rv = sslBuffer_Skip(&buf, 2, &lenOffset); if (rv != SECSuccess) { return SECFailure; } /* Encode the ciphertext in place. */ rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem, SSL_BUFFER_NEXT(&buf), &len, SSL_BUFFER_SPACE(&buf), in, inLen); if (rv != SECSuccess) { return SECFailure; } rv = sslBuffer_Skip(&buf, len, NULL); if (rv != SECSuccess) { return SECFailure; } rv = sslBuffer_InsertLength(&buf, lenOffset, 2); if (rv != SECSuccess) { return SECFailure; } /* MAC the entire output buffer into the output. */ PORT_Assert(buf.space - buf.len >= SHA256_LENGTH); rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, SSL_BUFFER_BASE(&buf), /* input */ SSL_BUFFER_LEN(&buf), SSL_BUFFER_NEXT(&buf), &len, /* output */ SHA256_LENGTH); if (rv != SECSuccess) { return SECFailure; } rv = sslBuffer_Skip(&buf, len, NULL); if (rv != SECSuccess) { return SECFailure; } *outLen = SSL_BUFFER_LEN(&buf); return SECSuccess; }