int32_t ZrtpDH::getPubKeyBytes(uint8_t *buf) const { dhCtx* tmpCtx = static_cast<dhCtx*>(ctx); if (pkType == DH2K || pkType == DH3K) { // get len of pub_key, prepend with zeros to DH size int size = getPubKeySize(); int32_t prepend = getDhSize() - size; if (prepend > 0) { memset(buf, 0, prepend); } bnExtractBigBytes(&tmpCtx->pubKey, buf + prepend, 0, size); return size; } if (pkType == EC25 || pkType == EC38 || pkType == E414) { int32_t len = getPubKeySize() / 2; bnExtractBigBytes(tmpCtx->pubPoint.x, buf, 0, len); bnExtractBigBytes(tmpCtx->pubPoint.y, buf+len, 0, len); return len * 2; } if (pkType == E255) { int32_t len = getPubKeySize(); bnExtractLittleBytes(tmpCtx->pubPoint.x, buf, 0, len); return len; } return 0; }
/* Initialize BSafe pubkey structure from a RSApub. */ static int rpubk_init(B_KEY_OBJ rpubk, RSApub const *pub, PGPMemoryMgrRef mgr) { A_RSA_KEY kdata; PGPByte *buf; PGPSize bufsize; int err; bufsize = bnBytes(&pub->n) + bnBytes(&pub->e); buf = PGPNewSecureData( mgr, bufsize, 0 ); kdata.modulus.data = buf; kdata.modulus.len = bnBytes(&pub->n); kdata.exponent.data = buf + kdata.modulus.len; kdata.exponent.len = bnBytes(&pub->e); bnExtractBigBytes (&pub->n, kdata.modulus.data, 0, kdata.modulus.len); bnExtractBigBytes (&pub->e, kdata.exponent.data, 0, kdata.exponent.len); err = B_SetKeyInfo (rpubk, KI_RSAPublic, (POINTER)&kdata); pgpAssert (err == 0); pgpClearMemory (buf, bufsize); PGPFreeData (buf); return err; }
int bnPrint(FILE *f, char const *prefix, BigNum const *bn, char const *suffix) { unsigned char temp[32]; /* How much to print on one line */ unsigned len; size_t i; if (prefix && fputs(prefix, f) < 0) return EOF; len = (bnBits(bn) + 7)/ 8; if (!len) { if (putc('0', f) < 0) return EOF; } else { while (len > sizeof(temp)) { len -= sizeof(temp); bnExtractBigBytes(bn, temp, len, sizeof(temp)); for (i = 0; i < sizeof(temp); i++) if (fprintf(f, "%02X", temp[i]) < 0) return EOF; if (putc('\\', f) < 0 || putc('\n', f) < 0) return EOF; if (prefix) { i = strlen(prefix); while (i--) if (putc(' ', f) < 0) return EOF; } } bnExtractBigBytes(bn, temp, 0, len); for (i = 0; i < len; i++) if (fprintf(f, "%02X", temp[i]) < 0) return EOF; } return suffix ? fputs(suffix, f) : 0; }
int rsa_EXTRACTKEYS(RSA_CTX *ctx,unsigned char **N,unsigned char **d, unsigned char **e){ /* we extract as big - endian */ /* unsigned int a=bnBits(&ctx->e); unsigned int b=a/8; b+=1; */ *N=(unsigned char*)Lmalloc((ctx->bits/8)+1); *d=(unsigned char*)Lmalloc((ctx->bits/8)+1); *e=(unsigned char*)Lmalloc((ctx->bits/8)+1); memset(*N,0,(ctx->bits/8)+1); memset(*d,0,(ctx->bits/8)+1); memset(*e,0,(ctx->bits/8)+1); bnExtractBigBytes(&ctx->n,(void*)*N,0,ctx->bits/8); bnExtractBigBytes(&ctx->d,(void*)*d,0,ctx->bits/8); bnExtractBigBytes(&ctx->e,(void*)*e,0,ctx->bits/8); N[(ctx->bits/8)+1]='\0'; d[(ctx->bits/8)+1]='\0'; e[(ctx->bits/8)+1]='\0'; return OK; }
/* * Move bytes between the given buffer and the given BigNum encoded in * base 256. I.e. after either of these, the buffer will be equal to * (bn / 256^lsbyte) % 256^len. The difference is which is altered to * match the other! */ PGPError PGPBigNumExtractBigEndianBytes( PGPBigNumRef bn, PGPByte * dest, PGPUInt32 lsbyte, PGPUInt32 len ) { PGPError err = kPGPError_NoErr; pgpValidateBigNum( bn ); bnExtractBigBytes( &bn->bn, dest, lsbyte, len ); return( err ); }
static zrtp_status_t _prepare_dhpart1(zrtp_stream_t *stream) { zrtp_proto_crypto_t* cc = stream->protocol->cc; zrtp_packet_DHPart_t *dh1 = &stream->messages.dhpart; uint16_t dh_length = (uint16_t)stream->pubkeyscheme->pv_length; zrtp_memcpy(dh1->rs1ID, cc->rs1.id.buffer, ZRTP_RSID_SIZE); zrtp_memcpy(dh1->rs2ID, cc->rs2.id.buffer, ZRTP_RSID_SIZE); zrtp_memcpy(dh1->auxsID, cc->auxs.id.buffer, ZRTP_RSID_SIZE); zrtp_memcpy(dh1->pbxsID, cc->pbxs.id.buffer, ZRTP_RSID_SIZE); bnExtractBigBytes(&stream->dh_cc.pv, dh1->pv, 0, dh_length); _zrtp_packet_fill_msg_hdr( stream, ZRTP_DHPART1, dh_length + ZRTP_DH_STATIC_SIZE + ZRTP_HMAC_SIZE, &dh1->hdr); return zrtp_status_ok; }
/*---------------------------------------------------------------------------*/ static zrtp_status_t _derive_s0(zrtp_stream_t* stream, int is_initiator) { static const zrtp_string32_t zrtp_kdf_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_KDF_STR); static const zrtp_string32_t zrtp_sess_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_SESS_STR); static const zrtp_string32_t zrtp_multi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_MULTI_STR); static const zrtp_string32_t zrtp_presh_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_PRESH_STR); zrtp_session_t *session = stream->session; zrtp_secrets_t* secrets = &session->secrets; zrtp_proto_crypto_t* cc = stream->protocol->cc; void* hash_ctx = NULL; char print_buff[256]; switch (stream->mode) { /* * S0 computing for FULL DH exchange * S0 computing. s0 is the master shared secret used for all * cryptographic operations. In particular, note the inclusion * of "total_hash", a hash of all packets exchanged up to this * point. This belatedly detects any tampering with earlier * packets, e.g. bid-down attacks. * * s0 = hash( 1 | DHResult | "ZRTP-HMAC-KDF" | ZIDi | ZIDr | * total_hash | len(s1) | s1 | len(s2) | s2 | len(s3) | s3 ) * The constant 1 and all lengths are 32 bits big-endian values. * The fields without length prefixes are fixed-witdh: * - DHresult is fixed to the width of the DH prime. * - The hash type string and ZIDs are fixed width. * - total_hash is fixed by the hash negotiation. * The constant 1 is per NIST SP 800-56A section 5.8.1, and is * a counter which can be incremented to generate more than 256 * bits of key material. * ======================================================================== */ case ZRTP_STREAM_MODE_DH: { zrtp_proto_secret_t *C[3] = { 0, 0, 0}; int i = 0; uint32_t comp_length = 0; zrtp_stringn_t *zidi = NULL, *zidr = NULL; struct BigNum dhresult; #if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) zrtp_uchar1024_t* buffer = zrtp_sys_alloc( sizeof(zrtp_uchar1024_t) ); if (!buffer) { return zrtp_status_alloc_fail; } #else zrtp_uchar1024_t holder; zrtp_uchar1024_t* buffer = &holder; #endif ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 from DH exchange and RS secrets...\n")); ZRTP_LOG(3,(_ZTU_,"\t my rs1ID:%s\n", hex2str(cc->rs1.id.buffer, cc->rs1.id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs1ID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs1ID comp:%s\n", hex2str(cc->rs1.peer_id.buffer, cc->rs1.peer_id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t my rs2ID:%s\n", hex2str(cc->rs2.id.buffer, cc->rs2.id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs2ID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs2ID comp:%s\n", hex2str(cc->rs2.peer_id.buffer, cc->rs2.peer_id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t my pbxsID:%s\n", hex2str(cc->pbxs.id.buffer, cc->pbxs.id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his pbxsID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.pbxsID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\this pbxsID comp:%s\n", hex2str(cc->pbxs.peer_id.buffer, cc->pbxs.peer_id.length, print_buff, sizeof(print_buff)))); hash_ctx = session->hash->hash_begin(session->hash); if (0 == hash_ctx) { ZRTP_LOG(1,(_ZTU_, "\tERROR! can't start hash calculation for S0 computing. ID=%u.\n", stream->id)); return zrtp_status_fail; } /* * NIST requires a 32-bit big-endian integer counter to be included * in the hash each time the hash is computed, which we have set to * the fixed value of 1, because we only compute the hash once. */ comp_length = zrtp_hton32(1L); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&comp_length, 4); switch (stream->pubkeyscheme->base.id) { case ZRTP_PKTYPE_DH2048: case ZRTP_PKTYPE_DH3072: case ZRTP_PKTYPE_DH4096: comp_length = stream->pubkeyscheme->pv_length; ZRTP_LOG(3,(_ZTU_,"DH comp_length=%u\n", comp_length)); break; case ZRTP_PKTYPE_EC256P: case ZRTP_PKTYPE_EC384P: case ZRTP_PKTYPE_EC521P: comp_length = stream->pubkeyscheme->pv_length/2; ZRTP_LOG(3,(_ZTU_,"ECDH comp_length=%u\n", comp_length)); break; default: break; } bnBegin(&dhresult); stream->pubkeyscheme->compute(stream->pubkeyscheme, &stream->dh_cc, &dhresult, &stream->dh_cc.peer_pv); bnExtractBigBytes(&dhresult, (uint8_t *)buffer, 0, comp_length); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)buffer, comp_length); bnEnd(&dhresult); #if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) zrtp_sys_free(buffer); #endif /* Add "ZRTP-HMAC-KDF" to the S0 hash */ session->hash->hash_update( session->hash, hash_ctx, (const int8_t*)&zrtp_kdf_label.buffer, zrtp_kdf_label.length); /* Then Initiator's and Responder's ZIDs */ if (stream->protocol->type == ZRTP_STATEMACHINE_INITIATOR) { zidi = ZSTR_GV(stream->session->zrtp->zid); zidr = ZSTR_GV(stream->session->peer_zid); } else { zidr = ZSTR_GV(stream->session->zrtp->zid); zidi = ZSTR_GV(stream->session->peer_zid); } session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&zidi->buffer, zidi->length); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&zidr->buffer, zidr->length); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&cc->mes_hash.buffer, cc->mes_hash.length); /* If everything is OK - RS1 should much */ if (!zrtp_memcmp(cc->rs1.peer_id.buffer, stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE)) { C[0] = &cc->rs1; secrets->matches |= ZRTP_BIT_RS1; } /* If we have lost our RS1 - remote party should use backup (RS2) instead */ else if (!zrtp_memcmp(cc->rs1.peer_id.buffer, stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE)) { C[0] = &cc->rs1; secrets->matches |= ZRTP_BIT_RS1; ZRTP_LOG(2,(_ZTU_,"\tINFO! We have lost our RS1 from previous broken exchange" " - remote party will use RS2 backup. ID=%u\n", stream->id)); } /* If remote party lost it's secret - we will use backup */ else if (!zrtp_memcmp(cc->rs2.peer_id.buffer, stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE)) { C[0] = &cc->rs2; cc->rs1 = cc->rs2; secrets->matches |= ZRTP_BIT_RS1; secrets->cached |= ZRTP_BIT_RS1; ZRTP_LOG(2,(_ZTU_,"\tINFO! Remote party has lost it's RS1 - use RS2 backup. ID=%u\n", stream->id)); } else { secrets->matches &= ~ZRTP_BIT_RS1; zrtp_cache_set_verified(session->zrtp->cache, ZSTR_GV(session->peer_zid), 0); zrtp_cache_reset_secure_since(session->zrtp->cache, ZSTR_GV(session->peer_zid)); ZRTP_LOG(2,(_ZTU_,"\tINFO! Our RS1 doesn't equal to other-side's one %s. ID=%u\n", cc->rs1.secret->_cachedflag ? " - drop verified!" : "", stream->id)); } if (!zrtp_memcmp(cc->rs2.peer_id.buffer, stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE)) { secrets->matches |= ZRTP_BIT_RS2; if (0 == C[0]) { C[0] = &cc->rs2; } } if (secrets->auxs && (!zrtp_memcmp(stream->messages.peer_dhpart.auxsID, cc->auxs.peer_id.buffer, ZRTP_RSID_SIZE)) ) { C[1] =&cc->auxs; secrets->matches |= ZRTP_BIT_AUX; } if ( secrets->pbxs && (!zrtp_memcmp(stream->messages.peer_dhpart.pbxsID, cc->pbxs.peer_id.buffer, ZRTP_RSID_SIZE)) ) { C[2] = &cc->pbxs; secrets->matches |= ZRTP_BIT_PBX; } /* Finally hashing matched shared secrets */ for (i=0; i<3; i++) { /* * Some of the shared secrets s1 through s5 may have lengths of zero * if they are null (not shared), and are each preceded by a 4-octet * length field. For example, if s4 is null, len(s4) is 00 00 00 00, * and s4 itself would be absent from the hash calculation, which * means len(s5) would immediately follow len(s4). */ comp_length = C[i] ? zrtp_hton32(ZRTP_RS_SIZE) : 0; session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&comp_length, 4); if (C[i]) { session->hash->hash_update( session->hash, hash_ctx, (const int8_t*)C[i]->secret->value.buffer, C[i]->secret->value.length ); ZRTP_LOG(3,(_ZTU_,"\tUse S%d in calculations.\n", i+1)); } } session->hash->hash_end(session->hash, hash_ctx, ZSTR_GV(cc->s0)); } break; /* S0 for for DH and Preshared streams */ /* * Compute all possible combinations of preshared_key: * hash(len(rs1) | rs1 | len(auxsecret) | auxsecret | len(pbxsecret) | pbxsecret) * Find matched preshared_key and derive S0 from it: * s0 = KDF(preshared_key, "ZRTP Stream Key", KDF_Context, negotiated hash length) * * INFO: Take into account that RS1 and RS2 may be swapped. * If no matched were found - generate DH commit. * ======================================================================== */ case ZRTP_STREAM_MODE_PRESHARED: { zrtp_status_t s = zrtp_status_ok; zrtp_string32_t presh_key = ZSTR_INIT_EMPTY(presh_key); ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 for PRESHARED from cached secret. ID=%u\n", stream->id)); /* Use the same hash as we used for Commitment */ if (is_initiator) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(session->secrets.rs1->value), (session->secrets.auxs->_cachedflag) ? ZSTR_GV(session->secrets.auxs->value) : NULL, (session->secrets.pbxs->_cachedflag) ? ZSTR_GV(session->secrets.pbxs->value) : NULL, ZSTR_GV(presh_key), NULL); if (zrtp_status_ok != s) { return s; } secrets->matches |= ZRTP_BIT_RS1; if (session->secrets.auxs->_cachedflag) { secrets->matches |= ZRTP_BIT_AUX; } if (session->secrets.pbxs->_cachedflag) { secrets->matches |= ZRTP_BIT_PBX; } } /* * Let's find appropriate hv key for Responder: * <RS1, 0, 0>, <RS1, AUX, 0>, <RS1, 0, PBX>, <RS1, AUX, PBX>. */ else { int res=-1; char* peer_key_id = (char*)stream->messages.peer_commit.hv+ZRTP_HV_NONCE_SIZE; zrtp_string8_t key_id = ZSTR_INIT_EMPTY(key_id); do { /* RS1 MUST be available at this stage.*/ s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), NULL, NULL, ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_RS1; break; } } if (session->secrets.pbxs->_cachedflag) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), NULL, ZSTR_GV(secrets->pbxs->value), ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_PBX; break; } } } if (session->secrets.auxs->_cachedflag) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), ZSTR_GV(secrets->auxs->value), NULL, ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_AUX; break; } } } if ((session->secrets.pbxs->_cachedflag) && (session->secrets.auxs->_cachedflag)) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), ZSTR_GV(secrets->auxs->value), ZSTR_GV(secrets->pbxs->value), ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_AUX; secrets->matches |= ZRTP_BIT_PBX; break; } } } } while (0); if (0 != res) { ZRTP_LOG(3,(_ZTU_,"\tINFO! Matched Key wasn't found - initate DH exchange.\n")); secrets->cached = 0; secrets->rs1->_cachedflag = 0; _zrtp_machine_start_initiating_secure(stream); return zrtp_status_ok; } } ZRTP_LOG(3,(_ZTU_,"\tUse RS1, %s, %s in calculations.\n", (session->secrets.matches & ZRTP_BIT_AUX) ? "AUX" : "NULL", (session->secrets.matches & ZRTP_BIT_PBX) ? "PBX" : "NULL")); _zrtp_kdf( stream, ZSTR_GV(presh_key), ZSTR_GV(zrtp_presh_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(cc->s0)); } break; /* * For FAST Multistream: * s0n = KDF(ZRTPSess, "ZRTP Multistream Key", KDF_Context, negotiated hash length) * ======================================================================== */ case ZRTP_STREAM_MODE_MULT: { ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 for MULTISTREAM from ZRTP Session key... ID=%u\n", stream->id)); _zrtp_kdf( stream, ZSTR_GV(session->zrtpsess), ZSTR_GV(zrtp_multi_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(cc->s0)); } break; default: break; } /* * Compute ZRTP session key for FULL streams only: * ZRTPSess = KDF(s0, "ZRTP Session Key", KDF_Context, negotiated hash length) */ if (!ZRTP_IS_STREAM_MULT(stream)) { if (session->zrtpsess.length == 0) { _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GV(zrtp_sess_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(session->zrtpsess)); } } return zrtp_status_ok; }
int32_t ZrtpDH::computeSecretKey(uint8_t *pubKeyBytes, uint8_t *secret) { dhCtx* tmpCtx = static_cast<dhCtx*>(ctx); int32_t length = getDhSize(); BigNum sec; if (pkType == DH2K || pkType == DH3K) { BigNum pubKeyOther; bnBegin(&pubKeyOther); bnBegin(&sec); bnInsertBigBytes(&pubKeyOther, pubKeyBytes, 0, length); if (pkType == DH2K) { bnExpMod(&sec, &pubKeyOther, &tmpCtx->privKey, &bnP2048); } else if (pkType == DH3K) { bnExpMod(&sec, &pubKeyOther, &tmpCtx->privKey, &bnP3072); } else { return 0; } bnEnd(&pubKeyOther); bnExtractBigBytes(&sec, secret, 0, length); bnEnd(&sec); return length; } if (pkType == EC25 || pkType == EC38 || pkType == E414) { int32_t len = getPubKeySize() / 2; EcPoint pub; bnBegin(&sec); INIT_EC_POINT(&pub); bnSetQ(pub.z, 1); // initialze Z to one, these are affine coords bnInsertBigBytes(pub.x, pubKeyBytes, 0, len); bnInsertBigBytes(pub.y, pubKeyBytes+len, 0, len); /* Generate agreement for responder: sec = pub * privKey */ ecdhComputeAgreement(&tmpCtx->curve, &sec, &pub, &tmpCtx->privKey); bnExtractBigBytes(&sec, secret, 0, length); bnEnd(&sec); FREE_EC_POINT(&pub); return length; } if (pkType == E255) { int32_t len = getPubKeySize(); EcPoint pub; bnBegin(&sec); INIT_EC_POINT(&pub); bnInsertLittleBytes(pub.x, pubKeyBytes, 0, len); /* Generate agreement for responder: sec = pub * privKey */ ecdhComputeAgreement(&tmpCtx->curve, &sec, &pub, &tmpCtx->privKey); bnExtractLittleBytes(&sec, secret, 0, length); bnEnd(&sec); FREE_EC_POINT(&pub); return length; } return -1; }
/* * Performs an RSA decryption. Returns a prefix of the unwrapped * data in the given buf. Returns the length of the untruncated * data, which may exceed "len". Returns <0 on error. */ int rsaPrivateDecrypt(PGPByte *outbuf, unsigned len, BigNum *bn, RSAsec const *sec) { unsigned bytes = bnBytes(&sec->n); PGPByte *buf = NULL; B_ALGORITHM_OBJ bobj = NULL; B_KEY_OBJ rprivk = NULL; unsigned int bufoutlen; PGPMemoryMgrRef mgr = bn->mgr; int err; buf = PGPNewSecureData (mgr, bytes, 0); if (buf == NULL) { err = kPGPError_OutOfMemory; goto error; } bnExtractBigBytes (bn, buf, 0, bytes); /* Initialize BSafe private key structure */ err = B_CreateAlgorithmObject (&bobj); CHKERR(err); err = B_SetAlgorithmInfo (bobj, AI_RSAPrivate, NULL); CHKERR(err); err = B_CreateKeyObject (&rprivk); CHKERR(err); err = rprivk_init(rprivk, sec, mgr); CHKERR(err); err = B_DecryptInit (bobj, rprivk, RSA_CHOOSER, (A_SURRENDER_CTX *)0); CHKERR(err); /* Do an RSA decryption to recover PKCS-1 padded key */ err = B_DecryptUpdate (bobj, buf, &bufoutlen, bytes, buf, bytes, (B_ALGORITHM_OBJ)NULL, (A_SURRENDER_CTX *)NULL); CHKERR(err); err = B_DecryptFinal (bobj, buf+bufoutlen, &bufoutlen, bytes-bufoutlen, (B_ALGORITHM_OBJ)NULL, (A_SURRENDER_CTX *)NULL); CHKERR(err); B_DestroyKeyObject (&rprivk); rprivk = NULL; B_DestroyAlgorithmObject (&bobj); bobj = NULL; /* Return to bn format */ bnSetQ (bn, 0); bnInsertBigBytes (bn, buf, 0, bytes); pgpClearMemory (buf, bytes); PGPFreeData (buf); buf = NULL; err = pgpPKCSUnpack(outbuf, len, bn, PKCS_PAD_ENCRYPTED, bytes); error: if (buf) { pgpClearMemory (buf, bytes); PGPFreeData (buf); } if (rprivk) B_DestroyKeyObject (&rprivk); if (bobj) B_DestroyAlgorithmObject (&bobj); return err; }
/* * Encrypt a buffer holding a session key with an RSA public key */ int rsaPublicEncrypt(BigNum *bn, PGPByte const *in, unsigned len, RSApub const *pub, PGPRandomContext const *rc) { unsigned bytes = bnBytes(&pub->n); PGPByte *buf = NULL; B_ALGORITHM_OBJ bobj = NULL; B_KEY_OBJ rpubk = NULL; unsigned int bufoutlen; PGPMemoryMgrRef mgr = bn->mgr; int err = 0; pgpPKCSPack(bn, in, len, PKCS_PAD_ENCRYPTED, bytes, rc); buf = PGPNewSecureData (mgr, bytes, 0); if (buf == NULL) { err = kPGPError_OutOfMemory; goto error; } bnExtractBigBytes (bn, buf, 0, bytes); bnSetQ (bn, 0); /* Initialize BSafe public key structure */ err = B_CreateAlgorithmObject (&bobj); CHKERR(err); err = B_SetAlgorithmInfo (bobj, AI_RSAPublic, NULL); CHKERR(err); err = B_CreateKeyObject (&rpubk); CHKERR(err); err = rpubk_init(rpubk, pub, mgr); CHKERR(err); err = B_EncryptInit (bobj, rpubk, RSA_CHOOSER, (A_SURRENDER_CTX *)0); CHKERR(err); /* Encrypt data */ err = B_EncryptUpdate (bobj, buf, &bufoutlen, bytes, buf, bytes, (B_ALGORITHM_OBJ)NULL, (A_SURRENDER_CTX *)NULL); CHKERR(err); err = B_EncryptFinal (bobj, buf+bufoutlen, &bufoutlen, bytes-bufoutlen, (B_ALGORITHM_OBJ)NULL, (A_SURRENDER_CTX *)NULL); CHKERR(err); B_DestroyKeyObject (&rpubk); rpubk = NULL; B_DestroyAlgorithmObject (&bobj); bobj = NULL; /* Return to bn format */ bnInsertBigBytes (bn, buf, 0, bytes); pgpClearMemory (buf, bytes); PGPFreeData (buf); buf = NULL; error: if (buf) { pgpClearMemory (buf, bytes); PGPFreeData (buf); } if (rpubk) B_DestroyKeyObject (&rpubk); if (bobj) B_DestroyAlgorithmObject (&bobj); return err; }
/* Initialize BSafe privkey structure from a RSAsec. */ static int rprivk_init(B_KEY_OBJ rprivk, RSAsec const *sec, PGPMemoryMgrRef mgr) { BigNum dmodp, dmodq, tmp; A_RSA_CRT_KEY kdata; PGPByte *buf; PGPSize bufsize; int err; /* Calculate d mod p-1 and d mod q-1 */ bnBegin(&dmodp, mgr, TRUE); bnBegin(&dmodq, mgr, TRUE); bnBegin(&tmp, mgr, TRUE); bnCopy(&tmp, &sec->p); bnSubQ(&tmp, 1); bnMod(&dmodp, &sec->d, &tmp); bnCopy(&tmp, &sec->q); bnSubQ(&tmp, 1); bnMod(&dmodq, &sec->d, &tmp); bufsize = bnBytes(&sec->n) + bnBytes(&sec->q) + bnBytes(&sec->p) + bnBytes(&dmodq) + bnBytes(&dmodp) + bnBytes(&sec->u); buf = PGPNewSecureData( mgr, bufsize, 0 ); kdata.modulus.data = buf; kdata.modulus.len = bnBytes(&sec->n); kdata.prime[0].data = kdata.modulus.data + kdata.modulus.len; kdata.prime[0].len = bnBytes(&sec->q); kdata.prime[1].data = kdata.prime[0].data + kdata.prime[0].len; kdata.prime[1].len = bnBytes(&sec->p); kdata.primeExponent[0].data = kdata.prime[1].data + kdata.prime[1].len; kdata.primeExponent[0].len = bnBytes(&dmodq); kdata.primeExponent[1].data = kdata.primeExponent[0].data + kdata.primeExponent[0].len; kdata.primeExponent[1].len = bnBytes(&dmodp); kdata.coefficient.data = kdata.primeExponent[1].data + kdata.primeExponent[1].len; kdata.coefficient.len = bnBytes(&sec->u); bnExtractBigBytes (&sec->n, kdata.modulus.data, 0, kdata.modulus.len); bnExtractBigBytes (&sec->q, kdata.prime[0].data, 0, kdata.prime[0].len); bnExtractBigBytes (&sec->p, kdata.prime[1].data, 0, kdata.prime[1].len); bnExtractBigBytes (&dmodq, kdata.primeExponent[0].data, 0, kdata.primeExponent[0].len); bnExtractBigBytes (&dmodp, kdata.primeExponent[1].data, 0, kdata.primeExponent[1].len); bnExtractBigBytes (&sec->u, kdata.coefficient.data, 0, kdata.coefficient.len); err = B_SetKeyInfo (rprivk, KI_RSA_CRT, (POINTER)&kdata); pgpAssert (err == 0); pgpClearMemory (buf, bufsize); PGPFreeData (buf); bnEnd(&dmodp); bnEnd(&dmodq); bnEnd(&tmp); return err; }