一、概述
1.數(shù)字簽名算法可以看做是一個(gè)帶有密鑰的消息摘要算法切心,并且這個(gè)密鑰包括了公鑰和私鑰朽寞。他是非對(duì)稱加密算法和消息摘要算法的結(jié)合體
2.數(shù)字簽名算法是公鑰基礎(chǔ)設(shè)施(PKI)挂洛,以及許多網(wǎng)絡(luò)安全機(jī)制的基礎(chǔ)
3.數(shù)字簽名算法有抗否認(rèn)的作用
4.遵循“私鑰簽名,公鑰驗(yàn)證”規(guī)則
5.常見的數(shù)字簽名算法有RSA/DSA/ECDSA
6.java6支持實(shí)現(xiàn)了DSA算法超营、部分RSA算法需要bouncycastle支持鸳玩,最牛的ECDSA算法(微軟用來做操作系統(tǒng)序列號(hào)的那個(gè))完全需要Bouncycastle支持
二、模型分析
1.甲方構(gòu)造密鑰對(duì)(公鑰+私鑰)演闭,公布公鑰給乙方
2.甲方使用私鑰對(duì)數(shù)據(jù)進(jìn)行簽名不跟,然后將“簽名+數(shù)據(jù)” 發(fā)送給乙方
3.乙方使用公鑰+數(shù)字簽名 驗(yàn)證數(shù)據(jù)
三、代碼分析
package com.ca.test;
import java.security.Key;
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 org.apache.commons.codec.binary.Base64;
/**
* 經(jīng)典的數(shù)字簽名算法RSA
* 數(shù)字簽名
* @author kongqz
* */
public class RSACoder {
//數(shù)字簽名米碰,密鑰算法
public static final String KEY_ALGORITHM="RSA";
/**
* 數(shù)字簽名
* 簽名/驗(yàn)證算法
* */
public static final String SIGNATURE_ALGORITHM="MD5withRSA";
/**
* RSA密鑰長度窝革,RSA算法的默認(rèn)密鑰長度是1024
* 密鑰長度必須是64的倍數(shù),在512到65536位之間
* */
private static final int KEY_SIZE=512;
//公鑰
private static final String PUBLIC_KEY="RSAPublicKey";
//私鑰
private static final String PRIVATE_KEY="RSAPrivateKey";
/**
* 初始化密鑰對(duì)
* @return Map 甲方密鑰的Map
* */
public static Map<String,Object> initKey() throws Exception{
//實(shí)例化密鑰生成器
KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);
//初始化密鑰生成器
keyPairGenerator.initialize(KEY_SIZE);
//生成密鑰對(duì)
KeyPair keyPair=keyPairGenerator.generateKeyPair();
//甲方公鑰
RSAPublicKey publicKey=(RSAPublicKey) keyPair.getPublic();
//甲方私鑰
RSAPrivateKey privateKey=(RSAPrivateKey) keyPair.getPrivate();
//將密鑰存儲(chǔ)在map中
Map<String,Object> keyMap=new HashMap<String,Object>();
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 簽名
* @param data待簽名數(shù)據(jù)
* @param privateKey 密鑰
* @return byte[] 數(shù)字簽名
* */
public static byte[] sign(byte[] data,byte[] privateKey) throws Exception{
//取得私鑰
PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(privateKey);
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//生成私鑰
PrivateKey priKey=keyFactory.generatePrivate(pkcs8KeySpec);
//實(shí)例化Signature
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
//初始化Signature
signature.initSign(priKey);
//更新
signature.update(data);
return signature.sign();
}
/**
* 校驗(yàn)數(shù)字簽名
* @param data 待校驗(yàn)數(shù)據(jù)
* @param publicKey 公鑰
* @param sign 數(shù)字簽名
* @return boolean 校驗(yàn)成功返回true见间,失敗返回false
* */
public static boolean verify(byte[] data,byte[] publicKey,byte[] sign) throws Exception{
//轉(zhuǎn)換公鑰材料
//實(shí)例化密鑰工廠
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公鑰
//密鑰材料轉(zhuǎn)換
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(publicKey);
//產(chǎn)生公鑰
PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
//實(shí)例化Signature
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
//初始化Signature
signature.initVerify(pubKey);
//更新
signature.update(data);
//驗(yàn)證
return signature.verify(sign);
}
/**
* 取得私鑰
* @param keyMap 密鑰map
* @return byte[] 私鑰
* */
public static byte[] getPrivateKey(Map<String,Object> keyMap){
Key key=(Key)keyMap.get(PRIVATE_KEY);
return key.getEncoded();
}
/**
* 取得公鑰
* @param keyMap 密鑰map
* @return byte[] 公鑰
* */
public static byte[] getPublicKey(Map<String,Object> keyMap) throws Exception{
Key key=(Key) keyMap.get(PUBLIC_KEY);
return key.getEncoded();
}
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//初始化密鑰
//生成密鑰對(duì)
Map<String,Object> keyMap=RSACoder.initKey();
//公鑰
byte[] publicKey=RSACoder.getPublicKey(keyMap);
//私鑰
byte[] privateKey=RSACoder.getPrivateKey(keyMap);
System.out.println("公鑰:/n"+Base64.encodeBase64String(publicKey));
System.out.println("私鑰:/n"+Base64.encodeBase64String(privateKey));
System.out.println("================密鑰對(duì)構(gòu)造完畢,甲方將公鑰公布給乙方聊闯,開始進(jìn)行加密數(shù)據(jù)的傳輸=============");
String str="RSA數(shù)字簽名算法";
System.out.println("原文:"+str);
//甲方進(jìn)行數(shù)據(jù)的加密
byte[] sign=RSACoder.sign(str.getBytes(), privateKey);
System.out.println("產(chǎn)生簽名:"+Base64.encodeBase64String(sign));
//驗(yàn)證簽名
boolean status=RSACoder.verify(str.getBytes(), publicKey, sign);
System.out.println("狀態(tài):"+status+"/n/n");
}
}
控制臺(tái)輸出:
公鑰:
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJXmcnNTaWUnib5uMMQI2VCAq/rCPoFonlGHBVhDatRH
GLEkZ2z/PiT1RxrmBdRxAb50LoNYGUOvOCieOJqU4B8CAwEAAQ==
私鑰:
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAleZyc1NpZSeJvm4wxAjZUICr+sI+
gWieUYcFWENq1EcYsSRnbP8+JPVHGuYF1HEBvnQug1gZQ684KJ44mpTgHwIDAQABAkBUaU3f5YO/
Q7GMe+6YJceCTsMJ1WJvayNkE52N44EAAhkfmbpmhwdcRgo0CnzAsiXdPeB1inynbnv1ornu/AlZ
AiEA/iTqVvxeYFjaYfvi38OxfNNeqpBMiPjv3XlYzEs4vR0CIQCW/qm+3Lv9YpLlqWGipBBrHGfu
yv4spXxiY/mkbh4ZawIhAO14JvOSqsjSHXSS/WHipFSj2H/9h1YxbUf/3AZAf0rNAiA88cTpuIZY
G3VXJSq3Tqkh0nFQvLYipxixTdDxQVD8yQIhAIgXKKDfKeEXdmx3untvAo1zh3//MhVoo3JygBsR
gSYn
================密鑰對(duì)構(gòu)造完畢,甲方將公鑰公布給乙方,開始進(jìn)行加密數(shù)據(jù)的傳輸=============
原文:RSA數(shù)字簽名算法
產(chǎn)生簽名:dxlBzv3voS7YDaaNCrUaIw7ITfHHDrdfwry9d5gSbMhKPWWfBecx0jA8jPmRuYQW2iViCDHUs3n7
Smu3VZDuZw==
狀態(tài):true
四米诉、總結(jié)
1.簽名算法對(duì)非對(duì)稱加密算法RSA的公鑰私鑰的使用是核心,配合信息摘要算法完成簽名操作篷帅。其實(shí)簽名看起來就是信息的摘要而已
2.密鑰處理方面和非對(duì)稱加密算法無異史侣,只是將加密、解密換成簽名魏身、驗(yàn)證
3.RSA的數(shù)字簽名算法的密鑰實(shí)現(xiàn)與RSA加密算法一致惊橱。所以簽名算法可以分為MD系列和SHA系列