您的位置:首页 > 编程语言 > Java开发

jsrsasign 前台签名,Java后台验证前台签名

2015-06-17 14:04 239 查看
rsa 具体是什么 这个就不在多说。算法实现啊应用啊 已经有很多了。今天记录下 这种特殊的需求,前台签名,后台验证

Java后台产生 密匙对

pom.xml 添加BC 依赖

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.51</version>
</dependency>


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 包含:

Signature - RSA/RSAPSS/ECDSA/DSA digital signtature class wrapper of Java JCE style

MessageDigest - cryptographic hash calculation class wrapper of Java JCE style

MAC - message authentication code hash calculation class wrapper of Java JCE style

ASN.1 encoder/generator

ASN.1 structure for X.509 ceritificate, CRL and CSR(PKCS#10) generation

ASN.1 structure for CMS SignedData generation

ASN.1 structure for RFC 3161 TimeStamp generation

ASN.1 structure for RFC 5126 CAdES Long Term Signature generation

simple ASN.1 data parser

simple X.509 certificate parser/reader

KEYUTIL - loading RSA/EC/DSA private/public key from PEM formatted PKCS#1/5/8 and X.509 certificate

JSON Web Siguature(JWS), JSON Web Token(JWT) and JSON Web Key(JWK)

更多的详细 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 可以通过签名。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: