RSA算法使用说明(非对称加密算法,算法采用RSA/ECB/OAEPPadding模式)
2、 确定public.pem文件的存放路径,同时修改代码中文件的输入路径,加载RSA公钥
3、 用标准的RSA加密库对敏感信息进行加密,选择RSA_PKCS1_OAEP_PADDING填充模式
(eg:Java的填充方式要选 " RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING")
4、 得到进行rsa加密并转base64之后的密文
5、 将密文传给微信侧相应字段,如付款接口(enc_bank_no/enc_true_name)
接口默认输出PKCS#1格式的公钥,商户需根据自己开发的语言选择公钥格式
RSA公钥格式PKCS#1,PKCS#8互转说明
- PKCS#1 转 PKCS#8:
openssl rsa -RSAPublicKey_in -in <filename> -pubout
- PKCS#8 转 PKCS#1:
openssl rsa -pubin -in <filename> -RSAPublicKey_out
- PKCS#1 格式密钥:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEArT82k67xybiJS9AD8nNAeuDYdrtCRaxkS6cgs8L9h83eqlDTlrdw
zBVSv5V4imTq/URbXn4K0V/KJ1TwDrqOI8hamGB0fvU13WW1NcJuv41RnJVua0QA
lS3tS1JzOZpMS9BEGeFvyFF/epbi/m9+2kUWG94FccArNnBtBqqvFncXgQsm98JB
3a62NbS1ePP/hMI7Kkz+JNMyYsWkrOUFDCXAbSZkWBJekY4nGZtK1erqGRve8Jbx
TWirAm/s08rUrjOuZFA21/EI2nea3DidJMTVnXVPY2qcAjF+595shwUKyTjKB8v1
REPB3hPF1Z75O6LwuLfyPiCrCTmVoyfqjwIDAQAB
-----END RSA PUBLIC KEY-----
- PKCS#8 格式密钥:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArT82k67xybiJS9AD8nNA
euDYdrtCRaxkS6cgs8L9h83eqlDTlrdwzBVSv5V4imTq/URbXn4K0V/KJ1TwDrqO
I8hamGB0fvU13WW1NcJuv41RnJVua0QAlS3tS1JzOZpMS9BEGeFvyFF/epbi/m9+
lkUWG94FccArNnBtBqqvFncXgQsm98JB3a42NbS1ePP/hMI7Kkz+JNMyYsWkrOUF
DCXAbSZkWBJekY4nGZtK1erqGRve8JbxTWirAm/s08rUrjOuZFA21/EI2nea3Did
JMTVnXVPY2qcAjF+595shwUKyTjKB8v1REPB3hPF1Z75O6LwuLfyPiCrCTmVoyfq
jwIDAQAB
-----END PUBLIC KEY-----
官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_7&index=4
代码:
1 public sealed class CryptoHelper 2 { 3 /// <summary> 4 /// RSA密钥转Pem密钥 5 /// </summary> 6 /// <param name="RSAKey">RSA密钥</param> 7 /// <param name="isPrivateKey">是否是私钥</param> 8 /// <returns>Pem密钥</returns> 9 public static string RSAKeyToPem(string RSAKey, bool isPrivateKey) 10 { 11 string pemKey = string.Empty; 12 var rsa = new RSACryptoServiceProvider(); 13 rsa.FromXmlString(RSAKey); 14 RSAParameters rsaPara = new RSAParameters(); 15 RsaKeyParameters key = null; 16 //RSA私钥 17 if (isPrivateKey) 18 { 19 rsaPara = rsa.ExportParameters(true); 20 key = new RsaPrivateCrtKeyParameters( 21 new BigInteger(1, rsaPara.Modulus), new BigInteger(1, rsaPara.Exponent), new BigInteger(1, rsaPara.D), 22 new BigInteger(1, rsaPara.P), new BigInteger(1, rsaPara.Q), new BigInteger(1, rsaPara.DP), new BigInteger(1, rsaPara.DQ), 23 new BigInteger(1, rsaPara.InverseQ)); 24 } 25 //RSA公钥 26 else 27 { 28 rsaPara = rsa.ExportParameters(false); 29 key = new RsaKeyParameters(false, 30 new BigInteger(1, rsaPara.Modulus), 31 new BigInteger(1, rsaPara.Exponent)); 32 } 33 using (TextWriter sw = new StringWriter()) 34 { 35 var pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(sw); 36 pemWriter.WriteObject(key); 37 pemWriter.Writer.Flush(); 38 pemKey = sw.ToString(); 39 } 40 return pemKey; 41 } 42 43 /// <summary> 44 /// Pem密钥转RSA密钥 45 /// </summary> 46 /// <param name="pemKey">Pem密钥</param> 47 /// <param name="isPrivateKey">是否是私钥</param> 48 /// <returns>RSA密钥</returns> 49 public static string PemToRSAKey(string pemKey, bool isPrivateKey) 50 { 51 string rsaKey = string.Empty; 52 object pemObject = null; 53 RSAParameters rsaPara = new RSAParameters(); 54 using (StringReader sReader = new StringReader(pemKey)) 55 { 56 var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(sReader); 57 pemObject = pemReader.ReadObject(); 58 } 59 //RSA私钥 60 if (isPrivateKey) 61 { 62 RsaPrivateCrtKeyParameters key = (RsaPrivateCrtKeyParameters)((AsymmetricCipherKeyPair)pemObject).Private; 63 rsaPara = new RSAParameters 64 { 65 Modulus = key.Modulus.ToByteArrayUnsigned(), 66 Exponent = key.PublicExponent.ToByteArrayUnsigned(), 67 D = key.Exponent.ToByteArrayUnsigned(), 68 P = key.P.ToByteArrayUnsigned(), 69 Q = key.Q.ToByteArrayUnsigned(), 70 DP = key.DP.ToByteArrayUnsigned(), 71 DQ = key.DQ.ToByteArrayUnsigned(), 72 InverseQ = key.QInv.ToByteArrayUnsigned(), 73 }; 74 } 75 //RSA公钥 76 else 77 { 78 RsaKeyParameters key = (RsaKeyParameters)pemObject; 79 rsaPara = new RSAParameters 80 { 81 Modulus = key.Modulus.ToByteArrayUnsigned(), 82 Exponent = key.Exponent.ToByteArrayUnsigned(), 83 }; 84 } 85 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 86 rsa.ImportParameters(rsaPara); 87 using (StringWriter sw = new StringWriter()) 88 { 89 sw.Write(rsa.ToXmlString(isPrivateKey ? true : false)); 90 rsaKey = sw.ToString(); 91 } 92 return rsaKey; 93 } 94 95 }
使用示例
var pub_key = CryptoHelper.PemToRSAKey(result.pub_key, false);
var publicKey = CryptoHelper.RSAKeyToPem(pub_key, false);
加密参数算法
1 public class Rsa 2 { 3 /** 默认编码字符集 */ 4 private static string DEFAULT_CHARSET = "UTF-8"; 5 /// <summary> 6 /// RSA公钥加密 7 /// </summary> 8 /// <param name="content"></param> 9 /// <param name="publicKeyPem"></param> 10 /// <param name="charset"></param> 11 /// <returns></returns> 12 public static string RSAEncrypt(string content, string publicKeyPem, string charset= "UTF-8") 13 { 14 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 15 rsa.PersistKeyInCsp = false; 16 RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, publicKeyPem); 17 if (string.IsNullOrEmpty(charset)) 18 { 19 charset = DEFAULT_CHARSET; 20 } 21 byte[] data = Encoding.GetEncoding(charset).GetBytes(content); 22 int maxBlockSize = rsa.KeySize / 8 - 11; //加密块最大长度限制 23 if (data.Length <= maxBlockSize) 24 { 25 byte[] cipherbytes = rsa.Encrypt(data, true); 26 return Convert.ToBase64String(cipherbytes); 27 } 28 MemoryStream plaiStream = new MemoryStream(data); 29 MemoryStream crypStream = new MemoryStream(); 30 Byte[] buffer = new Byte[maxBlockSize]; 31 int blockSize = plaiStream.Read(buffer, 0, maxBlockSize); 32 while (blockSize > 0) 33 { 34 Byte[] toEncrypt = new Byte[blockSize]; 35 Array.Copy(buffer, 0, toEncrypt, 0, blockSize); 36 Byte[] cryptograph = rsa.Encrypt(toEncrypt, false); 37 crypStream.Write(cryptograph, 0, cryptograph.Length); 38 blockSize = plaiStream.Read(buffer, 0, maxBlockSize); 39 } 40 41 return Convert.ToBase64String(crypStream.ToArray(), Base64FormattingOptions.None); 42 } 43 } 44 /// <summary>Extension method for initializing a RSACryptoServiceProvider from PEM data string.</summary> 45 public static class RSACryptoServiceProviderExtension 46 { 47 #region Methods 48 49 /// <summary>Extension method which initializes an RSACryptoServiceProvider from a DER public key blob.</summary> 50 public static void LoadPublicKeyDER(this RSACryptoServiceProvider provider, byte[] DERData) 51 { 52 byte[] RSAData = RSACryptoServiceProviderExtension.GetRSAFromDER(DERData); 53 byte[] publicKeyBlob = RSACryptoServiceProviderExtension.GetPublicKeyBlobFromRSA(RSAData); 54 provider.ImportCspBlob(publicKeyBlob); 55 } 56 57 /// <summary>Extension method which initializes an RSACryptoServiceProvider from a DER private key blob.</summary> 58 public static void LoadPrivateKeyDER(this RSACryptoServiceProvider provider, byte[] DERData) 59 { 60 byte[] privateKeyBlob = RSACryptoServiceProviderExtension.GetPrivateKeyDER(DERData); 61 provider.ImportCspBlob(privateKeyBlob); 62 } 63 64 /// <summary>Extension method which initializes an RSACryptoServiceProvider from a PEM public key string.</summary> 65 public static void LoadPublicKeyPEM(this RSACryptoServiceProvider provider, string sPEM) 66 { 67 byte[] DERData = RSACryptoServiceProviderExtension.GetDERFromPEM(sPEM); 68 RSACryptoServiceProviderExtension.LoadPublicKeyDER(provider, DERData); 69 } 70 71 /// <summary>Extension method which initializes an RSACryptoServiceProvider from a PEM private key string.</summary> 72 public static void LoadPrivateKeyPEM(this RSACryptoServiceProvider provider, string sPEM) 73 { 74 byte[] DERData = RSACryptoServiceProviderExtension.GetDERFromPEM(sPEM); 75 RSACryptoServiceProviderExtension.LoadPrivateKeyDER(provider, DERData); 76 } 77 78 /// <summary>Returns a public key blob from an RSA public key.</summary> 79 internal static byte[] GetPublicKeyBlobFromRSA(byte[] RSAData) 80 { 81 byte[] data = null; 82 UInt32 dwCertPublicKeyBlobSize = 0; 83 if (RSACryptoServiceProviderExtension.CryptDecodeObject(CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, 84 new IntPtr((int)CRYPT_OUTPUT_TYPES.RSA_CSP_PUBLICKEYBLOB), RSAData, (UInt32)RSAData.Length, CRYPT_DECODE_FLAGS.NONE, 85 data, ref dwCertPublicKeyBlobSize)) 86 { 87 data = new byte[dwCertPublicKeyBlobSize]; 88 if (!RSACryptoServiceProviderExtension.CryptDecodeObject(CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, 89 new IntPtr((int)CRYPT_OUTPUT_TYPES.RSA_CSP_PUBLICKEYBLOB), RSAData, (UInt32)RSAData.Length, CRYPT_DECODE_FLAGS.NONE, 90 data, ref dwCertPublicKeyBlobSize)) 91 throw new Win32Exception(Marshal.GetLastWin32Error()); 92 } 93 else 94 throw new Win32Exception(Marshal.GetLastWin32Error()); 95 return data; 96 } 97 98 /// <summary>Converts DER binary format to a CAPI CRYPT_PRIVATE_KEY_INFO structure.</summary> 99 internal static byte[] GetPrivateKeyDER(byte[] DERData) 100 { 101 byte[] data = null; 102 UInt32 dwRSAPrivateKeyBlobSize = 0; 103 IntPtr pRSAPrivateKeyBlob = IntPtr.Zero; 104 if (RSACryptoServiceProviderExtension.CryptDecodeObject(CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, new IntPtr((int)CRYPT_OUTPUT_TYPES.PKCS_RSA_PRIVATE_KEY), 105 DERData, (UInt32)DERData.Length, CRYPT_DECODE_FLAGS.NONE, data, ref dwRSAPrivateKeyBlobSize)) 106 { 107 data = new byte[dwRSAPrivateKeyBlobSize]; 108 if (!RSACryptoServiceProviderExtension.CryptDecodeObject(CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, new IntPtr((int)CRYPT_OUTPUT_TYPES.PKCS_RSA_PRIVATE_KEY), 109 DERData, (UInt32)DERData.Length, CRYPT_DECODE_FLAGS.NONE, data, ref dwRSAPrivateKeyBlobSize)) 110 throw new Win32Exception(Marshal.GetLastWin32Error()); 111 } 112 else 113 throw new Win32Exception(Marshal.GetLastWin32Error()); 114 return data; 115 } 116 117 /// <summary>Converts DER binary format to a CAPI CERT_PUBLIC_KEY_INFO structure containing an RSA key.</summary> 118 internal static byte[] GetRSAFromDER(byte[] DERData) 119 { 120 byte[] data = null; 121 byte[] publicKey = null; 122 CERT_PUBLIC_KEY_INFO info; 123 UInt32 dwCertPublicKeyInfoSize = 0; 124 IntPtr pCertPublicKeyInfo = IntPtr.Zero; 125 if (RSACryptoServiceProviderExtension.CryptDecodeObject(CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, new IntPtr((int)CRYPT_OUTPUT_TYPES.X509_PUBLIC_KEY_INFO), 126 DERData, (UInt32)DERData.Length, CRYPT_DECODE_FLAGS.NONE, data, ref dwCertPublicKeyInfoSize)) 127 { 128 data = new byte[dwCertPublicKeyInfoSize]; 129 if (RSACryptoServiceProviderExtension.CryptDecodeObject(CRYPT_ENCODING_FLAGS.X509_ASN_ENCODING | CRYPT_ENCODING_FLAGS.PKCS_7_ASN_ENCODING, new IntPtr((int)CRYPT_OUTPUT_TYPES.X509_PUBLIC_KEY_INFO), 130 DERData, (UInt32)DERData.Length, CRYPT_DECODE_FLAGS.NONE, data, ref dwCertPublicKeyInfoSize)) 131 { 132 GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); 133 try 134 { 135 info = (CERT_PUBLIC_KEY_INFO)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(CERT_PUBLIC_KEY_INFO)); 136 publicKey = new byte[info.PublicKey.cbData]; 137 Marshal.Copy(info.PublicKey.pbData, publicKey, 0, publicKey.Length); 138 } 139 finally 140 { 141 handle.Free(); 142 } 143 } 144 else 145 throw new Win32Exception(Marshal.GetLastWin32Error()); 146 } 147 else 148 throw new Win32Exception(Marshal.GetLastWin32Error()); 149 return publicKey; 150 } 151 152 /// <summary>Extracts the binary data from a PEM file.</summary> 153 internal static byte[] GetDERFromPEM(string sPEM) 154 { 155 UInt32 dwSkip, dwFlags; 156 UInt32 dwBinarySize = 0; 157 158 if (!RSACryptoServiceProviderExtension.CryptStringToBinary(sPEM, (UInt32)sPEM.Length, CRYPT_STRING_FLAGS.CRYPT_STRING_BASE64HEADER, null, ref dwBinarySize, out dwSkip, out dwFlags)) 159 throw new Win32Exception(Marshal.GetLastWin32Error()); 160 161 byte[] decodedData = new byte[dwBinarySize]; 162 if (!RSACryptoServiceProviderExtension.CryptStringToBinary(sPEM, (UInt32)sPEM.Length, CRYPT_STRING_FLAGS.CRYPT_STRING_BASE64HEADER, decodedData, ref dwBinarySize, out dwSkip, out dwFlags)) 163 throw new Win32Exception(Marshal.GetLastWin32Error()); 164 return decodedData; 165 } 166 167 #endregion Methods 168 169 #region P/Invoke Constants 170 171 /// <summary>Enumeration derived from Crypto API.</summary> 172 internal enum CRYPT_ACQUIRE_CONTEXT_FLAGS : uint 173 { 174 CRYPT_NEWKEYSET = 0x8, 175 CRYPT_DELETEKEYSET = 0x10, 176 CRYPT_MACHINE_KEYSET = 0x20, 177 CRYPT_SILENT = 0x40, 178 CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x80, 179 CRYPT_VERIFYCONTEXT = 0xF0000000 180 } 181 182 /// <summary>Enumeration derived from Crypto API.</summary> 183 internal enum CRYPT_PROVIDER_TYPE : uint 184 { 185 PROV_RSA_FULL = 1 186 } 187 188 /// <summary>Enumeration derived from Crypto API.</summary> 189 internal enum CRYPT_DECODE_FLAGS : uint 190 { 191 NONE = 0, 192 CRYPT_DECODE_ALLOC_FLAG = 0x8000 193 } 194 195 /// <summary>Enumeration derived from Crypto API.</summary> 196 internal enum CRYPT_ENCODING_FLAGS : uint 197 { 198 PKCS_7_ASN_ENCODING = 0x00010000, 199 X509_ASN_ENCODING = 0x00000001, 200 } 201 202 /// <summary>Enumeration derived from Crypto API.</summary> 203 internal enum CRYPT_OUTPUT_TYPES : int 204 { 205 X509_PUBLIC_KEY_INFO = 8, 206 RSA_CSP_PUBLICKEYBLOB = 19, 207 PKCS_RSA_PRIVATE_KEY = 43, 208 PKCS_PRIVATE_KEY_INFO = 44 209 } 210 211 /// <summary>Enumeration derived from Crypto API.</summary> 212 internal enum CRYPT_STRING_FLAGS : uint 213 { 214 CRYPT_STRING_BASE64HEADER = 0, 215 CRYPT_STRING_BASE64 = 1, 216 CRYPT_STRING_BINARY = 2, 217 CRYPT_STRING_BASE64REQUESTHEADER = 3, 218 CRYPT_STRING_HEX = 4, 219 CRYPT_STRING_HEXASCII = 5, 220 CRYPT_STRING_BASE64_ANY = 6, 221 CRYPT_STRING_ANY = 7, 222 CRYPT_STRING_HEX_ANY = 8, 223 CRYPT_STRING_BASE64X509CRLHEADER = 9, 224 CRYPT_STRING_HEXADDR = 10, 225 CRYPT_STRING_HEXASCIIADDR = 11, 226 CRYPT_STRING_HEXRAW = 12, 227 CRYPT_STRING_NOCRLF = 0x40000000, 228 CRYPT_STRING_NOCR = 0x80000000 229 } 230 231 #endregion P/Invoke Constants 232 233 #region P/Invoke Structures 234 235 /// <summary>Structure from Crypto API.</summary> 236 [StructLayout(LayoutKind.Sequential)] 237 internal struct CRYPT_OBJID_BLOB 238 { 239 internal UInt32 cbData; 240 internal IntPtr pbData; 241 } 242 243 /// <summary>Structure from Crypto API.</summary> 244 [StructLayout(LayoutKind.Sequential)] 245 internal struct CRYPT_ALGORITHM_IDENTIFIER 246 { 247 internal IntPtr pszObjId; 248 internal CRYPT_OBJID_BLOB Parameters; 249 } 250 251 /// <summary>Structure from Crypto API.</summary> 252 [StructLayout(LayoutKind.Sequential)] 253 struct CRYPT_BIT_BLOB 254 { 255 internal UInt32 cbData; 256 internal IntPtr pbData; 257 internal UInt32 cUnusedBits; 258 } 259 260 /// <summary>Structure from Crypto API.</summary> 261 [StructLayout(LayoutKind.Sequential)] 262 struct CERT_PUBLIC_KEY_INFO 263 { 264 internal CRYPT_ALGORITHM_IDENTIFIER Algorithm; 265 internal CRYPT_BIT_BLOB PublicKey; 266 } 267 268 #endregion P/Invoke Structures 269 270 #region P/Invoke Functions 271 272 /// <summary>Function for Crypto API.</summary> 273 [DllImport("advapi32.dll", SetLastError = true)] 274 [return: MarshalAs(UnmanagedType.Bool)] 275 internal static extern bool CryptDestroyKey(IntPtr hKey); 276 277 /// <summary>Function for Crypto API.</summary> 278 [DllImport("advapi32.dll", SetLastError = true)] 279 [return: MarshalAs(UnmanagedType.Bool)] 280 internal static extern bool CryptImportKey(IntPtr hProv, byte[] pbKeyData, UInt32 dwDataLen, IntPtr hPubKey, UInt32 dwFlags, ref IntPtr hKey); 281 282 /// <summary>Function for Crypto API.</summary> 283 [DllImport("advapi32.dll", SetLastError = true)] 284 [return: MarshalAs(UnmanagedType.Bool)] 285 internal static extern bool CryptReleaseContext(IntPtr hProv, Int32 dwFlags); 286 287 /// <summary>Function for Crypto API.</summary> 288 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 289 [return: MarshalAs(UnmanagedType.Bool)] 290 internal static extern bool CryptAcquireContext(ref IntPtr hProv, string pszContainer, string pszProvider, CRYPT_PROVIDER_TYPE dwProvType, CRYPT_ACQUIRE_CONTEXT_FLAGS dwFlags); 291 292 /// <summary>Function from Crypto API.</summary> 293 [DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)] 294 [return: MarshalAs(UnmanagedType.Bool)] 295 internal static extern bool CryptStringToBinary(string sPEM, UInt32 sPEMLength, CRYPT_STRING_FLAGS dwFlags, [Out] byte[] pbBinary, ref UInt32 pcbBinary, out UInt32 pdwSkip, out UInt32 pdwFlags); 296 297 /// <summary>Function from Crypto API.</summary> 298 [DllImport("crypt32.dll", SetLastError = true)] 299 [return: MarshalAs(UnmanagedType.Bool)] 300 internal static extern bool CryptDecodeObjectEx(CRYPT_ENCODING_FLAGS dwCertEncodingType, IntPtr lpszStructType, byte[] pbEncoded, UInt32 cbEncoded, CRYPT_DECODE_FLAGS dwFlags, IntPtr pDecodePara, ref byte[] pvStructInfo, ref UInt32 pcbStructInfo); 301 302 /// <summary>Function from Crypto API.</summary> 303 [DllImport("crypt32.dll", SetLastError = true)] 304 [return: MarshalAs(UnmanagedType.Bool)] 305 internal static extern bool CryptDecodeObject(CRYPT_ENCODING_FLAGS dwCertEncodingType, IntPtr lpszStructType, byte[] pbEncoded, UInt32 cbEncoded, CRYPT_DECODE_FLAGS flags, [In, Out] byte[] pvStructInfo, ref UInt32 cbStructInfo); 306 307 #endregion P/Invoke Functions 308 }
需要引用BouncyCastle.Crypto.dll