int ccrsa_verify_pkcs1v15(ccrsa_pub_ctx_t key, const uint8_t *oid, size_t digest_len, const uint8_t *digest, size_t sig_len, const uint8_t *sig, bool *valid) { size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(key), ccrsa_ctx_m(key)); cc_size n=ccrsa_ctx_n(key); cc_unit s[n]; *valid = false; int err; cc_require_action(sig_len==m_size,errOut,err=CCRSA_INVALID_INPUT); ccn_read_uint(n, s, sig_len, sig); cc_require((err=ccrsa_pub_crypt(key, s, s))==0,errOut); { unsigned char em[m_size]; ccn_write_uint_padded(n, s, m_size, em); #ifdef VERIFY_BY_ENCODE_THEN_MEMCMP unsigned char em2[m_size]; cc_require((err=ccrsa_emsa_pkcs1v15_encode(m_size, em2, digest_len, digest, oid))==0,errOut); /* digest len is too big ?*/ if(memcmp(em, em2, m_size)==0) *valid = true; #else if(ccrsa_emsa_pkcs1v15_verify(m_size, em, digest_len, digest, oid)==0) *valid = true; #endif } errOut: return err; }
int cczp_sqrt(cczp_const_t zp, cc_unit *r, const cc_unit *x) { cc_size n=cczp_n(zp); cc_unit t[n]; ccn_set(n,t,cczp_prime(zp)); int result = -1; // Square root can be computed as x^((p+1)/4) when p = 3 mod 4 cc_require(((t[0]&3) == 3),errOut); // Compute ((p+1)/4) ccn_add1(n, t, t, 1); ccn_shift_right(n, t, t, 2); // Exponentiation cczp_power_fast(zp,r,x,t); // Confirm that the result is valid // => r is not the square root of x cczp_mul(zp,t,r,r); cc_require(ccn_cmp(n,t,x)==0,errOut); // r^2 == x ? result=0; errOut: return result; }
static int generate_block(struct ccdrbg_nistctr_state * drbg, uint32_t *blk) { int rc; uint8_t temp2[CCADRBG_BLOCKSIZE(drbg)]; // the folowing lines are performed as rquested in Radar 19129408 if (drbg->strictFIPS) { rc = gen_block(drbg, temp2); cc_require(rc==CCDRBG_STATUS_OK, errOut); rc = gen_block(drbg, blk); cc_require(rc==CCDRBG_STATUS_OK, errOut); rc = cc_cmp_safe(CCADRBG_BLOCKSIZE(drbg), blk, temp2); rc = (rc==0) ? CCDRBG_STATUS_ABORT: CCDRBG_STATUS_OK; errOut: cc_clear(CCADRBG_BLOCKSIZE(drbg), temp2); }else{ rc=gen_block(drbg, blk); } if(rc==CCDRBG_STATUS_ABORT){ //The world as we know it has come to an end //the DRBG data structure is zeroized. subsequent calls to //DRBG ends up in NULL dereferencing and/or unpredictable state. //catastrophic error in SP 800-90A done((struct ccdrbg_state *)drbg); cc_abort(NULL); } return rc; }
int ccec_generate_key_internal_fips(ccec_const_cp_t cp, struct ccrng_state *rng, ccec_full_ctx_t key) { int result=CCEC_GENERATE_KEY_DEFAULT_ERR; /* Get base point G in projected form. */ ccec_point_decl_cp(cp, base); cczp_const_t zq = ccec_cp_zq(cp); cc_require((result=ccec_projectify(cp, base, ccec_cp_g(cp),rng))==0,errOut); /* Generate a random private key k. */ ccec_ctx_init(cp, key); cc_unit *k = ccec_ctx_k(key); cc_unit *q_minus_2 = ccec_ctx_x(key); // used as temp buffer int cmp_result=1; /* Need to test candidate against q-2 */ ccn_sub1(ccec_cp_n(cp), q_minus_2, cczp_prime(zq), 2); size_t i; /* Generate adequate random for private key */ for (i = 0; i < MAX_RETRY && cmp_result>0; i++) { /* Random bits */ cc_require(((result = ccn_random_bits(ccec_cp_order_bitlen(cp), k, rng)) == 0),errOut); /* If k <= q-2, the number is valid */ cmp_result=ccn_cmp(ccec_cp_n(cp), k, q_minus_2); } if (i >= MAX_RETRY) { result=CCEC_GENERATE_KEY_TOO_MANY_TRIES; } else { cc_assert(cmp_result<=0); /* k is now in range [ 0, q-2 ] ==> +1 for range [ 1, q-1 ] */ ccn_add1(ccec_cp_n(cp), k, k, 1); /* Calculate the public key for k. */ cc_require_action(ccec_mult(cp, ccec_ctx_point(key), k, base,rng) == 0 ,errOut, result=CCEC_GENERATE_KEY_MULT_FAIL); cc_require_action(ccec_is_point_projective(cp, ccec_ctx_point(key)),errOut, result=CCEC_GENERATE_NOT_ON_CURVE); cc_require_action(ccec_affinify(cp, ccec_ctx_point(key), ccec_ctx_point(key)) == 0,errOut, result=CCEC_GENERATE_KEY_AFF_FAIL); ccn_seti(ccec_cp_n(cp), ccec_ctx_z(key), 1); result=0; } errOut: return result; }
//make sure drbg is initialized, before calling this function static int validate_inputs(struct ccdrbg_nistctr_state *drbg, unsigned long entropyLength, unsigned long additionalInputLength, unsigned long psLength) { int rc=CCDRBG_STATUS_PARAM_ERROR; cc_require(drbg->keylen<=CCADRBG_MAX_KEYLEN, end); //keylen too long //NIST SP800 compliance checks if(drbg->use_df){ cc_require (psLength <= CCDRBG_MAX_PSINPUT_SIZE, end); //personalization string too long cc_require (entropyLength <= CCDRBG_MAX_ENTROPY_SIZE, end); //supplied too much entropy cc_require (additionalInputLength <= CCDRBG_MAX_ADDITIONALINPUT_SIZE, end); //additional input too long cc_require (entropyLength >= drbg->ecb->block_size, end); //supplied too litle entropy }else{ unsigned long seedlen = CCADRBG_SEEDLEN(drbg); //outlen + keylen cc_require (psLength <= seedlen, end); //personalization string too long cc_require (entropyLength == seedlen, end); //supplied too much or too little entropy cc_require (additionalInputLength <= seedlen, end); //additional input too long } rc=CCDRBG_STATUS_OK; end: return rc; }
// Use exactly // 2 * ccn_sizeof(ccec_cp_order_bitlen(cp)) bytes of random in total. // Half of the random for the actual generation, the other for the consistency check // The consistency check may require more random, therefore a DRBG is set to cover // this case. int ccec_generate_key_legacy(ccec_const_cp_t cp, struct ccrng_state *rng, ccec_full_ctx_t key) { int result; if((result = ccec_generate_key_internal_legacy(cp, rng, key))) return result; { // Create an rng using a drbg. // Signature may use a non deterministic amount of random // while input rng may be limited (this is the case for PBKDF2). // Agnostic of DRBG struct ccrng_drbg_state rng_drbg; struct ccdrbg_info info; uint8_t drbg_init_salt[ccn_sizeof(ccec_cp_order_bitlen(cp))]; cc_require((result = ccrng_generate(rng, sizeof(drbg_init_salt), drbg_init_salt))==0,errOut); // Set DRBG - NIST HMAC struct ccdrbg_nisthmac_custom custom = { .di = ccsha256_di(), .strictFIPS = 0, }; ccdrbg_factory_nisthmac(&info, &custom); // Init the rng drbg uint8_t state[info.size]; result = ccrng_drbg_init(&rng_drbg, &info, (struct ccdrbg_state *)state, sizeof(drbg_init_salt), drbg_init_salt); if(result == 0) { result = ccec_pairwise_consistency_check(key, (struct ccrng_state *)&rng_drbg) ? 0 : -1; } // Close the rng drbg ccrng_drbg_done(&rng_drbg); } errOut: return result; }
void ccmode_gcm_finalize(ccgcm_ctx *key, size_t tag_size, void *tag) { size_t x; cc_require(_CCMODE_GCM_KEY(key)->mode == CCMODE_GCM_MODE_TEXT,errOut); /* CRYPT_INVALID_ARG */ /* handle remaining ciphertext */ if (CCMODE_GCM_KEY_PAD_LEN(key)) { _CCMODE_GCM_KEY(key)->pttotlen += CCMODE_GCM_KEY_PAD_LEN(key) * (uint64_t)(8); ccmode_gcm_mult_h(key, CCMODE_GCM_KEY_X(key)); } /* length */ CC_STORE64_BE(_CCMODE_GCM_KEY(key)->totlen, CCMODE_GCM_KEY_PAD(key)); CC_STORE64_BE(_CCMODE_GCM_KEY(key)->pttotlen, CCMODE_GCM_KEY_PAD(key)+8); for (x = 0; x < 16; x++) { CCMODE_GCM_KEY_X(key)[x] ^= CCMODE_GCM_KEY_PAD(key)[x]; } ccmode_gcm_mult_h(key, CCMODE_GCM_KEY_X(key)); /* encrypt original counter */ CCMODE_GCM_KEY_ECB(key)->ecb(CCMODE_GCM_KEY_ECB_KEY(key), 1, CCMODE_GCM_KEY_Y_0(key), CCMODE_GCM_KEY_PAD(key)); uint8_t *out = tag; for (x = 0; x < 16 && x < tag_size; x++) { out[x] = CCMODE_GCM_KEY_PAD(key)[x] ^ CCMODE_GCM_KEY_X(key)[x]; } errOut: return; }
void ccmode_ccm_cbcmac(ccccm_ctx *key, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in) { cc_require(nbytes==0 || _CCMODE_CCM_NONCE(nonce_ctx)->mode == CCMODE_CCM_MODE_AAD,errOut); /* CRYPT_INVALID_ARG */ ccmode_ccm_macdata(key, nonce_ctx, 0, nbytes, in); errOut: return; }
//make sure state is initialized, before calling this function static int validate_inputs(struct ccdrbg_nisthmac_state *state, size_t entropyLength, size_t additionalInputLength, size_t psLength) { int rc; const struct ccdrbg_nisthmac_custom *custom=state->custom; const struct ccdigest_info *di = custom->di; rc =CCDRBG_STATUS_ERROR; //buffer size checks cc_require (di->output_size<=sizeof(state->v)/2, end); //digest size too long cc_require (di->output_size<=sizeof(state->key), end); //digest size too long //NIST SP800 compliance checks //the following maximum checks are redundant if long is 32 bits. rc=CCDRBG_STATUS_PARAM_ERROR; cc_require (psLength <= CCDRBG_MAX_PSINPUT_SIZE, end); //personalization string too long cc_require (entropyLength <= CCDRBG_MAX_ENTROPY_SIZE, end); //supplied too much entropy cc_require (additionalInputLength <= CCDRBG_MAX_ADDITIONALINPUT_SIZE, end); //additional input too long cc_require (entropyLength >= MIN_REQ_ENTROPY(di), end); //supplied too litle entropy cc_require(di->output_size<=NH_MAX_OUTPUT_BLOCK_SIZE, end); //the requested security strength is not supported rc=CCDRBG_STATUS_OK; end: return rc; }
static int validate_gen_params(uint64_t reseed_counter, size_t dataOutLength, size_t additionalLength) { int rc=CCDRBG_STATUS_PARAM_ERROR; // Zero byte in one request is a valid use-case (21208820) cc_require (dataOutLength <= CCDRBG_MAX_REQUEST_SIZE, end); //Requested too many bytes in one request cc_require (additionalLength<=CCDRBG_MAX_ADDITIONALINPUT_SIZE, end); //Additional input too long // 1. If (reseed_counter > 2^^48), then Return (“Reseed required”, Null, V, Key, reseed_counter). rc = CCDRBG_STATUS_NEED_RESEED; cc_require (reseed_counter <= CCDRBG_RESEED_INTERVAL, end); //Reseed required rc=CCDRBG_STATUS_OK; end: return rc; }
static int validate_gen_params(struct ccdrbg_nistctr_state *drbg, unsigned long dataOutLength, unsigned long additionalLength) { int rc=CCDRBG_STATUS_PARAM_ERROR; cc_require (dataOutLength >= 1, end); //Requested zero byte in one request cc_require (dataOutLength <= CCDRBG_MAX_REQUEST_SIZE, end); //Requested too many bytes in one request unsigned long max = drbg->use_df? CCDRBG_MAX_ADDITIONALINPUT_SIZE:CCADRBG_SEEDLEN(drbg); cc_require (additionalLength<=max, end); //Additional input too long // 1. If (reseed_counter > 2^^48), then Return (“Reseed required”, Null, V, Key, reseed_counter). cc_assert(sizeof(drbg->reseed_counter>=8)); //make sure it fits 2^48 rc = CCDRBG_STATUS_NEED_RESEED; cc_require (drbg->reseed_counter <= CCDRBG_RESEED_INTERVAL || !drbg->strictFIPS, end); //Reseed required rc=CCDRBG_STATUS_OK; end: return rc; }
size_t ccecies_encrypt_gcm_ciphertext_size(ccec_pub_ctx_t public_key, ccecies_gcm_t ecies, size_t plaintext_len ) { size_t public_key_size=0; public_key_size=ccecies_pub_key_size(public_key,ecies); cc_require(public_key_size>0, errOut); return public_key_size+ecies->mac_length+plaintext_len; errOut: return 0; // error }
static int tests_rng(const char *seed) { byteBuffer entropyBuffer; int status=-1; // Allocation error; if (seed==NULL || strlen(seed)<=0) { // If the seed is not in the argument, we generate one struct ccrng_system_state system_rng; size_t entropy_size=16; // Default size of the seed cc_require((entropyBuffer=mallocByteBuffer(entropy_size))!=NULL,errOut); cc_require((status=ccrng_system_init(&system_rng))==0, errOut); cc_require((status=ccrng_generate((struct ccrng_state *)&system_rng, entropyBuffer->len, entropyBuffer->bytes))==0, errOut); ccrng_system_done(&system_rng); cc_print("random seed value:",entropyBuffer->len,entropyBuffer->bytes); } else { // Otherwise, take the value from the arguments entropyBuffer = hexStringToBytes(seed); cc_print("input seed value:",entropyBuffer->len,entropyBuffer->bytes); } cc_require((status=ccrng_test_init(&test_rng, entropyBuffer->len,entropyBuffer->bytes))==0, errOut); return status; errOut: printf("Error initializing test rng: %d\n",status); return -1; }
int ccdh_generate_key(ccdh_const_gp_t gp, struct ccrng_state *rng, ccdh_full_ctx_t key) { int result=CCDH_ERROR_DEFAULT; ccdh_ctx_init(gp, key); const cc_unit *g = ccdh_gp_g(gp); cc_unit *x = ccdh_ctx_x(key); cc_unit *y = ccdh_ctx_y(key); /* Generate the private key: x per PKCS #3 */ cc_require((result=ccdh_generate_private_key(gp,x,rng))==0,errOut); /* Generate the public key: y=g^x mod p */ cczp_power(gp.zp, y, g, x); result = 0; errOut: return result; }
void ccmode_gcm_set_iv(ccgcm_ctx *key, size_t iv_size, const void *iv) { size_t x, y; const uint8_t *IV = iv; /* must be in IV mode */ cc_require(_CCMODE_GCM_KEY(key)->mode == CCMODE_GCM_MODE_IV,errOut); /* CRYPT_INVALID_ARG */ /* trip the ivmode flag */ if (iv_size + CCMODE_GCM_KEY_PAD_LEN(key) > 12) { _CCMODE_GCM_KEY(key)->ivmode |= 1; } x = 0; #ifdef CCMODE_GCM_FAST if (CCMODE_GCM_KEY_PAD_LEN(key) == 0) { for (x = 0; x < (iv_size & ~15U); x += 16) { for (y = 0; y < 16; y += sizeof(CCMODE_GCM_FAST_TYPE)) { *((CCMODE_GCM_FAST_TYPE*)(&CCMODE_GCM_KEY_X(key)[y])) ^= *((const CCMODE_GCM_FAST_TYPE*)(&IV[x + y])); } ccmode_gcm_mult_h(key, CCMODE_GCM_KEY_X(key)); _CCMODE_GCM_KEY(key)->totlen += 128; } IV += x; } #endif /* start adding IV data to the state */ for (; x < iv_size; x++) { CCMODE_GCM_KEY_PAD(key)[CCMODE_GCM_KEY_PAD_LEN(key)++] = *IV++; if (CCMODE_GCM_KEY_PAD_LEN(key) == 16) { /* GF mult it */ for (y = 0; y < 16; y++) { CCMODE_GCM_KEY_X(key)[y] ^= CCMODE_GCM_KEY_PAD(key)[y]; } ccmode_gcm_mult_h(key, CCMODE_GCM_KEY_X(key)); CCMODE_GCM_KEY_PAD_LEN(key) = 0; _CCMODE_GCM_KEY(key)->totlen += 128; } } errOut: return; }
// verify the signature in sig. The original (hash of the message) message is in digest int ccrsa_verify_pss(ccrsa_pub_ctx_t key, const struct ccdigest_info* di, const struct ccdigest_info* MgfDi, size_t digestSize, const uint8_t *digest, size_t sigSize, const uint8_t *sig, size_t saltSize, bool *valid) { const cc_size modBits =ccn_bitlen(ccrsa_ctx_n(key), ccrsa_ctx_m(key)); const cc_size modBytes = cc_ceiling(modBits, 8); const cc_size emBits = modBits-1; //as defined in §8.1.1 const cc_size emSize = cc_ceiling(emBits, 8); *valid = false; int rc=0; //1. if(modBytes!= sigSize) return CCRSA_INVALID_INPUT; if(digestSize != di->output_size) return CCRSA_INVALID_INPUT; //2. const cc_size modWords=ccrsa_ctx_n(key); cc_unit EM[modWords]; //EM islarge enough to fit sig variable //2.a read sig to tmp array and make sure it fits cc_require_action(ccn_read_uint(modWords, EM, sigSize, sig)==0,errOut,rc=CCRSA_INVALID_INPUT); //2.b cc_require((rc=ccrsa_pub_crypt(key, EM, EM))==0,errOut); //2.c ccn_swap(modWords, EM); //3 const size_t ofs = modWords*sizeof(cc_unit)-emSize; cc_assert(ofs<=sizeof(cc_unit)); //make sure sizes are consistent and we don't overrun buffers. rc|= ccrsa_emsa_pss_decode(di, MgfDi, saltSize, digestSize, digest, emBits, (uint8_t *) EM+ofs); *valid = (rc==0)?true:false; errOut: return rc; }
static int generate(struct ccdrbg_state *rng, unsigned long dataOutLength, void *dataOut, unsigned long additionalLength, const void *additional) { int rc = CCDRBG_STATUS_OK; unsigned long i; unsigned long len; uint8_t *p; uint32_t *temp; const char *input_string[1]; uint32_t length[1]; struct ccdrbg_nistctr_state *drbg = (struct ccdrbg_nistctr_state *)rng; uint32_t buffer[CCADRBG_OUTLEN(drbg)]; uint32_t additional_buffer[CCADRBG_SEEDLEN_INTS(drbg)]; unsigned long blocks = dataOutLength / CCADRBG_OUTLEN(drbg); /* [1] If reseed_counter > reseed_interval ... */ rc = validate_gen_params(drbg, dataOutLength, (additional !=NULL)?additionalLength:0); cc_require(rc==CCDRBG_STATUS_OK, errOut); /* [2] If (addional_input != Null), then */ if (additional && additionalLength) { if(drbg->use_df) { input_string[0] = additional; /* typecast: guaranteed to fit by the checks above */ length[0] = (uint32_t)additionalLength; /* [2.1] additional = Block_Cipher_df(additional, seedlen) */ rc = df(drbg, input_string, length, 1, (uint8_t *)additional_buffer, sizeof(additional_buffer)); cc_require(rc==CCDRBG_STATUS_OK, errOut); } else { cc_clear(sizeof(additional_buffer), additional_buffer); cc_assert(additionalLength==0 || additionalLength==sizeof(additional_buffer)); //additionalLength is validated above CC_MEMCPY(additional_buffer, additional, additionalLength); } /* [2.2] (Key, V) = Update(additional, Key, V) */ rc=drbg_update(drbg, additional_buffer); cc_require(rc==CCDRBG_STATUS_OK, errOut); } if (blocks && check_int_alignment(dataOut)) { /* [3] temp = Null */ temp = (uint32_t *)dataOut; for (i = 0; i < blocks; ++i) { // Here is the conundrum that is FIPS. // In order to test the DRBG for CAVS one must NOT set strictFIPS // and thus not have a compliant DRBG. That is the only way to // ensure that the CAVS test will pass. On the other hand the // 'normal' usage of the DRBG MUST set the strictFIPS flag. So // that which is used by our customers is NOT what was tested. rc = generate_block(drbg, temp); cc_require(rc==CCDRBG_STATUS_OK, errOut); temp += CCADRBG_OUTLEN_INTS(drbg); dataOutLength -= CCADRBG_OUTLEN(drbg); } dataOut = (uint8_t *)temp; } /* [3] temp = Null */ temp = buffer; len = CCADRBG_OUTLEN(drbg); /* [4] While (len(temp) < requested_number_of_bits) do: */ p = dataOut; while (dataOutLength > 0) { // See note above. rc = generate_block(drbg, temp); cc_require(rc==CCDRBG_STATUS_OK, errOut); if (dataOutLength < CCADRBG_OUTLEN(drbg)) len = dataOutLength; memcpy(p, temp, len); p += len; dataOutLength -= len; } /* [6] (Key, V) = Update(additional, Key, V) */ rc = drbg_update(drbg, additional && additionalLength ? &additional_buffer[0] : &drbg->nullInput[0]); cc_require(rc==CCDRBG_STATUS_OK, errOut); /* [7] reseed_counter = reseed_counter + 1 */ ++drbg->reseed_counter; errOut: cc_clear(sizeof(additional_buffer),additional_buffer); return rc; }
void ccaes_vng_ccm_encrypt(ccccm_ctx *key, ccccm_nonce *nonce_ctx, size_t nbytes, const void *in, void *out) { if (_CCMODE_CCM_NONCE(nonce_ctx)->mode == CCMODE_CCM_MODE_AAD) { if (CCMODE_CCM_KEY_AUTH_LEN(nonce_ctx)) { /* transition to new block between auth and enc data */ CCMODE_CCM_KEY_ECB(key)->ecb(CCMODE_CCM_KEY_ECB_KEY(key), 1, CCMODE_CCM_KEY_B_I(nonce_ctx), CCMODE_CCM_KEY_B_I(nonce_ctx)); CCMODE_CCM_KEY_AUTH_LEN(nonce_ctx) = 0; } _CCMODE_CCM_NONCE(nonce_ctx)->mode = CCMODE_CCM_MODE_TEXT; } cc_require(_CCMODE_CCM_NONCE(nonce_ctx)->mode == CCMODE_CCM_MODE_TEXT,errOut); /* CRYPT_INVALID_ARG */ #if defined(__x86_64__) if ( CC_HAS_AESNI() && CC_HAS_SupplementalSSE3() ) #endif { if (CCMODE_CCM_KEY_PAD_LEN(nonce_ctx) != 0) { size_t padl = CCMODE_CCM_KEY_PAD_LEN(nonce_ctx); if (padl>nbytes) padl = nbytes; ccmode_ccm_macdata(key, nonce_ctx, 0, padl, in); ccmode_ccm_crypt(key, nonce_ctx, padl, in, out); in += padl; out += padl; nbytes -= padl; } if (CCMODE_CCM_KEY_PAD_LEN(nonce_ctx) == 0) { #if defined(__ARM_NEON__) && !defined(__arm64__) if (nbytes>=16) { unsigned long nblocks = nbytes/16; ccm_encrypt(in, out, CCMODE_CCM_KEY_B_I(nonce_ctx), nblocks, CCMODE_CCM_KEY_ECB_KEY(key), CCMODE_CCM_KEY_A_I(nonce_ctx), CCMODE_CCM_KEY_ECB(key)->block_size - 1 - CCMODE_CCM_KEY_NONCE_LEN(nonce_ctx)); #else int *p = (int*) CCMODE_CCM_KEY_ECB_KEY(key); if (nbytes>=16) { unsigned long nblocks = nbytes/16; switch (p[240/4]) { case 10 : case 160 : ccm128_encrypt(in, out, CCMODE_CCM_KEY_B_I(nonce_ctx), nblocks, CCMODE_CCM_KEY_ECB_KEY(key), CCMODE_CCM_KEY_A_I(nonce_ctx), CCMODE_CCM_KEY_ECB(key)->block_size - 1 - CCMODE_CCM_KEY_NONCE_LEN(nonce_ctx)); break; case 12 : case 192 : ccm192_encrypt(in, out, CCMODE_CCM_KEY_B_I(nonce_ctx), nblocks, CCMODE_CCM_KEY_ECB_KEY(key), CCMODE_CCM_KEY_A_I(nonce_ctx), CCMODE_CCM_KEY_ECB(key)->block_size - 1 - CCMODE_CCM_KEY_NONCE_LEN(nonce_ctx)); break; case 14 : case 224 : ccm256_encrypt(in, out, CCMODE_CCM_KEY_B_I(nonce_ctx), nblocks, CCMODE_CCM_KEY_ECB_KEY(key), CCMODE_CCM_KEY_A_I(nonce_ctx), CCMODE_CCM_KEY_ECB(key)->block_size - 1 - CCMODE_CCM_KEY_NONCE_LEN(nonce_ctx)); break; } #endif nbytes &= 15; in += nblocks*16; out += nblocks*16; } } } ccmode_ccm_macdata(key, nonce_ctx, 0, nbytes, in); ccmode_ccm_crypt(key, nonce_ctx, nbytes, in, out); errOut: return; }
int ccecies_encrypt_gcm_composite(ccec_pub_ctx_t public_key, const ccecies_gcm_t ecies, uint8_t *exported_public_key, /* output - length from ccecies_pub_key_size */ uint8_t *ciphertext, /* output - length same as plaintext_len */ uint8_t *mac_tag, /* output - length ecies->mac_length */ size_t plaintext_len, const uint8_t *plaintext, size_t sharedinfo1_byte_len, const void *sharedinfo_1, size_t sharedinfo2_byte_len, const void *sharedinfo_2 ) { int status=-1; // Contexts: ccec_full_ctx_decl_cp(ccec_ctx_cp(public_key), ephemeral_key); size_t skey_size = ccec_cp_prime_size(ccec_ctx_cp(public_key)); uint8_t skey[skey_size]; const struct ccmode_gcm *gcm_encrypt=ecies->gcm; ccgcm_ctx_decl(gcm_encrypt->size,gcm_ctx); size_t exported_public_key_size; // 1) Generate ephemeral EC key pair cc_assert(ecies->rng!=NULL); cc_require(ccecdh_generate_key(ccec_ctx_cp(public_key), ecies->rng, ephemeral_key)==0,errOut); #if CC_DEBUG_ECIES ccec_print_full_key("Ephemeral key",ephemeral_key); #endif // 2) ECDH with input public key cc_require(ccecdh_compute_shared_secret(ephemeral_key, public_key, &skey_size, skey,ecies->rng)==0,errOut); #if CC_DEBUG_ECIES cc_print("Shared secret key",skey_size,skey); #endif // 3) Export ephemeral public key cc_require( ccecies_export(0, ecies->options, exported_public_key, ephemeral_key)==0, errOut); // 4) Derive Enc / Mac key // Hash(skey|00000001|sharedinfo_1) cc_assert(ecies->key_length<=skey_size); exported_public_key_size=ccecies_pub_key_size(ephemeral_key,ecies); if (ECIES_EPH_PUBKEY_IN_SHAREDINFO1 == (ecies->options & ECIES_EPH_PUBKEY_IN_SHAREDINFO1)) { // use ephemeral public key as shared info 1 cc_require(ccansikdf_x963(ecies->di, skey_size,skey, exported_public_key_size,exported_public_key, ecies->key_length,skey)==0,errOut); } else { cc_require(ccansikdf_x963(ecies->di, skey_size,skey, sharedinfo1_byte_len,sharedinfo_1, ecies->key_length,skey)==0,errOut); } #if CC_DEBUG_ECIES cc_print("Cipher key",ecies->key_length,skey); #endif // 5) Encrypt ccgcm_init(gcm_encrypt, gcm_ctx,ecies->key_length,skey); ccgcm_set_iv(gcm_encrypt,gcm_ctx,sizeof(ecies_iv_data),ecies_iv_data); if ((sharedinfo_2!=NULL) && (sharedinfo2_byte_len>0)) { ccgcm_gmac(gcm_encrypt,gcm_ctx,sharedinfo2_byte_len,sharedinfo_2); } else { ccgcm_gmac(gcm_encrypt,gcm_ctx,0,NULL); } ccgcm_update(gcm_encrypt,gcm_ctx, plaintext_len,plaintext, ciphertext); #if CC_DEBUG_ECIES cc_print("Encrypted message",plaintext_len,ciphertext); #endif // 6) Mac (with SharedInfo 2) // sec1, p51: recommended: SharedInfo2 ended in a counter giving its length. ccgcm_finalize(gcm_encrypt,gcm_ctx,ecies->mac_length,mac_tag); #if CC_DEBUG_ECIES cc_print("Mac Tag",ecies->mac_length,mac_tag); #endif // Success status=0; errOut: // Clear key material info ccgcm_ctx_clear(gcm_encrypt->size,gcm_ctx); cc_clear(sizeof(skey),skey); ccec_full_ctx_clear_cp(ccec_ctx_cp(public_key), ephemeral_key); return status; }