1 /** 2 * ECDSA 3 * 4 * Copyright: 5 * (C) 2007 Falko Strenzke, FlexSecure GmbH 6 * Manuel Hartl, FlexSecure GmbH 7 * (C) 2008-2010 Jack Lloyd 8 * (C) 2014-2015 Etienne Cimon 9 * 10 * License: 11 * Botan is released under the Simplified BSD License (see LICENSE.md) 12 */ 13 module botan.pubkey.algo.ecc_key; 14 15 import botan.constants; 16 static if (BOTAN_HAS_PUBLIC_KEY_CRYPTO && (BOTAN_HAS_ECDH || BOTAN_HAS_ECDSA || BOTAN_HAS_GOST_34_10_2001)): 17 18 public import botan.pubkey.pubkey; 19 public import botan.pubkey.algo.ec_group; 20 public import botan.math.numbertheory.numthry; 21 public import botan.math.ec_gfp.curve_gfp; 22 public import botan.math.ec_gfp.point_gfp; 23 public import botan.pubkey.pk_keys; 24 public import botan.pubkey.x509_key; 25 import botan.rng.rng; 26 import botan.pubkey.pkcs8; 27 import botan.asn1.der_enc; 28 import botan.asn1.ber_dec; 29 import memutils.vector; 30 import botan.utils.mem_ops; 31 import botan.utils.exceptn; 32 33 /** 34 * This class represents abstract ECC public keys. When encoding a key 35 * via an encoder that can be accessed via the corresponding member 36 * functions, the key will decide upon its internally stored encoding 37 * information whether to encode itself with or without domain 38 * parameters, or using the domain parameter oid. Furthermore, a public 39 * key without domain parameters can be decoded. In that case, it 40 * cannot be used for verification until its domain parameters are set 41 * by calling the corresponding member function. 42 */ 43 class ECPublicKey : PublicKey 44 { 45 public: 46 this(T)(in T options, const ref ECGroup dom_par, const ref PointGFp pub_point) 47 { 48 decodeOptions(options); 49 50 m_domain_params = dom_par.dup; 51 m_public_key = pub_point.dup; 52 m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; 53 54 if (domain().getCurve() != publicPoint().getCurve()) 55 throw new InvalidArgument("ECPublicKey: curve mismatch in constructor"); 56 } 57 58 this(T)(in T options, in AlgorithmIdentifier alg_id, 59 const ref SecureVector!ubyte key_bits) 60 { 61 decodeOptions(options); 62 63 m_domain_params = ECGroup(alg_id.parameters); 64 m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; 65 m_public_key = OS2ECP(key_bits, domain().getCurve()); 66 } 67 68 protected this(T)(in T options, in AlgorithmIdentifier alg_id) 69 { 70 decodeOptions(options); 71 //logTrace("ECGroup with alg_id.parameters"); 72 m_domain_params = ECGroup(alg_id.parameters); 73 m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; 74 } 75 76 final void decodeOptions(T)(in T options) { 77 static if (__traits(hasMember, T, "checkKey")) 78 m_check_key = &options.checkKey; 79 static if (__traits(hasMember, T, "algorithmIdentifier")) 80 m_algorithm_identifier = &options.algorithmIdentifier; 81 static if (__traits(hasMember, T, "x509SubjectPublicKey")) 82 m_subject_public_key = &options.x509SubjectPublicKey; 83 static if (__traits(hasMember, T, "msgParts")) 84 m_msg_parts = options.msgParts; 85 static if (__traits(hasMember, T, "algoName")) 86 m_algo_name = options.algoName; 87 else static assert(false, "No algoName found in " ~ T.stringof); 88 } 89 90 /// Used for object casting to the right type in the factory. 91 final override @property string algoName() const { 92 return m_algo_name; 93 } 94 95 /** 96 * Get the public point of this key. 97 * Throws: $(D InvalidState) is thrown if the 98 * domain parameters of this point are not set 99 * Returns: the public point of this key 100 */ 101 final ref const(PointGFp) publicPoint() const { return m_public_key; } 102 103 final override size_t maxInputBits() const { return domain().getOrder().bits(); } 104 105 final override size_t messagePartSize() const { 106 if (m_msg_parts == 1) return 0; 107 108 return domain().getOrder().bytes(); 109 } 110 111 final override size_t messageParts() const { return m_msg_parts; } 112 113 final override AlgorithmIdentifier algorithmIdentifier() const 114 { 115 if (m_algorithm_identifier) 116 return m_algorithm_identifier(this); 117 return AlgorithmIdentifier(getOid(), DER_domain()); 118 } 119 120 final override Vector!ubyte x509SubjectPublicKey() const 121 { 122 if (m_subject_public_key) 123 return m_subject_public_key(this); 124 return unlock(EC2OSP(publicPoint(), PointGFp.COMPRESSED)); 125 } 126 127 override bool checkKey(RandomNumberGenerator rng, bool b) const 128 { 129 return publicPoint().onTheCurve(); 130 } 131 132 /** 133 * Get the domain parameters of this key. 134 * Throws: $(D InvalidState) is thrown if the domain parameters of this point are not set 135 * Returns: the domain parameters of this key 136 */ 137 final ref const(ECGroup) domain() const { return m_domain_params; } 138 139 /** 140 * Set the domain parameter encoding to be used when encoding this key. 141 * 142 * Params: 143 * form = the encoding to use 144 */ 145 final void setParameterEncoding(ECGroupEncoding form) 146 { 147 if (form != EC_DOMPAR_ENC_EXPLICIT && form != EC_DOMPAR_ENC_IMPLICITCA && form != EC_DOMPAR_ENC_OID) 148 throw new InvalidArgument("Invalid encoding form for EC-key object specified"); 149 150 if ((form == EC_DOMPAR_ENC_OID) && (m_domain_params.getOid() == "")) 151 throw new InvalidArgument("Invalid encoding form OID specified for " 152 ~ "EC-key object whose corresponding domain " 153 ~ "parameters are without oid"); 154 155 m_domain_encoding = form; 156 } 157 158 /** 159 * Return the DER encoding of this keys domain in whatever format 160 * is preset for this particular key 161 */ 162 Vector!ubyte DER_domain() const { return domain().DER_encode(domainFormat()); } 163 164 /** 165 * Get the domain parameter encoding to be used when encoding this key. 166 * Returns: the encoding to use 167 */ 168 ECGroupEncoding domainFormat() const { return m_domain_encoding; } 169 170 override size_t estimatedStrength() const 171 { 172 return domain().getCurve().getP().bits() / 2; 173 } 174 175 /** 176 * Returns: public point value 177 */ 178 Vector!ubyte publicValue() const 179 { return unlock(EC2OSP(publicPoint(), PointGFp.UNCOMPRESSED)); } 180 protected: 181 182 ECGroup m_domain_params; 183 PointGFp m_public_key; 184 ECGroupEncoding m_domain_encoding; 185 186 string m_algo_name; 187 short m_msg_parts = 1; 188 bool function(in ECPrivateKey, RandomNumberGenerator, bool) m_check_key; 189 Vector!ubyte function(in ECPublicKey) m_subject_public_key; 190 AlgorithmIdentifier function(in ECPublicKey) m_algorithm_identifier; 191 } 192 193 /** 194 * This abstract class represents ECC private keys 195 */ 196 final class ECPrivateKey : ECPublicKey, PrivateKey, PKKeyAgreementKey 197 { 198 public: 199 /** 200 * ECPrivateKey constructor 201 */ 202 this(T)(in T options, RandomNumberGenerator rng, const ref ECGroup ec_group, const ref BigInt private_key) 203 { 204 if (private_key == 0) { 205 auto bi = BigInt(1); 206 m_private_key = BigInt.randomInteger(rng, bi, ec_group.getOrder()); 207 } 208 else 209 m_private_key = private_key.dup; 210 211 PointGFp public_key = ec_group.getBasePoint() * &m_private_key; 212 213 assert(public_key.onTheCurve(), "Generated public key point was on the curve"); 214 215 // logTrace("private key: ", m_private_key.toString()); 216 super(options, ec_group, public_key); 217 } 218 219 this(T)(in T options, const ref AlgorithmIdentifier alg_id, const ref SecureVector!ubyte key_bits) 220 { 221 super(options, alg_id); 222 PointGFp public_key; 223 OID key_parameters = OID(); 224 225 SecureVector!ubyte public_key_bits; 226 227 BERDecoder(key_bits) 228 .startCons(ASN1Tag.SEQUENCE) 229 .decodeAndCheck!size_t(1, "Unknown version code for ECC key") 230 .decodeOctetStringBigint(m_private_key) 231 .decodeOptional(key_parameters, (cast(ASN1Tag) 0), ASN1Tag.PRIVATE, key_parameters) 232 .decodeOptionalString(public_key_bits, ASN1Tag.BIT_STRING, 1, ASN1Tag.PRIVATE) 233 .endCons(); 234 if (!key_parameters.empty && key_parameters != alg_id.oid) 235 throw new DecodingError("ECPrivateKey - inner and outer OIDs did not match"); 236 237 if (public_key_bits.empty) 238 { 239 m_public_key = domain().getBasePoint() * &m_private_key; 240 assert(m_public_key.onTheCurve(), "Public point derived from loaded key was on the curve"); 241 } 242 else 243 { 244 m_public_key = OS2ECP(public_key_bits, m_domain_params.getCurve()); 245 // OS2ECP verifies that the point is on the curve 246 } 247 } 248 249 override bool checkKey(RandomNumberGenerator rng, bool b) const 250 { 251 if (m_check_key) 252 return m_check_key(this, rng, b); 253 254 return super.checkKey(rng, b); 255 } 256 257 SecureVector!ubyte pkcs8PrivateKey() const 258 { 259 return DEREncoder() 260 .startCons(ASN1Tag.SEQUENCE) 261 .encode(cast(size_t)(1)) 262 .encode(BigInt.encode1363(m_private_key, m_private_key.bytes()), 263 ASN1Tag.OCTET_STRING) 264 .endCons() 265 .getContents(); 266 } 267 268 override AlgorithmIdentifier pkcs8AlgorithmIdentifier() const { 269 if (algoName() == "GOST-34.10") 270 return AlgorithmIdentifier(getOid(), DER_domain()); 271 return super.algorithmIdentifier(); 272 } 273 274 /** 275 * Get the private key value of this key object. 276 * Returns: the private key value of this key object 277 */ 278 ref const(BigInt) privateValue() const 279 { 280 if (m_private_key == 0) 281 throw new InvalidState("ECPrivateKey.private_value - uninitialized"); 282 283 return m_private_key; 284 } 285 286 override Vector!ubyte publicValue() const { return super.publicValue(); } 287 288 private: 289 BigInt m_private_key; 290 }