RSA加密分为公钥加密和私钥解密以及可能的数字签名。
公钥、私钥分居客户端和服务器端,分别用于加密和解密。同时,私钥还用于签名,公钥还用于验证签名。
解密加密用到JDK中java.security、javax.crypto两个包中相关的接口和类
1.生成密钥的代码
- SecureRandom sr = new SecureRandom();
- KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA");
- // 注意密钥大小最好为1024,否则解密会有乱码情况.
- kg.initialize(1024, sr);
- KeyPair kp = kg.generateKeyPair();
- String privateKeyName = keyFile.substring(0,keyFile.lastIndexOf("."))+"_private"+keyFile.substring(keyFile.lastIndexOf("."));
- String publicKeyName = keyFile.substring(0,keyFile.lastIndexOf("."))+"_public"+keyFile.substring(keyFile.lastIndexOf("."));
- FileOutputStream fos = new FileOutputStream(privateKeyName);
- ObjectOutputStream oos = new ObjectOutputStream(fos);
- // 生成私钥
- oos.writeObject(kp.getPrivate());
- oos.close();
- //生成公钥
- fos = new FileOutputStream(publicKeyName);
- oos = new ObjectOutputStream(fos);
- oos.writeObject(kp.getPublic());
- oos.close();
2.加密、解密(RSA加密速度比较慢,原因是每次只能为最多117 bytes加密,加密之后为128 Bytes)
- //加密
- Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
- cipher.init(Cipher.ENCRYPT_MODE, (PublicKey)getKey(keyFile,"public"));
- return cipher.doFinal(text);
- //加密
- Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
- cipher.init(Cipher.DECRYPT_MODE, (PrivateKey)getKey(keyFile,"private"));
- return cipher.doFinal(text);
3.用私钥进行数字签名,用于服务器端验证客户端数据是否是正确数据。
- public byte[] getSignature(byte[] cipherText){
- try {
- coder = new RSASecurityCoder();
- Signature sig = Signature.getInstance("SHA1withRSA");
- PrivateKey privateKey = (PrivateKey)coder.getKey(this.key, "private");
- sig.initSign(privateKey);
- sig.update(cipherText);
- return sig.sign();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- public boolean verifySignature(byte[] cipherText,byte[] signature){
- try {
- coder = new RSASecurityCoder();
- Signature sig = Signature.getInstance("SHA1withRSA");
- PublicKey publicKey = (PublicKey)coder.getKey(this.key, "public");
- sig.initVerify(publicKey);
- sig.update(cipherText);
- return sig.verify(signature);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return false;
- }
数字签名是在客户端进行,所用的私钥不是和用于加密的公钥成对的。
也就是说这样的通信 要在客户端保存有 服务器端的公钥和本地的私钥,而服务器端应该保存有本地的私钥和客户端的公钥。