rsa 具体是什么 这个就不在多说。算法实现啊应用啊 已经有很多了。今天记录下 这种特殊的需求,前台签名,后台验证
Java后台产生 密匙对
pom.xml 添加BC 依赖
org.bouncycastle
bcprov-jdk15on
1.51
RSATools
package com.oscgc.securevideo.server.tool.rsa;
import java.io.IOException;
import java.io.StringWriter;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.util.io.pem.PemObject;
/**
* Created by Yq on 2015/6/10.
*/
public class RsaKeyTools {
public static final String PEM_PUBLICKEY = "PUBLIC KEY";
public static final String PEM_PRIVATEKEY = "PRIVATE KEY";
/**
* generateRSAKeyPair
*
* @param keySize
* @return
*/
public static KeyPair generateRSAKeyPair(int keySize) {
KeyPairGenerator generator = null;
SecureRandom random = new SecureRandom();
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
try {
generator = KeyPairGenerator.getInstance("RSA", "BC");
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (NoSuchProviderException e) {
e.printStackTrace();
}
generator.initialize(keySize, random);
KeyPair keyPair = generator.generateKeyPair();
return keyPair;
}
/**
* convertToPemKey
*
* @param publicKey
* @param privateKey
* @return
*/
public static String convertToPemKey(RSAPublicKey publicKey,
RSAPrivateKey privateKey) {
if (publicKey == null && privateKey == null) {
return null;
}
StringWriter stringWriter = new StringWriter();
try {
PEMWriter pemWriter = new PEMWriter(stringWriter, "BC");
if (publicKey != null) {
pemWriter.writeObject(new PemObject(PEM_PUBLICKEY,
publicKey.getEncoded()));
}
else { //此处产生的privatekey 的格式是 PKCS#8 的格式
pemWriter.writeObject(new PemObject(PEM_PRIVATEKEY,
privateKey.getEncoded()));
}
pemWriter.flush();
}
catch (IOException e) {
e.printStackTrace();
}
return stringWriter.toString();
}
public static byte[] sign(String data, byte[] privateKey) throws Exception {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(privateKey2);
signature.update(data.getBytes());
return signature.sign();
}
//后台测试签名的时候 要和前台保持一致,所以需要将结果转换
private static String bytes2String(byte[] bytes) {
StringBuilder string = new StringBuilder();
for (byte b : bytes) {
String hexString = Integer.toHexString(0x00FF & b);
string.append(hexString.length() == 1 ? "0" + hexString : hexString);
}
return string.toString();
}
public static boolean verify(String data,
byte[] publicKey,
byte[] signatureResult) {
try {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(publicKey2);
signature.update(data.getBytes());
return signature.verify(signatureResult);
}
catch (Exception e) {
e.printStackTrace();
}
return false;
}
//前台的签名结果是将byte 中的一些 负数转换成了正数, //但是后台验证的方法需要的又必须是转换之前的
public static byte[] hexStringToByteArray(String data) {
int k = 0;
byte[] results = new byte[data.length() / 2];
for (int i = 0; i + 1 < data.length(); i += 2, k++) {
results[k] = (byte) (Character.digit(data.charAt(i), 16) << 4);
results[k] += (byte) (Character.digit(data.charAt(i + 1), 16));
}
return results;
}
public static void main(String[] args) {
String str = "coder";
KeyPair k = generateRSAKeyPair(1024);
String publicKey = convertToPemKey((RSAPublicKey) k.getPublic(), null);
String privateKey = convertToPemKey(null,
(RSAPrivateKey) k.getPrivate());
System.out.println("publicKey__\n" + publicKey);
System.out.println("privateKey_\n" + privateKey);
try {
byte[] signautreResult = sign(str, k.getPrivate().getEncoded());
String signatureStr = bytes2String(signautreResult);
byte[] signatureResult2 = hexStringToByteArray(signatureStr);
boolean b = verify(str,
k.getPublic().getEncoded(),
signatureResult2);
System.out.print("iii " + b);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Javascript 签名用到的lib 是 jsrsasign 包含:
更多的详细 github 地址:https://kjur.github.io/jsrsasign/
在官网给定的签名例子代码如下:
function doSign() {
var rsa = new RSAKey();
rsa.readPrivateKeyFromPEMString(document.form1.prvkey1.value);
var hashAlg = document.form1.hashalg.value;
var hSig = rsa.signString(document.form1.msgsigned.value, hashAlg);
document.form1.siggenerated.value = linebrk(hSig, 64);
}
这里我们需要改动一下:
rsa.readPrivateKeyFromPEMString(document.form1.prvkey1.value);官方api 中对这个方法有这样的说明:
readPrivateKeyFromPEMString(keyPEM)
read PKCS#1 private key from a string
这个方法传入的privatekey 是需要 PKCS#1 格式的,但是后台 产生出来的private key 是PKCS#8的格式的,这里就不能用这个方法,签名会通不过。
查看jsrsasign 的 api
KEYUTIL - loading RSA/EC/DSA private/public key from PEM formatted PKCS#1/5/8 and X.509 certificate
因此 js 生成RSAkey 对象
rsa=KEYUTIL.getKey(document.form1.prvkey1.value);
这个方法支持PKCS#8 pem 格式的privatekey 可以通过签名。
来源:https://www.cnblogs.com/yqweber/p/4583140.html