天天看點

數字簽名算法

數字簽名算法主要包含RSA、DSA、ECDSA三種算法

1. 它的消息傳遞操作是:

  • 由消息發送方建構密匙對,
  • 由消息發送的一方公布公鑰至消息接收方,
  • 消息發送方對消息用私鑰做簽名處理
  • 消息接收方用公鑰對消息做驗證

2. RSA簽名算法主要分為MD系列和SHA系列。具體實作如下:

數字簽名算法

3. RSA的數字簽名代碼實作:

DSA簽名實作類似,ECDSA實作相比前兩者在密匙對成功的方式上存在差别。

import org.apache.commons.codec.binary.Base64;

import java.security.*;
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;

public class RSASignature {

    private static final String KEY_ALGORITHM="RSA";
    private static final String SIGNATURE_ALGORITHM="MD5withRSA";
    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 void main(String[] args) throws Exception {

        String str = "hello vison";
        Map<String, Object> map = initKey();
        byte[] privateKey = getPrivateKey(map);
        //簽名
        byte[] signData = sign(str.getBytes(), privateKey);
        System.out.println("signData: " + Base64.encodeBase64(signData));
        //校驗
        byte[] pulicKey = getPulicKey(map);
        boolean status = verify(str.getBytes(), pulicKey, signData);
        System.out.println("verify result: " + status);

    }

    /**
     *
     * @param data 待校驗的資料
     * @param key 公鑰
     * @param sign 資料簽名
     * @return boolean 校驗成功傳回true,否則傳回false
     * @throws Exception
     */
    public static boolean verify(byte[] data,byte[] key,byte[] sign)throws Exception{
        //擷取公鑰
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        //校驗資料
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(sign);
    }
    /**
     * 私鑰簽名
     * @param data 待簽名資料
     * @param key 私鑰
     * @return byte[] 加密資料
     * @throws Exception
     */
    public static byte[] sign(byte[] data,byte[] key) throws Exception {
        //擷取私鑰
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        //簽名
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
    }
    /**
     * 擷取私鑰
     * @param keyMap
     * @return
     */
    public static byte[] getPrivateKey(Map<String,Object> keyMap){
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return key.getEncoded();
    }
    /**
     * 擷取公鑰
     * @param keyMap
     * @return
     */
    public static byte[] getPulicKey(Map<String,Object> keyMap){
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return key.getEncoded();

    }
    /**
     * 初始化密匙對
     * @return Map 密鑰map
     * @throws Exception
     */
    public static Map<String,Object> initKey() throws Exception {
        //執行個體化密鑰對生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化
        keyPairGenerator.initialize(KEY_SIZE);
        //生成密匙對
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        //私鑰
        RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
        //公鑰
        RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
        //封裝密鑰
        HashMap<String, Object> map = new HashMap<>(2);
        map.put(PUBLIC_KEY,publicKey);
        map.put(PRIVATE_KEY,privateKey);
        return map;
    }
}