1 非對稱加密演算法 1.1 概述 1976年,美國學者Dime和Henman為解決信息公開傳送和密鑰管理問題,提出一種新的密鑰交換協議,允許在不安全的媒體上的通訊雙方交換信息,安全地達成一致的密鑰,這就是“公開密鑰系統”。 與對稱加密演算法不同,非對稱加密演算法需要兩個密鑰:公開密鑰(publickey ...
1 非對稱加密演算法
1.1 概述
1976年,美國學者Dime和Henman為解決信息公開傳送和密鑰管理問題,提出一種新的密鑰交換協議,允許在不安全的媒體上的通訊雙方交換信息,安全地達成一致的密鑰,這就是“公開密鑰系統”。
與對稱加密演算法不同,非對稱加密演算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種演算法叫作非對稱加密演算法。1.2 加密流程
如下圖所示,甲乙之間使用非對稱加密的方式完成了重要信息的安全傳輸。
2 RSA加密演算法
2.1 概述
RSA是目前最有影響力和最常用的公鑰加密演算法,它能夠抵抗到目前為止已知的絕大多數密碼攻擊,已被ISO推薦為公鑰數據加密標準。
RSA公開密鑰密碼體制。所謂的公開密鑰密碼體制就是使用不同的加密密鑰與解密密鑰,是一種“由已知加密密鑰推導出解密密鑰在計算上是不可行的”密碼體制。 在公開密鑰密碼體制中,加密密鑰(即公開密鑰)PK是公開信息,而解密密鑰(即秘密密鑰)SK是需要保密的。加密演算法E和解密演算法D也都是公開的。雖然解密密鑰SK是由公開密鑰PK決定的,但卻不能根據PK計算出SK。 正是基於這種理論,1978年出現了著名的RSA演算法,它通常是先生成一對RSA 密鑰,其中之一是保密密鑰,由用戶保存;另一個為公開密鑰,可對外公開,甚至可在網路伺服器中註冊。為提高保密強度,RSA密鑰至少為500位長,一般推薦使用1024位。這就使加密的計算量很大。為減少計算量,在傳送信息時,常採用傳統加密方法與公開密鑰加密方法相結合的方式,即信息採用改進的DES或IDEA對話密鑰加密,然後使用RSA密鑰加密對話密鑰和信息摘要。對方收到信息後,用不同的密鑰解密並可核對信息摘要。 RSA演算法是第一個能同時用於加密和數字簽名的演算法,也易於理解和操作。RSA是被研究得最廣泛的公鑰演算法,從提出到現今的三十多年裡,經歷了各種攻擊的考驗,逐漸為人們接受,普遍認為是目前最優秀的公鑰方案之一。2.2 演算法實現過程
1. 隨意選擇兩個大的質數p和q,p不等於q,計算N=pq。 2. 根據歐拉函數,不大於N且與N互質的整數個數為(p-1)(q-1)。 3. 選擇一個整數e與(p-1)(q-1)互質,並且e小於(p-1)(q-1)。 4. 用以下這個公式計算d:d× e ≡ 1 (mod (p-1)(q-1))。 5. 將p和q的記錄銷毀。 以上內容中,(N,e)是公鑰,(N,d)是私鑰。2.3 演算法缺點
1)產生密鑰很麻煩,受到素數產生技術的限制,因而難以做到一次一密。
2)安全性,RSA的安全性依賴於大數的因數分解,但並沒有從理論上證明破譯RSA的難度與大數分解難度等價,而且密碼學界多數人士傾向於因數分解不是NP問題。
3)速度太慢,由於RSA 的分組長度太大,為保證安全性,n 至少也要 600 bits以上,使運算代價很高,尤其是速度較慢,較對稱密碼演算法慢幾個數量級;且隨著大數分解技術的發展,這個長度還在增加,不利於數據格式的標準化。
2.4 java代碼實現加解密
1 package xin.dreaming.rsa; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.UnsupportedEncodingException; 5 import java.security.Key; 6 import java.security.KeyFactory; 7 import java.security.KeyPair; 8 import java.security.KeyPairGenerator; 9 import java.security.NoSuchAlgorithmException; 10 import java.security.interfaces.RSAPrivateKey; 11 import java.security.interfaces.RSAPublicKey; 12 import java.security.spec.PKCS8EncodedKeySpec; 13 import java.security.spec.X509EncodedKeySpec; 14 import java.util.HashMap; 15 import java.util.Map; 16 17 import javax.crypto.Cipher; 18 19 import org.bouncycastle.util.encoders.Base64; 20 21 /** 22 * Rsa工具類 23 * 24 * @author DREAMING.XIN 25 * 26 */ 27 public abstract class RsaUtils { 28 /** 29 * 生成公鑰私鑰對,使用預設模長1024。 30 * 31 * @return Object[] : 0:公鑰( RSAPublicKey ),1:私鑰( RSAPrivateKey ) 32 */ 33 34 private static final int DEFAULT_KEY_LEN = 2048; 35 36 public static Map<String, String> genKeyPair() { 37 return genKeyPair(DEFAULT_KEY_LEN); 38 39 } 40 41 /** 42 * 指定模長生成公私鑰對 43 * 44 * @param modulus 45 * @return 46 */ 47 public static Map<String, String> genKeyPair(int modulus) { 48 KeyPairGenerator keyPairGen; 49 try { 50 keyPairGen = KeyPairGenerator.getInstance("RSA"); 51 keyPairGen.initialize(modulus); 52 KeyPair keyPair = keyPairGen.generateKeyPair(); 53 54 Map<String, String> keyMaps = new HashMap<String, String>(); 55 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 56 keyMaps.put("publicKey", new String(Base64.encode(publicKey.getEncoded()))); 57 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 58 keyMaps.put("privateKey", new String(Base64.encode(privateKey.getEncoded()))); 59 60 return keyMaps; 61 } catch (NoSuchAlgorithmException e) { 62 throw new RuntimeException(e); 63 } 64 } 65 66 /** 67 * 公鑰加密 68 * 69 * @param publicKeyBytes 70 * @param data 71 * @param modulus 72 * 公鑰模長,範圍512-2048。 73 * @return 74 */ 75 public static byte[] encryptByPublicKey(byte[] publicKeyBytes, byte[] data, int modulus) { 76 try { 77 // RSA最大加密明文大小 78 int maxEncryptBlock = modulus / 8 - 11; 79 80 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes); 81 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 82 Key publicK = keyFactory.generatePublic(x509KeySpec); 83 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 84 cipher.init(Cipher.ENCRYPT_MODE, publicK); 85 int inputLen = data.length; 86 ByteArrayOutputStream out = new ByteArrayOutputStream(); 87 int offSet = 0; 88 byte[] cache; 89 int i = 0; 90 while (inputLen - offSet > 0) { 91 if (inputLen - offSet > maxEncryptBlock) { 92 cache = cipher.doFinal(data, offSet, maxEncryptBlock); 93 } else { 94 cache = cipher.doFinal(data, offSet, inputLen - offSet); 95 } 96 out.write(cache, 0, cache.length); 97 i++; 98 offSet = i * maxEncryptBlock; 99 } 100 byte[] encryptedData = out.toByteArray(); 101 out.close(); 102 return encryptedData; 103 } catch (Exception e) { 104 throw new RuntimeException(e); 105 } 106 107 } 108 109 /** 110 * 公鑰加密,密鑰模長使用預設長度1024。 111 * 112 * @param publicKeyBytes 113 * 公鑰RSAPublicKey getEncoded() 114 * @param data 115 * 要加密的位元組數組 116 */ 117 public static byte[] encryptByPublicKey(byte[] publicKeyBytes, byte[] data) { 118 return encryptByPublicKey(publicKeyBytes, data, DEFAULT_KEY_LEN); 119 } 120 121 /** 122 * 公鑰解密 123 * 124 * @param publicKeyBytes 125 * 公鑰RSAPublicKey getEncoded() 126 * @param encryptedData 127 * 被(私鑰)加密過的位元組數組 128 * @param modulus 129 * 模長,範圍512-2048 130 * @return 131 */ 132 public static byte[] decryptByPublicKey(byte[] publicKeyBytes, byte[] encryptedData, int modulus) { 133 // RSA最大解密密文大小 134 int maxDecryptBlock = modulus / 8; 135 try { 136 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes); 137 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 138 Key publicK = keyFactory.generatePublic(x509KeySpec); 139 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 140 cipher.init(Cipher.DECRYPT_MODE, publicK); 141 int inputLen = encryptedData.length; 142 ByteArrayOutputStream out = new ByteArrayOutputStream(); 143 int offSet = 0; 144 byte[] cache; 145 int i = 0; 146 // 對數據分段解密 147 while (inputLen - offSet > 0) { 148 if (inputLen - offSet > maxDecryptBlock) { 149 cache = cipher.doFinal(encryptedData, offSet, maxDecryptBlock); 150 } else { 151 cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); 152 } 153 out.write(cache, 0, cache.length); 154 i++; 155 offSet = i * maxDecryptBlock; 156 } 157 byte[] decryptedData = out.toByteArray(); 158 out.close(); 159 return decryptedData; 160 } catch (Exception e) { 161 throw new RuntimeException(e); 162 } 163 } 164 165 /** 166 * 公鑰解密,預設模長1024 167 * 168 * @param publicKeyBytes 169 * 公鑰RSAPublicKey getEncoded() 170 * @param encryptedData 171 * 被(私鑰)加密過的位元組數組 172 */ 173 public static byte[] decryptByPublicKey(byte[] publicKeyBytes, byte[] encryptedData) { 174 return decryptByPublicKey(publicKeyBytes, encryptedData, DEFAULT_KEY_LEN); 175 } 176 177 /** 178 * 私鑰加密 179 * 180 * @param privateKeyBytes 181 * 私鑰RSAPrivateKey getEncoded() 182 * @param data 183 * 要加密的位元組數組 184 * @param modulus 185 * 模長,範圍512-2048。 186 */ 187 public static byte[] encryptByPrivateKey(byte[] privateKeyBytes, byte[] data, int modulus) { 188 try { 189 // RSA最大加密明文大小 190 int maxEncryptBlock = modulus / 8 - 11; 191 192 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); 193 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 194 Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); 195 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 196 cipher.init(Cipher.ENCRYPT_MODE, privateK); 197 int inputLen = data.length; 198 ByteArrayOutputStream out = new ByteArrayOutputStream(); 199 int offSet = 0; 200 byte[] cache; 201 int i = 0; 202 while (inputLen - offSet > 0) { 203 if (inputLen - offSet > maxEncryptBlock) { 204 cache = cipher.doFinal(data, offSet, maxEncryptBlock); 205 } else { 206 cache = cipher.doFinal(data, offSet, inputLen - offSet); 207 } 208 out.write(cache, 0, cache.length); 209 i++; 210 offSet = i * maxEncryptBlock; 211 } 212 byte[] encryptedData = out.toByteArray(); 213 out.close(); 214 return encryptedData; 215 } catch (Exception e) { 216 throw new RuntimeException(e); 217 } 218 } 219 220 /** 221 * 私鑰加密,預設模長1024。 222 * 223 * @param privateKeyBytes 224 * 私鑰RSAPrivateKey getEncoded() 225 * @param data 226 * 要加密的位元組數組 227 */ 228 public static byte[] encryptByPrivateKey(byte[] privateKeyBytes, byte[] data) { 229 return encryptByPrivateKey(privateKeyBytes, data, DEFAULT_KEY_LEN); 230 } 231 232 /** 233 * 私鑰解密 234 * 235 * @param privateKeyBytes 236 * 私鑰RSAPrivateKey getEncoded() 237 * @param encryptedData 238 * 被(公鑰)加密過的位元組數組 239 * @param modulus 240 * 模長,範圍512-2048 241 */ 242 public static byte[] decryptByPrivateKey(byte[] privateKeyBytes, byte[] encryptedData, int modulus) { 243 try { 244 // RSA最大解密密文大小 245 int maxDecryptBlock = modulus / 8; 246 247 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); 248 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 249 Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); 250 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 251 cipher.init(Cipher.DECRYPT_MODE, privateK); 252 int inputLen = encryptedData.length; 253 ByteArrayOutputStream out = new ByteArrayOutputStream(); 254 int offSet = 0; 255 byte[] cache; 256 int i = 0; 257 while (inputLen - offSet > 0) { 258 if (inputLen - offSet > maxDecryptBlock) { 259 cache = cipher.doFinal(encryptedData, offSet, maxDecryptBlock); 260 } else { 261 cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); 262 } 263 out.write(cache, 0, cache.length); 264 i++; 265 offSet = i * maxDecryptBlock; 266 } 267 byte[] decryptedData = out.toByteArray(); 268 out.close(); 269 return decryptedData; 270 } catch (Exception e) { 271 throw new RuntimeException(e); 272 } 273 } 274 275 /** 276 * 私鑰解密,預設模長1024。 277 * 278 * @param privateKeyBytes 279 * 私鑰RSAPrivateKey getEncoded() 280 * @param encryptedData 281 * 被(公鑰)加密過的位元組數組 282 */ 283 public static byte[] decryptByPrivateKey(byte[] privateKeyBytes, byte[] encryptedData) { 284 return decryptByPrivateKey(privateKeyBytes, encryptedData, DEFAULT_KEY_LEN); 285 } 286 287 public static void main(String[] args) throws UnsupportedEncodingException { 288 // 加密原串 289 String value = "DREAMING.XIN"; 290 System.out.println("加密原串 : "); 291 System.out.println(value); 292 System.out.println("------------------------------------------------------------------------------------------"); 293 // 生成公私鑰對 294 Map<String, String> genKeyPair = genKeyPair(); 295 296 System.out.println("自行生成公私鑰對: "); 297 System.out.println(genKeyPair); 298 System.out.println("------------------------------------------------------------------------------------------"); 299 byte[] encryptByPublicKey = encryptByPublicKey(Base64.decode(genKeyPair.get("publicKey").getBytes("utf-8")), 300 value.getBytes()); 301 302 // 3、Base64編碼 303 byte[] encode = Base64.encode(encryptByPublicKey); 304 305 System.out.println("最終加密結果: "); 306 String sign = new String(encode, "utf-8"); 307 System.out.println(new String(encode, "utf-8")); 308 System.out.println("------------------------------------------------------------------------------------------"); 309 310 // 1、簽名密文->Base64解碼->RSA解密 311 byte[] signCipherArr = decryptByPrivateKey(Base64.decode(genKeyPair.get("privateKey").getBytes("utf-8")), 312 Base64.decode(sign.getBytes("utf-8"))); 313 System.out.println("解密結果: "); 314 System.out.println(new String (signCipherArr)); 315 System.out.println("------------------------------------------------------------------------------------------"); 316 317 } 318 }
輸出結果:
加密原串 : DREAMING.XIN ------------------------------------------------------------------------------------------ 自行生成公私鑰對: {publicKey=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkmRw1oug/LBmpkRsubsKoeEBQvGeRfUTMX8fTEuLJqKuWfHkB6HJ/08xf/BYhbL+GrUFk5DR/lbJdnD9SEx0ZDZHecrjj262T67izwf7d+rB3o7z5w/3Pk3p3Ye6Ns7SdGM6D8O6InUK4mQFSBKQhw25BqPzUQKb4DY/S+I2OAx1/qVB56Na+if5H9ttP8nhVVnQZXheTPh5Say0+ySFEBb1i2sxJQuwFLbtA9RkKNFSSB2+4sBrn5fRmemu6OGToR/WQ8KFa96+u9X2t41HPxa7dTF+g9btkEMWwbiXkPatjD9JaNXKKrueIQoDt/FKonUZQ0AafSs8r/xsrb4pfwIDAQAB, privateKey=MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCSZHDWi6D8sGamRGy5uwqh4QFC8Z5F9RMxfx9MS4smoq5Z8eQHocn/TzF/8FiFsv4atQWTkNH+Vsl2cP1ITHRkNkd5yuOPbrZPruLPB/t36sHejvPnD/c+Tendh7o2ztJ0YzoPw7oidQriZAVIEpCHDbkGo/NRApvgNj9L4jY4DHX+pUHno1r6J/kf220/yeFVWdBleF5M+HlJrLT7JIUQFvWLazElC7AUtu0D1GQo0VJIHb7iwGufl9GZ6a7o4ZOhH9ZDwoVr3r671fa3jUc/Frt1MX6D1u2QQxbBuJeQ9q2MP0lo1coqu54hCgO38UqidRlDQBp9Kzyv/Gytvil/AgMBAAECggEAWWoJ1bExIkYoXHO8qPDKfLduytHDZ11aXMgVeMdHddC1h3CMY/D47P0U8dz+ZKNAO1XH0ysIaD3gDXzT5z3zdWYF4CkBNxFbP25FUEjC2qrDwUk1RjNlQ2PZbRrCrUlEGBynUQuue+9bN435/9x+9E54bcrkCd37EUZxAMtpbG+bZ8/sizBsIQYfiKlGV3FJ68OTnkCzvjltYmzWn4q1a6CDqN40G6IfBJD1g1ENkkKJvi4hu6U7LhkpI3oil4+zZuxdGNphICz6L5CQVn01MahnfJlNszQD1H0sq/G9ymHtzYyvq6Fu8URjksw4doaqYVRuGuZL58qP33BNSzilwQKBgQDHZDC5YgViTmqAC9/GGnm1Cwhi8SkbsG0j6jCRx4e6nYgux4TOg9V6MdzXrm/w6X5ZtTTDPoB4vn+l2pX8SGyO1c2JfaL3w+iMahSAee6CFDbBzmiF5b+PiiKmYKzrNTtjPNkcDsrwErIhiyplgkj/+gsiVAepliJRUVTVeApvHwKBgQC79EUDck2kwSMsw3kXb/ZUIG6BPH0j/A0xn7SqcsVc/Rt3WFzfUJV9qCsN9TwGm3lk8fIsdXYoLrm96MlNOU3uNUzwwYwqespkdJ5R6iniWA+LAVuGgHhDYk84VFDxcldMLlG16O7uuIoUSeXdVwCChx1OllKFxsEj1z6X4mPZoQKBgQCy883zI/FXGK/m+kE9aFehUCSXwH+3lTFvEWnD/MNpjqdB7NnaC2JWiFf/z1QycS1wT/zp2retJrQj47nHMi0USPluk67nFhIpq69423ZfksrOSHVw7xFtP3n3vz6S3zTMzTjCQNiMfQsYpfFIJ5VjAERr6+TwpIlqWEd+S3152wKBgH+t6FP3ChepvCNkhpYNUODFR0wzsy8Gwk+7lhdT8A7DQi1IsY5iR6sc2mKY/TXf2A9i7IiXIrUZSMRhpp33F6GCQ8opMPaKg4LKVeJ/mARSnfxn56zvCMN9vSMe4/2hFvyBWrCgk+9HHUW7DZPWzlndP2NrapPF+N5IEhVLjVkBAoGABqIvu4Vpgg3viiE6PRmlA0iAnAz2ZnaqPS7Xk8+Ua44rCxTE62Vhm5ZbfQQzxlqFL/32NnJ3+zG/ONnWqdkGkvE5N/7NZg5CNzTPVqn/PbUAQ1L01yzcAETqr1dMLhGqlMMLkdbLO8VzoagVRuE+jSOwl3a+5Yq/cu0TMKLhrAE=} ------------------------------------------------------------------------------------------ 最終加密結果: YmGXP+nSAY23ENUryid4zdE6KRAfFGhQWPJ4NAM1odZIEZCh5BbOtw437E85TdzABNE+NTDVogq+AI8WfAiD0yUpDukdRrZMb/IwG5k7xCgsVo0Tgt2SiH9bZFkvMaIIWH6d90muVtA/dyGHPSk/WmdgSl3QCcsZ3JAzMeadZwtL685eBhJD6hwXwKLfQj1OQBlLH3R9D5gBNGf36RHyi20LteTOKIR9lvMQPGbsnvspqi7t3xo5ajLpeuCr9azEovP0UFiiaxrkGLYMG2YM91r7JXUCn2gtVuDnXPFVVfOj84mN51229UJwQWBZe0BGPLSpROmOUZeWj2gjvuyqGg== ------------------------------------------------------------------------------------------ 解密結果: DREAMING.XIN ------------------------------------------------------------------------------------------
2.5 java代碼實現加簽驗簽
1 package xin.dreaming.rsa; 2 3 import org.apache.commons.codec.binary.Base64; 4 5 import javax.crypto.Cipher; 6 import java.io.ByteArrayInputStream; 7 import java.security.KeyFactory; 8 import java.security.PrivateKey; 9 import java.security.PublicKey; 10 import java.security.Signature; 11 import java.security.cert.Certificate; 12 import java.security.cert.CertificateFactory; 13 import java.security.spec.PKCS8EncodedKeySpec; 14 15 /** 16 * 17 * @author DREAMING.XIN 18 * 19 */ 20 public class RSAUtil { 21 22 private static final String CHARSET = "UTF-8"; 23 24 private static final String algorithm = "SHA256withRSA"; 25 26 /** 27 * 網聯請求報文簽名 28 * 29 * @param privateKey 30 * 機構私鑰字元串 31 * @param content 32 * 簽名原文 33 * @return 簽名密文 34 * @throws Exception 35 */ 36 public static String sign(String privateKey, String content) throws Exception { 37 Signature signature = Signature.getInstance(algorithm); 38 signature.initSign(convertPrivateKey(privateKey)); 39 signature.update(content.getBytes(CHARSET)); 40 return Base64.encodeBase64String(signature.sign()); 41 } 42 43 /** 44 * 網聯返回報文驗簽 45 * 46 * @param publicKey 47 * 網聯公鑰字元串 48 * @param content 49 * 驗簽原文報文 50 * @param signStr 51 * 網聯返回簽名字元串 52 * @return 驗簽結果 53 * @throws Exception 54 */ 55 public static boolean vertify(String publicKey, String content, String signStr) throws Exception { 56 Signature signature = Signature.getInstance(algorithm); 57 signature.initVerify(convertPublicKey(publicKey)); 58 signature.update(content.getBytes(CHARSET)); 59 return signature.verify(Base64.decodeBase64(signStr.getBytes(CHARSET))); 60 } 61 62 /** 63 * 對稱密鑰公鑰加密 64 * 65 * @param publicKey 66 * 網聯公鑰字元串 67 * @param content 68 * 密鑰原文 69 * @return 加密密文 70 * @throws Exception 71 */ 72 public static String encryptByPublicKey(String publicKey, String content) throws Exception { 73 String result = null; 74 try { 75 Cipher cipher = cipher = Cipher.getInstance("RSA"); 76 cipher.init(Cipher.ENCRYPT_MODE, convertPublicKey(publicKey)); 77 byte[] encoded = cipher.doFinal(content.getBytes(CHARSET)); 78 result = Base64.encodeBase64String(encoded); 79 } catch (Exception e) { 80 81 } 82 return result; 83 } 84 85 /** 86 * 對稱密鑰密文解密 87 * 88 * @param privateKey 89 * 機構私鑰字元串 90 * @param content 91 * 網聯對稱密鑰密文 92 * @return 對稱密鑰明文 93 * @throws Exception 94 */ 95 public static String decryptByPrivateKey(String privateKey, String content) throws Exception { <