1. 程式人生 > >C#下實現RSA公鑰私鑰由pcks8格式(java)轉化為pcks1格式(非java)

C#下實現RSA公鑰私鑰由pcks8格式(java)轉化為pcks1格式(非java)

對於Pcks不瞭解的可以先看下PKCS標準,然後這裡暫時只有pcks8格式轉化為pcks1格式,暫時還沒能找到直接通過BouncyCastle來轉化pcks1格式到pcks8格式的方法或程式碼(當然可以藉由RSACryptoServiceProvider來進行讀取,然後再進行間接的轉化),只找到了通過openssl來轉化pcks1到pcks8的方法,以下為程式碼:
    using Org.BouncyCastle.Asn1.Pkcs;
    using Org.BouncyCastle.Asn1.X509;
    using Org.BouncyCastle.Crypto.Parameters;
    using Org.BouncyCastle.Pkcs;
    using Org.BouncyCastle.Security;
    using Org.BouncyCastle.X509;
    /// <summary>
    /// PKCS轉化輔助類
    /// </summary>
    public class RSAPcksTransferHelper
    {
        /// <summary>
        /// 將pcks8格式的RSA公鑰轉化為pcks1格式
        /// </summary>
        /// <param name="pubicKey">pcks8格式的RSA公鑰 base64格式</param>
        /// <returns>pcks1格式的RSA公鑰 base64格式</returns>
        public static string ConvertPublicKeyPkcs8ToPcks1(string pubicKey)
        {
            return Convert.ToBase64String(ConvertPublicKeyPkcs8ToPcks1(Convert.FromBase64String(pubicKey)));
        }
        /// <summary>
        /// 將pcks8格式的RSA公鑰轉化為pcks1格式
        /// </summary>
        /// <param name="pubicKey">pcks8格式的RSA公鑰</param>
        /// <returns>pcks1格式的RSA公鑰</returns>
        public static byte[] ConvertPublicKeyPkcs8ToPcks1(byte[] pubicKey)
        {
            RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(pubicKey);
            SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKeyParam);
            return spkInfo.GetPublicKey().ToAsn1Object().GetEncoded();
        }
        /// <summary>
        /// 將pcks8格式的RSA私鑰轉化為pcks1格式
        /// </summary>
        /// <param name="privateKey">pcks8格式的RSA私鑰 base64格式</param>
        /// <returns>pcks1格式的RSA私鑰 base64格式</returns>
        public static string ConvertPrivateKeyPkcs8ToPcks1(string privateKey)
        {
            return Convert.ToBase64String(ConvertPrivateKeyPkcs8ToPcks1(Convert.FromBase64String(privateKey)));
        }
        /// <summary>
        /// 將pcks8格式的RSA私鑰轉化為pcks1格式
        /// </summary>
        /// <param name="privateKey">pcks8格式的RSA私鑰</param>
        /// <returns>pcks1格式的RSA私鑰</returns>
        public static byte[] ConvertPrivateKeyPkcs8ToPcks1(byte[] privateKey)
        {
            RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(privateKey);
            PrivateKeyInfo pkInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
            return pkInfo.ParsePrivateKey().ToAsn1Object().GetEncoded();
        }
    }

測試程式碼如下:

        static void RSAPcksTransferDemo(int keyLength = 2048)
        {
            RsaKeyPairGenerator generator = new RsaKeyPairGenerator();
            generator.Init(new KeyGenerationParameters(new SecureRandom(), keyLength));
            var keyPair = generator.GenerateKeyPair();
            PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
            var pcks8Private = Convert.ToBase64String(privateKeyInfo.ToAsn1Object().GetEncoded());
            SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
            var pcks8Public = Convert.ToBase64String(publicKeyInfo.ToAsn1Object().GetEncoded());
            var pcks1Private = RSAPcksTransferHelper.ConvertPrivateKeyPkcs8ToPcks1(pcks8Private);
            var pcks1Public = RSAPcksTransferHelper.ConvertPublicKeyPkcs8ToPcks1(pcks8Public);

            Console.WriteLine("pcks8Private == pcks1Private:{0}", pcks8Private == pcks1Private);
            Console.WriteLine("pcks8Public == pcks1Public:{0}", pcks8Public == pcks1Public);

            Func<byte[], string, int> func = (b, s) =>
            {
                for (var i = 1; i < 100; i++)
                {
                    if (Convert.ToBase64String(b.Skip(i).ToArray()) == s)
                        return i;
                }
                return 0;
            };
            //移除pcks8前部宣告資訊來生成pcks1
            var number = func(Convert.FromBase64String(pcks8Private), pcks1Private);
            if (number != 0)
            {
                //RSA祕鑰不管keyLength為何值,始終固定返回26
                Console.WriteLine("pcks8Private need to remove prev {0} bytes", number);
                var pcks1PrivateWithRemove = Convert.ToBase64String(Convert.FromBase64String(pcks8Private).Skip(number).ToArray());
                Console.WriteLine("pcks1Private == pcks1PrivateWithRemove:{0}", pcks1Private == pcks1PrivateWithRemove);
            }
            number = func(Convert.FromBase64String(pcks8Public), pcks1Public);
            if (number != 0)
            {
                //RSA公鑰受keyLength影響,1024時返回22,2048,3072,4096時返回24,當然RSA祕鑰是以8增加長度的,所以可以通過迴圈1024+8來測試出22到24的改變規律
                Console.WriteLine("pcks8Public need to remove prev {0} bytes", number);
                var pcks1PublicWithRemove = Convert.ToBase64String(Convert.FromBase64String(pcks8Public).Skip(number).ToArray());
                Console.WriteLine("pcks1Public == pcks1PublicWithRemove:{0}", pcks1Public == pcks1PublicWithRemove);
            }
        }
注意測試程式碼裡除了通過輔助類來進行轉化外,還通過一種簡單的方式,即直接通過移除pcks8的宣告部分來達到生成pcks1的目的,測試結果如下:

私鑰不管祕鑰長度如何,始終移除pcks8格式最開始的26個byte

公鑰受長度影響,在1024時移除pcks8格式最開始的22個byte,2048開始往後均為24個byte