int cczp_random_prime(cc_size nbits, cczp_t zp, const cc_unit *e,
                       struct ccrng_state *rng) {
	cc_size lbits = nbits & (CCN_UNIT_BITS - 1);
    lbits = lbits == 0 ? CCN_UNIT_BITS : lbits;
    cc_unit msuMask = (~CC_UNIT_C(0)) >> (CCN_UNIT_BITS - lbits);
    cc_unit msBit = CC_UNIT_C(1) << (lbits - 1);
    cc_size n = ccn_nof(nbits);
    CCZP_N(zp) = n;
    for (;;) {
        /* Generate nbit wide random ccn. */
        if(ccn_random(n, CCZP_PRIME(zp), rng) != 0) return -1;
        /* Mask out unsued bit and set high bit. */
        CCZP_PRIME(zp)[n - 1] = (cczp_prime(zp)[n - 1] & msuMask) | msBit;
        ccn_set_bit(CCZP_PRIME(zp), nbits - 2, 1); /* Set second highest bit per X9.31 */
        ccn_set_bit(CCZP_PRIME(zp), 0U, 1);        /* Make it odd: set bit 0 to 1 */

		/* First ensure r - 1 and e are relatively prime */
        cc_unit tmp[n];
        ccn_sub1(n, tmp, cczp_prime(zp), 1);
        ccn_gcd(n, tmp, tmp, e);
        if (!ccn_is_one(n, tmp)) {
            //ccn_lprint(n, "gcd of r - 1 and e is ", tmp);
            continue;
        }

        if (cczp_rabin_miller(zp, CCRSA_PRIME_DEPTH))
            break;
    }
    return 0;
}
static int ccrsa_priv_init(ccrsa_priv_ctx_t privkey,
                           size_t p_size, const uint8_t* p,
                           size_t q_size, const uint8_t* q,
                           size_t dp_size, const uint8_t* dp,
                           size_t dq_size, const uint8_t* dq,
                           size_t qinv_size, const uint8_t* qinv)
{
    int result = -1;

    const cc_size np = cczp_n(ccrsa_ctx_private_zp(privkey));
    cc_size nq = cczp_n(ccrsa_ctx_private_zq(privkey));

    if (ccn_read_uint(np, CCZP_PRIME(ccrsa_ctx_private_zp(privkey)), p_size, p))
        goto errOut;
    cczp_init(ccrsa_ctx_private_zp(privkey));
    if (ccn_read_uint(np, ccrsa_ctx_private_dp(privkey), dp_size, dp))
        goto errOut;
    if (ccn_read_uint(np, ccrsa_ctx_private_qinv(privkey), qinv_size, qinv))
        goto errOut;

    if (ccn_read_uint(nq, CCZP_PRIME(ccrsa_ctx_private_zq(privkey)), q_size, q))
        goto errOut;

    nq = ccn_n(nq, cczp_prime(ccrsa_ctx_private_zq(privkey)));
    CCZP_N(ccrsa_ctx_private_zq(privkey)) = nq;

    cczp_init(ccrsa_ctx_private_zq(privkey));
    if (ccn_read_uint(nq, ccrsa_ctx_private_dq(privkey), dq_size, dq))
        goto errOut;

    result = 0;

errOut:
    return result;
}
Exemple #3
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;
}
size_t ccder_encode_rsa_priv_size(const ccrsa_full_ctx_t key) {
    ccrsa_priv_ctx_t privk = ccrsa_ctx_private(key);
    cc_size n = ccrsa_ctx_n(key);
	cc_unit version_0[ccn_nof(1)] = {0x00};
	return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
      ccder_sizeof_integer(ccn_nof(1), version_0) +
      ccder_sizeof_integer(n, ccrsa_ctx_m(key)) +
      ccder_sizeof_integer(n, ccrsa_ctx_e(key)) +
      ccder_sizeof_integer(n, ccrsa_ctx_d(key)) +
      ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zp(privk)), cczp_prime(ccrsa_ctx_private_zp(privk))) +
      ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zq(privk)), cczp_prime(ccrsa_ctx_private_zq(privk))) +
      ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zp(privk)), ccrsa_ctx_private_dp(privk)) +
      ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zq(privk)), ccrsa_ctx_private_dq(privk)) +
      ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zp(privk)), ccrsa_ctx_private_qinv(privk))
    );
}
Exemple #5
0
void cczp_div2(cczp_const_short_t  zp, cc_unit *r, const cc_unit *x) {
    if (x[0] & 1) {
        /* x is odd r = (x + p) >> 1 */
        cc_unit carry = ccn_add(cczp_n(zp), r, x, cczp_prime(zp));
        ccn_shift_right(cczp_n(zp), r, r, 1);
        r[cczp_n(zp) - 1] |= carry << (CCN_UNIT_BITS - 1);
    } else {
        /* x is even r = x >> 1 */
        ccn_shift_right(cczp_n(zp), r, x, 1);
    }
}
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;
}
int ccrsa_get_fullkey_components(const ccrsa_full_ctx_t key, 
                                 uint8_t *modulus, size_t *modulusLength, 
                                 uint8_t *exponent, size_t *exponentLength,
                                 uint8_t *p, size_t *pLength, 
                                 uint8_t *q, size_t *qLength)
{
    cc_size n = ccrsa_ctx_n(key);
    if(ccCoreZP2pointerAndData(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))),
                               cczp_prime(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))),
                               p, pLength )) return -1;
    if(ccCoreZP2pointerAndData(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))),
                               cczp_prime(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))),
                               q, qLength )) return -1;
    if(ccCoreZP2pointerAndData(n,
                               ccrsa_ctx_m(key),
                               modulus, modulusLength )) return -1;
    if(ccCoreZP2pointerAndData(n,
                               ccrsa_ctx_d(key),
                               exponent, exponentLength )) return -1;

    return 0;
}
void ccrsa_dump_full_key(ccrsa_full_ctx_t key) {
    ccn_cprint(ccrsa_ctx_n(key),      "uint8_t m[]  = ", ccrsa_ctx_m(key));
    ccn_cprint(ccrsa_ctx_n(key) + 1,  "uint8_t rm[] = ", cczp_recip(ccrsa_ctx_zm(key)));
    ccn_cprint(ccrsa_ctx_n(key),      "uint8_t e[]  = ", ccrsa_ctx_e(key));
    ccn_cprint(ccrsa_ctx_n(key),      "uint8_t d[]  = ", ccrsa_ctx_d(key));

    printf("cc_size np = %lu;\n", cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))));
    ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))),     "uint8_t p[]  = ",
               cczp_prime(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))));
    ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))) + 1, "uint8_t rp[] = ",
               cczp_recip(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))));
    printf("cc_size nq = %lu;\n", cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))));
    ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))),     "uint8_t q[]  = ",
               cczp_prime(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))));
    ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))) + 1, "uint8_t rq[] = ",
               cczp_recip(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))));
    ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))),     "uint8_t dp[] = ",
               ccrsa_ctx_private_dp(ccrsa_ctx_private(key)));
    ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))),     "uint8_t dq[] = ",
               ccrsa_ctx_private_dq(ccrsa_ctx_private(key)));
    ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))),     "uint8_t qinv[] = ",
               ccrsa_ctx_private_qinv(ccrsa_ctx_private(key)));
    printf("--\n");
}
int ccdh_import_priv(ccdh_const_gp_t gp, size_t in_len, const uint8_t *in,
                     ccdh_full_ctx_t key)
{
    const cc_unit *g = ccdh_gp_g(gp);
    ccdh_ctx_init(gp, key);
    cc_unit *x = ccdh_ctx_x(key);
    cc_unit *y = ccdh_ctx_y(key);

    if ((ccn_read_uint(ccdh_gp_n(gp), x, in_len, in)))
        return CCDH_INVALID_INPUT;
    
    if (ccn_cmp(ccdh_gp_n(gp), x, cczp_prime(gp.zp)) >= 0)
        return CCDH_SAFETY_CHECK;
    
    /* Generate the public key: y=g^x mod p */
    cczp_power(gp.zp, y, g, x);
    
    return 0;
}
Exemple #10
0
static void ccn_mod_521(cczp_const_t zp, cc_unit *r, const cc_unit *a, CC_UNUSED cc_ws_t ws) {
    cc_assert(cczp_n(zp) == CCN521_N);
    cc_unit t[CCN521_N];
    cc_unit t2[CCN521_N];
    cc_unit *select[2] __attribute__((aligned(16))) ={t,t2};
    cc_unit borrow;

#if CCN_UNIT_SIZE == 1
    ccn_shift_right(CCN521_N - 1, t2, &a[CCN521_N - 1], 1); // r = a521,...,a1041
    t2[CCN521_N - 1] += a[CCN521_N - 1] & CC_UNIT_C(1);
    t2[CCN521_N - 1] += ccn_add(CCN521_N - 1,t2,t2,a);
#else
    ccn_shift_right(CCN521_N, t2, &a[CCN512_N], 9);  // r = a521,...,a1041
    t2[CCN512_N] += a[CCN512_N] & CC_UNIT_C(0x1ff);  // r += (a512,...,a520)*2^512
    t2[CCN512_N] += ccn_add(CCN512_N,t2,t2,a);         // r += a0,...,a511
#endif
    borrow=ccn_sub(CCN521_N, t, t2, cczp_prime(zp));
    ccn_set(CCN521_N,r,select[borrow]);
}
Exemple #11
0
/* r = s^e (mod zp->prime).
 Caller provides recip of m as recip; s and r can have the same address. */
void
cczp_power(cczp_const_t zp, cc_unit *r, const cc_unit *s, const cc_unit *e) {
    cc_size n = cczp_n(zp);
    unsigned long ebitlen = ccn_bitlen(n, e);

    if (ebitlen == 0) {
        ccn_seti(n, r, 1);
        return;
    }

    CC_DECL_WORKSPACE(ws, CCZP_MUL_WORKSPACE_N(n)+n);
    cc_unit *r1=ws->start;
    ws->start+=n;

    /* do we actually need to handle this case where s>m */
	if (ccn_cmp(cczp_n(zp), s, cczp_prime(zp)) >= 0) {
        cc_unit *tbig=ws->start; // 2*n buffer
        ws->start+=2*n;
        ccn_zero(n, tbig + n);
        ccn_set(n, tbig, s);
        cczp_mod(zp, r, tbig, ws);
        ws->start-=2*n;
	} else {
        ccn_set(n, r, s);
	}

	if (ebitlen != 1)
    {
        cc_unit *R[2] __attribute__((aligned(16)))={r,r1};
        cczp_sqr_ws(zp, r1, r, ws);
        for (unsigned long bit = ebitlen - 2; bit < ebitlen; --bit) {
            cc_unit ki=ccn_bit(e, bit);
            cczp_mul_ws(zp, R[ki^1], R[ki], R[ki^1],ws);
            cczp_sqr_ws(zp, R[ki], R[ki], ws);
        }
    }
    ws->start-=n; // r
    CC_CLEAR_AND_FREE_WORKSPACE(ws);
}
Exemple #12
0
static void ccn_mod_384(cczp_const_t zp, cc_unit *r, const cc_unit *a, CC_UNUSED cc_ws_t ws) {
    cc_assert(cczp_n(zp) == CCN384_N);
    cc_unit s1[CCN384_N] = { ccn384_32(  Anil,  Anil,  Anil,  Anil,  Anil, A(23), A(22), A(21),  Anil,  Anil,  Anil,  Anil) };
    //cc_unit s2[CCN384_N] = { ccn384_32( A(23), A(22), A(21), A(20), A(19), A(18), A(17), A(16), A(15), A(14), A(13), A(12)) };
    cc_unit s3[CCN384_N] = { ccn384_32( A(20), A(19), A(18), A(17), A(16), A(15), A(14), A(13), A(12), A(23), A(22), A(21)) };
    cc_unit s4[CCN384_N] = { ccn384_32( A(19), A(18), A(17), A(16), A(15), A(14), A(13), A(12), A(20),  Anil, A(23),  Anil) };
    cc_unit s5[CCN384_N] = { ccn384_32(  Anil,  Anil,  Anil,  Anil, A(23), A(22), A(21), A(20),  Anil,  Anil,  Anil,  Anil) };
    cc_unit s6[CCN384_N] = { ccn384_32(  Anil,  Anil,  Anil,  Anil,  Anil,  Anil, A(23), A(22), A(21),  Anil,  Anil, A(20)) };
    cc_unit d1[CCN384_N] = { ccn384_32( A(22), A(21), A(20), A(19), A(18), A(17), A(16), A(15), A(14), A(13), A(12), A(23)) };
    cc_unit d2[CCN384_N] = { ccn384_32(  Anil,  Anil,  Anil,  Anil,  Anil,  Anil,  Anil, A(23), A(22), A(21), A(20),  Anil) };
    cc_unit d3[CCN384_N] = { ccn384_32(  Anil,  Anil,  Anil,  Anil,  Anil,  Anil,  Anil, A(23), A(23),  Anil,  Anil,  Anil) };
    cc_unit *select[2] __attribute__((aligned(16))) ={s1,s3};

    cc_unit carry,carry_mask;
    ccn_add(ccn_nof(160)+1, d2, d2, d3);  // smaller size and no carry possible
    ccn_add(ccn_nof(224)+1, s1, s1, s1);  // smaller size and no carry possible, alternatively cc_shiftl(s1, 1) but add is currently faster.
    ccn_add(ccn_nof(256)+1, s5, s5, s1);  // smaller size and no carry possible
    ccn_add(ccn_nof(256)+1, s5, s5, s6);  // smaller size and no carry possible

    carry = ccn_add(CCN384_N, r, a, &a[CCN384_N]);
    carry += ccn_add(CCN384_N, r, r, s3);
    carry += ccn_add(CCN384_N, r, r, s4);
    carry += ccn_add(CCN384_N, r, r, s5);
    carry -= ccn_sub(CCN384_N, d1, cczp_prime(zp), d1);
    carry += ccn_add(CCN384_N, r, r, d1);
    carry -= ccn_sub(CCN384_N, s3, r, d2);

    /* Reduce r mod p384 by subtraction of up to four multiples of p384. */
    carry_mask=CC_CARRY_3BITS(carry);
    carry -= (carry_mask & ccn_sub(CCN384_N,select[carry_mask],s3,cczp_prime(zp)));
    carry_mask=CC_CARRY_2BITS(carry);
    carry -= (carry_mask & ccn_sub(CCN384_N,select[carry_mask],s3,cczp_prime(zp)));
    carry_mask=CC_CARRY_2BITS(carry);
    carry -= (carry_mask & ccn_sub(CCN384_N,select[carry_mask],s3,cczp_prime(zp)));
    carry ^= ccn_sub(CCN384_N,s1,s3,cczp_prime(zp));

    ccn_set(CCN384_N,r,select[carry]);

    /* Sanity for debug */
    cc_assert(ccn_cmp(CCN384_N, r, cczp_prime(zp)) < 0);

}
Exemple #13
0
static int ccec_mult_ws(ccec_const_cp_t cp, ccec_projective_point_t r, const cc_unit *d, ccec_const_projective_point_t s, struct ccrng_state *rng, cc_ws_t ws) {
    cc_size n=ccec_cp_n(cp);
    size_t dbitlen=ccn_bitlen(n,d);

    cc_unit *R0=ws->start;          // R0 and R1 are full points:
    cc_unit *R1=ws->start+2*n;      // X in [0..n-1] and Y in [n..2n-1]
    ws->start+=4*n;
    cc_assert((ws->start)<=ws->end); // Check that provided workspace is sufficient;

    // Check edge cases

    // Scalar d must be <= q to
    // prevent intermediary results to be the point at infinity
    // corecrypto to take care to meet this requirement
    cc_assert(ccn_cmp(n,d,cczp_prime(ccec_cp_zq(cp)))<=0); // d <= q
    ccn_sub1(n,R0,cczp_prime(ccec_cp_zq(cp)),1); // q-1
    if (dbitlen < 1) {
        ccn_clear(n, ccec_point_x(r, cp));
        ccn_clear(n, ccec_point_y(r, cp));
        ccn_clear(n, ccec_point_z(r, cp));
    } else if (dbitlen == 1) {
        // If d=1 => r=s
        ccn_set(n, ccec_point_x(r, cp), ccec_const_point_x(s, cp));
        ccn_set(n, ccec_point_y(r, cp), ccec_const_point_y(s, cp));
        ccn_set(n, ccec_point_z(r, cp), ccec_const_point_z(s, cp));
    } else if (ccn_cmp(n,d,R0)==0) {
        // If d=(q-1) => r=-s
        // Case not handle by Montgomery Ladder because R1-R0 = s.
        // On the last iteration r=R0 => R1 is equal to infinity which is not supported
        ccn_set(n, ccec_point_x(r, cp), ccec_const_point_x(s, cp));
        ccn_sub(n, ccec_point_y(r, cp), cczp_prime(cp.zp), ccec_const_point_y(s, cp));
        ccn_set(n, ccec_point_z(r, cp), ccec_const_point_z(s, cp));
    }
    else {
        // Randomize buffer to harden against cache attacks
        // TODO: scalar randomization.
        cc_unit c=1;
        if (rng) ccn_random_bits(1,&c,rng);

        // Core of the EC scalar multiplication
        cc_unit dbit; // Bit of d at index i
        cc_unit *R[2] __attribute__((aligned(16)))={R0,R1};

        XYCZdblJac(cp,R[c^1],R[c^0],s,ws);

        // Main loop
        for (unsigned long i = dbitlen - 2; i>0; --i) {
            dbit=c^(ccn_bit(d, i));
            XYCZaddC(cp,R[dbit],R[1^dbit],ws);
            XYCZadd(cp,R[dbit],R[1^dbit],ws);
            // Per Montgomery Ladder:
            // Invariably, R1 - R0 = P at this point of the loop
        }

        // Last iteration
        dbit=c^(ccn_bit(d, 0));
        XYCZaddC(cp,R[dbit],R[1^dbit],ws);
        // If d0 =      0           1
        //          R1-R0=-P     R1-R0=P
        // Therefore we can reconstruct the Z coordinate
        // To save an inversion and keep the result in Jacobian projective coordinates,
        //  we compute coefficient for X and Y.
        XYCZrecoverCoeffJac(cp,
                            ccec_point_x(r, cp),
                            ccec_point_y(r, cp),
                            ccec_point_z(r, cp),
                            R[c^1],R[c^0],
                            (int)(dbit^c),
                            s,
                            ws);
        XYCZadd(cp,R[dbit],R[1^dbit],ws);

        // Apply coefficients
        cczp_mul_ws(cp.zp,  ccec_point_x(r, cp), ccec_point_x(r, cp), &(R[c][0]), ws); // X0 * lambdaX
        cczp_mul_ws(cp.zp,  ccec_point_y(r, cp), ccec_point_y(r, cp), &(R[c][n]), ws); // Y0 * lambdaY
    }
#if CCEC_MULT_DEBUG
    ccn_lprint(n, "Result X:", ccec_point_x(r, cp));
    ccn_lprint(n, "Result Y:", ccec_point_y(r, cp));
    ccn_lprint(n, "Result Z:", ccec_point_z(r, cp));
#endif
    ws->start-=4*n;

    return 0;
}
static CFDataRef SecRSAPrivateKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_full_ctx_t fullkey)
{
    ccrsa_priv_ctx_t privkey = ccrsa_ctx_private(fullkey);

    const cc_size np = cczp_n(ccrsa_ctx_private_zp(privkey));
    const cc_size nq = cczp_n(ccrsa_ctx_private_zq(privkey));

    size_t m_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey));
    size_t e_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_e(fullkey));
    size_t d_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey));

    size_t p_size = ccn_write_int_size(np, cczp_prime(ccrsa_ctx_private_zp(privkey)));
    size_t q_size = ccn_write_int_size(nq, cczp_prime(ccrsa_ctx_private_zq(privkey)));

    size_t dp_size = ccn_write_int_size(np, ccrsa_ctx_private_dp(privkey));
    size_t dq_size = ccn_write_int_size(nq, ccrsa_ctx_private_dq(privkey));

    size_t qinv_size = ccn_write_int_size(np, ccrsa_ctx_private_qinv(privkey));

    const size_t seq_size = 3 +
                            DERLengthOfItem(ASN1_INTEGER, m_size) +
                            DERLengthOfItem(ASN1_INTEGER, e_size) +
                            DERLengthOfItem(ASN1_INTEGER, d_size) +
                            DERLengthOfItem(ASN1_INTEGER, p_size) +
                            DERLengthOfItem(ASN1_INTEGER, q_size) +
                            DERLengthOfItem(ASN1_INTEGER, dp_size) +
                            DERLengthOfItem(ASN1_INTEGER, dq_size) +
                            DERLengthOfItem(ASN1_INTEGER, qinv_size);

    const size_t result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size);

	CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size);

    if (pkcs1 == NULL)
        return NULL;

	CFDataSetLength(pkcs1, result_size);

    uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1);

    *bytes++ = ASN1_CONSTR_SEQUENCE;

    DERSize itemLength = 4;
    DEREncodeLength(seq_size, bytes, &itemLength);
    bytes += itemLength;

    *bytes++ = ASN1_INTEGER;
    *bytes++ = 0x01;
    *bytes++ = 0x00;

    ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey), m_size, &bytes);
    ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_e(fullkey), e_size, &bytes);
    ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey), d_size, &bytes);

    ccasn_encode_int(np, cczp_prime(ccrsa_ctx_private_zp(privkey)), p_size, &bytes);
    ccasn_encode_int(nq, cczp_prime(ccrsa_ctx_private_zq(privkey)), q_size, &bytes);
    ccasn_encode_int(np, ccrsa_ctx_private_dp(privkey), dp_size, &bytes);
    ccasn_encode_int(nq, ccrsa_ctx_private_dq(privkey), dq_size, &bytes);
    ccasn_encode_int(np, ccrsa_ctx_private_qinv(privkey), qinv_size, &bytes);

    return pkcs1;
}