// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Security.Cryptography.Encryption.RC2.Tests;
using System.Text;
using Microsoft.DotNet.XUnitExtensions;
using Test.Cryptography;
using Xunit;

namespace System.Security.Cryptography.Rsa.Tests
{
    [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")]
    public static class RSAKeyFileTests
    {
        public static bool Supports384BitPrivateKeyAndRC2 { get; } = RSAFactory.Supports384PrivateKey && RC2Factory.IsSupported;
        public static bool SupportsLargeExponent { get; } = RSAFactory.SupportsLargeExponent;

        [Theory]
        [InlineData(false)]
        [InlineData(true)]
        public static void UseAfterDispose(bool importKey)
        {
            RSA rsa = importKey ? RSAFactory.Create(TestData.RSA2048Params) : RSAFactory.Create(1024);
            byte[] pkcs1Public;
            byte[] pkcs1Private;
            byte[] pkcs8Private;
            byte[] pkcs8EncryptedPrivate;
            byte[] subjectPublicKeyInfo;

            string pwStr = "Hello";
            // Because the PBE algorithm uses PBES2 the string->byte encoding is UTF-8.
            byte[] pwBytes = TestData.HelloBytes;

            PbeParameters pbeParameters = new PbeParameters(
                PbeEncryptionAlgorithm.Aes192Cbc,
                HashAlgorithmName.SHA256,
                3072);

            // Ensure the key was loaded, then dispose it.
            // Also ensures all of the inputs are valid for the disposed tests.
            using (rsa)
            {
                pkcs1Public = rsa.ExportRSAPublicKey();
                pkcs1Private = rsa.ExportRSAPrivateKey();
                pkcs8Private = rsa.ExportPkcs8PrivateKey();
                pkcs8EncryptedPrivate = rsa.ExportEncryptedPkcs8PrivateKey(pwStr, pbeParameters);
                subjectPublicKeyInfo = rsa.ExportSubjectPublicKeyInfo();
            }

            Assert.Throws<ObjectDisposedException>(() => rsa.ImportRSAPublicKey(pkcs1Public, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ImportRSAPrivateKey(pkcs1Private, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ImportPkcs8PrivateKey(pkcs8Private, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ImportEncryptedPkcs8PrivateKey(pwStr, pkcs8EncryptedPrivate, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ImportEncryptedPkcs8PrivateKey(pwBytes, pkcs8EncryptedPrivate, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ImportSubjectPublicKeyInfo(subjectPublicKeyInfo, out _));

            Assert.Throws<ObjectDisposedException>(() => rsa.ExportRSAPublicKey());
            Assert.Throws<ObjectDisposedException>(() => rsa.TryExportRSAPublicKey(pkcs1Public, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ExportRSAPrivateKey());
            Assert.Throws<ObjectDisposedException>(() => rsa.TryExportRSAPrivateKey(pkcs1Private, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ExportPkcs8PrivateKey());
            Assert.Throws<ObjectDisposedException>(() => rsa.TryExportPkcs8PrivateKey(pkcs8Private, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ExportEncryptedPkcs8PrivateKey(pwStr, pbeParameters));
            Assert.Throws<ObjectDisposedException>(() => rsa.TryExportEncryptedPkcs8PrivateKey(pwStr, pbeParameters, pkcs8EncryptedPrivate, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ExportEncryptedPkcs8PrivateKey(pwBytes, pbeParameters));
            Assert.Throws<ObjectDisposedException>(() => rsa.TryExportEncryptedPkcs8PrivateKey(pwBytes, pbeParameters, pkcs8EncryptedPrivate, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ExportSubjectPublicKeyInfo());
            Assert.Throws<ObjectDisposedException>(() => rsa.TryExportSubjectPublicKeyInfo(subjectPublicKeyInfo, out _));

            // Check encrypted import with the wrong password.
            // It shouldn't do enough work to realize it was wrong.
            pwBytes = Array.Empty<byte>();
            Assert.Throws<ObjectDisposedException>(() => rsa.ImportEncryptedPkcs8PrivateKey((ReadOnlySpan<char>)"", pkcs8EncryptedPrivate, out _));
            Assert.Throws<ObjectDisposedException>(() => rsa.ImportEncryptedPkcs8PrivateKey(pwBytes, pkcs8EncryptedPrivate, out _));
        }

        [ConditionalFact(nameof(SupportsLargeExponent))]
        public static void ReadWriteBigExponentPrivatePkcs1()
        {
            ReadWriteBase64PrivatePkcs1(
                @"
MIIEpQIBAAKCAQEAr4HBy9ggP2JKU57WYIF1NyOTooN9SJDkihne02lzEVYglo1r
4NPao4qnd74C7gtrk7ck6NzBK2MrT6gLvJJbzmJPTKfMYGMGs5QD4oyTLSTdVG/+
TvajfxB3CyIV6oy7W/Qn6MTYm3nrM4N1EAxfg+Vd6bRGbd++7kJTmu8z7xh7d2DD
saGyEDwtgURWSgwQOaCchc9rWXTrUW/I1mI8lK46WguztMeSlX1DI5FWbPPipSr7
DBQrngaBuJcmca8rgt05Cjm5Oc9xlWhofkmQpjBQyndo3NazeIQvGP2x9tn/CWuv
e+uY3Pkw1m/P1QP1jUG/9GIS4k46/EXqQr2IRwIFAgAABEECggEAZK+bpSYkg9qS
tT8TQ5/Q7xMBL4eavAPLfAbxIJkE81LB8iNRncSL+u67URsNlV9hZ7UOA0/qKrxZ
C06p+/DFH5/+oW95J65oHL9zWEUryinVhwXgyqEGATsJpvX1kRSY0sT9aRVYVIjl
862Jg2yTyHda+rTRPCAUJmvo7muKpmyelC1JNGbI46Nw+OY3jOldY34DZzZwvkvK
zl/NrdI42fMso13oRXdqxL82EYgSMoxJP5HCWpvUJnLQr6/eCvfmGQeNSLSF75GT
Pdz/tUWHuPUS0iPIGJTpF4SYLzxcZYcTUfRlWrAjxK2ZtrA6lvkEbOEkpHHoKPBf
jbO8fMzy0QKBgQDkOjgmqXIErjzYZJqE20u/ByXEsI+MQ4QFV6DNBOMTr20EYN3m
nNxQitBD1yUU2npmvJGM2WJPSFZEud7qsr4OESlW1HLPD9UfgP0zhy0tzFYqBYiw
EujJDOfSVLlHksbnoCs8yqFQ5npkN3rMSUea1etVVJOyEAywQQlW99c79QKBgQDE
3S163WylB0DTlz9AxN69urUff1GBq65ybDJZaj7dCu5E2q3dipt6hkxP/a4AxMsf
EBd7oBwEZvgS1SJhD4xFQ/HD71efqeE66NoaSo2uMHhh0s6sA1YCebYbZRSYmIP+
hsXHQg0xKDj8L3C+1ZtSKWVCAYgmZM76OLSKNyPpywKBgAns8VH1zdLJ5uUmgjZP
pbTtCU9iLkAxv0a4UTWKWE3MtTKLC9m2NYkYP0kVk9KjrK0U4KrNofGBtcfZPFft
JuYsn8Jq835KBkTs6Cp7qK7Yj/HY6cVsxmOFzbJE6z1X0X5q1CCxnJ4r7hgZK4Fi
ZbdNpV+jgl+SLZ2Og1t2vzBxAoGBAImzO2lXiRdLiDaMSUY51NMmciRXKkCy/mGR
A4Qijj29Ee7ZBAzQOXfp4Nf8i/xL9Kkyg1Kf8dllkLGPTqvvAwN5Tyk+iNx2Gz4j
r+yxnyn4pNKpBYtxTPP00Qcz8T6nK78fvsjXHhBtDOIRXzrS3gIDJcOHmgkcQTzW
OX+Ds8uJAoGAfFftdMkXb7p2wjGDICUVBixmTU1J/z4DcEejCdoQ8VkM4Bt6HNGk
Mm3HWIPf+TEQqwZartFAybmBdqiBCAmt7HXoZ2SglRWX70Z/qP1QkYHNLkkeQ75B
CE5b4bVi7nbp+SyaseWurZ0pGmM35N6FveZ6DXK05Vrc8gf3paUiXhU=",
                TestData.RsaBigExponentParams);
        }

        [Fact]
        [ActiveIssue("https://github.com/dotnet/runtime/issues/62547", TestPlatforms.Android)]
        public static void ReadWriteDiminishedDPPrivatePkcs1()
        {
            ReadWriteBase64PrivatePkcs1(
                @"
MIIBOwIBAAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQxm5NTLEHDwUd7idstLzPX
uah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQJBAK/m8jYvnK9exaSR+DAh
Ij12ip5pB+HOFOdhCbS/coNoIowa6WJGrd3Np1m9BBhouWloF8UB6Iu8/e/wAg+F
9ykCIQDzcnsehnYgVZTTxzoCJ01PGpgESilRyFzNEsb8V60ZewIhAMCyOujqUqn7
Q079SlHzXuvocqIdt4IM1EmIlrlU9GGvAh8Ijv3FFPUSLfANgfOIH9mX7ldpzzGk
rmaUzxQvyuVLAiEArCTM8dSbopUADWnD4jArhU50UhWAIaM6ZrKqC8k0RKsCIQDC
yZWUxoxAdjfrBGsx+U6BHM0Myqqe7fY7hjWzj4aBCw==",
                TestData.DiminishedDPParameters);
        }

        [ConditionalFact]
        [OuterLoop("RSA 16384 takes considerable time.")]
        public static void ReadWritePublicPkcs1()
        {
            // Do not move this to the [ConditionalFact], otherwise the platform will check if RSA 16384 is supported
            // during test discovery for innerloop, and the check itself is expensive.
            if (!ImportExport.Supports16384)
            {
                throw new SkipTestException("Platform does not support RSA 16384.");
            }

            ReadWriteBase64PublicPkcs1(
                @"
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",
                TestData.RSA16384Params);
        }

        [ConditionalFact(nameof(SupportsLargeExponent))]
        public static void ReadWriteSubjectPublicKeyInfo()
        {
            ReadWriteBase64SubjectPublicKeyInfo(
                @"
MIIBJDANBgkqhkiG9w0BAQEFAAOCAREAMIIBDAKCAQEAr4HBy9ggP2JKU57WYIF1
NyOTooN9SJDkihne02lzEVYglo1r4NPao4qnd74C7gtrk7ck6NzBK2MrT6gLvJJb
zmJPTKfMYGMGs5QD4oyTLSTdVG/+TvajfxB3CyIV6oy7W/Qn6MTYm3nrM4N1EAxf
g+Vd6bRGbd++7kJTmu8z7xh7d2DDsaGyEDwtgURWSgwQOaCchc9rWXTrUW/I1mI8
lK46WguztMeSlX1DI5FWbPPipSr7DBQrngaBuJcmca8rgt05Cjm5Oc9xlWhofkmQ
pjBQyndo3NazeIQvGP2x9tn/CWuve+uY3Pkw1m/P1QP1jUG/9GIS4k46/EXqQr2I
RwIFAgAABEE=",
                TestData.RsaBigExponentParams);
        }

        [Fact]
        public static void ReadWriteSubjectPublicKeyInfo_DiminishedDPKey()
        {
            ReadWriteBase64SubjectPublicKeyInfo(
                @"
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALc/WfXui9VeJLf/AprRaoVDyW0lPlQx
m5NTLEHDwUd7idstLzPXuah0WEjgao5oO1BEUR4byjYlJ+F89Cs4BhUCAwEAAQ==",
                TestData.DiminishedDPParameters);
        }


        [ConditionalFact]
        [OuterLoop("RSA 16384 takes considerable time.")]
        public static void ReadWriteRsa16384SubjectPublicKeyInfo()
        {
            // Do not move this to the [ConditionalFact], otherwise the platform will check if RSA 16384 is supported
            // during test discovery for innerloop, and the check itself is expensive.
            if (!ImportExport.Supports16384)
            {
                throw new SkipTestException("Platform does not support RSA 16384.");
            }

            ReadWriteBase64SubjectPublicKeyInfo(
                @"
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
5hHlolNkpw+thqvba8lMvzMCAwEAAQ==",
                TestData.RSA16384Params);
        }

        [ConditionalFact]
        [OuterLoop("RSA 16384 takes considerable time.")]
        public static void ReadWrite16384Pkcs8()
        {
            // Do not move this to the [ConditionalFact], otherwise the platform will check if RSA 16384 is supported
            // during test discovery for innerloop, and the check itself is expensive.
            if (!ImportExport.Supports16384)
            {
                throw new SkipTestException("Platform does not support RSA 16384");
            }

            ReadWriteBase64Pkcs8(
                @"
[encoded data, 12545 characters]
xBdaeIJFmTymL1LOru69mA9gwhuFFQ==",
                TestData.RSA16384Params);
        }

        [Fact]
        public static void ReadWriteDiminishedDPPkcs8()
        {
            ReadWriteBase64Pkcs8(
                @"
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAtz9Z9e6L1V4kt/8C
mtFqhUPJbSU+VDGbk1MsQcPBR3uJ2y0vM9e5qHRYSOBqjmg7UERRHhvKNiUn4Xz0
KzgGFQIDAQABAkEAr+byNi+cr17FpJH4MCEiPXaKnmkH4c4U52EJtL9yg2gijBrp
Ykat3c2nWb0EGGi5aWgXxQHoi7z97/ACD4X3KQIhAPNyex6GdiBVlNPHOgInTU8a
mARKKVHIXM0SxvxXrRl7AiEAwLI66OpSqftDTv1KUfNe6+hyoh23ggzUSYiWuVT0
Ya8CHwiO/cUU9RIt8A2B84gf2ZfuV2nPMaSuZpTPFC/K5UsCIQCsJMzx1JuilQAN
acPiMCuFTnRSFYAhozpmsqoLyTREqwIhAMLJlZTGjEB2N+sEazH5ToEczQzKqp7t
9juGNbOPhoEL",
                TestData.DiminishedDPParameters);
        }

        [Fact]
        public static void ReadEncryptedDiminishedDP()
        {
            // PBES1: PbeWithMD5AndDESCBC
            const string base64 = @"
MIIBgTAbBgkqhkiG9w0BBQMwDgQI4cFTpQ4kAU0CAggABIIBYO1zEiMx+W9RzsbC
rKGzDRko5PxWiX1xTya2pU2Nnt8FTstf2xWUQJtmPq3miMVHskgaXXgDc7O/cUkX
aM01UqvUxe1+PwrcllZPT6WeDLKWD0mVLGsY2BZz52UmoShXkraYovuHehyATHeL
CEZ1Nn0U+JBU0VlqwhAmD/sagZ7+aq0zggJGvr9wH0DZW5RWCncvG+iZXw/cPfQ9
gTlrGm8FIWTEwtt+nHv38Ep1zfG3DjLZ/o6IXX+KGykxdkWJVTIFrgCZ+TZ2KH9b
zL4zxrUq62QFTGlLiDXPmpua0ZksMlGfVAOyCdwZ/rfJQQomG4BeRF44jgVx5lkc
tirn7aQDNItvjDcSTWsgFNBx37TQAet0Xp2Lebc9tgWUyFimBca3PinZbWrr8e99
hw/nLtm9qs5I9nFM+RHdeqyhQ17FuH8hLEMXlre/3hkC2yGHEcgDQPWjTH+mSG2B
YMSYHxE=";

            ReadBase64EncryptedPkcs8(
                base64,
                "asdf",
                new PbeParameters(
                    PbeEncryptionAlgorithm.Aes192Cbc,
                    HashAlgorithmName.SHA256,
                    3072),
                TestData.DiminishedDPParameters);
        }

        [Fact]
        public static void ReadEncryptedRsa1032()
        {
            // PBES2: PBKDF2 + aes192
            const string base64 = @"
MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQINYt7wOn+km4CAggA
MB0GCWCGSAFlAwQBFgQQcR2qtVNKVc4VgYqcPMBlwASCAoBEX5M21ImLfqUlgTEC
oWc+QBANsfVV8xiWwXBLsVD7jZmoxY3LdpstO5POibHtVb2/6WtzbTitXO4QPRAu
h8NM2tXKO4j0vnnuw5/he78Yn3gQFm2IIZG56a6rKFVF5bGL2hP3yMiJHfKztPzM
bpwvTr8hhv/rsHCb1P93r57yAsSaJLmFfdhRMjghvPBMF8SvwLwkVaZf0qHDIpZS
BwKpBH1GmROzxUtajSAvCRPRQvjEWJqCEPRPNA+yfUGBOvicpe0kCivdTPvMPoC4
FtQp3UIg+RW295vSXy2qCZrRXxh8Svx+fYFqN1OZJcMtsbfFAv9QRvULvwMNsOUL
Wk5Mp2dZrvjH9UV+wtko0MmEnkBVYmoittU5r8d+flvcbzW+UVKqZzCgM0UMEwyT
M1gPgdGPGvRQDF31qfvw7OGYd6bRiJCABvvF9KOx2EUgNfBip/gNlKZA/aauDlpO
IKTHWXSq3SM1JhoK67ll+CCgCdnkWZ4E8Jggf56lpdA/95EoaQ4R7fgM/kHZlYrT
lkwaaY40AOzSGAqjVXOzU/xiLWijRv/oVkbgI9htXVkZMU3ZJm5+0fA3DjXwtSEV
1YiN3Gl1JTPu6D5lu/A+AVb81F8wiEzFB3yiksGJOcFnaBoBTwMnov17br1r3C+C
DUBFBkmtANNbN9l7pqcYxvQ5LcFhAn1Ndg+QoSNa9WSntHf+LPWC7meuRTFPp+la
spgL5k2ltwkIUc3+lmccmAbzTTwIyHuLflDDr8riC49NjPckoewehtqQtdKabbNG
T/fDiOpNfqEJV4QBWUd5k1Qd/qIDNmC7NsYerwJfwxZlOvGywAgO6gQEgwAsqY7a
rBZc";

            ReadBase64EncryptedPkcs8(
                base64,
                "easy",
                new PbeParameters(
                    PbeEncryptionAlgorithm.Aes256Cbc,
                    HashAlgorithmName.SHA384,
                    10583),
                TestData.RSA1032Parameters);
        }

        [ConditionalFact]
        [OuterLoop("RSA 16384 takes considerable time.")]
        public static void ReadEncryptedRsa16384()
        {
            // Do not move this to the [ConditionalFact], otherwise the platform will check if RSA 16384 is supported
            // during test discovery for innerloop, and the check itself is expensive.
            if (!ImportExport.Supports16384)
            {
                throw new SkipTestException("Platform does not support RSA 16384");
            }

            // PBES2: PBKDF2 + des (single DES, not 3DES).
            const string base64 = @"
[encoded data, 12610 characters]
pgCJTk846cb+AizgZMeOsYpTOgu2UL6cQiLtsYNz7WpDK3iS7Agj9EoL2ao7QxA=";

            ReadBase64EncryptedPkcs8(
                base64,
                "qwerty",
                new PbeParameters(
                    PbeEncryptionAlgorithm.Aes128Cbc,
                    HashAlgorithmName.SHA512,
                    short.MaxValue),
                TestData.RSA16384Params);
        }

        [ConditionalFact(typeof(RC2Factory), nameof(RC2Factory.IsSupported))]
        public static void ReadPbes2Rc2EncryptedDiminishedDP()
        {
            // PBES2: PBKDF2 + RC2-128
            const string base64 = @"
MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIKZEFT76zCFECAggA
AgEQMBkGCCqGSIb3DQMCMA0CAToECE1Yyzk6++IPBIIBYDDvaYLkET8eudcYLQMf
hw2nQEwDWDo4/E3wSzWJxsO6v4pdhyfCqVblHbxe/xVRKolJfj7DO6nzolcaA9/a
tCM9vvqyCaqoNvnOJ3HnCh5BMPrCsKxND2k8jzMhVrW7tRP31J5oj7TaeIJla+Ps
+AlBQZuy5ws4f2evIo1llOX2DAbJHm4SKO697Bj9kwT9K7K26ZxNCg/Tv5NHCGmN
4ykOIyhACyd27ICCR9mzvC48zJFAUdh2nZPeQRngSPW/bx83w+c7p3sBcAuKQfop
/aGr6Gf7jRtOF4dUhfLUmyS0XTqhz1lRwJDsBJ4s21VzrrwqL+p+mvy12t4yQeN6
L8jQJiKJgTAZa9e9YJ9YXEhTldvMY7WoCcaRbRvl3D+WvV1ibfnG5fl0BwFyTO6x
RdMKfFP3he4C+CFyGGslffbxCaJhKebeuOil5xxlvP8aBPVNDtQfSS1HXHd1/Ikq
1eo=";

            ReadBase64EncryptedPkcs8(
                base64,
                "rc2",
                new PbeParameters(
                    PbeEncryptionAlgorithm.Aes192Cbc,
                    HashAlgorithmName.SHA256,
                    3),
                TestData.DiminishedDPParameters);
        }

        [ConditionalFact(typeof(RC2Factory), nameof(RC2Factory.IsSupported))]
        public static void ReadPbes2Rc2EncryptedDiminishedDP_PasswordBytes()
        {
            // PBES2: PBKDF2 + RC2-128
            // [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Suppression approved. Unit test key.")]
            const string base64 = @"
MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIKZEFT76zCFECAggA
AgEQMBkGCCqGSIb3DQMCMA0CAToECE1Yyzk6++IPBIIBYDDvaYLkET8eudcYLQMf
hw2nQEwDWDo4/E3wSzWJxsO6v4pdhyfCqVblHbxe/xVRKolJfj7DO6nzolcaA9/a
tCM9vvqyCaqoNvnOJ3HnCh5BMPrCsKxND2k8jzMhVrW7tRP31J5oj7TaeIJla+Ps
+AlBQZuy5ws4f2evIo1llOX2DAbJHm4SKO697Bj9kwT9K7K26ZxNCg/Tv5NHCGmN
4ykOIyhACyd27ICCR9mzvC48zJFAUdh2nZPeQRngSPW/bx83w+c7p3sBcAuKQfop
/aGr6Gf7jRtOF4dUhfLUmyS0XTqhz1lRwJDsBJ4s21VzrrwqL+p+mvy12t4yQeN6
L8jQJiKJgTAZa9e9YJ9YXEhTldvMY7WoCcaRbRvl3D+WvV1ibfnG5fl0BwFyTO6x
RdMKfFP3he4C+CFyGGslffbxCaJhKebeuOil5xxlvP8aBPVNDtQfSS1HXHd1/Ikq
1eo=";

            ReadBase64EncryptedPkcs8(
                base64,
                "rc2"u8.ToArray(),
                new PbeParameters(
                    PbeEncryptionAlgorithm.Aes192Cbc,
                    HashAlgorithmName.SHA256,
                    3),
                TestData.DiminishedDPParameters);
        }

        [Fact]
        [ActiveIssue("https://github.com/dotnet/runtime/issues/62547", TestPlatforms.Android)]
        public static void ReadEncryptedDiminishedDP_EmptyPassword()
        {
            // [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Suppression approved. Unit test key.")]
            const string base64 = @"
MIIBgTAbBgkqhkiG9w0BBQMwDgQIJtjMez/9Gg4CAggABIIBYElq9UOOphEPU3b7
G/mV8M1uEdjigidMPih3b9IIJhrjMAEix2IjS+brFL7KRQgucpZZoaFU1utvkUHg
uKhKxjHV7uczG1NjRHmDdwpCadYx4dNaQpgGGAisFiED5hx8W8d9mAL1Kkaedhyb
qfTRO8LqB1SGl52mxIhZ4g5mCQH8uSOZc+k4jBhWBaSk0RaAHtIiKH6VmAiZ2r6C
7L3UTU1bhxlOMt0tABC+b4FMhEJVzl97na2KfpazpNVA4dr973rjqBid9QzXTRl6
Avdd74QjVeZug3ArZqS/3o8E0e2F2JKGty+A4dqFYxHIHvL/2N694HerYHiOJVan
nLHGUzIOxZNTB0TtcWJXP2xUBdHgdBP9/bL0qADYUhYN4e/7TQjuFpzqps3eQiVd
Dmw2pL/LzHORugcg9BxRkur91lenPNcLAvnke76tMGvSGkA82I9NpBDcGRK4cPie
5SeeJT4=";

            ReadBase64EncryptedPkcs8(
                base64,
                "",
                new PbeParameters(
                    PbeEncryptionAlgorithm.Aes192Cbc,
                    HashAlgorithmName.SHA256,
                    3),
                TestData.DiminishedDPParameters);
        }

        [Fact]
        public static void ReadEncryptedDiminishedDP_EmptyPasswordBytes()
        {
            // [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Suppression approved. Unit test key.")]
            const string base64 = @"
MIIBgTAbBgkqhkiG9w0BBQMwDgQIJtjMez/9Gg4CAggABIIBYElq9UOOphEPU3b7
G/mV8M1uEdjigidMPih3b9IIJhrjMAEix2IjS+brFL7KRQgucpZZoaFU1utvkUHg
uKhKxjHV7uczG1NjRHmDdwpCadYx4dNaQpgGGAisFiED5hx8W8d9mAL1Kkaedhyb
qfTRO8LqB1SGl52mxIhZ4g5mCQH8uSOZc+k4jBhWBaSk0RaAHtIiKH6VmAiZ2r6C
7L3UTU1bhxlOMt0tABC+b4FMhEJVzl97na2KfpazpNVA4dr973rjqBid9QzXTRl6
Avdd74QjVeZug3ArZqS/3o8E0e2F2JKGty+A4dqFYxHIHvL/2N694HerYHiOJVan
nLHGUzIOxZNTB0TtcWJXP2xUBdHgdBP9/bL0qADYUhYN4e/7TQjuFpzqps3eQiVd
Dmw2pL/LzHORugcg9BxRkur91lenPNcLAvnke76tMGvSGkA82I9NpBDcGRK4cPie
5SeeJT4=";

            ReadBase64EncryptedPkcs8(
                base64,
                Array.Empty<byte>(),
                new PbeParameters(
                    PbeEncryptionAlgorithm.Aes192Cbc,
                    HashAlgorithmName.SHA256,
                    3),
                TestData.DiminishedDPParameters);
        }

        [ConditionalFact(nameof(Supports384BitPrivateKeyAndRC2))]
        public static void ReadPbes1Rc2EncryptedRsa384()
        {
            // PbeWithSha1AndRC2CBC
            const string base64 = @"
MIIBMTAbBgkqhkiG9w0BBQswDgQIboOZHKKNEM8CAggABIIBEKOc+r+d5gI+TK7V
+cbYrqNfu7bJYI5CCdiQf87vslKQTZGqnmpGqh4NETq/oWXckWwN9I9PGyK2oCNt
w3OUZQsFgcUXeEICCTf503KGifUGS1cG9TZ31iIF2f8xC34C/k2edICwqd5/wDAH
uDdoj7ZESHfEpj9AF3mKPyxWWVGCNTYKXQZbPZMDCOWgfBSeNI7xQw6Cj0seR6C8
hVbGcdL1z/MmM2dw3kIafjpwg3RcrL2qL803aKKl/Ypq6oxR8aCISTqThB46YByD
Ac4+NzbL4Z4jfBWzxzXcua6ujp0jS+/5GxC57q1w+vtgaiJPmrtdierkJWyS9O5e
pWre7nAO4O6sP1JzXvVmwrS5C/hw";

            ReadBase64EncryptedPkcs8(
                base64,
                "pbes1rc2",
                new PbeParameters(
                    PbeEncryptionAlgorithm.TripleDes3KeyPkcs12,
                    HashAlgorithmName.SHA1,
                    2050),
                TestData.RSA384Parameters);
        }

        [Fact]
        public static void NoFuzzyRSAPublicKey()
        {
            using (RSA key = RSAFactory.Create())
            {
                int bytesRead = -1;
                byte[] rsaPriv = key.ExportRSAPrivateKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportRSAPublicKey(rsaPriv, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] spki = key.ExportSubjectPublicKeyInfo();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportRSAPublicKey(spki, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] pkcs8 = key.ExportPkcs8PrivateKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportRSAPublicKey(pkcs8, out bytesRead));

                Assert.Equal(-1, bytesRead);

                ReadOnlySpan<byte> passwordBytes = rsaPriv.AsSpan(0, 15);

                byte[] encryptedPkcs8 = key.ExportEncryptedPkcs8PrivateKey(
                    passwordBytes,
                    new PbeParameters(
                        PbeEncryptionAlgorithm.Aes256Cbc,
                        HashAlgorithmName.SHA512,
                        123));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportRSAPublicKey(encryptedPkcs8, out bytesRead));

                Assert.Equal(-1, bytesRead);
            }
        }

        [Fact]
        public static void NoFuzzySubjectPublicKeyInfo()
        {
            using (RSA key = RSAFactory.Create())
            {
                int bytesRead = -1;
                byte[] rsaPriv = key.ExportRSAPrivateKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportSubjectPublicKeyInfo(rsaPriv, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] rsaPub = key.ExportRSAPrivateKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportSubjectPublicKeyInfo(rsaPub, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] pkcs8 = key.ExportPkcs8PrivateKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportSubjectPublicKeyInfo(pkcs8, out bytesRead));

                Assert.Equal(-1, bytesRead);

                ReadOnlySpan<byte> passwordBytes = rsaPriv.AsSpan(0, 15);

                byte[] encryptedPkcs8 = key.ExportEncryptedPkcs8PrivateKey(
                    passwordBytes,
                    new PbeParameters(
                        PbeEncryptionAlgorithm.Aes256Cbc,
                        HashAlgorithmName.SHA512,
                        123));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportSubjectPublicKeyInfo(encryptedPkcs8, out bytesRead));

                Assert.Equal(-1, bytesRead);
            }
        }

        [Fact]
        public static void NoFuzzyRSAPrivateKey()
        {
            using (RSA key = RSAFactory.Create())
            {
                int bytesRead = -1;
                byte[] rsaPub = key.ExportRSAPublicKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportRSAPrivateKey(rsaPub, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] spki = key.ExportSubjectPublicKeyInfo();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportRSAPrivateKey(spki, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] pkcs8 = key.ExportPkcs8PrivateKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportRSAPrivateKey(pkcs8, out bytesRead));

                Assert.Equal(-1, bytesRead);

                ReadOnlySpan<byte> passwordBytes = spki.AsSpan(0, 15);

                byte[] encryptedPkcs8 = key.ExportEncryptedPkcs8PrivateKey(
                    passwordBytes,
                    new PbeParameters(
                        PbeEncryptionAlgorithm.Aes256Cbc,
                        HashAlgorithmName.SHA512,
                        123));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportRSAPrivateKey(encryptedPkcs8, out bytesRead));

                Assert.Equal(-1, bytesRead);
            }
        }

        [Fact]
        public static void NoFuzzyPkcs8()
        {
            using (RSA key = RSAFactory.Create())
            {
                int bytesRead = -1;

                byte[] rsaPub = key.ExportRSAPublicKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportPkcs8PrivateKey(rsaPub, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] spki = key.ExportSubjectPublicKeyInfo();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportPkcs8PrivateKey(spki, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] rsaPriv = key.ExportRSAPrivateKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportPkcs8PrivateKey(rsaPriv, out bytesRead));

                Assert.Equal(-1, bytesRead);

                ReadOnlySpan<byte> passwordBytes = spki.AsSpan(0, 15);

                byte[] encryptedPkcs8 = key.ExportEncryptedPkcs8PrivateKey(
                    passwordBytes,
                    new PbeParameters(
                        PbeEncryptionAlgorithm.Aes256Cbc,
                        HashAlgorithmName.SHA512,
                        123));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportPkcs8PrivateKey(encryptedPkcs8, out bytesRead));

                Assert.Equal(-1, bytesRead);
            }
        }

        [Fact]
        public static void NoFuzzyEncryptedPkcs8()
        {
            using (RSA key = RSAFactory.Create())
            {
                int bytesRead = -1;
                byte[] empty = Array.Empty<byte>();
                byte[] rsaPub = key.ExportRSAPublicKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportEncryptedPkcs8PrivateKey(empty, rsaPub, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] spki = key.ExportSubjectPublicKeyInfo();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportEncryptedPkcs8PrivateKey(empty, spki, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] rsaPriv = key.ExportRSAPrivateKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportEncryptedPkcs8PrivateKey(empty, rsaPriv, out bytesRead));

                Assert.Equal(-1, bytesRead);

                byte[] pkcs8 = key.ExportPkcs8PrivateKey();

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportEncryptedPkcs8PrivateKey(empty, pkcs8, out bytesRead));

                Assert.Equal(-1, bytesRead);
            }
        }

        [Fact]
        public static void NoPrivKeyFromPublicOnly()
        {
            using (RSA key = RSAFactory.Create())
            {
                RSAParameters srcParameters = TestData.RSA2048Params;
                RSAParameters rsaParameters = new RSAParameters
                {
                    Modulus = srcParameters.Modulus,
                    Exponent = srcParameters.Exponent,
                };

                key.ImportParameters(rsaParameters);

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportRSAPrivateKey());

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportRSAPrivateKey(Span<byte>.Empty, out _));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportPkcs8PrivateKey());

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportPkcs8PrivateKey(Span<byte>.Empty, out _));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<byte>.Empty,
                        new PbeParameters(PbeEncryptionAlgorithm.Aes192Cbc, HashAlgorithmName.SHA256, 72)));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<byte>.Empty,
                        new PbeParameters(PbeEncryptionAlgorithm.Aes192Cbc, HashAlgorithmName.SHA256, 72),
                        Span<byte>.Empty,
                        out _));
            }
        }

        [Fact]
        public static void BadPbeParameters()
        {
            using (RSA key = RSAFactory.Create())
            {
                Assert.ThrowsAny<ArgumentNullException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<byte>.Empty,
                        null));

                Assert.ThrowsAny<ArgumentNullException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<char>.Empty,
                        null));

                Assert.ThrowsAny<ArgumentNullException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<byte>.Empty,
                        null,
                        Span<byte>.Empty,
                        out _));

                Assert.ThrowsAny<ArgumentNullException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<char>.Empty,
                        null,
                        Span<byte>.Empty,
                        out _));

                // PKCS12 requires SHA-1
                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<byte>.Empty,
                        new PbeParameters(PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, HashAlgorithmName.SHA256, 72)));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<byte>.Empty,
                        new PbeParameters(PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, HashAlgorithmName.SHA256, 72),
                        Span<byte>.Empty,
                        out _));

                // PKCS12 requires SHA-1
                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<byte>.Empty,
                        new PbeParameters(PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, HashAlgorithmName.MD5, 72)));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        ReadOnlySpan<byte>.Empty,
                        new PbeParameters(PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, HashAlgorithmName.MD5, 72),
                        Span<byte>.Empty,
                        out _));

                // PKCS12 requires a char-based password
                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters(PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, HashAlgorithmName.SHA1, 72)));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters(PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, HashAlgorithmName.SHA1, 72),
                        Span<byte>.Empty,
                        out _));

                // Unknown encryption algorithm
                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters(0, HashAlgorithmName.SHA1, 72)));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters(0, HashAlgorithmName.SHA1, 72),
                        Span<byte>.Empty,
                        out _));

                // Unknown encryption algorithm (negative enum value)
                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters((PbeEncryptionAlgorithm)(-5), HashAlgorithmName.SHA1, 72)));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters((PbeEncryptionAlgorithm)(-5), HashAlgorithmName.SHA1, 72),
                        Span<byte>.Empty,
                        out _));

                // Unknown encryption algorithm (overly-large enum value)
                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters((PbeEncryptionAlgorithm)15, HashAlgorithmName.SHA1, 72)));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters((PbeEncryptionAlgorithm)15, HashAlgorithmName.SHA1, 72),
                        Span<byte>.Empty,
                        out _));

                // Unknown hash algorithm
                Assert.ThrowsAny<CryptographicException>(
                    () => key.ExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters(PbeEncryptionAlgorithm.Aes192Cbc, new HashAlgorithmName("Potato"), 72)));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.TryExportEncryptedPkcs8PrivateKey(
                        new byte[3],
                        new PbeParameters(PbeEncryptionAlgorithm.Aes192Cbc, new HashAlgorithmName("Potato"), 72),
                        Span<byte>.Empty,
                        out _));
            }
        }

        [Fact]
        public static void DecryptPkcs12WithBytes()
        {
            using (RSA key = RSAFactory.Create())
            {
                string charBased = "hello";
                byte[] byteBased = Encoding.UTF8.GetBytes(charBased);

                byte[] encrypted = key.ExportEncryptedPkcs8PrivateKey(
                    charBased,
                    new PbeParameters(
                        PbeEncryptionAlgorithm.TripleDes3KeyPkcs12,
                        HashAlgorithmName.SHA1,
                        123));

                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportEncryptedPkcs8PrivateKey(byteBased, encrypted, out _));
            }
        }

        [Fact]
        [ActiveIssue("https://github.com/dotnet/runtime/issues/62547", TestPlatforms.Android)]
        public static void DecryptPkcs12PbeTooManyIterations()
        {
            // pbeWithSHAAnd3-KeyTripleDES-CBC with 600,001 iterations
            byte[] high3DesIterationKey = Convert.FromBase64String(@"
MIIE8zAlBgoqhkiG9w0BDAEDMBcEELqdfpwjkWlJZnr3xs2n+qACAwknwQSCBMgnZse/OHib1lMC
jBuUdjQCib5+HEBd2PwrjRw8k/i3kOsPeuDRsTMVvqumYpN6frYWLxRSbd3oe7n5D6bxpBrGuhfO
d/98Ustg1BDXPSdJzOyCXjS4nm+pr5ZETXxM8HUISvmpC62mrBJue3JwHVXbpXFepMcy9ywfSfjg
GhNzSYPQwHLFLVHVd3Dcb8mApgVf9aMJIjw9SeE9KQ6PeOk1LXQsoMFf3h/Sap/nuR4M9F/qa9u/
SEtjptJRlRDecXhQLS7su6cjQ/3Z5PQObORlqF2RASOaEYRyrjjvQjH0+ZAIkQ6zyv1PrPpbeT9I
U5Hzlu00hfNyAy3TfR50EqT2jP7D6ugFbvnHoDRx0e3STTgBrfFc1tbdLijnq/rxb4QNBIV70+Kw
QL2mc8CdM/lP4hT4f1vdtgLdRF2gmxndZolveNc5nAheUwqNa8I16OzZnny9090KztJxhGWd57H8
QCvz2mS6z7FANeyo9cTZilHwwErkLUgmoaQXnnrs46VwF8oeH9ZhLiO4W+OfNLm6QvB/e3/inUj/
FZFxnTYCvSeRBTD5YhME+SnyGPbJiHOPJuSIwWXyRpZeg6wmMWfduEeGuThNNSf4Fxm0baFrC6CZ
4+jT0CurP6L4NxLPBafWP7BcA2XCeVQGQd1GT9cX2I1NkRcU7Q2u7oxWKMJaj0OELC+lZTTv6y3Q
x3I96z0Eddm1qfKQr9HQq+i8LXMwSxqNH+LOtdOEA3kqYq4GU6MdPr8Nx1TaGsiwLcz14GqPl3UQ
5so2ZKHZZsa9NSer/fWVaOwmYc50JW3N4jJpDFRjKVFP5GSzLfdTwl9nduM4atu4D9KZthQCwNGC
nEZ1nwGJywmO/XvLWopOMj0cUx2GQYOUV2Hfu93+MriiKjTFEnMcT7B/BOFRpgz4jg4S+6DcHwJh
cpdIvViajQXM3WwpxnVzskAxYNTYGV0aI9ZjrGBD4vZXM1s9hTlAZc41EmTqZlJPNZ75OzKD9LJS
Iot/jiWjJ03+WT8VVqw/mfTSy2apCE3pGGKdde6wlcR/N6JI1+lQahC+0j9yvUCZyqhiiVpcwaOa
dsxxZMJ+DiilMuRXMJCxKvx5kBZTpjuKR/WnKzSE70wgB1ulJE0RkZTYjWSUSf54bHC2XRGZLtfU
sXDcycjA33H+b0cxe25OZNJUTOoFJqji9RqBvzHuAVMXJvZESORMKbl6q47DbWwFvivfweUJNVO+
3fzCcrCfAFLwI0j+KaoVr0Qrfedr7OhVEZ/v57aYidUSl2VIpLmpJTUKRnvZ0rlg/WBauwWH1X4M
u7AExd+aHO8iv0gj+rTg5co0EcOu9i8cbAowg1ZZ1m6zXvHD7fZgE9iamBmklVOQwQXOJO7BCecn
C0ezYU4Ii8uo0fXJOMWkIA7KLGaQxBrxygnFK3A0RKNos7OXiLdB8RGDqjUZyqLUb3z/YisQEX8f
R40NElq8tzOa/TudOpNAqC8mgS25uTm7ws472gUE0z9uvcq1/MgkqE++xgmLAxGUN/l7EHSAmYKG
i33DDR38LaRqG9ho3brf466OkNooBv4MpD5SA63yfooytxOgeuaqbuTzKP/OSRqJNab9wctA9nfJ
gms2YM+honjUS1sXk1zdm/8=");

            using (RSA key = RSAFactory.Create())
            {
                Assert.ThrowsAny<CryptographicException>(
                    () => key.ImportEncryptedPkcs8PrivateKey((ReadOnlySpan<char>)"test", high3DesIterationKey, out _));
            }
        }

        [Fact]
        [ActiveIssue("https://github.com/dotnet/runtime/issues/62547", TestPlatforms.Android)]
        public static void ReadWriteRsa2048EncryptedPkcs8_Pbes2HighIterations()
        {
            // pkcs5PBES2 hmacWithSHA256 aes128-CBC with 600,001 iterations
            ReadBase64EncryptedPkcs8(@"
MIIFNjBgBgkqhkiG9w0BBQ0wUzAyBgkqhkiG9w0BBQwwJQQQAx6OUUzmK+vwC7a+OwhXygIDCSfB
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBCoLaQQpG01FJnpQdIRq2ioBIIE0MPy/p2uwTnP
mScPxFbrpBiPQHz5PKRjKLCN5JLArsppSz+XSHxfItFUSfBKEE7dYJrEXARmhA8e2roCrZkQnb9o
TX551EivHZhqmd91p6WHYb3ZCDQ6la1JfiuV4aJiJOlG0bDAkzEaiM9m9LE3G0J3Z3ELX+mGEGKD
W+Bz1a9jr204IJQc2VihTFe5t3mujV3X9UFZH3kqOCEreVVmmD64Ea2uDJ6dk3VgGhQ9QLjTDjc5
OSjdfuyuA4gliK/7ibFubtmnVTDSbAm5Excy9tvJqVhejv/wRhfeYZ2rpv3tTLP58WKt25GEmyyV
j86v3LB7DFnnBy4NkLCE55oVe64v/8StyEjEkMxz7Owz/ZW65EccPdk7JHZeBXPXNUdLxk1x40vW
nSRzqhLckfggDwtTCk0kwGUNGBMqr2ezXKrSeO3Qj05dAUvFt9PvbnrVtSnOjFPwx0exiDMUxOFE
Sz63M2tNNAJr43w60DXaIvMMoZ1kF1mwwL5GT+cs3Dn5KFHNLkZ5irIoHAkmKRHplI15Oqr+Ws2n
MUtV9BjDjtYHlwp1s1oFpHr9hu8HHv7QIEvyZbyMdKfPv9PEaNJR0SRhkyave+vl9zHCBhP1H2wU
4fESU1y+cJXZ5WUiJZ5C1wDYWyN5Q2z67Fd4OQXhRwHCeTCZPz3bykpadwlsihCNHrYybfLn61oz
2CswZjBeQuhDmUKWaj87fsNvSEHaEGTDnyLGEzgNb1OuIrqGiT0DvjfRsVED4ZL6jlDKgAaJe+Uq
EMt1UzKmAPeBA/IFOrNPw5B+rgKjVpsCdToX9I9b3cCvKhjxguuggpzkEOF4cdgR2MJk1mqdo7ck
2fI2A5kJx9SuEVL6eKqxyFkPdBMmljKyhomAjdBAIKQ4xt2ojEip7Q9qhmWK3U3meOiIc3qrsM/K
pGDiwH1CHc/0FbHAghiARawXAtzGGyfMXsZkUTAVnEqDfu5uw4pOlv+rm5GLWfLU8p73yc+kVfPR
MdWZI6Ftct0FP/KEibc6VSaENoVRAk+XApadkeFaEUQzFzoU7RhN9FONmnCL8Ui76Kfi1kLAxYJo
rXFQjatiLOAxV50uJSkE1ppmrU1YWHVyC3RkLLnQfq0Ypz9/x7W4PVDfCJQdnCCtOfHL5Qm8fL0l
uE22Y+gPDzoM1BEKvSgmZWTlZrovXwL4u70/nPeaB1HAVUEzsoEMOSSWDkHuhmgiZHUgQwkvzNjA
I3AJk0rl2tGBWdgsDtiiQamkXm0VwubTedIt2vj9h9kJYtUlvkCg7KfKxmTSJUynOyKfI1Mhx3vW
fvni4lYc7KLUEkcNMqNu5AliaPEJQksNNkRiyX7wK5TvA+v9mlqm6Gg7GuJ2oa1DiFf8MUB9CgiJ
pniangzMBkuSd+zvCAo9YAJoyrJoR2ibcWwo4wRSVwYsVF3bB4nB2w1GHQ6HAnPKHSjVDJZyoEh6
TvoFEWjb86tn2BR+qMKqXNBVSrgF2pa06BIs0daHKimYKaU0bnuzE/T+pckJfI0VvWB/Z8jvE1Xy
gpX/dwXfODsj4zcOw4gyP70lDxUWLEPtxhS5Ti0FEuge1XKn3+GOp3clVjGpXKpJTNLsPA/wlqlo
8/ojymwPxe641Pcfa4DsMgfleHnUOEbNZ4je",
                "test",
                new PbeParameters(
                    PbeEncryptionAlgorithm.Aes128Cbc,
                    HashAlgorithmName.SHA256,
                    600_001),
                TestData.RSA2048Params);
        }

        private static void ReadBase64EncryptedPkcs8(
            string base64EncPkcs8,
            string password,
            PbeParameters pbeParameters,
            in RSAParameters expected)
        {
            ReadWriteKey(
                base64EncPkcs8,
                expected,
                (RSA rsa, ReadOnlySpan<byte> source, out int read) =>
                    rsa.ImportEncryptedPkcs8PrivateKey(password, source, out read),
                rsa => rsa.ExportEncryptedPkcs8PrivateKey(password, pbeParameters),
                (RSA rsa, Span<byte> destination, out int written) =>
                    rsa.TryExportEncryptedPkcs8PrivateKey(password, pbeParameters, destination, out written),
                isEncrypted: true);
        }

        private static void ReadBase64EncryptedPkcs8(
            string base64EncPkcs8,
            byte[] passwordBytes,
            PbeParameters pbeParameters,
            in RSAParameters expected)
        {
            ReadWriteKey(
                base64EncPkcs8,
                expected,
                (RSA rsa, ReadOnlySpan<byte> source, out int read) =>
                    rsa.ImportEncryptedPkcs8PrivateKey(passwordBytes, source, out read),
                rsa => rsa.ExportEncryptedPkcs8PrivateKey(passwordBytes, pbeParameters),
                (RSA rsa, Span<byte> destination, out int written) =>
                    rsa.TryExportEncryptedPkcs8PrivateKey(passwordBytes, pbeParameters, destination, out written),
                isEncrypted: true);
        }

        private static void ReadWriteBase64PublicPkcs1(
            string base64PublicPkcs1,
            in RSAParameters expected)
        {
            RSAParameters expectedPublic = new RSAParameters
            {
                Modulus = expected.Modulus,
                Exponent = expected.Exponent,
            };

            ReadWriteKey(
                base64PublicPkcs1,
                expectedPublic,
                (RSA rsa, ReadOnlySpan<byte> source, out int read) =>
                    rsa.ImportRSAPublicKey(source, out read),
                rsa => rsa.ExportRSAPublicKey(),
                (RSA rsa, Span<byte> destination, out int written) =>
                    rsa.TryExportRSAPublicKey(destination, out written));
        }

        private static void ReadWriteBase64SubjectPublicKeyInfo(
            string base64SubjectPublicKeyInfo,
            in RSAParameters expected)
        {
            RSAParameters expectedPublic = new RSAParameters
            {
                Modulus = expected.Modulus,
                Exponent = expected.Exponent,
            };

            ReadWriteKey(
                base64SubjectPublicKeyInfo,
                expectedPublic,
                (RSA rsa, ReadOnlySpan<byte> source, out int read) =>
                    rsa.ImportSubjectPublicKeyInfo(source, out read),
                rsa => rsa.ExportSubjectPublicKeyInfo(),
                (RSA rsa, Span<byte> destination, out int written) =>
                    rsa.TryExportSubjectPublicKeyInfo(destination, out written));
        }

        private static void ReadWriteBase64PrivatePkcs1(
            string base64PrivatePkcs1,
            in RSAParameters expected)
        {
            ReadWriteKey(
                base64PrivatePkcs1,
                expected,
                (RSA rsa, ReadOnlySpan<byte> source, out int read) =>
                    rsa.ImportRSAPrivateKey(source, out read),
                rsa => rsa.ExportRSAPrivateKey(),
                (RSA rsa, Span<byte> destination, out int written) =>
                    rsa.TryExportRSAPrivateKey(destination, out written));
        }

        private static void ReadWriteBase64Pkcs8(string base64Pkcs8, in RSAParameters expected)
        {
            ReadWriteKey(
                base64Pkcs8,
                expected,
                (RSA rsa, ReadOnlySpan<byte> source, out int read) =>
                    rsa.ImportPkcs8PrivateKey(source, out read),
                rsa => rsa.ExportPkcs8PrivateKey(),
                (RSA rsa, Span<byte> destination, out int written) =>
                    rsa.TryExportPkcs8PrivateKey(destination, out written));
        }

        private static void ReadWriteKey(
            string base64,
            in RSAParameters expected,
            ReadKeyAction readAction,
            Func<RSA, byte[]> writeArrayFunc,
            WriteKeyToSpanFunc writeSpanFunc,
            bool isEncrypted = false)
        {
            bool isPrivateKey = expected.D != null;

            byte[] derBytes = Convert.FromBase64String(base64);
            byte[] arrayExport;
            byte[] tooBig;
            const int OverAllocate = 30;
            const int WriteShift = 6;

            using (RSA rsa = RSAFactory.Create())
            {
                readAction(rsa, derBytes, out int bytesRead);
                Assert.Equal(derBytes.Length, bytesRead);

                arrayExport = writeArrayFunc(rsa);

                RSAParameters rsaParameters = rsa.ExportParameters(isPrivateKey);
                ImportExport.AssertKeyEquals(expected, rsaParameters);
            }

            // Public key formats are stable.
            // Private key formats are not, since CNG recomputes the D value
            // and then all of the CRT parameters.
            if (!isPrivateKey)
            {
                Assert.Equal(derBytes.Length, arrayExport.Length);
                Assert.Equal(derBytes.ByteArrayToHex(), arrayExport.ByteArrayToHex());
            }

            using (RSA rsa = RSAFactory.Create())
            {
                Assert.ThrowsAny<CryptographicException>(
                    () => readAction(rsa, arrayExport.AsSpan(1), out _));

                Assert.ThrowsAny<CryptographicException>(
                    () => readAction(rsa, arrayExport.AsSpan(0, arrayExport.Length - 1), out _));

                readAction(rsa, arrayExport, out int bytesRead);
                Assert.Equal(arrayExport.Length, bytesRead);

                RSAParameters rsaParameters = rsa.ExportParameters(isPrivateKey);
                ImportExport.AssertKeyEquals(expected, rsaParameters);

                Assert.False(
                    writeSpanFunc(rsa, Span<byte>.Empty, out int bytesWritten),
                    "Write to empty span");

                Assert.Equal(0, bytesWritten);

                Assert.False(
                    writeSpanFunc(
                        rsa,
                        derBytes.AsSpan(0, Math.Min(derBytes.Length, arrayExport.Length) - 1),
                        out bytesWritten),
                    "Write to too-small span");

                Assert.Equal(0, bytesWritten);

                tooBig = new byte[arrayExport.Length + OverAllocate];
                tooBig.AsSpan().Fill(0xC4);

                Assert.True(writeSpanFunc(rsa, tooBig.AsSpan(WriteShift), out bytesWritten));
                Assert.Equal(arrayExport.Length, bytesWritten);

                Assert.Equal(0xC4, tooBig[WriteShift - 1]);
                Assert.Equal(0xC4, tooBig[WriteShift + bytesWritten + 1]);

                // If encrypted, the data should have had a random salt applied, so unstable.
                // Otherwise, we've normalized the data (even for private keys) so the output
                // should match what it output previously.
                if (isEncrypted)
                {
                    Assert.NotEqual(
                        arrayExport.ByteArrayToHex(),
                        tooBig.AsSpan(WriteShift, bytesWritten).ByteArrayToHex());
                }
                else
                {
                    Assert.Equal(
                        arrayExport.ByteArrayToHex(),
                        tooBig.AsSpan(WriteShift, bytesWritten).ByteArrayToHex());
                }
            }

            using (RSA rsa = RSAFactory.Create())
            {
                readAction(rsa, tooBig.AsSpan(WriteShift), out int bytesRead);
                Assert.Equal(arrayExport.Length, bytesRead);

                arrayExport.AsSpan().Fill(0xCA);

                Assert.True(
                    writeSpanFunc(rsa, arrayExport, out int bytesWritten),
                    "Write to precisely allocated Span");

                if (isEncrypted)
                {
                    Assert.NotEqual(
                        tooBig.AsSpan(WriteShift, bytesWritten).ByteArrayToHex(),
                        arrayExport.ByteArrayToHex());
                }
                else
                {
                    Assert.Equal(
                        tooBig.AsSpan(WriteShift, bytesWritten).ByteArrayToHex(),
                        arrayExport.ByteArrayToHex());
                }
            }
        }

        private delegate void ReadKeyAction(RSA rsa, ReadOnlySpan<byte> source, out int bytesRead);
        private delegate bool WriteKeyToSpanFunc(RSA rsa, Span<byte> destination, out int bytesWritten);
    }
}
