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(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、如果等式成立,接受签名,否则签名无效。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
时间:2020-06-23
常见的加密算法 基本的单向加密算法: BASE64严格地说,属于编码格式,而非加密算法 MD5(MessageDigestalgorithm5,信息摘要算法) SHA(SecureHashAlgorithm,安全散列算法) HMAC(HashMessageAuthenticationCode,散列消息鉴别码) 复杂的对称加密(DES.PBE).非对称加密算法: DES(DataEncryptionStandard,数据加密算法) PBE(Password-basedencryption,基于密码
Schnorr数字签名,供大家参考,具体内容如下 一.实验目的 学习Schnorr算法在数字签名方面的使用,掌握公钥签名中最基础的签名算法-Schnorr数字签名算法的编写. 二.实验要求 1. 熟悉Schnorr算法的描述,已经其使用场景. 2. 熟悉Schnorr数字签名算法. 3. 掌握如何使用java语言,实现Schnorr签名算法. 三.开发环境/p> JDK1.8,eclipse. 四.实验原理 数字签名是指消息发送方利用特定参数产生的一段消息码,该消息码可以用来标识消息发送者真实身
ElGamal数字签名,供大家参考,具体内容如下 一.实验目的 学习ElGamal算法在数字签名方面的使用,掌握教科书版本的ElGamal数字签名算法的编写,掌握ElGamal加密算法和ElGamal数字签名算法的异同. 二.实验要求 1.熟悉ElGamal数字签名算法. 2.掌握如何使用Java BigInteger类,简单实现教科书式的ElGamal公私钥签名算法. 3.了解ElGamal加密算法和ElGamal数字签名算法的异同. 三.开发环境 JDK 1.7,Java开发环境(本实验采用
本文实例讲述了Java实现的数字签名算法RSA.分享给大家供大家参考,具体如下: 一 背景介绍 数字签名:带有密钥(公钥.私钥)的消息摘要算法. 验证数据完整性.认证数据来源.抗否认. 私钥签名.公钥验证. 常用算法:RSA.DSA.ECDSA 二 RSA介绍 包括MD和SHA两类 三 Java代码实现 package com.imooc.security.rsa2; import java.security.KeyFactory; import java.security.KeyPair; i
RSA加密算法 我们来回顾一下RSA的加密算法.我们从公钥加密算法和签名算法的定义出发,用比较规范的语言来描述这一算法. RSA公钥加密体制包含如下3个算法:KeyGen(密钥生成算法),Encrypt(加密算法)以及Decrypt(解密算法). 密钥生成算法以安全常数作为输入,输出一个公钥PK,和一个私钥SK.安全常数用于确定这个加密算法的安全性有多高,一般以加密算法使用的质数p的大小有关.越大,质数p一般越大,保证体制有更高的安全性.在RSA中,密钥生成算法如下:算法首先随机产生两个不同大质
经过数字签名的文档,能够使作者之外的人无法对其进行修改.因此,在PDF文档中添加数字签名可以保证其安全性和真实性.同时根据添加内容的差异性,数字签名可分为文本数字签名.图片数字签名.图片及文本数字签名.本文将通过Spire.PDF for Java来演示如何在PDF文档中添加数字签名. 使用工具:Spire.PDF for Java 2.11.4 Jar文件获取及导入: 方法1:通过官网下载获取Jar包.下载后,解压文件,并将lib文件夹下的Spire.Pdf.jar文件导入Java程序.(如下
用Java数字签名提供XML安全 众所周知,XML在产品和项目开发中起着非常重要的作用.通过XML文档可以获取很多信息,还可以使用XML文件进行CRUD(增加.查询.更新和 删除)操作.然而值得注意的是,我们如何确保XML中的数据是来自经过认证的可信和可靠的来源.关于XML文件数据的可靠性和真实性存在很多问题.通常的 情况是,开发者直接处理XML文件而不去考虑数据的可靠性.有一些情况提出了上面的所有问题.现实生活中,每当我们从邮局收到一封信件时我们如何确定这封 信是来自我们的朋友?依据可能是他/
消息摘要 算法简述 定义 它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生.如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了.因此消息摘要保证了消息的完整性.消息摘要采用单向Hash 函数将需加密的明文"摘要"成一串密文,这一串密文亦称为数字指纹(Finger Print).它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致.这样这串摘要便可成为验证明文是否是
本文大纲 一.提出问题 二.数字签名 三.实现步骤 四.参考代码 五.后记 六.参考资料 一.提出问题 最近在做一个项目,需要对一个现成的产品的数据库进行操作,增加额外的功能.为此,需要对该产品对数据库有什么操作进行研究(至于怎么监控一个产品的操作会引发什么数据库操作,以后会详细解说).本来已经对数据库的操作了如指掌的,无意中发现数据库表里的每条记录都会有这样一个字段: 这感觉不妙了,字段名叫signature,顾名思义,就是签名的意思呀.难道数据库表中的每条记录都会有签名?也就是说如果我不能正
本文实例讲述了Java数字签名算法DSA.分享给大家供大家参考,具体如下: 一.介绍 DSS:Digital Signature Standard 数字签名标准 DSA:Digital Signature Algorithm 数字签名算法 DSA仅包含数字签名 二.参数说明 三.代码实现 package com.imooc.security.dsa; import java.security.KeyFactory; import java.security.KeyPair; import jav
java 使用DecimalFormat进行数字的格式化实例详解 简单实例: //获取DecimalFormat的方法DecimalFormat.getInstance(); public static void test1(DecimalFormat df) { //默认显示3位小数 double d = 1.5555555; System.out.println(df.format(d));//1.556 //设置小数点后最大位数为5 df.setMaximumFractionDigits(
java 进制转换实例详解 十进制转成十六进制: Integer.toHexString(int i) 十进制转成八进制 Integer.toOctalString(int i) 十进制转成二进制 Integer.toBinaryString(int i) 十六进制转成十进制 Integer.valueOf("FFFF",16).toString() 八进制转成十进制 Integer.valueOf("876",8).toString() 二进制转十进制 Integ
Java身份证验证方法实例详解 身份证号码验证 1.号码的结构 公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成.排列顺序从左至右依次为:六位数字地址码, 八位数字出生日期码,三位数字顺序码和一位数字校验码. 2.地址码(前六位数) 表示编码对象常住户口所在县(市.旗.区)的行政区划代码,按GB/T2260的规定执行. 3.出生日期码(第七位至十四位) 表示编码对象出生的年.月.日,按GB/T7408的规定执行,年.月.日代码之间不用分隔符. 4.顺序码(第十五位至十七位) 表示在同
一.你了解类吗? 在Java中,类文件是以.java为后缀的代码文件,在每个类文件中最多只允许出现一个public类,当有public类的时候,类文件的名称必须和public类的名称相同,若不存在public,则类文件的名称可以为任意的名称(当然以数字开头的名称是不允许的). 在类内部,对于成员变量,如果在定义的时候没有进行显示的赋值初始化,则Java会保证类的每个成员变量都得到恰当的初始化: 1)对于 char.short.byte.int.long.float.double等基本数据类型的
Java 反射机制的实例详解 前言 今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来.那样太low了,今天跟我一起来学习学习一种更加高大上的方式来实现. 正文 Java反射机制定义 Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 用一句话总结就是反射可以实现在运行时可以知道任意一个类的属性和方法. 反射
java 代理机制的实例详解 前言: java代理分静态代理和动态代理,动态代理有jdk代理和cglib代理两种,在运行时生成新的子类class文件.本文主要练习下动态代理,代码用于备忘.对于代理的原理和机制,网上有很多写的很好的,就不班门弄斧了. jdk代理 实例代码 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; publi
Java 序列化和反序列化实例详解 在分布式应用中,对象只有经过序列化才能在各个分布式组件之间传输,这就涉及到两个方面的技术-发送者将对象序列化,接受者将对象反序列化,下面就是一个很好的例子! 1.实体-Employee import java.io.Serializable; public class Employee implements Serializable{ /** * */ private static final long serialVersionUID = 1L; publi
java 中匿名内部类的实例详解 原来的面貌: class TT extends Test{ void show() { System.out.println(s+"~~~哈哈"); System.out.println("超级女声"); } TT tt=new TT(); tt.show(); 只是说我们这里采用的是匿名的形式来处理. 重写了Test的show()方法,在重写好了以后,又调用了重写后的show()方法 实现代码: package cn.com; c
Java中File的实例详解 File 代表文件或者目录的类 构造函数 File(File parent,String child)---代表了指定父目录下的指定的子文件或者子目录 File(String pathname)---代表了指定路径对应的文件或者目录对象 重要方法 创建 createNewFile()---只能用来创建文件,并且一次只能创建一个文件,要求文件存储的目录必须真实存在 mkdir()---只能用来创建目录,不能用来创建多层目录 mkdirs()---创建多层目录 删除 d