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;
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}
Exemple #5
0
//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;
}
Exemple #9
0
//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;
}
Exemple #10
0
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;
}
Exemple #11
0
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
}
Exemple #13
0
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;
}
Exemple #16
0
// 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;
}
Exemple #17
0
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;
}