CSL_error CSL_VerifyEccSig( CSLOSDigest digest, u32 digestSize, CSLOSEccPublicKey publicKey, CSLOSEccSig sign){ CSL_error reterr = CSL_OK; field_boolean res; CSL_VerifyEccSig_big_locals *big_locals; #ifdef __KERNEL__ big_locals = kmalloc(sizeof(*big_locals), GFP_KERNEL); if (!big_locals) return CSL_NO_MEMORY; #else CSL_VerifyEccSig_big_locals _big_locals; big_locals = &_big_locals; #endif alg_init_233_bit_ECDSA(&big_locals->base, NUM_BITS); OS2ECP(publicKey, OCTET_STRING_LEN*2, &big_locals->public_key); OS2ECP(sign, OCTET_STRING_LEN*2, (point *)&big_locals->signature); alg_poly_ECDSA_verify((char *)digest, digestSize, &big_locals->base, &big_locals->public_key, &big_locals->signature, &res); reterr = res == CSL_TRUE ? CSL_OK : CSL_VERIFY_ERROR; #ifdef __KERNEL__ kfree(big_locals); #endif return reterr; }
EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, const secure_vector<byte>& key_bits) { m_domain_params = EC_Group(alg_id.parameters); m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; OID key_parameters; secure_vector<byte> public_key_bits; BER_Decoder(key_bits) .start_cons(SEQUENCE) .decode_and_check<size_t>(1, "Unknown version code for ECC key") .decode_octet_string_bigint(m_private_key) .decode_optional(key_parameters, ASN1_Tag(0), PRIVATE) .decode_optional_string(public_key_bits, BIT_STRING, 1, PRIVATE) .end_cons(); if(!key_parameters.empty() && key_parameters != alg_id.oid) throw Decoding_Error("EC_PrivateKey - inner and outer OIDs did not match"); if(public_key_bits.empty()) { m_public_key = domain().get_base_point() * m_private_key; BOTAN_ASSERT(m_public_key.on_the_curve(), "Public point derived from loaded key was on the curve"); } else { m_public_key = OS2ECP(public_key_bits, domain().get_curve()); // OS2ECP verifies that the point is on the curve } }
CSL_error CSL_GenerateEccSharedKey(CSLOSEccPrivateKey privateKey, CSLOSEccPublicKey publicKey, CSLOSEccSharedKey sharedKey, u32 numBytes){ field_2n pvtkey, sharedkey; point publickey; CSLOSEccSharedKey sharedKeyCopy; CSL_error error = CSL_OK; if(numBytes > sizeof(CSLOSEccSharedKey)){ return CSL_OVERFLOW; } poly_elliptic_init_233_bit(); OS2FEP(privateKey, &pvtkey); OS2ECP(publicKey, OCTET_STRING_LEN*2, &publickey); error = alg_generate_shared_key(&named_point, &named_curve, &publickey, &pvtkey, &sharedkey); /* collect the result into output */ #ifdef KDF1 post_process_key(&sharedkey, sharedKeyCopy); #else FE2OSP(sharedKeyCopy, &sharedkey); #endif /* convert to octet string of desired length */ memcpy(sharedKey, sharedKeyCopy, numBytes); return error; }
/* * This call is used for precomputing the public key in expanded form * before using the shared key version with precomputing */ CSL_error CSL_PrecomputeFour(CSLOSEccPublicKey publicKey, CSLOSEccExpPublicKey prePublicKey){ point publickey; int j; #ifdef __KERNEL__ point *precomputedpublickey = kmalloc(sizeof(point) * 16, GFP_KERNEL); if (!precomputedpublickey) return CSL_NO_MEMORY; #else point precomputedpublickey[16]; #endif OS2ECP(publicKey, OCTET_STRING_LEN*2, &publickey); alg_do_precompute_four(&publickey, &(precomputedpublickey[0]), &named_curve); for(j = 0; j < 16; j++){ EC2OSP(&(precomputedpublickey[j]), (prePublicKey + ((OCTET_STRING_LEN*2)*j)), OCTET_STRING_LEN*2); } #ifdef __KERNEL__ kfree(precomputedpublickey); #endif return CSL_OK; }
void key_bits(const MemoryRegion<byte>& bits) { key->mp_public_point.reset( new PointGFp( OS2ECP(bits, key->domain_parameters().get_curve()) )); key->X509_load_hook(); }
EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, const std::vector<uint8_t>& key_bits) : m_domain_params{EC_Group(alg_id.parameters)}, m_public_key{OS2ECP(key_bits, domain().get_curve())} { if (!domain().get_oid().empty()) m_domain_encoding = EC_DOMPAR_ENC_OID; else m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; }
PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) : Object(session, props) { m_domain_params = EC_Group(props.ec_params()); secure_vector<uint8_t> ec_point; BER_Decoder(props.ec_point()).decode(ec_point, OCTET_STRING); m_public_key = OS2ECP(ec_point, m_domain_params.get_curve()); m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; }
int sm2_dec ( sm2_prvkey *prvkey, unsigned char *ciphertext, unsigned int clen, unsigned char*plaintext, unsigned int *plen ) { point_affn_t ksG; #ifndef MUL_BITS unsigned char tmp[FIELD_SIZE_IN_BYTES*2]; #else unsigned char tmp[32*2]; #endif unsigned char *hash = tmp; int c1len, xylen; unsigned int i; int ret; point_affn_init(ksG); c1len = OS2ECP(ksG, ciphertext, clen); if(c1len < 0 || (clen - c1len <= SM3_HASH_LEN) ) { point_affn_clear(ksG); return 1; } mpz_BarrettSetBuf(&pXbufFieldPrime); point_affn_mul(ksG, ksG, prvkey->s); xylen = sizeof(tmp); EC2OSP_XY(tmp, &xylen, ksG); point_affn_clear(ksG); *plen = clen-c1len-SM3_HASH_LEN; sm2_KDF1_ex(plaintext, *plen, tmp, xylen, ALG_HASH_SM3, 1); for(i=0; i<*plen; i++) plaintext[i] = ciphertext[c1len+SM3_HASH_LEN+i]^plaintext[i]; sm2_hash(tmp, xylen/2, plaintext, *plen, tmp+xylen/2, xylen/2, hash); if( !memcmp(hash, ciphertext+c1len, SM3_HASH_LEN) ) ret = 0; else { memset(plaintext, 0, *plen); ret = 1; } return ret; }
PointGFp OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp& curve) { // Should we really be doing this? if(data_len <= 1) return PointGFp(curve); // return zero std::pair<BigInt, BigInt> xy = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b()); PointGFp point(curve, xy.first, xy.second); if(!point.on_the_curve()) throw Illegal_Point("OS2ECP: Decoded point was not on the curve"); return point; }
EC_Group::EC_Group(const std::vector<uint8_t>& ber_data) { BER_Decoder ber(ber_data); BER_Object obj = ber.get_next_object(); if(obj.type_tag == NULL_TAG) throw Decoding_Error("Cannot handle ImplicitCA ECDSA parameters"); else if(obj.type_tag == OBJECT_ID) { OID dom_par_oid; BER_Decoder(ber_data).decode(dom_par_oid); *this = EC_Group(dom_par_oid); } else if(obj.type_tag == SEQUENCE) { BigInt p, a, b; std::vector<uint8_t> sv_base_point; BER_Decoder(ber_data) .start_cons(SEQUENCE) .decode_and_check<size_t>(1, "Unknown ECC param version code") .start_cons(SEQUENCE) .decode_and_check(OID("1.2.840.10045.1.1"), "Only prime ECC fields supported") .decode(p) .end_cons() .start_cons(SEQUENCE) .decode_octet_string_bigint(a) .decode_octet_string_bigint(b) .end_cons() .decode(sv_base_point, OCTET_STRING) .decode(m_order) .decode(m_cofactor) .end_cons() .verify_end(); m_curve = CurveGFp(p, a, b); m_base_point = OS2ECP(sv_base_point, m_curve); } else throw Decoding_Error("Unexpected tag while decoding ECC domain params"); }
CSL_error CSL_GenerateEccSharedKeyPre(CSLOSEccPrivateKey privateKey, CSLOSEccExpPublicKey publicKey, CSLOSEccSharedKey sharedKey, u32 numBytes){ field_2n pvtkey, sharedkey; CSLOSEccSharedKey sharedKeyCopy; CSL_error error = CSL_OK; int j; #ifdef __KERNEL__ point *precomputedpublickey = kmalloc(sizeof(point) * 16, GFP_KERNEL); if (!precomputedpublickey) return CSL_NO_MEMORY; #else point precomputedpublickey[16]; #endif poly_elliptic_init_233_bit(); OS2FEP(privateKey, &pvtkey); /* convert public key to point variable */ for(j=0; j< 16; j++){ OS2ECP((publicKey + (2*OCTET_STRING_LEN*j)), (2*OCTET_STRING_LEN), &(precomputedpublickey[j])); } error = alg_generate_shared_key_pre(&named_point, &named_curve, &precomputedpublickey[0], &pvtkey, &sharedkey); /* collect the result into output */ #ifdef KDF1 post_process_key(&sharedkey, sharedKeyCopy); #else FE2OSP(sharedKeyCopy, &sharedkey); #endif /* convert to octet string of desired length */ memcpy(sharedKey, sharedKeyCopy, numBytes); #ifdef __KERNEL__ kfree(precomputedpublickey); #endif return error; }
int sm2_load_pubkey ( sm2_pubkey *pubkey, unsigned char *data, unsigned int n ) { if( n != 48 && n != 64 && n != 49 && n != 65 ) return 1; point_affn_init(pubkey->sG); pubkey->sG->infinity = 0; if(n%2 == 1) OS2ECP(pubkey->sG, data, n); else OS2ECP_XY(pubkey->sG, data, n); pubkey->ecp = ECPUCMP; // dump_point(pubkey->sG, "sG"); return 0; }
int sm2_load_prvkey ( sm2_prvkey *prvkey , unsigned char *data, unsigned int n ) { if( n != 24 && n != 32 ) return 1; mpz_init(prvkey->s); OS2IP(prvkey->s, data, FIELD_SIZE_IN_BYTES); point_affn_init(prvkey->sG); prvkey->sG->infinity = 0; OS2ECP(prvkey->sG, data+FIELD_SIZE_IN_BYTES, n-FIELD_SIZE_IN_BYTES); point_affn_init(prvkey->sG); point_affn_mul(prvkey->sG, GENERATOR, prvkey->s); // dump_point(prvkey->sG, "sG"); return 0; }
EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, const secure_vector<byte>& key_bits) : m_domain_params{EC_Group(alg_id.parameters)}, m_public_key{OS2ECP(key_bits, domain().get_curve())}, m_domain_encoding{EC_DOMPAR_ENC_EXPLICIT} {}
/* * Create a new Client Key Exchange message */ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, Handshake_State& state, const Policy& policy, Credentials_Manager& creds, const Public_Key* server_public_key, const std::string& hostname, RandomNumberGenerator& rng) { const std::string kex_algo = state.ciphersuite().kex_algo(); if(kex_algo == "PSK") { std::string identity_hint = ""; if(state.server_kex()) { TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params()); identity_hint = reader.get_string(2, 0, 65535); } const std::string psk_identity = creds.psk_identity("tls-client", hostname, identity_hint); append_tls_length_value(m_key_material, psk_identity, 2); SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity); std::vector<byte> zeros(psk.length()); append_tls_length_value(m_pre_master, zeros, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } else if(state.server_kex()) { TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params()); SymmetricKey psk; if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") { std::string identity_hint = reader.get_string(2, 0, 65535); const std::string psk_identity = creds.psk_identity("tls-client", hostname, identity_hint); append_tls_length_value(m_key_material, psk_identity, 2); psk = creds.psk("tls-client", hostname, psk_identity); } if(kex_algo == "DH" || kex_algo == "DHE_PSK") { BigInt p = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); BigInt Y = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); if(reader.remaining_bytes()) throw Decoding_Error("Bad params size for DH key exchange"); if(p.bits() < policy.minimum_dh_group_size()) throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, "Server sent DH group of " + std::to_string(p.bits()) + " bits, policy requires at least " + std::to_string(policy.minimum_dh_group_size())); /* * A basic check for key validity. As we do not know q here we * cannot check that Y is in the right subgroup. However since * our key is ephemeral there does not seem to be any * advantage to bogus keys anyway. */ if(Y <= 1 || Y >= p - 1) throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, "Server sent bad DH key for DHE exchange"); DL_Group group(p, g); if(!group.verify_group(rng, false)) throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, "DH group validation failed"); DH_PublicKey counterparty_key(group, Y); DH_PrivateKey priv_key(rng, group); PK_Key_Agreement ka(priv_key, "Raw"); secure_vector<byte> dh_secret = CT::strip_leading_zeros( ka.derive_key(0, counterparty_key.public_value()).bits_of()); if(kex_algo == "DH") m_pre_master = dh_secret; else { append_tls_length_value(m_pre_master, dh_secret, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } append_tls_length_value(m_key_material, priv_key.public_value(), 2); } else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") { const byte curve_type = reader.get_byte(); if(curve_type != 3) throw Decoding_Error("Server sent non-named ECC curve"); const u16bit curve_id = reader.get_u16bit(); const std::string name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); if(name == "") throw Decoding_Error("Server sent unknown named curve " + std::to_string(curve_id)); EC_Group group(name); std::vector<byte> ecdh_key = reader.get_range<byte>(1, 1, 255); ECDH_PublicKey counterparty_key(group, OS2ECP(ecdh_key, group.get_curve())); ECDH_PrivateKey priv_key(rng, group); PK_Key_Agreement ka(priv_key, "Raw"); secure_vector<byte> ecdh_secret = ka.derive_key(0, counterparty_key.public_value()).bits_of(); if(kex_algo == "ECDH") m_pre_master = ecdh_secret; else { append_tls_length_value(m_pre_master, ecdh_secret, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } append_tls_length_value(m_key_material, priv_key.public_value(), 1); } #if defined(BOTAN_HAS_SRP6) else if(kex_algo == "SRP_SHA") { const BigInt N = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); const BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); std::vector<byte> salt = reader.get_range<byte>(1, 1, 255); const BigInt B = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); const std::string srp_group = srp6_group_identifier(N, g); const std::string srp_identifier = creds.srp_identifier("tls-client", hostname); const std::string srp_password = creds.srp_password("tls-client", hostname, srp_identifier); std::pair<BigInt, SymmetricKey> srp_vals = srp6_client_agree(srp_identifier, srp_password, srp_group, "SHA-1", salt, B, rng); append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2); m_pre_master = srp_vals.second.bits_of(); } #endif else { throw Internal_Error("Client_Key_Exchange: Unknown kex " + kex_algo); } reader.assert_done(); } else { // No server key exchange msg better mean RSA kex + RSA key in cert if(kex_algo != "RSA") throw Unexpected_Message("No server kex but negotiated kex " + kex_algo); if(!server_public_key) throw Internal_Error("No server public key for RSA exchange"); if(auto rsa_pub = dynamic_cast<const RSA_PublicKey*>(server_public_key)) { const Protocol_Version offered_version = state.client_hello()->version(); m_pre_master = rng.random_vec(48); m_pre_master[0] = offered_version.major_version(); m_pre_master[1] = offered_version.minor_version(); PK_Encryptor_EME encryptor(*rsa_pub, "PKCS1v15"); const std::vector<byte> encrypted_key = encryptor.encrypt(m_pre_master, rng); append_tls_length_value(m_key_material, encrypted_key, 2); } else throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Expected a RSA key in server cert but got " + server_public_key->algo_name()); } state.hash().update(io.send(*this)); }