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

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

  • 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  可以通过签名。

 

jsrsasign 前台签名,Java后台验证前台签名_第1张图片

转载于:https://my.oschina.net/hejunbinlan/blog/1475337

你可能感兴趣的:(java,javascript,后端)