银川企业网站建设,东莞网站主页制作,管理咨询师证书含金量,普宁房产网在公钥密码学中(也称为非对称密码学)#xff0c;加密机制依赖于两个密钥#xff1a;公钥和私钥。公钥用于加密消息#xff0c;而只有私钥的所有者才能解密消息。实际应用中通常需要对公钥和私钥进行序列化#xff0c;然后分发密钥实现在不同场景、不同语言环境中使用。本文… 在公钥密码学中(也称为非对称密码学)加密机制依赖于两个密钥公钥和私钥。公钥用于加密消息而只有私钥的所有者才能解密消息。实际应用中通常需要对公钥和私钥进行序列化然后分发密钥实现在不同场景、不同语言环境中使用。本文主要介绍如何生成RSA密钥对并序列化为文件最后使用密钥对进行跨语言应用。 概念介绍
RSA, 即 Rivest–Shamir–Adleman,是非对称加密算法。不同于对称加密算法(如AES、DES)它需要两个密钥公钥可共享给任何人用于加密信息私钥仅我们自己保存用于解密数据。 X.509 是定义公钥证书格式的标准用于描述公钥及其他信息。 PKCS8 是存储私钥的标准。为了安全起见可以使用对称加密算法对私钥再次进行加密。该标准不仅可以处理RSA私钥还可以处理其他算法。PKCS8私钥通常通过PEM编码格式进行交换。 DER 是最流行的数据存储编码格式如X.509证书文件、PKCS8私钥文件。它是二进制编码格式内容不能通过文本文件直接查看。 PEM 是对DER证书内容进行base64编码的机制PEM也能编码其他类型数据如公钥、私钥以及请求证书。PEM文件还可能包括一些格式信息示例如下
-----BEGIN PUBLIC KEY-----
...Base64 encoding of the DER encoded certificate...
-----END PUBLIC KEY-----生成RSA密钥对
正式开始加密之前需要生成RSA密钥对。可以使用java.security包中的KeyPairGenerator类实现
KeyPairGenerator generator KeyPairGenerator.getInstance(RSA);
generator.initialize(2048);
KeyPair pair generator.generateKeyPair();生成密钥为2048个字节下面可以生成公钥和私钥
PrivateKey privateKey pair.getPrivate();
PublicKey publicKey pair.getPublic();现在可以使用公钥加密数据私钥解密数据。在加密数据之前我们可能需要传输密钥下面先看看如何把密钥保存为文件。
保存密钥文件
把密钥对存储在内存中不是好的选项大多数情况下密钥不会变化因此可以存储为文件还可能需要分发给别人。
DER编码文件
通过getEncoded()方法返回密钥内容的字节数组
try (FileOutputStream fos new FileOutputStream(public.key)) {fos.write(publicKey.getEncoded());
}从文件中读取key返回字节数组
File publicKeyFile new File(public.key);
byte[] publicKeyBytes Files.readAllBytes(publicKeyFile.toPath());然后使用KeyFactory类重新创建密钥实例
KeyFactory keyFactory KeyFactory.getInstance(RSA);
EncodedKeySpec publicKeySpec new X509EncodedKeySpec(publicKeyBytes);
keyFactory.generatePublic(publicKeySpec);密钥字节内容需要使用EncodedKeySpec进行包装。这里使用X509EncodedKeySpec标准它是缺省标准。上面实例实现了公钥的保存和读取也可以使用同样方式实现对私钥的保存和读取。这里需要提醒的是尽可能保障私钥的安全我们还可以对私钥进行对称加密防止非法访问带来安全问题。
PEM编码文件
DER编码文件是二进制格式不能使用文本文件直接查看。下面介绍存储密钥为PEM编码文件即使用BASE64进行编码保存为文本文件。
首先是文件写入 Base64.Encoder encoder Base64.getEncoder();// 密钥对的文件名String outFile pairFileName;FileOutputStream out new FileOutputStream(outFile .key);out.write(encoder.encode(privateKey.getEncoded()));out.close();System.err.println(Private key format: privateKey.getFormat());out new FileOutputStream(outFile .pub);out.write(encoder.encode(publicKey.getEncoded()));out.close();System.err.println(Public key format: publicKey.getFormat());没有特别的部分仅使用encoder.encode进行Base64编码。
下面是读取过程 /* Read all the public key bytes */Path path Paths.get(fileName .pub);byte[] bytes Files.readAllBytes(path);Base64.Decoder deCoder Base64.getDecoder();/* Generate public key. */X509EncodedKeySpec ks new X509EncodedKeySpec(deCoder.decode(bytes));KeyFactory kf KeyFactory.getInstance(RSA);PublicKey publicKey kf.generatePublic(ks);System.err.println(Public key format: publicKey.getFormat());没有太多要解释的仅多了一步解码过程私钥的读取过程类似。
如果PEM文件包括格式信息则读取前需要先处理
public RSAPrivateKey readPrivateKey(File file) throws Exception {String key new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());Base64.Decoder deCoder Base64.getDecoder();String privateKeyPEM key.replace(-----BEGIN PRIVATE KEY-----, ).replaceAll(System.lineSeparator(), ).replace(-----END PRIVATE KEY-----, );byte[] encoded deCoder.decode(privateKeyPEM);KeyFactory keyFactory KeyFactory.getInstance(RSA);PKCS8EncodedKeySpec keySpec new PKCS8EncodedKeySpec(encoded);return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}RSA加密解密数据
加密过程
现在如何对简单字符串进行加密解密。首先定义明文字符串
String secretMessage These are secret messages;需要使用Cipher对象并初始化为公钥加密模式
Cipher encryptCipher Cipher.getInstance(RSA);
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);准备好cipher对象使用doFinal方法加密消息它的参数为字节数组因此调用前需要对字符串进行转换
byte[] secretMessageBytes secretMessage.getBytes(StandardCharsets.UTF_8);)
byte[] encryptedMessageBytes encryptCipher.doFinal(secretMessageBytes);啊哈终于成功加密了消息。如果需要在数据库中存储消息或通过REST API发送消息仍然需要使用BASE64进行编码
String encodedMessage Base64.getEncoder().encodeToString(encryptedMessageBytes);Base64.getEncoder()是apache commons提供的工具类。编码后消息更易使用、方便读取。
解密过程
现在解释解密密文为明文。仍然需要cipher实例这次初始化为解密模式同时需要传入私钥
Cipher decryptCipher Cipher.getInstance(RSA);
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);和前面一样执行DoFinal方法
byte[] decryptedMessageBytes decryptCipher.doFinal(encryptedMessageBytes);
String decryptedMessage new String(decryptedMessageBytes, StandardCharsets.UTF_8);需要说明的是如果是Base64格式需要先解码。
跨语言使用
我们使用Golang生成rsa密钥对然后通过java解密或验证。
golang生成密钥对
func main() {// Create the keys pairpriv, pub : GenerateRsaKeyPair()// Export the keys to pem stringpriv_pem : ExportRsaPrivateKeyAsPemStr(priv)pub_pem, _ : ExportRsaPublicKeyAsPemStr(pub)writeFile(priv_pem, pri.key)writeFile(pub_pem, pub.key)// 使用公钥加密文本var reqCode string These are secret messagesreqCodes, _ : rsa.EncryptPKCS1v15(rand.Reader, pub, []byte(reqCode))reqString : base64.StdEncoding.EncodeToString(reqCodes)writeFile(reqString, reqStr.txt)
} func writeFile(content string, fileName string) {file, _ : os.Create(fileName)defer file.Close()_, _ file.WriteString(content)
}func GenerateRsaKeyPair() (*rsa.PrivateKey, *rsa.PublicKey) {privkey, _ : rsa.GenerateKey(rand.Reader, 2048)return privkey, privkey.PublicKey
}func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) (string, error) {pubkey_bytes, err : x509.MarshalPKIXPublicKey(pubkey)if err ! nil {return , err}pubkey_pem : pem.EncodeToMemory(pem.Block{Type: RSA PUBLIC KEY,Bytes: pubkey_bytes,},)return string(pubkey_pem), nil
}func ExportRsaPrivateKeyAsPemStr(privkey *rsa.PrivateKey) string {privkey_bytes, _ : x509.MarshalPKCS8PrivateKey(privkey)privkey_pem : pem.EncodeToMemory(pem.Block{Type: RSA PRIVATE KEY,Bytes: privkey_bytes,},)return string(privkey_pem)
}
java用私钥解密
这里使用java8 进行解密
public static void main(String[] args) throws Exception {RsaTools tools new RsaTools();// 读取待解密文件内容byte[] deString Files.readAllBytes(Paths.get(reqStr.txt));String result tools.decrypt(new String(deString, StandardCharsets.UTF_8));System.out.println(result);
}// 从文件加载私钥
public PrivateKey readPrivateKey(File file) throws Exception {KeyFactory factory KeyFactory.getInstance(RSA);try (FileReader keyReader new FileReader(file);PemReader pemReader new PemReader(keyReader)) {PemObject pemObject pemReader.readPemObject();byte[] content pemObject.getContent();PKCS8EncodedKeySpec privKeySpec new PKCS8EncodedKeySpec(content);return factory.generatePrivate(privKeySpec);}
}// 利用私钥解密
public String decrypt(String deStr) throws Exception {Cipher decryptCipher Cipher.getInstance(RSA);PrivateKey privateKey readPrivateKey(new File(pri.key));decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);// 密文需要使用Base64解码byte[] decryptedMessageBytes decryptCipher.doFinal(Base64.getDecoder().decode(deStr));String decryptedMessage new String(decryptedMessageBytes, StandardCharsets.UTF_8);return decryptedMessage;
}总结
本文介绍了如何生成RSA密钥对并利用相关标准生成密钥文件最后通过实例展示如何实现跨语言应用。