ECDSA密钥对生成以及在Token中的应用
1 概述
本文主要讲述了如何利用Openssl
生成ECDSA
密钥对,并利用Auth0
库进行Token
生成及验证的过程。
2 ECDSA
2.1 简介
ECC
(Elliptic Curve Cryptography
,椭圆曲线加密)是一种基于椭圆曲线数学的公钥加密算法,而ECDSA
是使用ECC
对数字签名算法(DSA
)的模拟,总的来说ECC
相比起常见的RSA
更加安全并且生成密钥对的过程会更快。本文不会涉及过多原理性的东西,只是作简单的介绍,想要详情了解这些算法的可以戳这里。
2.2 密钥对生成
在Openssl
中生成ECDSA
密钥对的流程如下:
openssl ecparam -genkey -name secp521r1 -out private.pem #生成私钥
openssl ec -in private.pem -pubout -out public.pem #生成公钥
参数说明如下:
ecparam
:EC
参数设置以及生成命令-genkey
:使用特定参数生成EC
私钥-name
:ec
参数,可以使用openssl ecparam -list_curves
查看,这里用的是secp521r1
-out
:输出文件名ec
:EC
密钥处理命令-in
:输入文件-pubout
:默认情况下会输出私钥,加上该选项会变成输出公钥(如果输入是公钥的情况下该参数会自动设置)
执行完命令后就成功生成密钥对了,可以查看一下:
密钥对生成之后就可以准备一下生成Token
了。
3 Auth0
中的Token
应用
3.1 Auth0
Auth0
提供了验证以及授权服务,这里利用官方提供的Java
实现去生成Token
(这里插一句题外话,Java
常用的Token
实现还有一个叫JJWT
的库),首先引入包:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.12.0</version>
</dependency>
Gradle
:
compile group: 'com.auth0', name: 'java-jwt', version: '3.12.0'
引入后来看一下支持的加密算法,如下图:
最简单的使用HMAC
算法生成的Token
如下:
System.out.println(JWT.create().withIssuer("issuer").withAudience("content").sign(Algorithm.HMAC512("password")));
当然这不是本文的重点,本文的重点是介绍如何利用ECDSA
去生成Token
。
首先Auth0
提供的签名api
如下:
JWT.create().sign(Algorithm)
其中Algorithm
可以取值如下:
想要使用ECDSA
算法需要提供一个ECDSAKeyProvider
或一个ECPublicKey
和一个ECPrivateKey
,这里选择后一种方式实现。
3.2 密钥对处理
官方并没有提供如何生成ECPublicKey
/ECPrivateKey
的方法,甚至连从文件读取密钥对的方法都没有提供,笔者从官方提供的测试代码中发现了如下方法:
其中核心就是读取密钥对的两个方法:
readPublicKeyFromFile
readPrivateKeyFromFile
从import
结果可以看到这是一个工具类:
但问题是官方该工具类是测试使用的,换句话说不对外暴露的,在IDEA
中直接引入会报错:
因此直接找到该工具类的源码(链接可以戳这里,需要引入bouncycastle
包,Maven
仓库链接可以戳这里)
package com.auth0.jwt;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class PemUtils {
private static byte[] parsePEMFile(File pemFile) throws IOException {
if (!pemFile.isFile() || !pemFile.exists()) {
throw new FileNotFoundException(String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath()));
}
PemReader reader = new PemReader(new FileReader(pemFile));
PemObject pemObject = reader.readPemObject();
byte[] content = pemObject.getContent();
reader.close();
return content;
}
private static PublicKey getPublicKey(byte[] keyBytes, String algorithm) {
PublicKey publicKey = null;
try {
KeyFactory kf = KeyFactory.getInstance(algorithm);
EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
publicKey = kf.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
System.out.println("Could not reconstruct the public key, the given algorithm could not be found.");
} catch (InvalidKeySpecException e) {
System.out.println("Could not reconstruct the public key");
}
return publicKey;
}
private static PrivateKey getPrivateKey(byte[] keyBytes, String algorithm) {
PrivateKey privateKey = null;
try {
KeyFactory kf = KeyFactory.getInstance(algorithm);
EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
privateKey = kf.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
System.out.println("Could not reconstruct the private key, the given algorithm could not be found.");
} catch (InvalidKeySpecException e) {
System.out.println("Could not reconstruct the private key");
}
return privateKey;
}
public static PublicKey readPublicKeyFromFile(String filepath, String algorithm) throws IOException {
byte[] bytes = PemUtils.parsePEMFile(new File(filepath));
return PemUtils.getPublicKey(bytes, algorithm);
}
public static PrivateKey readPrivateKeyFromFile(String filepath, String algorithm) throws IOException {
byte[] bytes = PemUtils.parsePEMFile(new File(filepath));
return PemUtils.getPrivateKey(bytes, algorithm);
}
}
直接复制该工具类后,将前一步生成的private.pem
以及public.pem
放置合适位置,通过工具类读取并生成Token
:
public class Main {
public static void main(String[] args) {
try {
ECPublicKey publicKey = (ECPublicKey) PemUtils.readPublicKeyFromFile("src/main/resources/public.pem","EC");
ECPrivateKey privateKey = (ECPrivateKey) PemUtils.readPrivateKeyFromFile("src/main/resources/private.pem","EC");
Algorithm algorithm = Algorithm.ECDSA512(publicKey,privateKey);
String token = JWT.create()
.withIssuer("issuer")
.sign(algorithm);
JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(JWT.decode(token));
} catch (Exception e) {
e.printStackTrace();
}
}
}
但是会报错说私钥是null
:
从官方issue
中查到了类似的问题:
回答说是密钥格式的问题,其中提到的pkcs8
是私钥格式转换命令:
将私钥的格式进行转换:
openssl pkcs8 -topk8 -inform pem -in private.pem -outform pem -nocrypt -out newprivate.pem
参数说明:
pkcs8
:私钥格式转换命令-topk8
:读取私钥并转换为PKCS#8
格式-inform
:指定输入格式,默认pem
,使用该参数并配合-topk8
后会生成加密后的PKCS#8
格式的私钥-in
:输入文件-outform
:与-inform
类似-nocrypt
:在这里主要配合-inform
+-topk8
使用,生成不加密的PrivateKeyInfo
而不是加密的PKCS#8 EncryptedPrivateKeyInfo
,因为一些软件(比如某些版本的Java
代码)使用的是不加密格式的私钥-out
:输出文件
转换后就可以生成Token
了。
3.3 生成Token
最后readPrivateKeyFromFile
中的参数修改为新的私钥即可:
ECPrivateKey privateKey = (ECPrivateKey) PemUtils.readPrivateKeyFromFile("src/main/resources/newprivate.pem","EC");
4 参考源码
包含了示例密钥对以及如何使用(Gradle
版的):
5 参考网站
3、Elliptic Curve Cryptography: breaking security and a comparison with RSA
5、StackExange-https://superuser.com/questions/1103401/generate-an-ecdsa-key-and-csr-with-openssl
6、auth0/java-jwt Issue - ECDSA key version mismatch from openssl pem files #270
8、codota-How to useECDSA512methodincom.auth0.jwt.algorithms.Algorithm
如果觉得文章好看,欢迎点赞。
同时欢迎关注微信公众号:氷泠之路。
ECDSA密钥对生成以及在Token中的应用的更多相关文章
- jwt认证生成后的token如何传回后端并解析的详解
jwt认证生成后的token后端解析 一.首先前端发送token token所在的位置headers {'authorization':token的值',Content-Type':applicati ...
- EF CodeFirst生成数据库到Sqlserver中
EF CodeFirst简单实例这篇文章介绍了如何用EF去快速生成数据库.但是这个并没有生成到sqlserver中,总觉得不爽.下面就来讲一下,如何将数据库生成到sqlserver中. 按照EF Co ...
- 如果使用mybatis的逆向工程生成的po类及mapper,如果我们想要进行的对数据库的操作在mapper中没有对应的接口函数:比如生成的mapper接口中没有按照姓名及性别混合条件查询。我们的解决办法是:使用逆向工程生成的对应表的Example文件。
1.使用mybatis逆向工程生成的po类中包含UserExample文件(我的数据库表名为User). 2. 创建UserExample对象,然后对加入条件.对应的测试代码为: /* * 通过姓名和 ...
- Springboot中使用自定义参数注解获取 token 中用户数据
使用自定义参数注解获取 token 中User数据 使用背景 在springboot项目开发中需要从token中获取用户信息时通常的方式要经历几个步骤 拦截器中截获token TokenUtil工具类 ...
- COMMENT方法 用于在生成的SQL语句中添加注释内容,
COMMENT方法 用于在生成的SQL语句中添加注释内容,例如: $this->comment('查询考试前十名分数') ->field('username,score') ->li ...
- C#怎么在生成解决方案的过程中执行perl脚本(C#早期绑定)
转载 怎么在生成解决方案的过程中执行perl脚本 早期绑定在编译期间识别并检查方法.属性.函数,并在应用程序执行之前执行其他优化.在这个绑定中,编译器已经知道它是什么类型的对象以及它拥有的方法或属性. ...
- 支付宝打造公共账号业务网关, RSA密钥对生成
作者: 玉龙 版权全部,同意转载. 请注明出处(创建金融_玉龙 http://www.weibo.com/u/1872245125) 原文地址: http://blog.csdn.net/ ...
- 如何生成Azure SAS Token
在Azure PaaS服务密钥的安全性文章中,提到过客户端实际上发送的是Token,而不是密钥.那么Token是该如何生成呢? Azure相应服务的SDK其实都提供了或者内置了生成Token的方法,可 ...
- Git SSH密钥对生成以及多个SSH存在情况配置
一.使用Git Bash 生成一个新的SSH密钥 1. 打开 Git Bash. 2. 邮箱设置粘贴下面的文字,替换成为你自己的邮箱. Github SSH 1 $ ssh-keygen -t rsa ...
随机推荐
- Vue学习笔记-vue调试工具vue-devtools安装及使用
一 使用环境: windows 7 64位操作系统 二 vue调试工具vue-devtools安装及使用 1.下载: 百度中查找 "vue-devtools下载" 找到最新 ...
- Docker私有仓库的搭建与使用
目录 Docker搭建私有仓库 一.搭建registry私有仓库 1.拉取私有仓库registry镜像 2.启动私有仓库容器 3.修改deamon.json 4.重启docker 5.启动regist ...
- go的循环
目录 go的循环 一.语法 二.语法简写 1.省略第一部分 2.省略第二部分 3.省略第三部分 4.全省略:死循环 5.终极写法,简洁变形 go的循环 Go中只有for循环,没有while循环.因为w ...
- 第35天学习打卡(输入框 TextField监听 简易计算器,组合+内部类回顾复习 画笔 鼠标监听 窗口监听 键盘监听)
1.输入框 TextField监听 package com.kuang.lesson02; import java.awt.*; import java.awt.event.ActionEven ...
- 力扣208. 实现 Trie (前缀树)
原题 以下是我的代码,就是简单的字符串操作,可以ac但背离了题意,我之前没接触过Trie 1 class Trie: 2 3 def __init__(self): 4 ""&qu ...
- docker apollo配置中心分布式部署
Apollo 简介 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服 ...
- CVE-2015-1635-HTTP.SYS远程执行代码
这个漏洞刚好是在挖SRC的时候找到的,漏洞危害能打到服务器蓝屏,以下只作验证 参考 https://www.jianshu.com/p/2e00da8a12de https://blog.csdn.n ...
- JAVA-标识符、变量、数据类型
标识符和关键字 所有的标识符否应该以字母a ~ z和 A ~Z ,美元符($).下划线(_)开始. 首字符之后可以是字母a ~ z和 A ~Z ,美元符($).下划线(_)的任意字符组合. 注 ...
- 常见 git 需求整理(持续更新中)
首发于 语雀文档 突然感觉自己对 git 还是挺熟悉的,因为团队里新来的七八号应届生来问我 git 问题,基本没有答不上的情况,但为了能更好地对知识进行整理,还是记录一下为好. (希望能)持续更新.. ...
- FreeBSD 日常应用
freebsd日常应用 办公libreoffice或者apache openoffice 设计 图像编辑:gimp 矢量图设计:lnkscape 视频剪辑:openshot 视频特效:natron 编 ...