eclipse實現ECDSA數字簽名
ECDSA數字簽名,供大家參考,具體內容如下
一,實驗目的
通過使用密碼學庫實現基於橢圓曲線的簽名方案,能夠編寫簡單的實驗程式碼進行正確的ECDSA簽名和驗證。
二、 實驗要求
熟悉ECDSA演算法基本原理;
瞭解如何使用Java簡單實現用ECDSA演算法;
掌握用ECDSA簽名演算法的簡單程式碼實驗。
三、開發環境
JDK1.8,Java相關開發環境(本實驗採用Windows+eclipse作為實驗環境)要求參與實驗的同學提前安裝好jdk
四、實驗內容
【1-1】ECDSA簽名和驗證實驗
1.使用如下的函式進行系統初始化併產生金鑰:
public static void KeyGenerator() throws Exception { // //初始化簽名 System.out.println("系統正在初始化……"); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); keyPairGenerator.initialize(256); KeyPair keyPair = keyPairGenerator.generateKeyPair(); ECPublicKey ecPublicKey = (ECPublicKey)keyPair.getPublic(); ECPrivateKey ecPrivateKey = (ECPrivateKey)keyPair.getPrivate(); //把公鑰和私鑰分別儲存在publicKey.key和privateKey.key檔案裡 String path = new File("").getCanonicalPath(); out(path + "\\privateKey.key",Base64.getEncoder().encodeToString(ecPrivateKey.getEncoded())); out(path + "\\publicKey.key",Base64.getEncoder().encodeToString(ecPublicKey.getEncoded())); System.out.println("你的公鑰存放在:" + path + "\\publicKey.key"); System.out.println("你的私鑰存放在:" + path + "\\privateKey.key"); System.out.println("系統已完成初始化。"); }
其中,使用public static KeyPairGenerator getInstance(String algorithm);產生金鑰對生成器,這個方法需要一個字串作為引數,用於說明使用哪個金鑰演算法,例如本演算法中使用橢圓曲線“EC”。
使用public void initialize(int keysize);初始化金鑰對。引數keysize用於說明生成的key的長度,理論上說是這個引數的值越大,加密的資料就越難以被破解,但在加密時也越消耗計算資源。
使用keyPairGenerator.generateKeyPair().getPublic();動態生成公鑰
使用keyPairGenerator.generateKeyPair().getPrivate();動態生成私鑰
2.使用如下的函式執行簽名過程:
//執行簽名過程 public static byte[] SignGen(byte[] ECprivateKey) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance("EC"); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(ECprivateKey); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Signature signature = Signature.getInstance("SHA1withECDSA"); signature.initSign(privateKey); signature.update(data.getBytes()); byte[] result = signature.sign(); return result; }
其中,使用KeyFactory.getInstance(String algorithm);例項化一個金鑰工廠,這個方法需要一個字串作為引數,用於說明使用哪個金鑰演算法,例如本演算法中使用橢圓曲線“EC”。
使用new PKCS8EncodedKeySpec(ECprivateKey) ;和keyFactory.generatePrivate(pkcs8En
codedKeySpec);將私鑰從位元組陣列轉換為私鑰
使用Signature.getInstance(String algorithm);指定簽名使用的雜湊函式,本演算法中使用SHA1
使用signature.initSign(privateKey);和signature.update(data.getBytes());為訊息簽名
3.使用如下的函式實現驗證簽名:
//驗證簽名過程 public static booleanVerifiGen(byte[] ECpublicKey,byte[] result) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance("EC"); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(ECpublicKey); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); Signature signature = Signature.getInstance("SHA1withECDSA"); signature.initVerify(publicKey); signature.update(data.getBytes()); boolean bool = signature.verify(result); return bool; }
其中,使用KeyFactory.getInstance(String algorithm);例項化一個金鑰工廠,這個方法需要一個字串作為引數,用於說明使用哪個金鑰演算法,例如本演算法中使用橢圓曲線“EC”。
使用new PKCS8EncodedKeySpec(ECpublicKey) ;和keyFactory.generatePrivate(pkcs8En
codedKeySpec);將公鑰從位元組陣列轉換為公鑰
使用Signature.getInstance(String algorithm);指定簽名使用的雜湊函式,本演算法中使用SHA1
使用signature.initVerify(publicKey); 和signature.update(data.getBytes());驗證簽名是否正確
使用signature.verify(result);返回驗證結果,true orfalse
【1-2】參考程式碼
package ECDSA.demo; import java.io.*; import java.security.*; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.Scanner; public class ECDSA { private static String data ; //初始化系統 public static void KeyGenerator() throws Exception { System.out.println("系統正在初始化……"); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); keyPairGenerator.initialize(256); KeyPair keyPair = keyPairGenerator.generateKeyPair(); ECPublicKey ecPublicKey = (ECPublicKey)keyPair.getPublic(); ECPrivateKey ecPrivateKey = (ECPrivateKey)keyPair.getPrivate(); //把公鑰和私鑰分別儲存在publicKey.key和privateKey.key檔案裡 String path = new File("").getCanonicalPath(); out(path + "\\privateKey.key",Base64.getEncoder().encodeToString(ecPublicKey.getEncoded())); System.out.println("你的公鑰存放在:" + path + "\\publicKey.key"); System.out.println("你的私鑰存放在:" + path + "\\privateKey.key"); System.out.println("系統已完成初始化。"); } //執行簽名過程 public static byte[] SignGen(byte[] ECprivateKey) throws Exception { PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(ECprivateKey); KeyFactory keyFactory = KeyFactory.getInstance("EC"); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Signature signature = Signature.getInstance("SHA1withECDSA"); signature.initSign(privateKey); signature.update(data.getBytes()); byte[] result = signature.sign(); return result; } //驗證簽名過程 public static boolean VerifiGen(byte[] ECpublicKey,byte[] result) throws Exception { X509EncodedKeySpec x509encodedkeyspec= new X509EncodedKeySpec(ECpublicKey); KeyFactory keyFactory = KeyFactory.getInstance("EC"); PublicKey publicKey = keyFactory.generatePublic(x509encodedkeyspec); Signature signature = Signature.getInstance("SHA1withECDSA"); signature.initVerify(publicKey); signature.update(data.getBytes()); boolean bool = signature.verify(result); return bool; } //封裝輸出流 public static void out(String path,String val) { try { val = Base64.getEncoder().encodeToString(val.getBytes("utf-8")); FileWriter fw = new FileWriter(path); BufferedWriter bw = new BufferedWriter(fw); PrintWriter outs = new PrintWriter(bw); outs.println(val); outs.flush(); outs.close(); } catch (Exception ex) { ex.printStackTrace(); } } // 從檔案中讀取公私鑰 public static byte[] read(String path){ byte[] sk = null; try { File f=new File(path); FileReader fr=new FileReader(f); BufferedReader br=new BufferedReader(fr); String line=null; StringBuffer sb=new StringBuffer(); while((line=br.readLine())!=null) { byte[] b = Base64.getDecoder().decode(line); String[] key = new String(b,"utf-8").split(","); System.out.println("\n"); if(key.length == 1){ sk = Base64.getDecoder().decode(key[0]); } else{ throw new Exception("檔案錯誤"); } } br.close(); return sk; } catch(Exception ex) { ex.printStackTrace(); } return sk; } public static void main(String[] args) { // TODO Auto-generated method stub try { KeyGenerator(); Scanner sc = new Scanner(System.in); String str = ""; //輸入要簽名的資訊 sc.useDelimiter("\n"); System.out.print("\n"+"請輸入輸入要簽名的資訊按回車結束:"); if (sc.hasNext()) { data = sc.next(); } //獲取私鑰地址 sc.useDelimiter("\n"); System.out.print("\n"+"請輸入私鑰地址按回車結束:"); if (sc.hasNext()) { str = sc.next(); } //獲取私鑰 byte[] ECprivateKey = read(str.substring(0,str.length()-1)); //產生簽名 byte[] result = SignGen(ECprivateKey); System.out.println("數字簽名的結果:"+ Base64.getEncoder().encodeToString(result)); new Scanner(System.in); sc.useDelimiter("\n"); System.out.print("\n"+"請輸入公鑰地址按回車結束:"); if (sc.hasNext()) { str = sc.next(); } //獲取公鑰 byte[] ECpublicKey = read(str.substring(0,str.length()-1)); boolean bool = VerifiGen(ECpublicKey,result); if(bool == true){ System.out.println("數字簽名的驗證結果:通過驗證!"); } else { System.out.println("請檢查地址輸入地址是否有誤或檔案內容是否被篡改!"); } } catch (Exception ex) { System.out.println("請檢查地址輸入地址是否有誤或檔案內容是否被篡改!"); // System.out.println(ex); } } }
【1-3】擴充套件參考資料
1、ESCDA演算法原理:
ECDSA是ECC與DSA的結合,簽名演算法為ECC。
簽名過程如下:
1、選擇一條橢圓曲線Ep(a,b),和基點G;
2、選擇私有金鑰k(k<n,n為G的階),利用基點G計算公開金鑰K=kG;
3、產生一個隨機整數r(r<n),計算點R=rG;
4、將原資料和點R的座標值x,y作為引數,計算SHA1做為hash,即Hash=SHA1(原資料,x,y);
5、計算s≡r - Hash * k (mod n)
6、r和s做為簽名值,如果r和s其中一個為0,重新從第3步開始執行
驗證過程如下:
1、接受方在收到訊息(m)和簽名值(r,s)後,進行以下運算
2、計算:sG+H(m)P=(x1,y1),r1≡ x1 mod p。
3、驗證等式:r1 ≡ r mod p。
4、如果等式成立,接受簽名,否則簽名無效。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。