goLang之路(RSA加密算法)

发布于:2024-12-07 ⋅ 阅读:(146) ⋅ 点赞:(0)

RSA加密算法

RSA之go与Java

加解密算法对应关系

Go Java
EncryptPKCS1v15 RSA/ECB/PKCS1Padding(加密模式)
DecryptPKCS1v15 RSA/ECB/PKCS1Padding(解密模式)
EncryptOAEP(可以指定具体的hash算法) RSA/ECB/OAEPWithSHA-1AndMGF1Paddinggo的sha1算法)(加密模式)RSA/ECB/OAEPWithSHA-256AndMGF1Paddinggo的sha256算法)(加密模式)
DecryptOAEP(可以指定具体的hash算法) RSA/ECB/OAEPWithSHA-1AndMGF1Paddinggo的sha1算法)(解密模式)RSA/ECB/OAEPWithSHA-256AndMGF1Paddinggo的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中生成密钥对非常简单

// 1024 密钥位数
key, err := rsa.GenerateKey(rand.Reader, 1024)
// key本身就是私钥,而公钥包含在私钥的一个字段内
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);
  • pkcs1方式编码密钥和公钥
key, _ := rsa.GenerateKey(rand.Reader, 1024)

// pkcs1 方式相对比较老,新的系统普遍使用 pkcs8 处理私钥
privateByte := x509.MarshalPKCS1PrivateKey(key)
publicByte := x509.MarshalPKCS1PublicKey(&key.PublicKey)
privateByteBase64 := base64.StdEncoding.EncodeToString(privateByte)
publicByteBase64 := base64.StdEncoding.EncodeToString(publicByte)

p("私钥:", privateByteBase64)
p("公钥:", publicByteBase64)
  • pkcs8方式

密钥反序列化为密钥对象

/*反序列化私钥*/
privateKeyDec, _ := base64.StdEncoding.DecodeString(privateByteBase64)
privateKey, _ := x509.ParsePKCS1PrivateKey(privateKeyDec)
/*反序列化公钥*/
publicKeyDec, _ := base64.StdEncoding.DecodeString(publicByteBase64)
publicKey, _ := x509.ParsePKCS1PublicKey(publicKeyDec)

留一个示例(Go与Java交互)

Go(加密、签名)

// 生成RSA私钥
	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
	}
	// 将加密后的数据进行Base64编码
	encryptedBase64 := base64.StdEncoding.EncodeToString(encryptedData)
	fmt.Println("Base64编码后的密文:", encryptedBase64)

	// 将私钥转换为Base64编码字符串
	privateKeyBase64 := privateKeyToBase64(privateKey)
	fmt.Println("Base64编码后的私钥:", privateKeyBase64)

	// 将公钥转换为Base64编码字符串
	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(解密、验签)

解密

// Go生成的私钥
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==";
// Go生成的密文
String base64EncryptedText = "U2PeiPR52FVkDuBWdTcg0Cu0SAiVIQ0GuPh8TYivP91rGwIf/nRQsZ5pznEVX3YPypV0caJWInk6p6HEW3D4C1mGnrnG5BttDTKIFneyN8Yv46LOg83Tykk+1vY47+OflLBPYX4zIFSLBUyQMPJUaFWAYmQ3Zy/32Bm2i3gl/H9foeM4Mf+BBdrv2jRKdm738e5V6xvOhQbcW7K4eav0MhX+0PXJPSlwgXch7Fh1dRj50Gb2srVYgvg/pshHIHEZgkfsry60xmn9qBkqFIHybqlow0l5632TMU3qDnLTXt1Z1goos0/QSzIRlWkwDr9IRMfo1H9AFcajrNRP1aJIpw==";
PrivateKey privateKey = getPrivateKeyFromBase64(base64PrivateKey);
// 将Base64编码的密文字符串转换为字节数组
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);
    }

验签

// Go 生成的公钥
String publicStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwsTqgcW8vD+Ac9mnE1T2DDP7Nu2voifcC4xS60gvtC8cDKhqMP3B/Vno2InJ06EP94VZFukXZlbQaIF5U2z5Dyp/iT+yPjQnG6ZBL9IjrPovL1rvcUkDZu+yqajvKM0FCz+NsPIzO8pjlRGjIlfGKC9Of1XutxUwlux5aR55NA0vXCN60giz4DK2HFIKQioITwOduEeYL1xinUpY7lGLkouPJRjrVvvcjzgb5QCeLS5vxQ6EsmrzcomnAKfnGar1dvSVUqJk0lu9nrWygJngRsotLG4VbwRVTklWH49rEr5fkPtaal4avtjCiXXNalHscv/nU/fwF1okKCIt5hmV+QIDAQAB";
// Go 生成的签名
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);

网站公告

今日签到

点亮在社区的每一天
去签到