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 #2
0
void cczp_mul_ws(cczp_const_t zp, cc_unit *t, const cc_unit *x, const cc_unit *y, cc_ws_t ws) {
    //ccn_lprint(cczp_n(zp),"x: ",x);
    //ccn_lprint(cczp_n(zp),"y: ",y);
    cc_unit *tbig=ws->start;
    ws->start+=(2 * cczp_n(zp));
    ccn_mul_ws(cczp_n(zp), tbig, x, y, ws);
    //ccn_lprint(2*cczp_n(zp),"tbig: ",tbig);
    zp.zp->mod_prime(zp.zp, t, tbig, ws);
    ws->start-=(2 * cczp_n(zp));
}
Exemple #3
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);
    }
}
Exemple #4
0
void ccz_invmod(ccz *r, const ccz *s, const ccz *t) {
    ccz_set_sign(r, 1);
    ccz_set_capacity(r, ccz_n(t));

    ccz_zp_decl(t, zt);
    cc_unit u[cczp_n(zt)];
    cczp_modn(zt, u, ccz_n(s), s->u);

    cczp_mod_inv_slow(zt, r->u, u);
    ccz_set_n(r, ccn_n(cczp_n(zt), r->u));
}
Exemple #5
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 #7
0
void ccz_sqrmod(ccz *r, const ccz *s, const ccz *t) {
    ccz_set_sign(r, 1);
    ccz_set_capacity(r, CC_MAX(2 * ccz_n(s), ccz_n(t)));
    ccz_zp_decl(t, zt);
    ccn_sqr(ccz_n(s), r->u, s->u);
    cczp_modn(zt, r->u, 2 * ccz_n(s), r->u);
    ccz_set_n(r, ccn_n(cczp_n(zt), r->u));
}
Exemple #8
0
/* r = s^e (mod zp->prime).
 Caller provides recip of m as recip; s and r can have the same address. */
void cczp_powern(cczp_const_t zp, cc_unit *r, const cc_unit *s, size_t ebitlen, const cc_unit *e) {
    assert(r != s);
    assert(r != e);
    if (ebitlen == 0) {
        ccn_seti(cczp_n(zp), r, 1);
		return;
	}

    cczp_modn(zp, r, cczp_n(zp), s);

	if (ebitlen == 1)
		return;

	for (unsigned long bit = ebitlen - 2; bit < ebitlen; --bit) {
        cczp_mul(zp, r, r, r);  // cczp_sqr
        if (ccn_bit(e, bit)) {
            cczp_mul(zp, r, r, s);
		}
	}
}
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;
}
Exemple #10
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);
}
static inline ccdh_full_ctx_t SecDH_priv(SecDHContext dh)
{
    void *p = dh;
    cczp_t zp = { .u = p };
    cc_size s = ccn_sizeof_n(cczp_n(zp));
    ccdh_full_ctx_t priv = { .hdr = (struct ccdh_ctx_header *)(p+ccdh_gp_size(s)) };
    return priv;
}

static inline size_t SecDH_context_size(size_t p_len)
{
    cc_size n = ccn_nof_size(p_len);
    cc_size real_p_len = ccn_sizeof_n(n);
    size_t context_size = ccdh_gp_size(real_p_len)+ccdh_full_ctx_size(real_p_len);
    return context_size;
}
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");
}
Exemple #13
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 #14
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);

}
static OSStatus ccrsa_full_decode(ccrsa_full_ctx_t fullkey, size_t pkcs1_size, const uint8_t* pkcs1)
{
    OSStatus result = errSecParam;

	DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size};
    DERRSAKeyPair decodedKey;

	require_noerr_action(DERParseSequence(&keyItem,
                                          DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs,
                                          &decodedKey, sizeof(decodedKey)),
                         errOut, result = errSecDecode);

    require_noerr(ccrsa_pub_init(fullkey,
                                 decodedKey.n.length, decodedKey.n.data,
                                 decodedKey.e.length, decodedKey.e.data),
                  errOut);
    ccn_read_uint(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey),
                  decodedKey.d.length, decodedKey.d.data);
    {
        ccrsa_priv_ctx_t privkey = ccrsa_ctx_private(fullkey);
        CCZP_N(ccrsa_ctx_private_zp(privkey)) = ccn_nof((ccn_bitsof_n(ccrsa_ctx_n(fullkey)) / 2) + 1);
        CCZP_N(ccrsa_ctx_private_zq(privkey)) = cczp_n(ccrsa_ctx_private_zp(privkey));

        // TODO: Actually remember decodedKey.d.

        require_noerr(ccrsa_priv_init(privkey,
                                     decodedKey.p.length, decodedKey.p.data,
                                      decodedKey.q.length, decodedKey.q.data,
                                      decodedKey.dp.length, decodedKey.dp.data,
                                      decodedKey.dq.length, decodedKey.dq.data,
                                      decodedKey.qInv.length, decodedKey.qInv.data),
                      errOut);
    }

    result = errSecSuccess;

errOut:
    return result;
}
static inline ccdh_full_ctx_t vmdh_priv(struct vmdh *dh)
{
    void *p = dh;
    cczp_t zp = { .u = p };
    cc_size s = ccn_sizeof_n(cczp_n(zp));
    ccdh_full_ctx_t priv = { .hdr = (struct ccdh_ctx_header *)(p+ccdh_gp_size(s)) };
    return priv;
}

static uint32_t param_g = 5;

static const uint8_t param_p[] = {
    0xED, 0x42, 0x06, 0xE1, 0xDD, 0x09, 0x93, 0xA6,
    0x81, 0xAE, 0x00, 0x0D, 0xBF, 0x84, 0x7F, 0x7D,
    0x87, 0x64, 0x6B, 0x77, 0x24, 0x03, 0xB8, 0xC0,
    0xDC, 0xBE, 0x5B, 0x9C, 0x8E, 0x71, 0x09, 0x24,
    0x53, 0x77, 0x7F, 0x5D, 0x1A, 0xAD, 0x92, 0xD8,
    0xFE, 0xCD, 0x5C, 0xB4, 0xCA, 0x09, 0x17, 0x11,
    0xF3, 0x82, 0x01, 0x39, 0x4A, 0x09, 0xBA, 0x29,
    0x95, 0x2B, 0xC4, 0xCC, 0x56, 0x21, 0x97, 0x13
};

static const uint8_t client_priv[] = {
    0x32, 0x34, 0x73, 0x16, 0x7d, 0x79, 0xde, 0x47,
    0x22, 0x93, 0xf5, 0x86, 0x47, 0xf6, 0x7f, 0x7a,
    0xb6, 0x30, 0x16, 0x5b, 0xbf, 0xe1, 0x36, 0x0b,
    0xb4, 0xd2, 0x84, 0x3e, 0x57, 0x5f, 0xcb, 0xc6,
    0x6a, 0xae, 0x5d, 0x59, 0x4b, 0x70, 0x53, 0x22,
    0xb0, 0x51, 0x89, 0x30, 0x74, 0xfc, 0x95, 0x51,
    0x9c, 0xc9, 0xf7, 0xac, 0x8c, 0x37, 0xfd, 0xc1,
    0x0e, 0x02, 0x6e, 0x69, 0x6c, 0xca, 0x2a, 0x95
};

static const uint8_t client_pub[] = {
    0x15, 0xDF, 0x17, 0x6E, 0xB4, 0x95, 0xA7, 0x92,
    0x41, 0xB6, 0xF1, 0x93, 0x19, 0xDB, 0x34, 0xF1,
    0xE0, 0x0D, 0x62, 0xCD, 0x55, 0xC7, 0x0B, 0x27,
    0xB7, 0x53, 0x1A, 0x28, 0x65, 0x11, 0xF0, 0xF6,
    0xA6, 0xE1, 0x5B, 0x86, 0x1D, 0x67, 0x85, 0x19,
    0x6D, 0xD6, 0x80, 0xFF, 0x5C, 0xEB, 0xC3, 0x2D,
    0xC3, 0xCB, 0xD2, 0xD4, 0x66, 0x93, 0xF4, 0xFC,
    0xF1, 0xF4, 0x8B, 0x61, 0x0F, 0x02, 0xF5, 0x19
};

static const uint8_t server_pub[] = {
    0x73, 0xC5, 0xF8, 0xF8, 0xB8, 0x9C, 0xB0, 0x5F,
    0xD6, 0xC6, 0x49, 0x5C, 0x70, 0xF5, 0x90, 0xB3,
    0x8A, 0xD3, 0xD0, 0x12, 0x99, 0x47, 0x60, 0xC2,
    0x5B, 0xF7, 0x18, 0x3A, 0x19, 0xF5, 0x01, 0xA3,
    0x67, 0xBF, 0x57, 0x28, 0x7E, 0x99, 0xA8, 0xDB,
    0x97, 0xA4, 0xAF, 0xF2, 0x68, 0x47, 0xAB, 0x48,
    0xE3, 0x4D, 0xF2, 0x94, 0xB4, 0xCC, 0xFC, 0x0C,
    0x50, 0xAD, 0xEF, 0x2E, 0x80, 0xA6, 0x20, 0x29
};

static const uint8_t pw[] = {
	0x31, 0x32, 0x33, 0x34
};

static const uint8_t pw_encr[] = {
    0x42, 0xd7, 0xa1, 0x08, 0x15, 0x8f, 0xdd, 0xc8,
    0xe8, 0x75, 0xea, 0xa2, 0xc2, 0x20, 0x28, 0xfa
};

#if 0
static void hexdump(const uint8_t *bytes, size_t len) {
	size_t ix;
	for (ix = 0; ix < len; ++ix) {
		printf("%02X", bytes[ix]);
	}
	printf("\n");
}
Exemple #17
0
size_t SecDHGetMaxKeyLength(SecDHContext dh) {
    cczp_const_t zp;
    zp.u = (cc_unit *)dh;

    return ccn_sizeof_n(cczp_n(zp));
}
Exemple #18
0
void cczp_mul(cczp_const_t zp, cc_unit *t, const cc_unit *x, const cc_unit *y) {
    CC_DECL_WORKSPACE(ws,CCZP_MUL_WORKSPACE_N(cczp_n(zp)));
    cczp_mul_ws(zp,t,x,y,ws);
    CC_FREE_WORKSPACE(ws);
}
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;
}