Ejemplo n.º 1
0
        public byte[] ExportPrivateKey(
            ReadOnlySpan <byte> passwordBytes,
            S2kParameters s2kParameters)
        {
            DSAParameters dsaParameters = new DSAParameters();

            byte[] secretPart = Array.Empty <byte>();

            try
            {
                dsaParameters = dsa.ExportParameters(true);
                secretPart    = CryptoPool.Rent(MPInteger.GetMPEncodedLength(dsaParameters.X !));
                MPInteger.TryWriteInteger(dsaParameters.X, secretPart, out var secretSize);
                int publicKeySize       = MPInteger.GetMPEncodedLength(dsaParameters.P !, dsaParameters.Q !, dsaParameters.G !, dsaParameters.Y !);
                int encryptedSecretSize = S2kBasedEncryption.GetEncryptedLength(s2kParameters, secretSize);
                int expectedLength      = publicKeySize + encryptedSecretSize;
                var destination         = new byte[expectedLength];
                WriteOpenPgpPublicKey(dsaParameters, destination);
                S2kBasedEncryption.EncryptSecretKey(passwordBytes, s2kParameters, secretPart.AsSpan(0, secretSize), destination.AsSpan(publicKeySize));
                return(destination);
            }
            finally
            {
                CryptoPool.Return(secretPart);
                CryptographicOperations.ZeroMemory(dsaParameters.X);
            }
        }
Ejemplo n.º 2
0
 public static int GetEncryptedLength(
     S2kParameters s2kParameters,
     int sourceLength,
     int version = 4)
 {
     if (version >= 4)
     {
         // 4 bytes for usage tag, encryption algorithm, s2k type, hash algorithm
         // 8 bytes for salt
         // 1 byte for iteration count
         // IV of cipher's block size in bytes
         // 20 for SHA-1 checksum
         using var symmetricAlgorithm = PgpUtilities.GetSymmetricAlgorithm(s2kParameters.EncryptionAlgorithm);
         return
             (4 + 8 + 1 +
              ((symmetricAlgorithm.BlockSize + 7) / 8) +
              sourceLength +
              (s2kParameters.UsageTag == S2kUsageTag.Checksum ? 2 : 20));
     }
     else
     {
         using var symmetricAlgorithm = PgpUtilities.GetSymmetricAlgorithm(s2kParameters.EncryptionAlgorithm);
         // 1 for encryption algorithm, hash is fixed at MD5, no salt and no iterations, 2 bytes for checksum
         return(1 + ((symmetricAlgorithm.BlockSize + 7) / 8) + sourceLength + 2);
     }
 }
Ejemplo n.º 3
0
        public byte[] ExportPrivateKey(
            ReadOnlySpan <byte> passwordBytes,
            S2kParameters s2kParameters)
        {
            RSAParameters rsaParameters = new RSAParameters();

            byte[] secretPart = Array.Empty <byte>();

            try
            {
                rsaParameters = rsa.ExportParameters(true);

                secretPart = CryptoPool.Rent(MPInteger.GetMPEncodedLength(rsaParameters.D !, rsaParameters.P !, rsaParameters.Q !, rsaParameters.InverseQ !));
                MPInteger.TryWriteInteger(rsaParameters.D, secretPart, out var dBytesWritten);
                MPInteger.TryWriteInteger(rsaParameters.P, secretPart.AsSpan(dBytesWritten), out var pBytesWritten);
                MPInteger.TryWriteInteger(rsaParameters.Q, secretPart.AsSpan(dBytesWritten + pBytesWritten), out var qBytesWritten);
                MPInteger.TryWriteInteger(rsaParameters.InverseQ, secretPart.AsSpan(dBytesWritten + pBytesWritten + qBytesWritten), out var iqBytesWritten);
                int secretSize = dBytesWritten + pBytesWritten + qBytesWritten + iqBytesWritten;

                int encryptedSecretSize = S2kBasedEncryption.GetEncryptedLength(s2kParameters, secretSize);
                int expectedLength      =
                    MPInteger.GetMPEncodedLength(rsaParameters.Modulus !, rsaParameters.Exponent !) +
                    encryptedSecretSize;
                var destination = new byte[expectedLength];

                MPInteger.TryWriteInteger(rsaParameters.Modulus, destination, out int modulusWritten);
                MPInteger.TryWriteInteger(rsaParameters.Exponent, destination.AsSpan(modulusWritten), out int exponentWritten);

                S2kBasedEncryption.EncryptSecretKey(passwordBytes, s2kParameters, secretPart.AsSpan(0, secretSize), destination.AsSpan(modulusWritten + exponentWritten));

                return(destination.AsSpan(0, modulusWritten + exponentWritten + encryptedSecretSize).ToArray());
            }
            finally
            {
                CryptoPool.Return(secretPart);
                CryptographicOperations.ZeroMemory(rsaParameters.D);
                CryptographicOperations.ZeroMemory(rsaParameters.P);
                CryptographicOperations.ZeroMemory(rsaParameters.Q);
                CryptographicOperations.ZeroMemory(rsaParameters.InverseQ);
                CryptographicOperations.ZeroMemory(rsaParameters.DP);
                CryptographicOperations.ZeroMemory(rsaParameters.DQ);
            }
        }
Ejemplo n.º 4
0
        public byte[] ExportPrivateKey(
            ReadOnlySpan <byte> passwordBytes,
            S2kParameters s2kParameters)
        {
            ECParameters ecParameters = new ECParameters();

            byte[] secretPart = Array.Empty <byte>();

            try
            {
                ecParameters = ecdh.ExportParameters(true);
                if (ecdh is X25519)
                {
                    Array.Reverse(ecParameters.D !);
                }

                int secretSize = MPInteger.GetMPEncodedLength(ecParameters.D !);
                secretPart = CryptoPool.Rent(secretSize);
                MPInteger.TryWriteInteger(ecParameters.D, secretPart, out var _);

                int encryptedSecretLength = S2kBasedEncryption.GetEncryptedLength(s2kParameters, secretSize);
                int estimatedLength       =
                    32 /* OID */ +
                    MPInteger.GetMPEncodedLength(ecParameters.Q.X !, ecParameters.Q.Y !) + 1 /* EC Point type */ +
                    4 /* KDF Parameters */ +
                    encryptedSecretLength;
                var destination = new byte[estimatedLength];
                WriteOpenPgpECParameters(ecParameters, destination, out int bytesWritten);
                WriteKDFParameters(destination.AsSpan(bytesWritten));

                S2kBasedEncryption.EncryptSecretKey(passwordBytes, s2kParameters, secretPart.AsSpan(0, secretSize), destination.AsSpan(bytesWritten + 4));
                return(destination.AsSpan(0, bytesWritten + 4 + encryptedSecretLength).ToArray());
            }
            finally
            {
                CryptoPool.Return(secretPart);
                if (ecParameters.D != null)
                {
                    CryptographicOperations.ZeroMemory(ecParameters.D);
                }
            }
        }
Ejemplo n.º 5
0
        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);
            }
        }