You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
324 lines
13 KiB
324 lines
13 KiB
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) |
|
#pragma warning disable |
|
using System; |
|
using System.Collections; |
|
using System.IO; |
|
using System.Text; |
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.CryptoPro; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.EdEC; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Oiw; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Pkcs; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Rosstandart; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Sec; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X9; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Generators; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Encoders; |
|
|
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Security |
|
{ |
|
public sealed class PublicKeyFactory |
|
{ |
|
private PublicKeyFactory() |
|
{ |
|
} |
|
|
|
public static AsymmetricKeyParameter CreateKey( |
|
byte[] keyInfoData) |
|
{ |
|
return CreateKey( |
|
SubjectPublicKeyInfo.GetInstance( |
|
Asn1Object.FromByteArray(keyInfoData))); |
|
} |
|
|
|
public static AsymmetricKeyParameter CreateKey( |
|
Stream inStr) |
|
{ |
|
return CreateKey( |
|
SubjectPublicKeyInfo.GetInstance( |
|
Asn1Object.FromStream(inStr))); |
|
} |
|
|
|
public static AsymmetricKeyParameter CreateKey( |
|
SubjectPublicKeyInfo keyInfo) |
|
{ |
|
AlgorithmIdentifier algID = keyInfo.AlgorithmID; |
|
DerObjectIdentifier algOid = algID.Algorithm; |
|
|
|
// TODO See RSAUtil.isRsaOid in Java build |
|
if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption) |
|
|| algOid.Equals(X509ObjectIdentifiers.IdEARsa) |
|
|| algOid.Equals(PkcsObjectIdentifiers.IdRsassaPss) |
|
|| algOid.Equals(PkcsObjectIdentifiers.IdRsaesOaep)) |
|
{ |
|
RsaPublicKeyStructure pubKey = RsaPublicKeyStructure.GetInstance( |
|
keyInfo.ParsePublicKey()); |
|
|
|
return new RsaKeyParameters(false, pubKey.Modulus, pubKey.PublicExponent); |
|
} |
|
else if (algOid.Equals(X9ObjectIdentifiers.DHPublicNumber)) |
|
{ |
|
Asn1Sequence seq = Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()); |
|
|
|
DHPublicKey dhPublicKey = DHPublicKey.GetInstance(keyInfo.ParsePublicKey()); |
|
|
|
BigInteger y = dhPublicKey.Y.Value; |
|
|
|
if (IsPkcsDHParam(seq)) |
|
return ReadPkcsDHParam(algOid, y, seq); |
|
|
|
DHDomainParameters dhParams = DHDomainParameters.GetInstance(seq); |
|
|
|
BigInteger p = dhParams.P.Value; |
|
BigInteger g = dhParams.G.Value; |
|
BigInteger q = dhParams.Q.Value; |
|
|
|
BigInteger j = null; |
|
if (dhParams.J != null) |
|
{ |
|
j = dhParams.J.Value; |
|
} |
|
|
|
DHValidationParameters validation = null; |
|
DHValidationParms dhValidationParms = dhParams.ValidationParms; |
|
if (dhValidationParms != null) |
|
{ |
|
byte[] seed = dhValidationParms.Seed.GetBytes(); |
|
BigInteger pgenCounter = dhValidationParms.PgenCounter.Value; |
|
|
|
// TODO Check pgenCounter size? |
|
|
|
validation = new DHValidationParameters(seed, pgenCounter.IntValue); |
|
} |
|
|
|
return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation)); |
|
} |
|
else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement)) |
|
{ |
|
Asn1Sequence seq = Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()); |
|
|
|
DerInteger derY = (DerInteger)keyInfo.ParsePublicKey(); |
|
|
|
return ReadPkcsDHParam(algOid, derY.Value, seq); |
|
} |
|
else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm)) |
|
{ |
|
ElGamalParameter para = new ElGamalParameter( |
|
Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); |
|
DerInteger derY = (DerInteger)keyInfo.ParsePublicKey(); |
|
|
|
return new ElGamalPublicKeyParameters( |
|
derY.Value, |
|
new ElGamalParameters(para.P, para.G)); |
|
} |
|
else if (algOid.Equals(X9ObjectIdentifiers.IdDsa) |
|
|| algOid.Equals(OiwObjectIdentifiers.DsaWithSha1)) |
|
{ |
|
DerInteger derY = (DerInteger)keyInfo.ParsePublicKey(); |
|
Asn1Encodable ae = algID.Parameters; |
|
|
|
DsaParameters parameters = null; |
|
if (ae != null) |
|
{ |
|
DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object()); |
|
parameters = new DsaParameters(para.P, para.Q, para.G); |
|
} |
|
|
|
return new DsaPublicKeyParameters(derY.Value, parameters); |
|
} |
|
else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey)) |
|
{ |
|
X962Parameters para = X962Parameters.GetInstance(algID.Parameters.ToAsn1Object()); |
|
|
|
X9ECParameters x9; |
|
if (para.IsNamedCurve) |
|
{ |
|
x9 = ECKeyPairGenerator.FindECCurveByOid((DerObjectIdentifier)para.Parameters); |
|
} |
|
else |
|
{ |
|
x9 = new X9ECParameters((Asn1Sequence)para.Parameters); |
|
} |
|
|
|
Asn1OctetString key = new DerOctetString(keyInfo.PublicKeyData.GetBytes()); |
|
X9ECPoint derQ = new X9ECPoint(x9.Curve, key); |
|
ECPoint q = derQ.Point; |
|
|
|
if (para.IsNamedCurve) |
|
{ |
|
return new ECPublicKeyParameters("EC", q, (DerObjectIdentifier)para.Parameters); |
|
} |
|
|
|
ECDomainParameters dParams = new ECDomainParameters(x9); |
|
return new ECPublicKeyParameters(q, dParams); |
|
} |
|
else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)) |
|
{ |
|
Gost3410PublicKeyAlgParameters gostParams = Gost3410PublicKeyAlgParameters.GetInstance(algID.Parameters); |
|
DerObjectIdentifier publicKeyParamSet = gostParams.PublicKeyParamSet; |
|
|
|
X9ECParameters ecP = ECGost3410NamedCurves.GetByOidX9(publicKeyParamSet); |
|
if (ecP == null) |
|
return null; |
|
|
|
Asn1OctetString key; |
|
try |
|
{ |
|
key = (Asn1OctetString)keyInfo.ParsePublicKey(); |
|
} |
|
catch (IOException e) |
|
{ |
|
throw new ArgumentException("error recovering GOST3410_2001 public key", e); |
|
} |
|
|
|
int fieldSize = 32; |
|
int keySize = 2 * fieldSize; |
|
|
|
byte[] keyEnc = key.GetOctets(); |
|
if (keyEnc.Length != keySize) |
|
throw new ArgumentException("invalid length for GOST3410_2001 public key"); |
|
|
|
byte[] x9Encoding = new byte[1 + keySize]; |
|
x9Encoding[0] = 0x04; |
|
for (int i = 1; i <= fieldSize; ++i) |
|
{ |
|
x9Encoding[i] = keyEnc[fieldSize - i]; |
|
x9Encoding[i + fieldSize] = keyEnc[keySize - i]; |
|
} |
|
|
|
ECPoint q = ecP.Curve.DecodePoint(x9Encoding); |
|
|
|
return new ECPublicKeyParameters("ECGOST3410", q, publicKeyParamSet); |
|
} |
|
else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94)) |
|
{ |
|
Gost3410PublicKeyAlgParameters algParams = Gost3410PublicKeyAlgParameters.GetInstance(algID.Parameters); |
|
|
|
Asn1OctetString key; |
|
try |
|
{ |
|
key = (Asn1OctetString)keyInfo.ParsePublicKey(); |
|
} |
|
catch (IOException e) |
|
{ |
|
throw new ArgumentException("error recovering GOST3410_94 public key", e); |
|
} |
|
|
|
byte[] keyBytes = Arrays.Reverse(key.GetOctets()); // was little endian |
|
|
|
BigInteger y = new BigInteger(1, keyBytes); |
|
|
|
return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet); |
|
} |
|
else if (algOid.Equals(EdECObjectIdentifiers.id_X25519)) |
|
{ |
|
return new X25519PublicKeyParameters(GetRawKey(keyInfo)); |
|
} |
|
else if (algOid.Equals(EdECObjectIdentifiers.id_X448)) |
|
{ |
|
return new X448PublicKeyParameters(GetRawKey(keyInfo)); |
|
} |
|
else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519)) |
|
{ |
|
return new Ed25519PublicKeyParameters(GetRawKey(keyInfo)); |
|
} |
|
else if (algOid.Equals(EdECObjectIdentifiers.id_Ed448)) |
|
{ |
|
return new Ed448PublicKeyParameters(GetRawKey(keyInfo)); |
|
} |
|
else if (algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256) |
|
|| algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512)) |
|
{ |
|
Gost3410PublicKeyAlgParameters gostParams = Gost3410PublicKeyAlgParameters.GetInstance(algID.Parameters); |
|
DerObjectIdentifier publicKeyParamSet = gostParams.PublicKeyParamSet; |
|
|
|
ECGost3410Parameters ecDomainParameters =new ECGost3410Parameters( |
|
new ECNamedDomainParameters(publicKeyParamSet, ECGost3410NamedCurves.GetByOidX9(publicKeyParamSet)), |
|
publicKeyParamSet, |
|
gostParams.DigestParamSet, |
|
gostParams.EncryptionParamSet); |
|
|
|
Asn1OctetString key; |
|
try |
|
{ |
|
key = (Asn1OctetString)keyInfo.ParsePublicKey(); |
|
} |
|
catch (IOException e) |
|
{ |
|
throw new ArgumentException("error recovering GOST3410_2012 public key", e); |
|
} |
|
|
|
int fieldSize = 32; |
|
if (algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512)) |
|
{ |
|
fieldSize = 64; |
|
} |
|
int keySize = 2 * fieldSize; |
|
|
|
byte[] keyEnc = key.GetOctets(); |
|
if (keyEnc.Length != keySize) |
|
throw new ArgumentException("invalid length for GOST3410_2012 public key"); |
|
|
|
byte[] x9Encoding = new byte[1 + keySize]; |
|
x9Encoding[0] = 0x04; |
|
for (int i = 1; i <= fieldSize; ++i) |
|
{ |
|
x9Encoding[i] = keyEnc[fieldSize - i]; |
|
x9Encoding[i + fieldSize] = keyEnc[keySize - i]; |
|
} |
|
|
|
ECPoint q = ecDomainParameters.Curve.DecodePoint(x9Encoding); |
|
|
|
return new ECPublicKeyParameters(q, ecDomainParameters); |
|
} |
|
else |
|
{ |
|
throw new SecurityUtilityException("algorithm identifier in public key not recognised: " + algOid); |
|
} |
|
} |
|
|
|
private static byte[] GetRawKey(SubjectPublicKeyInfo keyInfo) |
|
{ |
|
/* |
|
* TODO[RFC 8422] |
|
* - Require keyInfo.Algorithm.Parameters == null? |
|
*/ |
|
return keyInfo.PublicKeyData.GetOctets(); |
|
} |
|
|
|
private static bool IsPkcsDHParam(Asn1Sequence seq) |
|
{ |
|
if (seq.Count == 2) |
|
return true; |
|
|
|
if (seq.Count > 3) |
|
return false; |
|
|
|
DerInteger l = DerInteger.GetInstance(seq[2]); |
|
DerInteger p = DerInteger.GetInstance(seq[0]); |
|
|
|
return l.Value.CompareTo(BigInteger.ValueOf(p.Value.BitLength)) <= 0; |
|
} |
|
|
|
private static DHPublicKeyParameters ReadPkcsDHParam(DerObjectIdentifier algOid, |
|
BigInteger y, Asn1Sequence seq) |
|
{ |
|
DHParameter para = new DHParameter(seq); |
|
|
|
BigInteger lVal = para.L; |
|
int l = lVal == null ? 0 : lVal.IntValue; |
|
DHParameters dhParams = new DHParameters(para.P, para.G, null, l); |
|
|
|
return new DHPublicKeyParameters(y, dhParams, algOid); |
|
} |
|
} |
|
} |
|
#pragma warning restore |
|
#endif
|
|
|