public static ECDiffieHellmanKey CreatePrivate( ReadOnlySpan <byte> fingerprint, ReadOnlySpan <byte> password, ReadOnlySpan <byte> source, out int publicKeySize) { var ecParameters = ReadOpenPgpECParameters(source, out publicKeySize); // TODO: Validation byte kdfSize = source[publicKeySize]; var kdfParameters = source.Slice(publicKeySize + 1, kdfSize).ToArray(); byte[] paramsArray = new byte[source.Length - publicKeySize]; try { S2kBasedEncryption.DecryptSecretKey(password, source.Slice(publicKeySize + kdfSize + 1), paramsArray, out int bytesWritten); Debug.Assert(bytesWritten != 0); ecParameters.D = MPInteger.ReadInteger(paramsArray, out int dConsumed).ToArray(); return(new ECDiffieHellmanKey(CreateECDiffieHellman(ecParameters), kdfParameters, fingerprint.ToArray())); } finally { CryptographicOperations.ZeroMemory(paramsArray); CryptographicOperations.ZeroMemory(ecParameters.D); } }
public static DsaKey CreatePrivate( ReadOnlySpan <byte> password, ReadOnlySpan <byte> source, out int publicKeySize) { var dsaParameters = ReadOpenPgpPublicKey(source, out publicKeySize); byte[] xArray = new byte[source.Length - publicKeySize]; try { S2kBasedEncryption.DecryptSecretKey(password, source.Slice(publicKeySize), xArray, out int bytesWritten); dsaParameters.X = MPInteger.ReadInteger(xArray, out int xConsumed).ToArray(); // Make sure Q, X have the same length (DSA implementation on Windows requires it) int qxLength = Math.Max(dsaParameters.X.Length, dsaParameters.Q !.Length); ResizeArrayIfNeeded(ref dsaParameters.Q, qxLength); ResizeArrayIfNeeded(ref dsaParameters.X, qxLength); return(new DsaKey(DSA.Create(dsaParameters))); } finally { CryptographicOperations.ZeroMemory(xArray); CryptographicOperations.ZeroMemory(dsaParameters.X); } }
public bool TryDecryptSessionInfo(ReadOnlySpan <byte> encryptedSessionData, Span <byte> sessionData, out int bytesWritten) { var pEnc = MPInteger.ReadInteger(encryptedSessionData, out int pointBytesRead); encryptedSessionData = encryptedSessionData.Slice(pointBytesRead); int keyLen = encryptedSessionData[0]; var keyEnc = encryptedSessionData.Slice(1, keyLen); var publicParams = ecdh.PublicKey.ExportParameters(); var publicPoint = DecodePoint(pEnc); var otherEcdh = CreateECDiffieHellman(new ECParameters { Curve = publicParams.Curve, Q = publicPoint }); var derivedKey = ecdh.DeriveKeyFromHash( otherEcdh.PublicKey, PgpUtilities.GetHashAlgorithmName(this.hashAlgorithm), new byte[] { 0, 0, 0, 1 }, CreateUserKeyingMaterial(publicParams.Curve.Oid)); derivedKey = derivedKey.AsSpan(0, PgpUtilities.GetKeySize(this.symmetricAlgorithm) / 8).ToArray(); var C = SymmetricKeyWrap.AESKeyWrapDecrypt(derivedKey, keyEnc.ToArray()); var data = UnpadSessionData(C); if (sessionData.Length >= data.Length) { data.CopyTo(sessionData); bytesWritten = data.Length; return(true); } bytesWritten = 0; return(false); }
public bool VerifySignature( ReadOnlySpan <byte> rgbHash, ReadOnlySpan <byte> rgbSignature, PgpHashAlgorithm hashAlgorithm) { var signature = MPInteger.ReadInteger(rgbSignature, out var _); return(rsa.VerifyHash(rgbHash, signature, PgpUtilities.GetHashAlgorithmName(hashAlgorithm), RSASignaturePadding.Pkcs1)); }
public static RSAParameters ReadOpenPgpPublicKey(ReadOnlySpan <byte> source, out int bytesRead) { var rsaParameters = new RSAParameters(); rsaParameters.Modulus = MPInteger.ReadInteger(source, out int modulusConsumed).ToArray(); source = source.Slice(modulusConsumed); rsaParameters.Exponent = MPInteger.ReadInteger(source, out int exponentConsumed).ToArray(); bytesRead = modulusConsumed + exponentConsumed; return(rsaParameters); }
private static ElGamalParameters ReadOpenPgpPublicKey(ReadOnlySpan <byte> source, out int bytesRead) { var elgamalParameters = new ElGamalParameters(); elgamalParameters.P = MPInteger.ReadInteger(source, out int pConsumed).ToArray(); source = source.Slice(pConsumed); elgamalParameters.G = MPInteger.ReadInteger(source, out int gConsumed).ToArray(); source = source.Slice(gConsumed); elgamalParameters.Y = MPInteger.ReadInteger(source, out int yConsumed).ToArray(); bytesRead = pConsumed + gConsumed + yConsumed; return(elgamalParameters); }
public bool TryDecryptSessionInfo(ReadOnlySpan <byte> encryptedSessionData, Span <byte> sessionData, out int bytesWritten) { var mp = MPInteger.ReadInteger(encryptedSessionData, out var _); var data = rsa.Decrypt(mp.ToArray(), RSAEncryptionPadding.Pkcs1); if (sessionData.Length >= data.Length) { data.CopyTo(sessionData); bytesWritten = data.Length; return(true); } bytesWritten = 0; return(false); }
public bool VerifySignature( ReadOnlySpan <byte> rgbHash, ReadOnlySpan <byte> rgbSignature, PgpHashAlgorithm hashAlgorithm) { var asnWriter = new AsnWriter(AsnEncodingRules.DER); using (var scope = asnWriter.PushSequence()) { asnWriter.WriteIntegerUnsigned(MPInteger.ReadInteger(rgbSignature, out int rConsumed)); asnWriter.WriteIntegerUnsigned(MPInteger.ReadInteger(rgbSignature.Slice(rConsumed), out var _)); } return(dsa.VerifySignature(rgbHash, asnWriter.Encode(), DSASignatureFormat.Rfc3279DerSequence)); }
public bool TryDecryptSessionInfo(ReadOnlySpan <byte> encryptedSessionData, Span <byte> sessionData, out int bytesWritten) { var g = MPInteger.ReadInteger(encryptedSessionData, out var gBytesRead); var p = MPInteger.ReadInteger(encryptedSessionData.Slice(gBytesRead), out var _); var halfLength = Math.Max(g.Length, p.Length); var inputData = new byte[halfLength * 2]; g.CopyTo(inputData.AsSpan(halfLength - g.Length)); p.CopyTo(inputData.AsSpan(inputData.Length - p.Length)); var data = elGamal.Decrypt(inputData, RSAEncryptionPadding.Pkcs1); if (sessionData.Length >= data.Length) { data.CopyTo(sessionData); bytesWritten = data.Length; return(true); } bytesWritten = 0; return(false); }
public new static EdDsaKey CreatePrivate( ReadOnlySpan <byte> password, ReadOnlySpan <byte> source, out int publicKeySize) { var ecParameters = ReadOpenPgpECParameters(source, out publicKeySize); byte[] paramsArray = new byte[source.Length - publicKeySize]; try { S2kBasedEncryption.DecryptSecretKey(password, source.Slice(publicKeySize), paramsArray, out int bytesWritten); Debug.Assert(bytesWritten != 0); ecParameters.D = MPInteger.ReadInteger(paramsArray, out int dConsumed).ToArray(); return(new EdDsaKey(CreateEdDsa(ecParameters))); } finally { CryptographicOperations.ZeroMemory(paramsArray); CryptographicOperations.ZeroMemory(ecParameters.D); } }
private static DSAParameters ReadOpenPgpPublicKey(ReadOnlySpan <byte> source, out int bytesRead) { var dsaParameters = new DSAParameters(); dsaParameters.P = MPInteger.ReadInteger(source, out int pConsumed).ToArray(); source = source.Slice(pConsumed); dsaParameters.Q = MPInteger.ReadInteger(source, out int qConsumed).ToArray(); source = source.Slice(qConsumed); dsaParameters.G = MPInteger.ReadInteger(source, out int gConsumed).ToArray(); source = source.Slice(gConsumed); dsaParameters.Y = MPInteger.ReadInteger(source, out int yConsumed).ToArray(); bytesRead = pConsumed + qConsumed + gConsumed + yConsumed; // Make sure P, G, Y have the same length (DSA implementation on Windows requires it) int pgyLength = Math.Max(Math.Max(dsaParameters.P !.Length, dsaParameters.G !.Length), dsaParameters.Y !.Length); ResizeArrayIfNeeded(ref dsaParameters.P, pgyLength); ResizeArrayIfNeeded(ref dsaParameters.G, pgyLength); ResizeArrayIfNeeded(ref dsaParameters.Y, pgyLength); return(dsaParameters); }
public static ElGamalKey CreatePrivate( ReadOnlySpan <byte> password, ReadOnlySpan <byte> source, out int bytesRead) { var elgamalParameters = ReadOpenPgpPublicKey(source, out bytesRead); byte[] xArray = new byte[source.Length - bytesRead]; try { S2kBasedEncryption.DecryptSecretKey(password, source.Slice(bytesRead), xArray, out int bytesWritten); elgamalParameters.X = MPInteger.ReadInteger(xArray, out int xConsumed).ToArray(); bytesRead = source.Length; return(new ElGamalKey(ElGamal.Create(elgamalParameters))); } finally { CryptographicOperations.ZeroMemory(xArray); CryptographicOperations.ZeroMemory(elgamalParameters.X); } }
protected static ECParameters ReadOpenPgpECParameters(ReadOnlySpan <byte> source, out int bytesRead) { ECParameters ecParameters = new ECParameters(); int oidLength = source[0]; // TODO: Validate oidLength var oidBytes = new byte[oidLength + 2]; oidBytes[0] = 6; oidBytes[1] = (byte)oidLength; source.Slice(1, oidLength).CopyTo(oidBytes.AsSpan(2)); var oid = new Oid(AsnDecoder.ReadObjectIdentifier(oidBytes, AsnEncodingRules.DER, out _)); ecParameters.Curve = ECCurve.CreateFromOid(oid); var pointBytes = MPInteger.ReadInteger(source.Slice(oidLength + 1), out bytesRead); bytesRead += oidLength + 1; ecParameters.Q = DecodePoint(pointBytes); return(ecParameters); }
public static RsaKey CreatePrivate( ReadOnlySpan <byte> password, ReadOnlySpan <byte> source, out int publicKeyBytes, int version = 4) { var rsaParameters = ReadOpenPgpPublicKey(source, out publicKeyBytes); byte[] paramsArray = new byte[source.Length - publicKeyBytes]; try { S2kBasedEncryption.DecryptSecretKey(password, source.Slice(publicKeyBytes), paramsArray, out int bytesWritten, version); Debug.Assert(bytesWritten != 0); int halfModulusLength = (rsaParameters.Modulus !.Length + 1) / 2; rsaParameters.D = new byte[rsaParameters.Modulus.Length]; rsaParameters.P = new byte[halfModulusLength]; rsaParameters.Q = new byte[halfModulusLength]; rsaParameters.DP = new byte[halfModulusLength]; rsaParameters.DQ = new byte[halfModulusLength]; rsaParameters.InverseQ = new byte[halfModulusLength]; var privateSource = new ReadOnlySpan <byte>(paramsArray); var d = MPInteger.ReadInteger(privateSource, out int dConsumed); privateSource = privateSource.Slice(dConsumed); var p = MPInteger.ReadInteger(privateSource, out int pConsumed); privateSource = privateSource.Slice(pConsumed); var q = MPInteger.ReadInteger(privateSource, out int qConsumed); //source = source.Slice(qConsumed); // Technically InverseQ follows but it's often incorrect // FIXME: These BigIntegers cannot be cleared from memory var D = new BigInteger(d, isBigEndian: true, isUnsigned: true); var P = new BigInteger(p, isBigEndian: true, isUnsigned: true); var Q = new BigInteger(q, isBigEndian: true, isUnsigned: true); var DP = BigInteger.Remainder(D, P - BigInteger.One); var DQ = BigInteger.Remainder(D, Q - BigInteger.One); // Lot of the public keys in the test suite have this wrong (switched P/Q) var InverseQ = BigInteger.ModPow(Q, P - BigInteger.One - BigInteger.One, P); d.CopyTo(rsaParameters.D.AsSpan(rsaParameters.D.Length - d.Length)); p.CopyTo(rsaParameters.P.AsSpan(rsaParameters.P.Length - p.Length)); q.CopyTo(rsaParameters.Q.AsSpan(rsaParameters.Q.Length - q.Length)); DP.TryWriteBytes(rsaParameters.DP.AsSpan(rsaParameters.DP.Length - DP.GetByteCount(isUnsigned: true)), out var _, isBigEndian: true, isUnsigned: true); DQ.TryWriteBytes(rsaParameters.DQ.AsSpan(rsaParameters.DQ.Length - DQ.GetByteCount(isUnsigned: true)), out var _, isBigEndian: true, isUnsigned: true); InverseQ.TryWriteBytes(rsaParameters.InverseQ.AsSpan(rsaParameters.InverseQ.Length - InverseQ.GetByteCount(isUnsigned: true)), out var _, isBigEndian: true, isUnsigned: true); return(new RsaKey(RSA.Create(rsaParameters))); } finally { CryptographicOperations.ZeroMemory(paramsArray); CryptographicOperations.ZeroMemory(rsaParameters.D); CryptographicOperations.ZeroMemory(rsaParameters.P); CryptographicOperations.ZeroMemory(rsaParameters.Q); CryptographicOperations.ZeroMemory(rsaParameters.DP); CryptographicOperations.ZeroMemory(rsaParameters.DQ); CryptographicOperations.ZeroMemory(rsaParameters.InverseQ); } }
public static void EncryptSecretKey( ReadOnlySpan <byte> password, S2kParameters s2kParameters, ReadOnlySpan <byte> source, Span <byte> destination, int version = 4) { if (password.Length == 0) { destination[0] = (byte)S2kUsageTag.None; source.CopyTo(destination.Slice(1)); return; } using var c = PgpUtilities.GetSymmetricAlgorithm(s2kParameters.EncryptionAlgorithm); int keySizeInBytes = (c.KeySize + 7) / 8; Span <byte> keyBytes = stackalloc byte[keySizeInBytes]; if (version <= 3) { MakeKey(password, PgpHashAlgorithm.MD5, Array.Empty <byte>(), 0, keyBytes); destination[0] = (byte)s2kParameters.EncryptionAlgorithm; c.GenerateIV(); c.IV.CopyTo(destination.Slice(1)); int bytesWritten = 13 + ((c.BlockSize + 7) / 8); destination = destination.Slice(bytesWritten); c.Key = keyBytes.ToArray(); int checksum = 0; foreach (var b in source) { checksum += b; } for (int i = 0; i < 4; i++) { using var encryptor = new ZeroPaddedCryptoTransform(c.CreateEncryptor()); destination[0] = source[0]; destination[1] = source[1]; var mpInteger = MPInteger.ReadInteger(source, out int bytesConsumed).ToArray(); source = source.Slice(bytesConsumed); var data = encryptor.TransformFinalBlock(mpInteger, 0, mpInteger.Length); data.AsSpan().CopyTo(destination.Slice(2)); destination = destination.Slice(2 + data.Length); CryptographicOperations.ZeroMemory(mpInteger); if (i != 4) { c.IV = data.AsSpan(data.Length - (c.BlockSize / 8)).ToArray(); } } destination[0] = (byte)(checksum >> 8); destination[1] = (byte)(checksum); } else { var salt = new byte[8]; RandomNumberGenerator.Fill(salt); byte rawIterationCount = 0x60; int iterationCount = (16 + (rawIterationCount & 15)) << ((rawIterationCount >> 4) + 6); MakeKey(password, s2kParameters.HashAlgorithm, salt, iterationCount, keyBytes); destination[0] = (byte)s2kParameters.UsageTag; destination[1] = (byte)s2kParameters.EncryptionAlgorithm; destination[2] = 3; // Salted & iterated destination[3] = (byte)s2kParameters.HashAlgorithm; salt.CopyTo(destination.Slice(4)); destination[12] = rawIterationCount; c.GenerateIV(); c.IV.CopyTo(destination.Slice(13)); int bytesWritten = 13 + ((c.BlockSize + 7) / 8); destination = destination.Slice(bytesWritten); c.Key = keyBytes.ToArray(); using var encryptor = new ZeroPaddedCryptoTransform(c.CreateEncryptor()); byte[] checksumBytes; if (s2kParameters.UsageTag == S2kUsageTag.Sha1) { using var sha1 = IncrementalHash.CreateHash(HashAlgorithmName.SHA1); sha1.AppendData(source); checksumBytes = sha1.GetHashAndReset(); } else { int checksum = 0; foreach (var b in source) { checksum += b; } checksumBytes = new byte[] { (byte)(checksum >> 8), (byte)checksum }; } var decSource = new byte[source.Length + checksumBytes.Length]; source.CopyTo(decSource); checksumBytes.CopyTo(decSource, source.Length); var data = encryptor.TransformFinalBlock(decSource, 0, decSource.Length); data.AsSpan().CopyTo(destination); CryptographicOperations.ZeroMemory(data); CryptographicOperations.ZeroMemory(decSource); } }