ECDSA数字签名,供大家参考,具体内容如下
一,实验目的
通过使用密码学库实现基于椭圆曲线的签名方案,能够编写简单的实验代码进行正确的ECDSA签名和验证。
二、 实验要求
1、熟悉ECDSA算法基本原理;
2、了解如何使用Java简单实现用ECDSA算法;
3、掌握用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(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 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、如果等式成立,接受签名,否则签名无效。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持易盾网络。