RSA加密算法
RSA之go与Java
加解密算法对应关系
Go |
Java |
EncryptPKCS1v15 |
RSA/ECB/PKCS1Padding(加密模式) |
DecryptPKCS1v15 |
RSA/ECB/PKCS1Padding(解密模式) |
EncryptOAEP(可以指定具体的hash算法) |
RSA/ECB/OAEPWithSHA-1AndMGF1Padding(go的sha1算法)(加密模式)RSA/ECB/OAEPWithSHA-256AndMGF1Padding(go的sha256算法)(加密模式) |
DecryptOAEP(可以指定具体的hash算法) |
RSA/ECB/OAEPWithSHA-1AndMGF1Padding(go的sha1算法)(解密模式)RSA/ECB/OAEPWithSHA-256AndMGF1Padding(go的sha256算法)(解密模式) |
签名算法对应关系
Go |
Java |
rsa.SignPKCS1v15(指定不同的hash算法,对应Java算法名称前面的SHA名称) |
SHA1withRSA、SHA256withRSA、SHA384withRSA、SHA512withRSA(对应sign方法) |
rsa.VerifyPKCS1v15(指定不同的hash算法,对应Java算法名称前面的SHA名称) |
SHA1withRSA、SHA256withRSA、SHA384withRSA、SHA512withRSA(对应sign方法) |
rsa.SignPSS()(同样指定不同的hash算法) |
RSASSA-PSS(配合PSSParameterSpec(指定具体的hash算法) 使用)sign方法 |
rsa.VerifyPSS(同样指定不同的hash算法) |
RSASSA-PSS(配合PSSParameterSpec(指定具体的hash算法) 使用)verify方法 |
密钥系列化与反序列化
Go |
Java |
x509.MarshalPKCS1PrivateKey |
标准库不支持 PKCS#1 |
x509.MarshalPKCS1PublicKey |
标准库不支持 PKCS#1 |
x509.ParsePKCS1PrivateKey |
标准库不支持 PKCS#1 |
x509.ParsePKCS1PublicKey |
标准库不支持 PKCS#1 |
x509.MarshalPKCS8PrivateKey |
PrivateKey#getEncoded |
x509.MarshalPKIXPublicKey |
PublicKey.getEncoded() |
x509.ParsePKCS8PrivateKey |
PKCS8EncodedKeySpec |
x509.ParsePKIXPublicKey |
X509EncodedKeySpec |
生成密钥对
go中生成密钥对非常简单
key, err := rsa.GenerateKey(rand.Reader, 1024)
publicKey := key.PublicKey
密钥序列化为字符串(pkcs1标准不推荐再使用,而且Java标准库也不提供支持)
java需借助 Bouncy Castle 等第三方库解析PKCS1的密钥。大致代码如下
RSAPrivateKeyStructure keyStructure = new RSAPrivateKeyStructure((ASN1Sequence) ASN1Sequence.fromByteArray(Base64.getDecoder().decode(base64PrivateKey)));
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(keyStructure.getModulus(), keyStructure.getPrivateExponent());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
key, _ := rsa.GenerateKey(rand.Reader, 1024)
privateByte := x509.MarshalPKCS1PrivateKey(key)
publicByte := x509.MarshalPKCS1PublicKey(&key.PublicKey)
privateByteBase64 := base64.StdEncoding.EncodeToString(privateByte)
publicByteBase64 := base64.StdEncoding.EncodeToString(publicByte)
p("私钥:", privateByteBase64)
p("公钥:", publicByteBase64)
密钥反序列化为密钥对象
privateKeyDec, _ := base64.StdEncoding.DecodeString(privateByteBase64)
privateKey, _ := x509.ParsePKCS1PrivateKey(privateKeyDec)
publicKeyDec, _ := base64.StdEncoding.DecodeString(publicByteBase64)
publicKey, _ := x509.ParsePKCS1PublicKey(publicKeyDec)
留一个示例(Go与Java交互)
Go(加密、签名)
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
fmt.Println("生成私钥失败:", err)
return
}
publicKey := privateKey.PublicKey
plaintext := []byte("这是一段要加密的文字")
encryptedData, err := rsa.EncryptPKCS1v15(rand.Reader, &publicKey, plaintext)
if err != nil {
fmt.Println("加密失败:", err)
return
}
encryptedBase64 := base64.StdEncoding.EncodeToString(encryptedData)
fmt.Println("Base64编码后的密文:", encryptedBase64)
privateKeyBase64 := privateKeyToBase64(privateKey)
fmt.Println("Base64编码后的私钥:", privateKeyBase64)
publicKeyBase64 := publicKeyToBase64(&publicKey)
fmt.Println("Base64编码后的公钥:", publicKeyBase64)
hashed := sha256.Sum256(plaintext)
sha256, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed[:])
if err != nil {
panic(err)
}
p("签名:", base64.StdEncoding.EncodeToString(sha256))
Java(解密、验签)
解密
String base64PrivateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCmcxhZF3Q0TBMavmcUueq2BJ09QbXUM+rYrPbIXFN5wecrpGs1T+gaZ6HnKTkHLR55iBhVfJ6QTjRcdkREZ86EwkhlJItKp8P9HlR+cNdoDTXMLYKZmSrZ2o0gS5wjGd8f6bil+BauIac8uWOgXULIU8QnAAJECflvcAsJWIlhbTG3gaDSGlBODmViTMxe64WowEaLdo3MFUZhTF/i3Q+KhLan8l99pLrA5ufXx9pMrexMsbzuNW/9AKV4j++ANRuxIhMPY4UauFCOEgtbBx6BWKUXK9/eGO7LJSeOQoZBM2yDnsobVojCjSSQmuInue3PE0i7GcBlw0X+oOgpY/G/AgMBAAECggEBAIm09xPeP5l0xul9VTLkjbaBIsWnM5OYUFdq4dDp8XXuYh7NLJUywsf1rRDeHfw969SIL/mp3FVvHgrRHbGqYEWdpt9m2IavPYqQKT9ihBPlufhuPnptKfKKye9KHqc7pEl2x/knwzvVQ9MNXcsy3Sl3g/TwIO/BgMgdXkQhJ6edpY4+bag238UmVCqe2oRvpqiSN477afBsa1JNyfY1UEjku+wvj1wNJ56NPS3TAeq1B8XIBGB7IooVAXB4OU4k1zf1FvYeNguiMBOIUh/Gdl3Z+FXMt3hvI8yoNJre3KupmR8j3TzlgkhJgg53ZZTUfgjzy479DwUhYQYvqcICeMECgYEAxpGPldUHLP+1kxutnVHEDPCIF8bqndh3RMKLG0ggY62RDphCOfzzMnYLPjA9CgIdIPo9gPRKcMYsJ2rNJMaSX3LuA7po4BNlG7aMkQT5Ztaa1XtFg3GsS+UjYnbF6Aj1Gt+UUc7SdrJs/WrRzxMD2IGX34mkEjAdaQzudvsJ3JkCgYEA1pdf/2/OCLbj2qNM1dsnFEhfUFw+dmbnvRHl1H8+DDWKkiFZVGEwbdp2mtosvlw/dZXNdeW2VBULjCLBGkfgA5cxXUJomSjT5anfPD0LtJZJSvRlD7P9dAY59/5ySiCRi7/ko7ID6fWhJvpNj0sOMR1tafkoVTB9eX4OAHYeIBcCgYEAizLDSy+5BgyDxwpiHKSTINcFMFXbZqe2hFc0mP1o5zdnNqn50xjFi5xAqWm7gGaW8OU7dEjMXl4t2bv+70bcmVjCDY8BsgMmn9TKmWa5RyQuCnWN92UaeWG5+m50sgKFgD83hFnOJDNUQBo/1j/oNEA0rRmaEL32AAx2pqW49hECgYEAjm5c5mNkQn550AWxmwRh9OFwehsvzlDRIbo+bQOjwGDNP97otsvnZBKrxG5pYlRCPp6Wh9lXYomxZ2st9m6cbmWs+zR3zqi9tGNC622tVkimDx0V8w1JffggA82cOD1TvYk5jbk7Rc+mDgP29NQhcFIS7FLXBWww7DHRw1ai+jMCgYAglIzt0lUc6Yx5OUOtnm/3Tn1gH1NmktAXyC1JNQxxp9CBHDtD038LJHuArSyLp1hxRzoJ4E5cmUTWLLx4v5pMGunrcDPZrj/oJBfFDc5SItDZ6H2PKqrN0ZvyqxUxW6NIwhKpkjEif9SayrDZP5vHDbcVp8ScMJKwz7ynUkRCcg==";
String base64EncryptedText = "U2PeiPR52FVkDuBWdTcg0Cu0SAiVIQ0GuPh8TYivP91rGwIf/nRQsZ5pznEVX3YPypV0caJWInk6p6HEW3D4C1mGnrnG5BttDTKIFneyN8Yv46LOg83Tykk+1vY47+OflLBPYX4zIFSLBUyQMPJUaFWAYmQ3Zy/32Bm2i3gl/H9foeM4Mf+BBdrv2jRKdm738e5V6xvOhQbcW7K4eav0MhX+0PXJPSlwgXch7Fh1dRj50Gb2srVYgvg/pshHIHEZgkfsry60xmn9qBkqFIHybqlow0l5632TMU3qDnLTXt1Z1goos0/QSzIRlWkwDr9IRMfo1H9AFcajrNRP1aJIpw==";
PrivateKey privateKey = getPrivateKeyFromBase64(base64PrivateKey);
byte[] encryptedBytes = Base64.getDecoder().decode(base64EncryptedText);
byte[] decryptedBytes = decrypt(privateKey, encryptedBytes);
System.out.println("解密后的文本: " + new String(decryptedBytes));
public static PrivateKey getPrivateKeyFromBase64(String base64PrivateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] privateKeyBytes = Base64.getDecoder().decode(base64PrivateKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
return keyFactory.generatePrivate(keySpec);
}
public static byte[] decrypt(PrivateKey privateKey, byte[] encryptedData) throws NoSuchPaddingException, java.security.InvalidKeyException, javax.crypto.IllegalBlockSizeException, javax.crypto.BadPaddingException, NoSuchAlgorithmException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(encryptedData);
}
验签
String publicStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwsTqgcW8vD+Ac9mnE1T2DDP7Nu2voifcC4xS60gvtC8cDKhqMP3B/Vno2InJ06EP94VZFukXZlbQaIF5U2z5Dyp/iT+yPjQnG6ZBL9IjrPovL1rvcUkDZu+yqajvKM0FCz+NsPIzO8pjlRGjIlfGKC9Of1XutxUwlux5aR55NA0vXCN60giz4DK2HFIKQioITwOduEeYL1xinUpY7lGLkouPJRjrVvvcjzgb5QCeLS5vxQ6EsmrzcomnAKfnGar1dvSVUqJk0lu9nrWygJngRsotLG4VbwRVTklWH49rEr5fkPtaal4avtjCiXXNalHscv/nU/fwF1okKCIt5hmV+QIDAQAB";
String sign = "RjYdalZyJpqOTjQwK1VJd2kD+5gHnTliqbhhpLfda7lq7BWlQ84VzRy+rs3W2yBI1aJtNKj8ByXwD9jJh51fmMunCPZ/Uv6tpuuSGGE0mAeIE3gl1aPSipjvKO7PBpYMsbFxI4NiL9Zh0LKLStUj4Xtc92pmXJdcL80JlTEdxC+vx7dsO/GXzM0TGskFD1whpYETLFEFc4ASD9AXMBNVycdv4jWFO/SRN+LUtpTQsSWC/K7o8wlXCqFE4zsOnj/fgG2uKwt7aZMyZN/hdLP3T+MftXaFeVFOphh/9E6SvOCqo7mP9MXu5SUBL2/pfDpV5fxeNzVW6I8VnfxMLgnHFA==";
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicStr));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
String plain = "这是一段要加密的文字";
byte[] bytes = plain.getBytes(StandardCharsets.UTF_8);
signature.update(bytes);
boolean verify = signature.verify(Base64.getDecoder().decode(sign));
System.out.println("验签结果:" + verify);