C#下實現RSA公鑰私鑰由pcks8格式(java)轉化為pcks1格式(非java)
阿新 • • 發佈:2019-02-03
對於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(); } }
測試程式碼如下:
注意測試程式碼裡除了通過輔助類來進行轉化外,還通過一種簡單的方式,即直接通過移除pcks8的宣告部分來達到生成pcks1的目的,測試結果如下: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格式最開始的26個byte
公鑰受長度影響,在1024時移除pcks8格式最開始的22個byte,2048開始往後均為24個byte