Rsa签名算法详解
签名生成规则与验证签名规则如下:
①每次生成签名时该算法都会生成一对对应的公钥和私钥对,
②所以在应用中一般都会采取使用同一对密钥对进行签名与验签(建议使用静态变量)保证对方验证签名时用的公钥是与你生成签名用的是同一对,否则就不能通过验证
③将自己生成的秘钥对中的公钥交给对方用来验证你的签名,私钥用来生成签名
④同样的对方也会选定一组密钥对将公钥给你用来验证签名,用他的私钥来生成签名
⑤备注:一般对安全性要求比较高的企业,不仅仅限与用rsa签名来保证安全,还会对rsa签名再次加密,比如本案例就使用了base64来加密和解密,同样大家也可以采取其他的措施来增加安全性比如:aes等
注意事项:
①在获取对方的签名的时候注意是否有 系统会自动生成空格(尤其是签名串在换行的时候)
②在拼装对方的加密串转换成byte类型时注意是否跟对方的 字符编码保持一致
①每次生成签名时该算法都会生成一对对应的公钥和私钥对,
②所以在应用中一般都会采取使用同一对密钥对进行签名与验签(建议使用静态变量)保证对方验证签名时用的公钥是与你生成签名用的是同一对,否则就不能通过验证
③将自己生成的秘钥对中的公钥交给对方用来验证你的签名,私钥用来生成签名
④同样的对方也会选定一组密钥对将公钥给你用来验证签名,用他的私钥来生成签名
⑤备注:一般对安全性要求比较高的企业,不仅仅限与用rsa签名来保证安全,还会对rsa签名再次加密,比如本案例就使用了base64来加密和解密,同样大家也可以采取其他的措施来增加安全性比如:aes等
注意事项:
①在获取对方的签名的时候注意是否有 系统会自动生成空格(尤其是签名串在换行的时候)
②在拼装对方的加密串转换成byte类型时注意是否跟对方的 字符编码保持一致
具体的实现代码如下
package com.xxx.web.util; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** * @Description: (签名工具类) * @author keguan_li * @date 2016年9月22日 */ public class RSAUtils { /** */ /** * 加密算法RSA */ public static final String KEY_ALGORITHM = "RSA"; /** */ /** * 签名算法 */ public static final String SIGNATURE_ALGORITHM = "MD5withRSA";//有几种算法MD5withRSA是其中一种 public static final String CHARSET = "UTF-8"; /** * initKey()生成公钥与私钥 * 将生成的公钥与对方互换 * 因为每次生成签名的时候公钥和私钥都会随机变化(一对密钥对) * 所以要将自己的私钥和对方的公钥设成静态变量 * 保证每次生成签名用的都是同一个私钥 */ public static final String privateKey="MIICeAIB2QcCQQCvpSVi/IElHyzvvPxRKsTYz/Z"; public static final String publicKey="MIGfMA0GCSqGSvcuK3QJ3i9ZhBpOoyd4JOwIDAQAB"; /** * 生成签名 * @param retSignPacket * @param strPriKey * @return * @throws Exception */ public static String addSign(String retSignPacket) throws Exception{ byte[] bytesKey = decryptBASE64(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(bytesKey); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(priKey); signature.update(retSignPacket.getBytes(CHARSET)); String sign = encryptBASE64(signature.sign()); return sign; } /** * 校验数字签名 * * @param data * 加密数据 * @param publicKey * 公钥 * @param sign * 数字签名 * * @return 校验成功返回true 失败返回false * @throws Exception * */ public static boolean verify(byte[] data, String sign) throws Exception { // 解密由base64编码的公钥 byte[] keyBytes = decryptBASE64(publicKey); // 构造X509EncodedKeySpec对象 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); // KEY_ALGORITHM 指定的加密算法 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 取公钥匙对象 PublicKey pubKey = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(pubKey); signature.update(data); // 验证签名是否正常 boolean ret = signature.verify(decryptBASE64(sign)); System.out.println("验签结果:" + ret); return ret; } public static Map<String, Object> initKey() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); // 公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put("RSAPublicKey", encryptBASE64(publicKey.getEncoded())); keyMap.put("RSAPrivateKey", encryptBASE64(privateKey.getEncoded())); System.out.println("私钥为(生成签名用) : "); String priKey = encryptBASE64(privateKey.getEncoded()); System.out.println(priKey); System.out.println("*****************"); System.out.println("公钥为(验证签名用) : "); String pubKey = encryptBASE64(publicKey.getEncoded()); System.out.println(pubKey); return keyMap; } /** * BASE64解密 * * @param key * @return * @throws Exception */ @SuppressWarnings("restriction") public static byte[] decryptBASE64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); } /** * BASE64加密 * * @param key * @return * @throws Exception */ @SuppressWarnings("restriction") public static String encryptBASE64(byte[] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); } public static void main(String[] args) throws Exception { initKey();//该方法生成签名,私钥本地用于本地签名,公钥交给对方用于验证你的签名 addSign("a");//生成签名的方法,a为你要生成签名的签名串,还有用于生成签名的私钥,已写成静态常量 verify("a".getBytes(),"b");//验证签名的方法,a为你拼接的对方的加密串(在转成byte时字符集编码要与对方的字符集编码保持一致),b为对方的签名,还有对方的公钥我已经将其写成静态常量了 } }