一、加密算法分类
1、密钥
密钥,一般就是一个字符串或数字,在加密或者解密时传递给加密或解密算法,以使算法能够正确对明文加密或者对密文解密。
2、加密算法分类
大体上分为单向加密和双向加密。
2.1、单向加密
单向加密就是非可逆加密,就是不可解密的加密方法,由于其在加密后会生成唯一的加密串,故而经常用于检测数据传输过程中是否被修改。常见的单向加密有MD5、SHA、HMAC。我们只是把他们作为加密的基础,单纯的以上三种加密并不可靠。
2.2、双向加密
双向加密又可以分为对称加密和非对称加密。如果你想进行加解密操作的时候需要具备两样东西:密钥和加解密算法。
2.3、对称加密
对称加密算法的特点是加密使用的密钥和解密使用的密钥是相同的。也就是说,加密和解密都是使用的同一个密钥。因此对称加密算法要保证安全性的话,密钥自然要做好保密,只能让使用的人知道,不能对外公开。
2.4、非对称加密
在非对称加密算法中,有公钥的私钥两种密钥,其中 ,公钥是公开的,不需要保密,私钥由个人持有,必须妥善保管和注意保密。加密和解密使用两种不同的密钥,是它得名的原因。常见的、应用很广的非对称加密算法:RSA。
二、RSA
1、RSA加密算法是一种非对称加密算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。这样就可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程,分别称为公钥和私钥。两者之间有数字相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥,公钥是公开的(可能同时多人持有)。
2、RSA加密、签名区别
加密和签名都是为了安全性考虑,但略有不同。常有人问加密和签名是用私钥还是公钥?其实都是对加密和签名的作用有所混淆。简单的说,加密是为了防止信息被泄露,而签名是为了防止信息被篡改。这里举两个例子说明:
第一个场景:战场上,B要给A传递一条信息,内容指令为:坚守阵地!
RSA的加密过程如下:
(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留;公钥为公开的,任何人可以获取。
(2)A传递自己的公钥给B,B用A的公钥对消息进行加密。
(3)A接收到B的加密信息,利用A自己的私钥对消息进行解密。
在这个过程中,只有两次传递过程,第一次是A传递公钥给B,第二次是B传递加密信息给A,即使敌方截获,也没有危险性,因为只有A的私钥才能对消息进行解密,防止了消息内容的泄露。
第二个场景:A收到B发的加密信息后,需要进行回复“收到”。
RSA的签名过程如下:
(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留;公钥为公开的,任何人可以获取。
(2)A用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给B。
(3)B收到消息后,再获取A的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是A回复的。
在这个过程中,只有两次传递过程,第一次是A传递加签的消息和消息本身给B,第二次是B获取A的公钥,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带签名的回复给B,防止了消息内容的篡改。
但是,综合两个场景会发现。第一个场景虽然被截获的消息没有泄露,但是可以利用截获的公钥,将假指令进行加密,然后传递给A。第二个场景虽然截获的消息不能被篡改,但是消息的内容可以利用公钥验签来获得,并不能防止被泄露。所以在实际应用中,要根据具体情况使用,也可以同时使用加密和签名,比如A和B都有一套自己的公钥和私钥,当A要给B发送消息时,先用B的公钥对消息加密,再对加密的消息使用A的私钥加签名,达到既不泄露也不被篡改,更能保证消息的安全性。
总结:公钥加密、私钥解密、私钥签名、公钥验签。
三、Java中RSA签名算法实现
package cn.csdn.rsa;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
* @author kyrie
* @Description: Java实现RSA签名算法
* @date 2022/1/24 13:54
*/
public class RSACoder {
//非对称加密算法
public static final String KEY_ALGORITHM = "RSA";
//数字签名 签名/验证算法
public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
//公钥
private static final String PUBLIC_KEY = "RSAPublicKey";
//私钥
private static final String PRIVATE_KEY = "RSAPrivateKey";
//RSA密钥长度默认1024位,密钥长度必须是64的倍数,范围在512-65536位之间
private static final int KEY_SIZE = 512;
/**
* 私钥解密
*/
public static byte[] decryptByPrivateKey(byte[] data, byte[] key)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
//取得私钥
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//对数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 公钥解密
*/
public static byte[] decryptByPublicKey(byte[] data, byte[] key)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
//取得公钥
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成公钥
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
//对数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* 公钥加密
*/
public static byte[] encryptByPublicKey(byte[] data, byte[] key)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
//取得公钥
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成公钥
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
//对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* 私钥加密
*/
public static byte[] encryptByPrivateKey(byte[] data, byte[] key)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
//取得私钥
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 取得私钥
*/
public static byte[] getPrivateKey(Map<String, Object> keyMap)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return key.getEncoded();
}
/**
* 取得公钥
*/
public static byte[] getPublicKey(Map<String, Object> keyMap)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return key.getEncoded();
}
/**
* 初始化密钥
*/
public static Map<String, Object> initKey() throws NoSuchAlgorithmException {
//实例化密钥生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
//初始化密钥对生成器
keyPairGenerator.initialize(KEY_SIZE);
//生成密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
//公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
//封装密钥
Map<String, Object> keyMap = new HashMap<>();
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 签名
*
* @param data 待签名数据
* @param privateKey 私钥
* @return 数字签名
*/
public static byte[] sign(byte[] data, byte[] privateKey)
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
//转换私钥材料
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey);
//实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//取私钥对象
PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//实例化Signature
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
//初始化Signature
signature.initSign(priKey);
//更新
signature.update(data);
//签名
return signature.sign();
}
/**
* 公钥校验
*
* @param data 待校验数据
* @param publicKey 公钥
* @param sign 数字签名
* @return 校验成功返回true 失败返回false
*/
public static boolean verify(byte[] data, byte[] publicKey, byte[] sign)
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
//转换公钥材料
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
//实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成公钥
PublicKey pubKey = keyFactory.generatePublic(keySpec);
//实例化Signature
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
//初始化Signature
signature.initVerify(pubKey);
//更新
signature.update(data);
//验证
return signature.verify(sign);
}
/**
* 私钥签名
*
* @param data 待签名数据
* @param privateKey 私钥
* @return 十六进行签名字符串
*/
public static String sign(byte[] data, String privateKey)
throws DecoderException, InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
byte[] sign = sign(data, getKey(privateKey));
return Hex.encodeHexString(sign);
}
/**
* 公钥校验
*
* @param data 待校验数据
* @param publicKey 公钥
* @param sign 签名
* @return 成功返回true,失败返回false
*/
public static boolean verify(byte[] data, String publicKey, String sign)
throws DecoderException, InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
return verify(data, getKey(publicKey), Hex.decodeHex(sign.toCharArray()));
}
/**
* 私钥加密
*/
public static byte[] encryptByPrivateKey(byte[] data, String key)
throws DecoderException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
return encryptByPrivateKey(data, getKey(key));
}
/**
* 公钥加密
*/
public static byte[] encryptByPublicKey(byte[] data, String key)
throws DecoderException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
return encryptByPublicKey(data, getKey(key));
}
/**
* 私钥解密
*/
public static byte[] decryptByPrivateKey(byte[] data, String key)
throws DecoderException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
return decryptByPrivateKey(data, getKey(key));
}
/**
* 公钥解密
*/
public static byte[] decryptByPublicKey(byte[] data, String key)
throws DecoderException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
return decryptByPublicKey(data, getKey(key));
}
/**
* 初始化密钥
*
* @return 十六进制编码密钥
*/
public static String getPrivateKeyString(Map<String, Object> keyMap)
throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
// return Base64.encodeBase64String(getPrivateKey(keyMap));
return Hex.encodeHexString(getPrivateKey(keyMap));
}
/**
* 初始化密钥
*
* @return 十六进制编码密钥
*/
public static String getPublicKeyString(Map<String, Object> keyMap)
throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
// return Base64.encodeBase64String(getPublicKey(keyMap));
return Hex.encodeHexString(getPublicKey(keyMap));
}
/**
* 获取密钥
*
* @param key 密钥
* @return 密钥
*/
public static byte[] getKey(String key) throws DecoderException {
return Hex.decodeHex(key.toCharArray());
// return Base64.decodeBase64(key);
}
public static void main(String[] args)
throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidKeySpecException, NoSuchPaddingException, DecoderException, SignatureException {
Map<String, Object> keyMap = RSACoder.initKey();
//获取并打印公钥
String publicKey = RSACoder.getPublicKeyString(keyMap);
System.out.println("publicKey=" + publicKey);
//获取并打印私钥
String privateKey = RSACoder.getPrivateKeyString(keyMap);
System.out.println("privateKey=" + privateKey);
// 公钥加密、私钥解密
String inputStr = "有内鬼终止交易,密文代码:001002003007";
byte[] data = inputStr.getBytes();
System.out.println("原文:" + inputStr);
byte[] encodeData = RSACoder.encryptByPublicKey(data, publicKey);
System.out.println("加密后:" + Hex.encodeHexString(encodeData));
byte[] decodeData = RSACoder.decryptByPrivateKey(encodeData, privateKey);
System.out.println("解密后:" + new String(decodeData));
//私钥签名、公钥校验
String sign = RSACoder.sign(data, privateKey);
System.out.println("签名后:" + sign);
System.out.println("校验=" + RSACoder.verify(data, publicKey, sign));
}
}
代码原文:JAVA中RSA签名算法实现 - 兵阳的个人页面 - OSCHINA - 中文开源技术交流社区
青年人的责任重大!努力吧...