Blog Archives

2023 微软技术直通车:用R语言一步一步学懂机器学习

跨界知识聚会系列文章,“知识是用来分享和传承的”,各种会议、论坛、沙龙都是分享知识的绝佳场所。我也有幸作为演讲嘉宾参加了一些国内的大型会议,向大家展示我所做的一些成果。从听众到演讲感觉是不一样的,把知识分享出来,你才能收获更多。

关于作者

  • 张丹,数据分析师/程序员/Quant: R,Java,Nodejs
  • blog: http://fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/meeting-ms-direct-20230311

前言

连续2周开线下会,很累也很兴奋。线下的感觉又回来了,比起线上的会,有了很多的互动和交流。上周AI Bootcamp大会上,由于时间太紧,只是把准备分享内容,给大家过了一遍,并没有深入到代码上演示。本周小厂、人少、时间充裕,可以好好讲讲R语言的代码实现。R语言在人工智能技术使用上的优势和可落地的技术实现。

目录

  1. 我分享的主题:用R语言一步一步学懂机器学习
  2. 会议体验和照片分享

1. 我分享的主题:用R语言一步一步学懂机器学习

AI技术继续引领科技创新,R语言机器学习作为可落地的技术,将帮我们利用数据向着智能化的方向前进。比如,用于信用贷款的风险评价领域的评分卡模型,基于逻辑回归和xgboost实现;用于金融资产配置的资本资产定价模型,基于线性回归实现;用于垃圾邮件分类,基于Bayes实现;用于团伙识别,基于图算法实现。

本次分享的PPT和代码,我上传到了github:https://github.com/bsspirit/ml

我主要为分几个部分进行介绍,包括机器学习是什么,机器学习几个重要任务,回归,分类,聚类,降维(升维),模型评估,优化,样本选择,autoML自动化。

本次分享重点在R语言的代码实现:

  • 线性回归,三次样条回归
  • 逻辑回归,决策树,朴素贝叶斯,xgboost,神经网络
  • 混淆矩阵,查准,查全,AUC, ROC
  • 模型自动化,样本切分,5折交叉

2. 会议体验和照片分享

经过三年的努力,我们终于迎来了“脱下口罩”的胜利。微软技术直通车也将秉承初衷,回归线下,为大家提供更亲切、更近距离、更有亲身感受的面对面活动。微软技术直通车第十二期,作为“脱下”后时代回归的首期,于2023年3月11日在微软(中国)总部圆满举行,本次邀请华北区微软技术专家和大家一起实践和体验最新的微软 .Net技术和充满炙热的人工智能技术,分享相关行业的发展前景和从业经验,提高微软相关技术给大家带来的潜在价值。

本次会议官方会议纪要页: https://mp.weixin.qq.com/s/J33rQaxXuWN6m2zz79k0YA

活动日志:

2.1 会议主题

本次活动由 3位MVP:刘海峰,郝冠军,张丹一起作为分享嘉宾。

刘海峰,主题:ChatGPT——触手可及,机会在哪里?【视频回看

微软资深MVP,软积木CEO,刘海峰先生的《ChatGPT——触手可及,机会在哪里?》教大家用好ChatGTP,详细讲解了Azure OpenAI背后的逻辑,并介绍了如何最终实践落地等实践性的设计。从而利用最新的人工智能技术带来更多的商机和更高的工作效率。

郝冠军,主题:在 . NET 中处理 PDF 文件。【视频回看

微软资深MVP,《ASP.NET 本质论》作者,郝冠军先生的《在 . NET 中处理 PDF 文件》给大家讲述了PDF的基本格式,以及怎样利用 .Net解决PDF字体问题和处理PDF的库,如何进行显示和打印效果的优化,并且能够从PDF中完美提出所需的内容,从而高效智能的处理PDF文档。

张丹,主题:用R语言一步一步学懂机器学习。【视频回看

微软MVP,R语言实践者,北京青萌数海科技有限公司CTO,张丹先生的《用R语言一步一步学懂机器学习》告诉大家人工智能技术在各个领域中的应用越来越广泛,我们已经生活中已充满了AI。R语言在机器学习的各个领域,都有非常强大的支持,R社区贡献了各种的算法包方便我们直接应用,包括回归,分类,聚类,神经网络,autoML自动化机器学习,模型优化和模型评价等各种应用方向。AI技术继续引领科技创新,R语言机器学习作为可落地的技术,将帮我们利用数据向着智能化的方向前进。

2.2 相关照片

主持人:刘力科

现场大合照

还是线下会议好啊,有互动性,能看到大家的反应,专注在技术本身。微软技术直通车,每季度都带来新的技术分享。

转载请注明出处:
http://blog.fens.me/meeting-ms-direct-20230311

2023 微软Global AI : R语言中的机器学习

跨界知识聚会系列文章,“知识是用来分享和传承的”,各种会议、论坛、沙龙都是分享知识的绝佳场所。我也有幸作为演讲嘉宾参加了一些国内的大型会议,向大家展示我所做的一些成果。从听众到演讲感觉是不一样的,把知识分享出来,你才能收获更多。

关于作者

  • 张丹,数据分析师/程序员/Quant: R,Java,Nodejs
  • blog: http://fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/meeting-ms-global-ai-20230304

前言

ChatGPT风靡全球,人工智能再次推向了新的时代,如何将AI服务融入应用程序和落地使用来提升工作效率、创造更大的价值,将是企业和个人未来所面临的机会和挑战。

我从R语言机器学习的角度,来介绍了人工智能技术的发展,R语言在人工智能技术使用上的优势和可落地的技术实现。

目录

  1. 我分享的主题:R语言中的机器学习
  2. 会议体验和照片分享

1. 我分享的主题:R语言中的机器学习

AI技术继续引领科技创新,R语言机器学习作为可落地的技术,将帮我们利用数据向着智能化的方向前进。比如,用于信用贷款的风险评价领域的评分卡模型,基于逻辑回归和xgboost实现;用于金融资产配置的资本资产定价模型,基于线性回归实现;用于垃圾邮件分类,基于Bayes实现;用于团伙识别,基于图算法实现。

本次分享的PPT和代码,我上传到了github:https://github.com/bsspirit/ml

我主要为分几个部分进行介绍,包括机器学习是什么,机器学习几个重要任务,回归,分类,聚类,降维(升维),模型评估,优化,样本选择,autoML自动化。

人工智能的进化发展:

具体的任务方向和技术:

2. 会议体验和照片分享

本次活动是微软Global AI Bootcamp 北京站——ChatGPT专场的活动,主要由微软MVP给大家进行一些技术分享。(Global AI Bootcamp 是由对 Microsoft Azure 上的人工智能充满热情的当地社区组织在世界各地举办的活动。活动是质量内容、真棒演讲和与社区中志同道合的同龄人进行实践学习的完美平衡。)

本次会议报名页: https://www.huodongxing.com/go/chatgpt?td=8372911588190

时间地点:
时间:2023年 3月4日 14:00-17:00
地点:丹棱街5号微软亚太研发集团总部1号楼

活动日志:

13:30-14:00Global AI Bootcamp北京站 签到
14:00-14:10主办方致辞
14:10-16:10嘉宾演讲
16:10-16:40圆桌会议
16:40-17:00问答抽奖

2.1 会议主题

本次活动由 4位MVP(刘海峰,张丹,徐磊,李佳芮)和1位微软员工(卢建晖)一起作为分享嘉宾。

卢建晖,主题:打造你人生中的第一个OpenAI 应用。微软云技术布道师,热爱编程,热爱分享,专注在人工智能,物联网,云原生等领域。

张丹,主题:R语言中的机器学习。微软MVP,R语言实践者,北京青萌数海科技有限公司CTO,10年以上互联网应用架构经验,在R、大数据、数据分析等方面有深厚的积累。精通量化投资交易策略,熟悉中国金融二级市场、交易规则和投研体系。

徐磊,主题:被开发者低估的AI编程助手-Github Copilot。微软技术社区区域总监,Devops社区领袖,SmartIDE开源项目创始人;写了十几年代码但还没写够的程序员

李佳芮,主题:ChatGPT: AI与人 [替代] 还是[共生]。句子互动创始&CEO,微软 AI MVP,中文首本对话式交互图书《Chatbot从0到1》作者,全球最大的对话式交互 RPA SDK 开源框架 Wechaty 联合作者,Combinator W19 校友,对话式营销开创者。

刘海峰,主题:用Azure OpenAI来打造语音助理机器人。微软MVP、软积木 CEO

2.2 相关照片

MVP和现场组织人员

现场大合照

现场的零食

现场的同学们在认真听课

好久没有参加线下会了,久违的感觉,线下真好。感谢组织会议的工作人员,感谢MVP项目负责人霸姐的支持,感谢摄影师老丁。

转载请注明出处:
http://blog.fens.me/meeting-ms-global-ai-20230304

用R语言10分钟上手神经网络模型

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹,分析师/程序员/Quant: R,Java,Nodejs
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-nn-neuralnet/

前言

“神经网络”,“深度学习”,已经不是纯学术的词了,有很多的算法已经落地为我们生活中的各种产品,比如人脸识别,智能客服,从图片中提词,AI作诗,AI作画,chatGPT,AphlaGo等,各种的AI算法应用出圈,打破很多行业壁垒,甚至机器比人类更有创造力,做的更好。这些AI应用出圈的背后,很大程度上是依赖于神经网络的高速发展。

跟上时代的脚步,我将用R语言详细地介绍神经网络建模和应用的过程,以动手操作为主。本文是神经网络的第一篇文章:用R语言10分钟上手神经网络模型neuralnet。

目录

  1. 神经网络介绍
  2. neuralnet包介绍
  3. 神经元模型:零隐藏层
  4. 单层神经网络(感知机):一个隐藏层
  5. 单层神经网络:多分类
  6. 两层神经网络(多层感知器):多分类
  7. 多层神经网络(深度学习)

1. 神经网络介绍

神经网络,也称为人工神经网络 (ANN) 是机器学习的子集,并且是深度学习算法的核心。其名称和结构是受人类大脑的启发,模仿了生物神经元信号相互传递的方式。

人工神经网络 (ANN) 由节点层组成,包含一个输入层、一个或多个隐藏层和一个输出层。 每个节点也称为一个人工神经元,它们连接到另一个节点,具有相关的权重和阈值。 如果任何单个节点的输出高于指定的阈值,那么该节点将被激活,并将数据发送到网络的下一层。 否则,不会将数据传递到网络的下一层。

从单层神经网络(感知器)开始,到包含一个隐藏层的两层神经网络,再到多层的深度神经网络,一共有三次兴起过程。

在神经网络中,处理单元通常按层次分布于神经网络的输入层、隐层和输出层中,因此分别称之为输入节点、隐节点和输出节点,各自的功能如下所示:

  • 输入节点:接受与处理训练数据集中的各输入变量值
  • 隐藏点:实现非线性数据的线性变换
  • 输出节点:给出输出变量的分类或预测结果

2. neuralnet包介绍

在R语言里面,有好几个包都支持神经网络模型,neuralnet包就一个常用包。

neuralnet包,安装过程很简单。


# 安装
> install.packages("neuralnet")

# 加载
> library(neuralnet)

# 设置工作路径
> setwd("C:/work/R/neural/neural_networks")

neuralnet包中的,neuralnet()函数可用于神经网络的模型训练,是这个包中最核心的函数,neuralnet()函数参数很多,是需要我们仔细了解的。

neuralnet()函数,在训练神经网络模型时,支持使用反向传播(BP)、弹性反向传播(RPROP)、无权重回溯、修正的全球收敛版本(GRPROP)训练神经网络,函数允许通过自定义选择误差和激活函数进行灵活设置。此外,还实现了广义权重的计算。

查看neuralnet()函数


> neuralnet
function (formula, data, hidden = 1, threshold = 0.01, stepmax = 1e+05, 
    rep = 1, startweights = NULL, learningrate.limit = NULL, 
    learningrate.factor = list(minus = 0.5, plus = 1.2), learningrate = NULL, 
    lifesign = "none", lifesign.step = 1000, algorithm = "rprop+", 
    err.fct = "sse", act.fct = "logistic", linear.output = TRUE, 
    exclude = NULL, constant.weights = NULL, likelihood = FALSE) 

...

参数列表:

  • formula: 定义模型的公式。
  • data: data.frame格式,训练集原始数据。
  • hidden: 整数向量,指定每层中隐藏神经元的数量,如c(3,2)为二个隐藏层,第一层3个节点,第二层2个节点。
  • threshold: 数值型,停止条件阈值,指定误差函数的偏导数作为停止标准的阈值。
  • stepmax: 数值型,停止条件最大迭代次数,达到这个最大值就会停止神经网络的训练过程。
  • rep: 神经网络训练的重复次数。
  • startweights: 模型起始值的权重向量,设置为NULL用于随机初始化。
  • learningrate.limit: 一个向量或一个列表,包含学习率的最低和最高限制,仅用于RPROP和GRPROP。
  • learningrate.factor: 一个向量或一个列表,包含学习率的上限和下限的乘法系数,仅用于RPROP和GRPROP。
  • learningrate: 数值型,指定传统反向传播使用的学习率,只用于传统的反向传播。
  • lifesign: 字符串,指定函数在计算神经网络时的打印量,’none’, ‘minimal’ or ‘full’。
  • lifesign.step: 整数型,指定在完全lifesign模式下打印最小阈值的步长。
  • algorithm: 字符串,包含用于计算神经网络的算法类型。以下类型是可能的:”backprop”,”rprop+”,”rprop-“,”sag”,或 “slr”。backprop’指的是反向传播,’rprop+’和’rprop-‘指的是带有和不带有权重回溯的弹性反向传播,而’sag’和’slr’则是诱导使用修改后的全局收敛算法(GRPROP)。
  • err.fct: 损失函数,用于计算误差的函数,可以使用字符串’sse’和’ce’,它们代表平方误差之和和交叉熵。
  • act.fct: 激活函数,用于平滑协变量或神经元与权重的交叉积的结果。字符串 “logistic”和 “tanh” 可以用于logistic函数和切线双曲。
  • linear.output:逻辑值,是否线性输出,即是回归还是分类。TRUE表示输出节点的激活函数为线性函数,FALSE表示非线性函数,在B-P中为FALSE
  • exclude: 一个向量或一个矩阵,指定从计算中排除的权重。如果给定的是一个向量,必须知道权重的确切位置。一个有n行3列的矩阵将排除n个权重,其中第一列代表层,第二列代表输入神经元,第三列代表权重的输出神经元。
  • constant.weights: 一个向量,指定训练过程中不需要训练的权重,固定值。
  • likelihood: 逻辑值,如果误差函数等于负对数似然函数,将计算信息准则AIC和BIC。

在实际建模过程中,我们主要使用formula,data,hidden,threshold,algorithm,err.fct,act.fct,linear.output这个参数。

3. 神经元模型:零隐藏层

我们先建立一个最简单的网络模型,只有输入节点和输出节点,不包括隐藏层。这种结构都不算是神经网络,是神经网络的前身神经元模型。神经元模型是一个包含输入,输出与计算功能的模型。输入可以类比为神经元的树突,而输出可以类比为神经元的轴突,计算则可以类比为细胞核。

查看iris数据集


> head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

以iris数据集的全量数据做为输入,对单一目标Species==”setosa”,做二分类的模型,判断是否属于是setosa的种类。


# 没有隐藏层
> nn <- neuralnet(Species=="setosa"~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, 
+                 data = iris,hidden = 0)

# 查看网络结构 
> plot(nn)

从输出的神经网络结构图中,我们可以看到,四个输入节点为iris数据集的4个参数(Sepal.Length Sepal.Width Petal.Length Petal.Width Species),输出节点(Species)为模型训练目标,蓝色节点1为这一层的偏差权重(截距)值,从输入节点到输出节点的连线上,有权重值。我们训练神经网络模型,就是为了算出这些权重值,反复迭代。

接下来,我们查看模型的各种输出结果,都在nn这个对象中。

  • call:模型函数
  • response:因变量数据
  • covariate:自变量数据
  • model.list:模型函数
  • err.fct:损失函数
  • act.fct:激活函数
  • linear.output:是否线性输出
  • data:原始数据集
  • exclude:指定从计算中排除的权重
  • net.result:预测值结果
  • weights:各个节点的权重值列表
  • generalized.weights:广义权重
  • startweights:各个节点的初始权重(初始权值为在的正态分布随机数)
  • result.matrix:结果矩阵,终止迭代时各个节点的权重,迭代次数,损失函数值和权重的最大调整量

首先,来查看结果矩阵result.matrix。

> nn$result.matrix
                                             [,1]
error                                1.533438e+00
reached.threshold                    9.212915e-03
steps                                6.297000e+03
Intercept.to.Species == "setosa"     1.202943e-01
Sepal.Length.to.Species == "setosa"  6.432600e-02
Sepal.Width.to.Species == "setosa"   2.441786e-01
Petal.Length.to.Species == "setosa" -2.230368e-01
Petal.Width.to.Species == "setosa"  -5.935682e-02
  • error,损失函数值,1.533438,值越小
  • reached.threshold,终止条件,权重的最大调整量9.212915e-03
  • steps,整个训练执行了6297步
  • Intercept.to.Species,偏差权重(截距),值为1.202943e-01
  • Sepal.Length.to.Species,Sepal.Length变量权重
  • Sepal.Width.to.Species,Sepal.Width变量权重
  • Petal.Length.to.Species,Petal.Length变量权重
  • Petal.Width.to.Species,Petal.Width变量权重

查看连接的初始的权重,随机分配的,分别对应5个不同输入节点到输出节点的权重。


> nn$startweights 
[[1]]
[[1]][[1]]
           [,1]
[1,]  0.5797599
[2,] -0.3526484
[3,]  1.7074446
[4,]  1.3395568
[5,]  0.7781903

查看模型最终的连接权重列表,从startweights初始到weights最终结果。


> nn$weights
[[1]]
[[1]][[1]]
            [,1]
[1,]  0.12029435
[2,]  0.06432600
[3,]  0.24417858
[4,] -0.22303683
[5,] -0.05935682

查看模型中的广义权重,分别对应每个样本数据的权重值


# 取前6条
> head(nn$generalized.weights[[1]])
           [,1]       [,2]       [,3]        [,4]
[1,]  3.1084343  11.799476 -10.777840  -2.8683080
[2,]  0.4883183   1.853634  -1.693141  -0.4505957
[3,]  0.7288879   2.766825  -2.527265  -0.6725814
[4,]  0.4490363   1.704522  -1.556939  -0.4143483
[5,] 20.4485892  77.621919 -70.901170 -18.8689374
[6,] -3.7104548 -14.084718  12.865219   3.4238224

查看模型的计算函数


# 模型公式
> nn$call
neuralnet(formula = Species == "setosa" ~ Sepal.Length + Sepal.Width + 
    Petal.Length + Petal.Width, data = iris, hidden = 0)

# 损失函数
> nn$err.fct
function (x, y) 
{
    1/2 * (y - x)^2
}


attr(,"type")
[1] "sse"

# 激活函数
> nn$act.fct
function (x) 
{
    1/(1 + exp(-x))
}


attr(,"type")
[1] "logistic"

查看模型的变量


# 模型的变量定义
> nn$model.list       
$response
[1] "Species == \"setosa\""

$variables
[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width" 

# 查看自变量,取前6条
> head(nn$covariate)
     Sepal.Length Sepal.Width Petal.Length Petal.Width
[1,]          5.1         3.5          1.4         0.2
[2,]          4.9         3.0          1.4         0.2
[3,]          4.7         3.2          1.3         0.2
[4,]          4.6         3.1          1.5         0.2
[5,]          5.0         3.6          1.4         0.2
[6,]          5.4         3.9          1.7         0.4

查看因变量的实际值,对模型预测输出变量的预测概率值。


# 查看因变量,实际值,取前6条
> head(nn$response)
  Species == "setosa"
1                TRUE
2                TRUE
3                TRUE
4                TRUE
5                TRUE
6                TRUE

# 模型预测结果,取前6条
> head(nn$net.result[[1]])
          [,1]
[1,] 0.9788590
[2,] 0.8439046
[3,] 0.9021788
[4,] 0.8267209
[5,] 0.9968443
[6,] 1.0170459

通过建立一个最简单的网络模型,我们就能了解 neuralnet() 函数的是怎么使用的了,涉及到的内容还是很多的。对于零隐藏层的网络而言,就可以理解为一个线性模型。

4. 单层神经网络(感知机):一个隐藏层

接下来,我们建立一个真正的神经网络模型,包括输入节点、输出节点、1个隐藏层节,还是以iris数据集的全量数据做为输入,对单一目标Species==”setosa”,做二分类的模型,判断是否属于是setosa的种类。

代码只是改动一处,让hidden=1。


# 训练
> n1 <- neuralnet(Species=="setosa"~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, 
+ data = iris,hidden=1) 

# 画出网络结构 
> plot(n1)

从图的输出,我们看到网络结构中,多了一个隐藏层。

查看结果矩阵


> n1$result.matrix
                                          [,1]
error                             1.899890e-04
reached.threshold                 9.246323e-03
steps                             2.260000e+02
Intercept.to.1layhid1             1.384797e-01
Sepal.Length.to.1layhid1          5.431059e-01
Sepal.Width.to.1layhid1           3.122608e+00
Petal.Length.to.1layhid1         -2.053056e+00
Petal.Width.to.1layhid1          -8.719302e+00
Intercept.to.Species == "setosa" -6.759521e-04
1layhid1.to.Species == "setosa"   1.001522e+00

error的损失值为0.00019,整个训练执行了226步,比神经元模型的零隐藏层,有了大幅的提升。一下子就把分类问题解决了,太神奇了吧。

5. 单层神经网络:多分类

我们增加点难度,用单层神经网路,做个多分类的。


# 单层网络
> n2a <- neuralnet(Species~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, 
+ data = iris,hidden=1) 

# 画图
> plot(n2a)

从网络结构看,输出为4个节点,隐藏层为一个节点,输出3个节点,为3类。输出结果惨不忍睹,error竟然达到了25,基本都是错了。

接下来,我们试试增加隐藏层节点数,从1个变成2个,看看做个多分类的效果。


# 单层网络,2个节点
> n2b <- neuralnet(Species~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, 
+ data = iris,hidden=c(2)) 

> plot(n2b)

从网络结构看,输出为4个节点,隐藏层为两个节点,输出3个节点,为3类。输出结果一下就不错了,error为1.9,步骤是15981,这个结果是能用的。

由于一层神经网络的感知器也只能做线性分类任务,在10年后,才对于两层神经网络的研究才带来神经网络的复苏。

6. 两层神经网络(多层感知器):多分类

下面我们要建立一个两层神经网络模型,包括输入层、输出层、2个隐藏层,还是以iris数据集的全量数据做为输入,对单一目标Species做三分类的模型。

首先,先尝2个隐藏层,每层一个节点,试试模型效果。


# 2个隐藏层,每层1个节点
> n3a <- neuralnet(Species~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, + data = iris,hidden=c(1,1)) > n3a$result.matrix
                                  [,1]
error                     25.000112366
reached.threshold          0.007309118
steps                    358.000000000
Intercept.to.1layhid1      2.677698687
Sepal.Length.to.1layhid1  -0.737245035
Sepal.Width.to.1layhid1    3.844506938
Petal.Length.to.1layhid1  -1.018677154
Petal.Width.to.1layhid1  -10.512582993
Intercept.to.2layhid1     -0.771711595
1layhid1.to.2layhid1       3.469423693
Intercept.to.setosa       -0.510039484
2layhid1.to.setosa         1.612291660
Intercept.to.versicolor    0.754101331
2layhid1.to.versicolor    -0.804506879
Intercept.to.virginica     0.755525924
2layhid1.to.virginica     -0.807147653

error达到了25,又是一个不可接受的结果。

在层数不变的情况下,继续增加每层的节点数,调整为每个隐藏层2个节点。从结果矩阵看,多个很多参数的输出,这些节点都是有神经网络自动生成了,也就是不可解释的因素。


# 2个隐藏层,每层2个节点
> n3b <- neuralnet(Species~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, + data = iris,hidden=c(2,2)) # 结果矩阵 > n3b$result.matrix
                                 [,1]
error                    24.999473404
reached.threshold         0.008004802
steps                    83.000000000
Intercept.to.1layhid1    -0.493094700
Sepal.Length.to.1layhid1 -1.519304930
Sepal.Width.to.1layhid1  -1.217278013
Petal.Length.to.1layhid1  3.491582287
Petal.Width.to.1layhid1   3.469063900
Intercept.to.1layhid2    -0.921659140
Sepal.Length.to.1layhid2 -2.263419044
Sepal.Width.to.1layhid2   0.410851516
Petal.Length.to.1layhid2  1.581399076
Petal.Width.to.1layhid2  -1.453986728
Intercept.to.2layhid1     0.898644804
1layhid1.to.2layhid1     -2.635824185
1layhid2.to.2layhid1     -2.577338580
Intercept.to.2layhid2    -0.829242612
1layhid1.to.2layhid2     -0.706157301
1layhid2.to.2layhid2      1.549670915
Intercept.to.setosa      -0.436567651
2layhid1.to.setosa        1.527644298
2layhid2.to.setosa        1.165157296
Intercept.to.versicolor   0.374083691
2layhid1.to.versicolor   -1.298521851
2layhid2.to.versicolor    1.805614407
Intercept.to.virginica    0.455763243
2layhid1.to.virginica    -1.181002787
2layhid2.to.virginica     1.253298145

# 画图
> plot(n3b)

效果依然不好,error为24.99,完全不能使用。

下来的操作,就是继续加节点。在层数不变的情况下,继续增加每层的节点数,调整为每个隐藏层3个节点。


# 2个隐藏层,每层3个节点
> n3c <- neuralnet(Species~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, + data = iris,hidden=c(3,3)) > n3c$result.matrix
                                  [,1]
error                     9.861760e-01
reached.threshold         9.760993e-03
steps                     1.842800e+04
Intercept.to.1layhid1     7.178501e-01
Sepal.Length.to.1layhid1  2.725448e-01
Sepal.Width.to.1layhid1   1.376482e+00
Petal.Length.to.1layhid1 -1.262652e+00
Petal.Width.to.1layhid1  -1.997635e+00
Intercept.to.1layhid2    -2.753156e+00
Sepal.Length.to.1layhid2 -1.465864e+00
Sepal.Width.to.1layhid2   4.125512e+00
Petal.Length.to.1layhid2 -6.026538e-01
Petal.Width.to.1layhid2   2.743376e+00
Intercept.to.1layhid3     1.379399e+00
Sepal.Length.to.1layhid3 -2.256887e-01
Sepal.Width.to.1layhid3   1.027688e+00
Petal.Length.to.1layhid3  3.221391e-01
Petal.Width.to.1layhid3  -2.847147e+00
Intercept.to.2layhid1    -2.353385e+00
1layhid1.to.2layhid1     -1.315389e+03
1layhid2.to.2layhid1      3.555585e+01
1layhid3.to.2layhid1      6.903238e+01
Intercept.to.2layhid2    -6.702997e-01
1layhid1.to.2layhid2      1.352140e+00
1layhid2.to.2layhid2     -5.184099e-02
1layhid3.to.2layhid2     -2.994567e-01
Intercept.to.2layhid3    -3.106167e+00
1layhid1.to.2layhid3      4.958443e+00
1layhid2.to.2layhid3     -2.185125e-01
1layhid3.to.2layhid3     -1.677417e+00
Intercept.to.setosa       4.026726e-01
2layhid1.to.setosa       -1.575905e-02
2layhid2.to.setosa       -1.461912e+00
2layhid3.to.setosa        2.965282e+00
Intercept.to.versicolor   6.790011e-01
2layhid1.to.versicolor   -9.706799e-01
2layhid2.to.versicolor    1.210438e+00
2layhid3.to.versicolor   -2.833834e+00
Intercept.to.virginica   -2.389590e-01
2layhid1.to.virginica     9.950653e-01
2layhid2.to.virginica     7.442383e-01
2layhid3.to.virginica    -3.957608e-01

# 画图
> plot(n3c)

瞬间,模型效果又达到了惊人的新高度,error为0.986,只能用神奇来形容,我也不知道为什么,算法的“玄学” 由此而来。

7. 多层神经网络(深度学习):多个隐藏层

在上个步骤中,我们是层数不变增加每层节点数,当然我们也可以节点数不变,增加更多的层数来操作。继续增加到3层的,保持节点数每个隐藏层2个节点进行测试。


# 3个隐藏层,每层2个节点
> n3d <- neuralnet(Species~ Sepal.Length + Sepal.Width + Petal.Length + 
                         Petal.Width, + data = iris,hidden=c(2,2,2)) 

# 结果矩阵 
> n3d$result.matrix
                                  [,1]
error                     9.814611e-01
reached.threshold         9.856631e-03
steps                     2.599500e+04
Intercept.to.1layhid1     4.377454e+00
Sepal.Length.to.1layhid1  2.988690e+00
Sepal.Width.to.1layhid1   4.895009e+00
Petal.Length.to.1layhid1  4.739920e+00
Petal.Width.to.1layhid1   5.049575e+00
Intercept.to.1layhid2     1.713367e+00
Sepal.Length.to.1layhid2  4.900288e-01
Sepal.Width.to.1layhid2   6.486628e-01
Petal.Length.to.1layhid2 -1.317743e+00
Petal.Width.to.1layhid2  -1.286672e+00
Intercept.to.2layhid1    -5.678148e+01
1layhid1.to.2layhid1     -5.584444e+01
1layhid2.to.2layhid1      9.250502e+02
Intercept.to.2layhid2     1.417653e+01
1layhid1.to.2layhid2      1.370346e+01
1layhid2.to.2layhid2     -3.770254e+01
Intercept.to.3layhid1    -1.702465e+00
2layhid1.to.3layhid1      1.833016e+00
2layhid2.to.3layhid1      4.370202e+00
Intercept.to.3layhid2    -2.525917e+00
2layhid1.to.3layhid2      8.186075e+00
2layhid2.to.3layhid2      1.849959e+00
Intercept.to.setosa       1.991064e+00
3layhid1.to.setosa       -2.193503e+00
3layhid2.to.setosa        1.780463e-01
Intercept.to.versicolor  -2.462871e+00
3layhid1.to.versicolor    2.184454e+00
3layhid2.to.versicolor    1.303726e+00
Intercept.to.virginica    1.471821e+00
3layhid1.to.virginica     9.088568e-03
3layhid2.to.virginica    -1.481810e+00

# 画图
> plot(n3d)

三个隐藏的模型效果,同样能达到非常好的效果,error为0.981。

通过不停的增加层数的节点数,神经网络模型会越来越好,但是计算的复杂度会越来越高,从结果矩阵的输出,我们就可感觉到,输出的变量一次比一次多,都不知道这些变量是干什么用的,要想去解释这个模型根本就无从下手。

保持理性的思维,虽然神经网络可以无限帮我们提升模型的效果,但由于不可以解释,“玄之又玄”,需要在适合场景来使用,而不是全都交给神经网络。本文为神经网络的入门文章第一篇,针对这个主题,我们也准备多写几篇文章,来用R语言进行详细的描述。

说多少理论都不如上手一试。本文代码已上传到github: https://github.com/bsspirit/neural_networks/blob/main/01_neuralnet.r

转载请注明出处:
http://blog.fens.me/r-nn-neuralnet/

打赏作者

用R语言实现RSA+AES混合加密

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹,分析师/程序员/Quant: R,Java,Nodejs
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-crypto-aes-rsa/

前言

我们在日常的数据通信过程中,互联网各种应用软件,虽然让我们越来越方便,但也存在各种隐私泄露,数据被盗取的情况。基于我们对RSA、AES和证书的知识,结合R语言工具,自治一个数据通讯系统吧,保证自己在和别人传输数据过程中的数据隐私。

由于最近对密码学产生兴趣,让用R语言做一个密码学的访问,因此对R语言中openssl包进行了研究,本文为openssl的第四篇文章,用R语言实现RSA+AES混合加密。openssl的文章分别是,R语言进行非对称加密RSAR语言进行AES对称加密R语言配合openssl生成管理应用x509证书用R语言实现RSA+AES混合加密

加密算法涉及到密码学的很多深入的知识,我并没有深入研究,本文只针对于openssl的使用,如果有任何与专业教材不符合的描述,请以专业教材为准。

目录

  1. 用openssl生成秘钥key
  2. RSA+AES混合加密

1. 用openssl生成秘钥key

用openssl包,有6种秘钥的生成方案,分别是aes秘钥,rsa秘钥,dsa秘钥,ec秘钥,x25519秘钥,ed25519秘钥。

  • aes_keygen(length = 16),AES对称加密,只有一个秘钥。
  • rsa_keygen(bits = 2048),RSA非对称加密,包括公钥和私钥。
  • dsa_keygen(bits = 1024),DSA非对称加密,包括公钥和私钥。
  • ec_keygen(curve = c(“P-256”, “P-384”, “P-521”)),椭圆曲线非对称加密,包括公钥和私钥。
  • x25519_keygen(),非对称加密,包括公钥和私钥。
  • ed25519_keygen(),非对称加密,包括公钥和私钥。

生成AES的秘钥


# 生成秘钥
> aes<-aes_keygen(length = 16);aes
aes e0:ad:28:fa:05:04:c0:6b:7c:ba:ad:f9:00:1d:44:22 

# 查看结构
> str(aes)
 'aes' raw [1:16] e0 ad 28 fa ...

生成RSA公钥和私钥

code>
# 生成秘钥
> rsa<-rsa_keygen(bits = 2048);rsa
[2048-bit rsa private key]
md5: c4db98bb1d161082cc41b56b5863cce9
sha256: c4d58b626f4e7ebc20fe12830bd7e1b647ef12151672008eaf9bf709bdbeee50

# 查看结构
> str(rsa)
List of 4
 $ type  : chr "rsa"
 $ size  : int 2048
 $ pubkey:List of 5
  ..$ type       : chr "rsa"
  ..$ size       : int 2048
  ..$ ssh        : chr "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCt7BCaSxvC4UkPiDcwrZFgliC960t+uo+cGMRivq ..."
  ..$ fingerprint: 'hash' raw [1:32] c4 d5 8b 62 ...
  ..$ data       :List of 2
  .. ..$ e: 'bignum' raw [1:3] 01 00 01
  .. ..$ n: 'bignum' raw [1:257] 00 ad ec 10 ...
 $ data  :List of 8
  ..$ e : 'bignum' raw [1:3] 01 00 01
  ..$ n : 'bignum' raw [1:257] 00 ad ec 10 ...
  ..$ p : 'bignum' raw [1:129] 00 e7 61 0c ...
  ..$ q : 'bignum' raw [1:129] 00 c0 6d d7 ...
  ..$ d : 'bignum' raw [1:256] 2e 20 dc 4e ...
  ..$ dp: 'bignum' raw [1:128] 4b 61 43 ce ...
  ..$ dq: 'bignum' raw [1:129] 00 92 1c 55 ...
  ..$ qi: 'bignum' raw [1:129] 00 af 11 51 ...

# 获得公钥
> rsa$pubkey
[2048-bit rsa public key]
md5: c4db98bb1d161082cc41b56b5863cce9
sha256: c4d58b626f4e7ebc20fe12830bd7e1b647ef12151672008eaf9bf709bdbeee50

其他的非对称加密算法的生成公钥和私钥的代码,与RSA的代码结构是一致的。

2. RSA+AES混合加密

在前面两篇文章中,我们已经分别掌握了AES对称加密技术RSA非对称加密技术,两种技术其实都自己的特征和使用的场景。

  • AES对称加密技术,加密和解密使用同一个密钥,加密速度快,密钥最长只有256个bit,执行速度快,易于硬件实现,但只有一个秘钥,一方泄露就会不安全。
  • RSA非对称加密技术,使用公钥加密和私钥解密,加密速度慢,私钥长度可以设置1024bit,2048bit,4096bit,长度越长,越安全,但是生成密钥越慢,加解密也越耗时。

结合上面两种加密技术的特征,我们可以设计一套RSA+AES混合加密方案,让数据加密传输能够使用到两种技术的优点。

方案优势:

  • 单纯的使用 RSA(非对称加密)方式的话,效率会很低,因为非对称加密解密方式虽然很保险,但是过程复杂,需要时间长;
  • 但是,RSA 优势在于数据传输安全,且对于几个字节的数据,加密和解密时间基本可以忽略,所以用它加密 AES 秘钥(一般16个字节)再合适不过了;
  • 单纯的使用 AES(对称加密)方式的话,死板且不安全。这种方式使用的密钥是一个固定的密钥,客户端和服务端是一样的,一旦密钥被人获取,那么,我们所发的每一条数据都会被都对方破解;
  • 但是,AES有个很大的优点,那就是加密解密效率很高,而我们传输正文数据时,正号需要这种加解密效率高的,所以这种方式适合用于传输量大的数据内容;

我从互联网找了RSA+AES混合加密的一个设计思路,RSA+AES的混合加密时,AES用于给传输的数据加密,然后通过RSA给AES的秘钥加密,所以接收到数据后,就需要先解密得到AES的秘钥,然后通过AES秘钥再去解密得到数据。

我画了一个示意图:

操作步骤:

  • 第1步,B系统:一次性,生成RSA私钥(rsa_key)和公钥(rsa_pubkey)。
  • 第2步,A系统:一次性,生成AES秘钥(aes_key),获得把RSA公钥(rsa_pubkey),用RSA公钥对AES秘钥加密,生成(aes_key_mi)。
  • 第3步,B系统:一次性,获得把加密后的AES秘钥(aes_key_mi),用RSA私钥(rsa_key)对AES私钥解密,得到(aes_key2)。
  • 第4步,A系统:生成获得数据(dat)并进行序列化(dat_serial),用AES秘钥(aes_key)进行加密生成(dat_mi)
  • 第5步,B系统:获得加密后的数据(dat_mi),用AES秘钥(aes_key2)进行解密(x_serial2),再反序列化获得原始数据(dat2)。

接下来,我们用R语言来模拟实现。

第一步,B系统:一次性,生成RSA私钥(rsa_key)和公钥(rsa_pubkey)。


# RSA私钥
> rsa_key <- rsa_keygen();rsa_key
[2048-bit rsa private key]
md5: 2fbb4bada8e942967577155c8d0e3251
sha256: 29e6aaabfd49fe884c505ed12130eb61d32090e8251503b2f69bb06a6c23c3c5

# RSA公钥
> rsa_pubkey <- rsa_key$pubkey; rsa_pubkey
[2048-bit rsa public key]
md5: 2fbb4bada8e942967577155c8d0e3251
sha256: 29e6aaabfd49fe884c505ed12130eb61d32090e8251503b2f69bb06a6c23c3c5

第2步,A系统:一次性,生成AES秘钥(aes_key),获得把RSA公钥(rsa_pubkey),用RSA公钥对AES秘钥加密,生成(aes_key_mi)。

 
# RSA公钥
> rsa_pubkey
[2048-bit rsa public key]
md5: 2fbb4bada8e942967577155c8d0e3251
sha256: 29e6aaabfd49fe884c505ed12130eb61d32090e8251503b2f69bb06a6c23c3c5

# AES秘钥
> aes_key <- aes_keygen();aes_key
aes d5:bf:bd:f0:6a:05:0b:f7:0d:04:4f:68:64:f5:7c:02 

# 把AES秘钥加密
> aes_key_mi <- rsa_encrypt(aes_key, rsa_pubkey)

第3步,B系统:一次性,获得把加密后的AES秘钥(aes_key_mi),用RSA私钥(rsa_key)对AES私钥解密,得到(aes_key2)。

code>
# 获得加密后的AES秘钥
> aes_key_mi

# 用RSA私钥对AES私钥解密
> aes_key2<-rsa_decrypt(aes_key_mi,rsa_key);aes_key2
 [1] d5 bf bd f0 6a 05 0b f7 0d 04 4f 68 64 f5 7c 02

第4步,A系统:生成获得数据(dat)并进行序列化(dat_serial),用AES秘钥(aes_key)进行加密生成(dat_mi)。


> # 原始数据
> dat<-iris[1:3,];dat
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa

# 序列化
> dat_serial <- serialize(dat, NULL)

# 用AES秘钥进行加密生成
> dat_mi <- aes_cbc_encrypt(x_serial, key = aes_key)

第5步,B系统:获得加密后的数据(dat_mi),用AES秘钥(aes_key2)进行解密(x_serial2),再反序列化获得原始数据(dat2)。


# 获得加密数据
> dat_mi

# 解密
> dat_serial2<-aes_cbc_decrypt(dat_mi,aes_key2);x_serial2

# 反序列化
> dat2<-unserialize(x_serial2);dat2
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa

有了本文的思路基础,接下来就可以自己设计一套软件程序了,把重要的信息加密,给对的人,也不怕中间过程被截获了。话说微信传输,已经没有隐私可言了,只能信自己了。

本文是介绍openssl包使用的第四篇文章,原想着R语言做密码学知识到哪天才能用上,没想到马上就用上了。

转载请注明出处:
http://blog.fens.me/r-crypto-aes-rsa/

打赏作者

用R语言配合openssl命令行生成和管理x509证书

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹,分析师/程序员/Quant: R,Java,Nodejs
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-crypto-openssl-cert/

前言

openssl工具博大精深,本文尝试了使用 openssl 的命令行工具结合R语言中的openssl包的工具,进行了秘钥生成,证书生成,证书管理,证书下载,证书验证等的功能尝试,对秘钥和x509证书进行生成、管理和应用。本文为openssl的第三篇文章,R语言配合openssl生成管理应用x509证书。

由于最近对密码学产生兴趣,使用R语言做一个密码学的研究,因此对R语言中openssl包进行了研究,openssl的文章分别是,R语言进行非对称加密RSAR语言进行AES对称加密R语言配合openssl生成管理应用x509证书用R语言实现RSA+AES混合加密

加密算法涉及到密码学的很多深入的知识,我并没有深入研究,本文只针对于openssl的使用,如果有任何与专业教材不符合的描述,请以专业教材为准。

目录

  1. X.509证书的基本知识
  2. 用 openssl 命令工具生成证书
  3. 用 R语言进行证书管理
  4. 获取网站证书并验证

1. X.509证书的基本知识

在互联网应用中,为保证服务器端和客户端的相互信息、数据安全等的要求,做大量使用到证书用来确认双方身份。X.509证书主要用于识别互联网通信和计算机网络中的身份,保护数据传输安全。

X.509证书的结构优势在于它是由公钥和私钥组成的密钥对而构建的。公钥和私钥能够用于加密和解密信息,验证发送者的身份和确保消息本身的安全性。基于X.509的PKI最常见的用例是使用SSL证书让网站与用户之间实现HTTPS安全浏览。X.509协议同样也适用于应用程序安全的代码签名、数字签名和其他重要的互联网协议。

证书文件的常用的扩展名和秘钥扩展名。

  • .crt .cer .der,证书文件(Certificate),通常是DER二进制格式的
  • .pem,der编码的证书再进行Base64编码的数据存放在”—–BEGIN CERTIFICATE—–“和”—–END CERTIFICATE—–“之中
  • .key,密钥文件,私钥和公钥匙
  • .csr,证书认证签名请求(Certificate signing request)

在本地的window环境中,可以运行 certmgr.msc 来查看本地系统中,所有提前预制的CA机构证书。

2. 用 openssl 命令工具生成证书

我们来模拟一下网站向CA申请证书的互联网应用场景,由于并不是去真实的CA机构申请证书,我们可以把CA机构一起进行模拟。自己设定一个CA机构生成一个CA机构证书,再生成一个自己网站(fens.me)的证书,然后用CA的证书对自己的网站证书进行签名,来模拟一个实际网站申请证书的过程。

我接下来通过命令行openssl工具生成证书。本机环境为window10,通过安装Git工具,使用自带的Mingw64的工具中的openssl环境。


# 查看openssl 版本
dan@DanZhang MINGW64 /c/work/R/encrypt/n1
$ openssl version
OpenSSL 1.1.1d  10 Sep 2019

2.1 生成CA根证书的步骤
我们要生成自签名的证书,所以我们需要自己扮演CA,作为CA颁发证书的机构。

操作步骤:生成CA私钥(ca.key)–>生成自签名得到根证书(.crt)

第一步,生成CA私钥(ca.key),生成CA认证机构的证书密钥key。
使用命令:openssl genrsa -out ca.key 2048
参数:

  • -out ca.key:将生成的私钥保存至ca.key文件。
  • 2048为要生成的私钥的长度。

# 生成CA私钥ca.key
dan@DanZhang MINGW64 /c/work/R/encrypt/n1
$ openssl genrsa -out ca.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.............................................................................+++++
...............................+++++
e is 65537 (0x010001)

# 查看生成的ca.key的内容
$ cat ca.key
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA1iLmJeJHYeVutw6Ui+V/tZs2SS4GFzTWRkoRmmt4Z+5jQMt/
dv94WbjmKyvNNrXiNiGz1jZQsw2Bj+22rSKjGEh4Qipjpcc+AOfl99V3diH8YM/c
wj6dNFKqqmpJHtzDSbhOudPbwDsFugq3dyVsV1hMKrlEBetI7Qj/8kZSie1KL+QS
00G+ISCHUes8f/eFHgd7sMXpOb65NJhAKZGSeT49V+IeF1M82VJEyV+x1p/C3ppA
L9PTt3RFftTQJjXW48tIfS3R85E0libyeQnlxM3slEf2UnO16wq/7j3KmWiPD9vm
tPnhNjKbBr6PbtAR+CAsSpxaVLMpA1PDydqsCQIDAQABAoIBAQDKI22QK3do0TTf
NrNBECarH1ZyZDC5rVXsSjUtyO+DZIRrAO5VPbm1MJaOAC4azD07Djt+Jg2tyD0a
ybIc48qDvL1Q8ETalCdSoZXzip3XdSORnAZvkr3BS5vxfJ2Dta/fok0mm/ggEVdJ
lJ41qa0JEr/rwLGWyNExeMJrSLjXmt4S3fkZNJ12icCRKddeFyTL17LEf6lENXol
e/SWuvB1+RhZb73eJVMPTJcoRXulJ0/pUD2QxLMn/YhvMVH8A13v9TipmS51mwLP
FN8F9BNm2K6QXHgQLghjYbpDk1pRTzj+4Yr6dbWZipHSWWJy1WKMm93M+5VNuG6a
tKGj/HQ1AoGBAPhhIxczFZxhd4qs6t09OkU2aEpGYcdMGEYFd7OUYhjUOhXHUMMC
uUWAq2555VaUrKhlqovp+uTdMESop7Ac6gfSH0yG1rTLSiFCuOsNcBx1FKUgCh3Q
OP0JugH6yOJuCwyT1DCoipGbq/sjhaUmb+sqwN+IhcQ6vCw4Qnp2emvfAoGBANy0
zdG7PIL2i9Rub38+cR0/rFdZJFqWQXv/j1c+o+cAQfzsk6jPV5uR+St+HXyafMNu
I7po1mvp7v1UJceFrynZGqdS0FNALmDAnySaPoyhqSjk+nB88MkSEcACr64Smumw
5DHkU3hO+hhayCzPIsILiU67jXvIP3F5GabxNGUXAoGAGN+JZxJbkKyGDyIf5wXx
puq66O1Bb3bkW2bCxP4QENJ3+qRaJx1HtnkbMdYNLG15GOgNezN0R6UK52VIXa+X
lC7rqXs7VyGgi9IluIxA9OiYp6yctr2aZ2So9vfJVDuW6ayILFNEhS5ku6KkCJTf
0loWtIv0cWE8ZOVBawggXFsCgYBWw612Ggl74rit1ox2lXGacgGqhRzJj/BGcv1C
6xk8ItnOOKMD5h8mxYgTFQ06gvExUwcwrS4+VkThykbf3SozZWoZBXFoiP6ygocN
uKWGW7dIoFvkBPoT0cqwlV3DLQVBgYz0IDLARSwEjwvKsdOUPTzJeunwE5T9YwI2
ovRaGQKBgF0zysxImSvnC8jQFB5+jw5dCnP8gXDljZPDJhxwlkbNc85ikA27vSkQ
+ql0YOsgka3DH4ISOpMGJXaCTkI86OXtLlG0HBjLgiiyYQnFieQ1xPB3PfCPKWHl
G84TmLUw9uxC08jV0r7UfIDBxv7kNGDLJqyTmsCYON9EXbbt03ac
-----END RSA PRIVATE KEY-----

第二步,生成自签名得到根证书(ca.crt),CA的基本信息,生成证书时填入的信息,包含国家,地区,公司,域名等信息。
使用命令:openssl req -new -x509 -key ca.key -out ca.crt -days 365
参数说明:

  • -new :说明生成证书请求文件
  • -x509 :说明生成自签名证书
  • -key :指定已有的秘钥文件生成秘钥请求,只与生成证书请求选项-new配合。
  • -days:证书有效天数
  • -out :-out 指定生成的证书请求或者自签名证书名称

# 自签名得到根证书(.crt)
dan@DanZhang MINGW64 /c/work/R/encrypt/n1
$  openssl req -new -x509 -key ca.key -out ca.crt -days 365
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:ZH
State or Province Name (full name) [Some-State]:BJ
Locality Name (eg, city) []:BEIJING
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:myca.com
Email Address []:bsspirit@gmail.com

2.2 生成用户证书的步骤
接下来,生成我自己的博客的 fens.me 网站的秘钥,然后生成证书请求,用CA的证书进行签名,最后自己网站的证书。。

生成私钥(.key)–>生成证书请求(.csr)–>用CA根证书签名得到证书(.crt)

第一步,生成私钥(fens.me.key)


dan@DanZhang MINGW64 /c/work/R/encrypt/n1
$ openssl genrsa -out fens.me.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
...............................................................................................................+++++
.................................+++++
e is 65537 (0x010001)

第二步,生成CSR(Certificate Signing Request)证书请求(fens.me.csr)


dan@DanZhang MINGW64 /c/work/R/encrypt/n1
$ openssl req -new -key fens.me.key -out fens.me.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:ZH
State or Province Name (full name) [Some-State]:BJ
Locality Name (eg, city) []:BEIJING
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:fens.me
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:bsspirit@gmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:fens.me
An optional company name []:

查看CSR文件中的信息,需要用到openssl命令工具来查看


dan@DanZhang MINGW64 /c/work/R/encrypt/n1
$ openssl req -text -noout -verify -in fens.me.csr
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = ZH, ST = BJ, L = BEIJING, O = Internet Widgits Pty Ltd, OU = fens.me, emailAddress = bsspirit@gmail.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:b5:d3:98:e5:0f:57:19:a0:dd:c1:aa:7d:de:55:
                    c7:e7:ae:dc:03:30:68:f8:71:32:8b:c2:14:d8:b3:
                    31:ec:55:ca:70:fb:e2:17:8b:86:8f:c6:10:4e:fb:
                    4f:25:80:cf:9b:cf:6d:46:b6:ba:90:8f:a1:68:ba:
                    c2:ef:c4:99:e2:8a:0b:7f:af:7b:37:d7:5c:5a:5f:
                    0c:10:b3:3a:ab:b1:a6:c0:9d:8a:42:42:68:0c:c3:
                    07:52:b3:39:c1:8e:9f:dc:7b:c5:88:11:9d:7f:cd:
                    ad:95:27:42:47:a8:af:74:dc:66:df:d7:29:0b:ae:
                    3c:f6:4a:d2:dc:6b:20:60:5d:59:37:55:c0:48:68:
                    40:31:67:b5:d6:68:13:ed:f1:b2:70:00:7f:b0:c5:
                    1a:ba:e3:f5:c4:42:97:ef:1b:68:3c:43:ff:dc:81:
                    0d:7a:6f:f4:88:60:ce:47:32:7b:64:27:a0:e7:89:
                    e7:fa:60:73:6a:64:77:34:d9:6b:2a:f5:9b:c4:6f:
                    49:82:84:43:01:8a:ea:90:d6:0b:5c:f1:19:9f:56:
                    c2:c1:df:22:29:28:79:40:5f:72:13:ac:9b:b0:6f:
                    0b:b6:09:9f:c4:a8:12:5d:51:16:f0:81:e2:41:6a:
                    2a:74:56:bf:48:77:26:84:f9:57:f3:f9:f4:af:94:
                    68:bd
                Exponent: 65537 (0x10001)
        Attributes:
            challengePassword        :fens.me
    Signature Algorithm: sha256WithRSAEncryption
         10:cf:2f:82:24:a5:48:b0:c9:c2:79:00:eb:ba:70:8f:02:f4:
         cb:7a:b8:9b:d9:eb:9c:dd:34:03:9e:d7:3a:bd:7d:08:af:11:
         2c:a5:3e:0b:40:8c:3e:64:bb:c6:8b:b0:b0:6a:cb:59:b9:9b:
         e1:a1:d9:bc:ec:10:ed:d8:29:f2:a3:fd:f1:94:c6:4e:26:95:
         23:25:28:b7:01:fa:3d:bd:96:8b:b5:e8:f4:6b:c3:b9:67:a9:
         29:27:96:18:51:98:3a:45:87:31:35:6c:16:51:be:60:40:6e:
         2d:ea:0d:d6:0c:36:6f:5d:24:4e:c1:20:f7:42:7b:9e:62:81:
         e6:38:88:03:0a:7e:15:01:8e:ab:ac:9b:30:93:21:72:19:bf:
         9d:4d:51:ba:30:74:34:4f:1b:30:4d:c8:74:ca:e8:3e:15:a5:
         ec:2c:0e:79:4f:d1:11:56:0f:da:38:d0:6b:1e:54:ac:50:28:
         04:d2:8d:b4:6b:f3:d1:ee:a5:f2:43:6f:4c:73:42:13:df:66:
         30:4f:6c:16:6f:99:91:9f:56:ec:c2:99:aa:e1:82:28:2a:ce:
         e2:4e:9e:95:c4:52:fa:be:7a:8e:1e:32:6f:f9:83:92:c1:8a:
         da:a8:a1:ef:e6:df:14:bb:16:c0:b9:67:8d:71:43:69:d4:2e:
         2d:6a:9d:4c
verify OK

第三步,用CA根证书签名得到证书。实际过程中,会把上面生成的fens.me.csrR文件发给CA,请求CA签名,从而生成网站证书 fens.me.crt。


dan@DanZhang MINGW64 /c/work/R/encrypt/n1
$ openssl x509 -req -in fens.me.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out fens.me.crt -days 365
Signature ok
subject=C = ZH, ST = BJ, L = BEIJING, O = Internet Widgits Pty Ltd, OU = fens.me, emailAddress = bsspirit@gmail.com
Getting CA Private Key

# 查看证书中的内容
$ openssl x509 -in fens.me.crt -text -noout
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 1 (0x1)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = ZH, ST = BJ, L = BEIJING, O = Internet Widgits Pty Ltd, CN = myca.com, emailAddress = bsspirit@gmail.com
        Validity
            Not Before: Nov 30 09:47:58 2022 GMT
            Not After : Nov 30 09:47:58 2023 GMT
        Subject: C = ZH, ST = BJ, L = BEIJING, O = Internet Widgits Pty Ltd, OU = fens.me, emailAddress = bsspirit@gmail.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:b5:d3:98:e5:0f:57:19:a0:dd:c1:aa:7d:de:55:
                    c7:e7:ae:dc:03:30:68:f8:71:32:8b:c2:14:d8:b3:
                    31:ec:55:ca:70:fb:e2:17:8b:86:8f:c6:10:4e:fb:
                    4f:25:80:cf:9b:cf:6d:46:b6:ba:90:8f:a1:68:ba:
                    c2:ef:c4:99:e2:8a:0b:7f:af:7b:37:d7:5c:5a:5f:
                    0c:10:b3:3a:ab:b1:a6:c0:9d:8a:42:42:68:0c:c3:
                    07:52:b3:39:c1:8e:9f:dc:7b:c5:88:11:9d:7f:cd:
                    ad:95:27:42:47:a8:af:74:dc:66:df:d7:29:0b:ae:
                    3c:f6:4a:d2:dc:6b:20:60:5d:59:37:55:c0:48:68:
                    40:31:67:b5:d6:68:13:ed:f1:b2:70:00:7f:b0:c5:
                    1a:ba:e3:f5:c4:42:97:ef:1b:68:3c:43:ff:dc:81:
                    0d:7a:6f:f4:88:60:ce:47:32:7b:64:27:a0:e7:89:
                    e7:fa:60:73:6a:64:77:34:d9:6b:2a:f5:9b:c4:6f:
                    49:82:84:43:01:8a:ea:90:d6:0b:5c:f1:19:9f:56:
                    c2:c1:df:22:29:28:79:40:5f:72:13:ac:9b:b0:6f:
                    0b:b6:09:9f:c4:a8:12:5d:51:16:f0:81:e2:41:6a:
                    2a:74:56:bf:48:77:26:84:f9:57:f3:f9:f4:af:94:
                    68:bd
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         7d:5e:a2:f1:c4:91:19:4f:c3:6a:88:7c:33:4b:d8:fc:20:e3:
         e4:ad:38:23:5e:90:95:46:fe:4a:45:4d:70:58:2a:90:c2:b9:
         53:a4:80:90:b4:6d:a5:b9:c0:b0:73:8c:ff:9d:f2:b4:06:93:
         da:66:67:e2:85:0e:9b:11:64:70:c5:b6:a2:93:8b:3e:00:cb:
         1c:34:0c:3a:34:86:16:8b:7a:c6:e4:6a:8e:4f:cb:86:ea:25:
         1d:dc:18:1b:c4:74:b0:a5:d1:a4:e7:f6:f4:e8:44:c4:13:e0:
         a5:b5:3f:c5:54:ae:f3:e4:ee:9a:53:6a:53:73:e3:84:df:65:
         ac:93:de:94:46:9a:4b:2f:7f:d4:cb:b9:de:ac:9b:72:9b:68:
         f4:bf:59:e8:79:b0:c5:cd:2a:7c:70:d1:ff:2b:3c:10:0a:8b:
         d4:36:33:68:d4:d7:1f:0e:16:98:f6:10:eb:a5:23:a8:22:9f:
         66:f5:0a:b0:1b:05:54:ab:4c:08:cf:55:c2:46:13:de:b0:e7:
         2c:76:6a:3d:5f:ec:44:f0:9c:75:d6:13:ca:d1:20:02:7c:9c:
         ea:48:58:aa:e2:15:02:37:a3:07:f9:40:89:4e:ba:2a:02:19:
         a3:e7:9f:65:00:d5:e1:27:dd:63:50:74:30:b8:7b:8b:4b:95:
         93:f2:ec:b1

查看当前目录中的文件,共5个


dan@DanZhang MINGW64 /c/work/R/encrypt/n1
$ ll
total 20
-rw-r--r-- 1 dan 197121 1448 Nov 30 17:40 ca.crt
-rw-r--r-- 1 dan 197121 1702 Nov 30 15:26 ca.key
-rw-r--r-- 1 dan 197121 1294 Nov 30 17:47 fens.me.crt
-rw-r--r-- 1 dan 197121 1096 Nov 30 17:45 fens.me.csr
-rw-r--r-- 1 dan 197121 1702 Nov 30 17:44 fens.me.key

2.3 查看证书
用windows程序打开证书,左边是  fens.me.crt证书,右边为ca.crt根证书。

  • ca.crt根证书,是我们自己的生成的,未获得电脑的信任。通过安装ca.crt根证书,让本机电脑获得信任。
  • fens.me.crt证书,用ca.crt根证书颁发的。

这样我们就完成了,就openssl命令行工具生成自制证书的过程,一路下来还是挺顺利的。

3. 用 R语言进行证书管理

本来我是打算用R语言openssl包,重现上面的证书生成的过程,但查了很多资料发现在R中,并没有用于证书生成的函数支持,只能做证书的一些管理和验证。那么,我就把openssl包中,能有关证书支持的函数,做一个介绍。

证书相关的函数:

  • read_cert,读取证书文件
  • read_cert_bundle,读取证书包
  • read_pem,以pem格式,读证书
  • read_pubkey,读取公钥
  • write_pem,以pem格式,输出秘钥和证书
  • write_pkcs1,以pkcs格式,输出秘钥和证书
  • write_ssh,以ssh格式,输出秘钥和证书
  • ca_bundle,X509证书集合
  • certificates,证书检查
  • cert_verify,证书验证

我们用R语言API来读取刚才生成ca.key秘钥查看秘钥的信息,并比较确认生成key的秘钥格式。

3.1 取读ca.key的私钥
使用read_key() 以私钥方式进行读取。


# 以私钥方式进行读取                             
> cakey<-read_key("./ca.key");cakey
[2048-bit rsa private key]
md5: 87be025db1f33785aafa00aa83388a8b
sha256: c03bc0d35b4593ff81cde4545b1aa62f80e754545297f30669bdcce29a910a45

# 查看cakey结构
> str(cakey)
List of 4
 $ type  : chr "rsa"
 $ size  : int 2048
 $ pubkey:List of 5
  ..$ type       : chr "rsa"
  ..$ size       : int 2048
  ..$ ssh        : chr "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWIuYl4kdh5 ..."
  ..$ fingerprint: 'hash' raw [1:32] c0 3b c0 d3 ...
  ..$ data       :List of 2
  .. ..$ e: 'bignum' raw [1:3] 01 00 01
  .. ..$ n: 'bignum' raw [1:257] 00 d6 22 e6 ...
 $ data  :List of 8
  ..$ e : 'bignum' raw [1:3] 01 00 01
  ..$ n : 'bignum' raw [1:257] 00 d6 22 e6 ...
  ..$ p : 'bignum' raw [1:129] 00 f8 61 23 ...
  ..$ q : 'bignum' raw [1:129] 00 dc b4 cd ...
  ..$ d : 'bignum' raw [1:257] 00 ca 23 6d ...
  ..$ dp: 'bignum' raw [1:128] 18 df 89 67 ...
  ..$ dq: 'bignum' raw [1:128] 56 c3 ad 76 ...
  ..$ qi: 'bignum' raw [1:128] 5d 33 ca cc ...

# 查看ssh格式
> ca.ssh<-write_ssh(cakey);ca.ssh
[1] "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWIuYl4kdh5W63DpSL5X+1mzZJLgYXNNZGShGaa3hn7mNAy392/3hZuOYrK802teI2IbPWNlCzDYGP7batIqMYSHhCKmOlxz4A5+X31Xd2Ifxgz9zCPp00Uqqqakke3MNJuE6509vAOwW6Crd3JWxXWEwquUQF60jtCP/yRlKJ7Uov5BLTQb4hIIdR6zx/94UeB3uwxek5vrk0mEApkZJ5Pj1X4h4XUzzZUkTJX7HWn8LemkAv09O3dEV+1NAmNdbjy0h9LdHzkTSWJvJ5CeXEzeyUR/ZSc7XrCr/uPcqZaI8P2+a0+eE2MpsGvo9u0BH4ICxKnFpUsykDU8PJ2qwJ"

# 查看der格式
> ca.der<-write_der(cakey);ca.der
   [1] 30 82 04 a3 02 01 00 02 82 01 01 00 d6 22 e6 25 e2 47 61 e5 6e b7 0e 94
  [25] 8b e5 7f b5 9b 36 49 2e 06 17 34 d6 46 4a 11 9a 6b 78 67 ee 63 40 cb 7f
  [49] 76 ff 78 59 b8 e6 2b 2b cd 36 b5 e2 36 21 b3 d6 36 50 b3 0d 81 8f ed b6
  [73] ad 22 a3 18 48 78 42 2a 63 a5 c7 3e 00 e7 e5 f7 d5 77 76 21 fc 60 cf dc
  [97] c2 3e 9d 34 52 aa aa 6a 49 1e dc c3 49 b8 4e b9 d3 db c0 3b 05 ba 0a b7
 [121] 77 25 6c 57 58 4c 2a b9 44 05 eb 48 ed 08 ff f2 46 52 89 ed 4a 2f e4 12
 [145] d3 41 be 21 20 87 51 eb 3c 7f f7 85 1e 07 7b b0 c5 e9 39 be b9 34 98 40
 [169] 29 91 92 79 3e 3d 57 e2 1e 17 53 3c d9 52 44 c9 5f b1 d6 9f c2 de 9a 40
 [193] 2f d3 d3 b7 74 45 7e d4 d0 26 35 d6 e3 cb 48 7d 2d d1 f3 91 34 96 26 f2
 [217] 79 09 e5 c4 cd ec 94 47 f6 52 73 b5 eb 0a bf ee 3d ca 99 68 8f 0f db e6
 [241] b4 f9 e1 36 32 9b 06 be 8f 6e d0 11 f8 20 2c 4a 9c 5a 54 b3 29 03 53 c3
 [265] c9 da ac 09 02 03 01 00 01 02 82 01 01 00 ca 23 6d 90 2b 77 68 d1 34 df
 [289] 36 b3 41 10 26 ab 1f 56 72 64 30 b9 ad 55 ec 4a 35 2d c8 ef 83 64 84 6b
 [313] 00 ee 55 3d b9 b5 30 96 8e 00 2e 1a cc 3d 3b 0e 3b 7e 26 0d ad c8 3d 1a
 [337] c9 b2 1c e3 ca 83 bc bd 50 f0 44 da 94 27 52 a1 95 f3 8a 9d d7 75 23 91
 [361] 9c 06 6f 92 bd c1 4b 9b f1 7c 9d 83 b5 af df a2 4d 26 9b f8 20 11 57 49
 [385] 94 9e 35 a9 ad 09 12 bf eb c0 b1 96 c8 d1 31 78 c2 6b 48 b8 d7 9a de 12
 [409] dd f9 19 34 9d 76 89 c0 91 29 d7 5e 17 24 cb d7 b2 c4 7f a9 44 35 7a 25
 [433] 7b f4 96 ba f0 75 f9 18 59 6f bd de 25 53 0f 4c 97 28 45 7b a5 27 4f e9
 [457] 50 3d 90 c4 b3 27 fd 88 6f 31 51 fc 03 5d ef f5 38 a9 99 2e 75 9b 02 cf
 [481] 14 df 05 f4 13 66 d8 ae 90 5c 78 10 2e 08 63 61 ba 43 93 5a 51 4f 38 fe
 [505] e1 8a fa 75 b5 99 8a 91 d2 59 62 72 d5 62 8c 9b dd cc fb 95 4d b8 6e 9a
 [529] b4 a1 a3 fc 74 35 02 81 81 00 f8 61 23 17 33 15 9c 61 77 8a ac ea dd 3d
 [553] 3a 45 36 68 4a 46 61 c7 4c 18 46 05 77 b3 94 62 18 d4 3a 15 c7 50 c3 02
 [577] b9 45 80 ab 6e 79 e5 56 94 ac a8 65 aa 8b e9 fa e4 dd 30 44 a8 a7 b0 1c
 [601] ea 07 d2 1f 4c 86 d6 b4 cb 4a 21 42 b8 eb 0d 70 1c 75 14 a5 20 0a 1d d0
 [625] 38 fd 09 ba 01 fa c8 e2 6e 0b 0c 93 d4 30 a8 8a 91 9b ab fb 23 85 a5 26
 [649] 6f eb 2a c0 df 88 85 c4 3a bc 2c 38 42 7a 76 7a 6b df 02 81 81 00 dc b4
 [673] cd d1 bb 3c 82 f6 8b d4 6e 6f 7f 3e 71 1d 3f ac 57 59 24 5a 96 41 7b ff
 [697] 8f 57 3e a3 e7 00 41 fc ec 93 a8 cf 57 9b 91 f9 2b 7e 1d 7c 9a 7c c3 6e
 [721] 23 ba 68 d6 6b e9 ee fd 54 25 c7 85 af 29 d9 1a a7 52 d0 53 40 2e 60 c0
 [745] 9f 24 9a 3e 8c a1 a9 28 e4 fa 70 7c f0 c9 12 11 c0 02 af ae 12 9a e9 b0
 [769] e4 31 e4 53 78 4e fa 18 5a c8 2c cf 22 c2 0b 89 4e bb 8d 7b c8 3f 71 79
 [793] 19 a6 f1 34 65 17 02 81 80 18 df 89 67 12 5b 90 ac 86 0f 22 1f e7 05 f1
 [817] a6 ea ba e8 ed 41 6f 76 e4 5b 66 c2 c4 fe 10 10 d2 77 fa a4 5a 27 1d 47
 [841] b6 79 1b 31 d6 0d 2c 6d 79 18 e8 0d 7b 33 74 47 a5 0a e7 65 48 5d af 97
 [865] 94 2e eb a9 7b 3b 57 21 a0 8b d2 25 b8 8c 40 f4 e8 98 a7 ac 9c b6 bd 9a
 [889] 67 64 a8 f6 f7 c9 54 3b 96 e9 ac 88 2c 53 44 85 2e 64 bb a2 a4 08 94 df
 [913] d2 5a 16 b4 8b f4 71 61 3c 64 e5 41 6b 08 20 5c 5b 02 81 80 56 c3 ad 76
 [937] 1a 09 7b e2 b8 ad d6 8c 76 95 71 9a 72 01 aa 85 1c c9 8f f0 46 72 fd 42
 [961] eb 19 3c 22 d9 ce 38 a3 03 e6 1f 26 c5 88 13 15 0d 3a 82 f1 31 53 07 30
 [985] ad 2e 3e 56 44 e1 ca 46 df dd 2a 33 65 6a 19 05
 [ reached getOption("max.print") -- omitted 191 entries ]

# 查看pkcs1格式
> ca.pkcs1<-write_pkcs1(cakey);ca.pkcs1
[1] "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA1iLmJeJHYeVutw6Ui+V/tZs2SS4GFzTWRkoRmmt4Z+5jQMt/\ndv94WbjmKyvNNrXiNiGz1jZQsw2Bj+22rSKjGEh4Qipjpcc+AOfl99V3diH8YM/c\nwj6dNFKqqmpJHtzDSbhOudPbwDsFugq3dyVsV1hMKrlEBetI7Qj/8kZSie1KL+QS\n00G+ISCHUes8f/eFHgd7sMXpOb65NJhAKZGSeT49V+IeF1M82VJEyV+x1p/C3ppA\nL9PTt3RFftTQJjXW48tIfS3R85E0libyeQnlxM3slEf2UnO16wq/7j3KmWiPD9vm\ntPnhNjKbBr6PbtAR+CAsSpxaVLMpA1PDydqsCQIDAQABAoIBAQDKI22QK3do0TTf\nNrNBECarH1ZyZDC5rVXsSjUtyO+DZIRrAO5VPbm1MJaOAC4azD07Djt+Jg2tyD0a\nybIc48qDvL1Q8ETalCdSoZXzip3XdSORnAZvkr3BS5vxfJ2Dta/fok0mm/ggEVdJ\nlJ41qa0JEr/rwLGWyNExeMJrSLjXmt4S3fkZNJ12icCRKddeFyTL17LEf6lENXol\ne/SWuvB1+RhZb73eJVMPTJcoRXulJ0/pUD2QxLMn/YhvMVH8A13v9TipmS51mwLP\nFN8F9BNm2K6QXHgQLghjYbpDk1pRTzj+4Yr6dbWZipHSWWJy1WKMm93M+5VNuG6a\ntKGj/HQ1AoGBAPhhIxczFZxhd4qs6t09OkU2aEpGYcdMGEYFd7OUYhjUOhXHUMMC\nuUWAq2555VaUrKhlqovp+uTdMESop7Ac6gfSH0yG1rTLSiFCuOsNcBx1FKUgCh3Q\nOP0JugH6yOJuCwyT1DCoipGbq/sjhaUmb+sqwN+IhcQ6vCw4Qnp2emvfAoGBANy0\nzdG7PIL2i9Rub38+cR0/rFdZJFqWQXv/j1c+o+cAQfzsk6jPV5uR+St+HXyafMNu\nI7po1mvp7v1UJceFrynZGqdS0FNALmDAnySaPoyhqSjk+nB88MkSEcACr64Smumw\n5DHkU3hO+hhayCzPIsILiU67jXvIP3F5GabxNGUXAoGAGN+JZxJbkKyGDyIf5wXx\npuq66O1Bb3bkW2bCxP4QENJ3+qRaJx1HtnkbMdYNLG15GOgNezN0R6UK52VIXa+X\nlC7rqXs7VyGgi9IluIxA9OiYp6yctr2aZ2So9vfJVDuW6ayILFNEhS5ku6KkCJTf\n0loWtIv0cWE8ZOVBawggXFsCgYBWw612Ggl74rit1ox2lXGacgGqhRzJj/BGcv1C\n6xk8ItnOOKMD5h8mxYgTFQ06gvExUwcwrS4+VkThykbf3SozZWoZBXFoiP6ygocN\nuKWGW7dIoFvkBPoT0cqwlV3DLQVBgYz0IDLARSwEjwvKsdOUPTzJeunwE5T9YwI2\novRaGQKBgF0zysxImSvnC8jQFB5+jw5dCnP8gXDljZPDJhxwlkbNc85ikA27vSkQ\n+ql0YOsgka3DH4ISOpMGJXaCTkI86OXtLlG0HBjLgiiyYQnFieQ1xPB3PfCPKWHl\nG84TmLUw9uxC08jV0r7UfIDBxv7kNGDLJqyTmsCYON9EXbbt03ac\n-----END RSA PRIVATE KEY-----\n"

# 查看PEM格式
> ca.pem<-write_pem(cakey);ca.pem
[1] "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDWIuYl4kdh5W63\nDpSL5X+1mzZJLgYXNNZGShGaa3hn7mNAy392/3hZuOYrK802teI2IbPWNlCzDYGP\n7batIqMYSHhCKmOlxz4A5+X31Xd2Ifxgz9zCPp00Uqqqakke3MNJuE6509vAOwW6\nCrd3JWxXWEwquUQF60jtCP/yRlKJ7Uov5BLTQb4hIIdR6zx/94UeB3uwxek5vrk0\nmEApkZJ5Pj1X4h4XUzzZUkTJX7HWn8LemkAv09O3dEV+1NAmNdbjy0h9LdHzkTSW\nJvJ5CeXEzeyUR/ZSc7XrCr/uPcqZaI8P2+a0+eE2MpsGvo9u0BH4ICxKnFpUsykD\nU8PJ2qwJAgMBAAECggEBAMojbZArd2jRNN82s0EQJqsfVnJkMLmtVexKNS3I74Nk\nhGsA7lU9ubUwlo4ALhrMPTsOO34mDa3IPRrJshzjyoO8vVDwRNqUJ1KhlfOKndd1\nI5GcBm+SvcFLm/F8nYO1r9+iTSab+CARV0mUnjWprQkSv+vAsZbI0TF4wmtIuNea\n3hLd+Rk0nXaJwJEp114XJMvXssR/qUQ1eiV79Ja68HX5GFlvvd4lUw9MlyhFe6Un\nT+lQPZDEsyf9iG8xUfwDXe/1OKmZLnWbAs8U3wX0E2bYrpBceBAuCGNhukOTWlFP\nOP7hivp1tZmKkdJZYnLVYoyb3cz7lU24bpq0oaP8dDUCgYEA+GEjFzMVnGF3iqzq\n3T06RTZoSkZhx0wYRgV3s5RiGNQ6FcdQwwK5RYCrbnnlVpSsqGWqi+n65N0wRKin\nsBzqB9IfTIbWtMtKIUK46w1wHHUUpSAKHdA4/Qm6AfrI4m4LDJPUMKiKkZur+yOF\npSZv6yrA34iFxDq8LDhCenZ6a98CgYEA3LTN0bs8gvaL1G5vfz5xHT+sV1kkWpZB\ne/+PVz6j5wBB/OyTqM9Xm5H5K34dfJp8w24jumjWa+nu/VQlx4WvKdkap1LQU0Au\nYMCfJJo+jKGpKOT6cHzwyRIRwAKvrhKa6bDkMeRTeE76GFrILM8iwguJTruNe8g/\ncXkZpvE0ZRcCgYAY34lnEluQrIYPIh/nBfGm6rro7UFvduRbZsLE/hAQ0nf6pFon\nHUe2eRsx1g0sbXkY6A17M3RHpQrnZUhdr5eULuupeztXIaCL0iW4jED06JinrJy2\nvZpnZKj298lUO5bprIgsU0SFLmS7oqQIlN/SWha0i/RxYTxk5UFrCCBcWwKBgFbD\nrXYaCXviuK3WjHaVcZpyAaqFHMmP8EZy/ULrGTwi2c44owPmHybFiBMVDTqC8TFT\nBzCtLj5WROHKRt/dKjNlahkFcWiI/rKChw24pYZbt0igW+QE+hPRyrCVXcMtBUGB\njPQgMsBFLASPC8qx05Q9PMl66fATlP1jAjai9FoZAoGAXTPKzEiZK+cLyNAUHn6P\nDl0Kc/yBcOWNk8MmHHCWRs1zzmKQDbu9KRD6qXRg6yCRrcMfghI6kwYldoJOQjzo\n5e0uUbQcGMuCKLJhCcWJ5DXE8Hc98I8pYeUbzhOYtTD27ELTyNXSvtR8gMHG/uQ0\nYMsmrJOawJg430Rdtu3Tdpw=\n-----END PRIVATE KEY-----\n"

再以纯文本方式进行读取ca.key文件,并与PEM和pkcs1格式进行对比,发现key与pkcs1格式项目,这样就明确了ca.key是用pkcs1格式进行存储的。


# 以纯文本方式进行读取
> ca.txt<-readLines("./ca.key");ca.txt
 [1] "-----BEGIN RSA PRIVATE KEY-----"                                 
 [2] "MIIEowIBAAKCAQEA1iLmJeJHYeVutw6Ui+V/tZs2SS4GFzTWRkoRmmt4Z+5jQMt/"
 [3] "dv94WbjmKyvNNrXiNiGz1jZQsw2Bj+22rSKjGEh4Qipjpcc+AOfl99V3diH8YM/c"
 [4] "wj6dNFKqqmpJHtzDSbhOudPbwDsFugq3dyVsV1hMKrlEBetI7Qj/8kZSie1KL+QS"
 [5] "00G+ISCHUes8f/eFHgd7sMXpOb65NJhAKZGSeT49V+IeF1M82VJEyV+x1p/C3ppA"
 [6] "L9PTt3RFftTQJjXW48tIfS3R85E0libyeQnlxM3slEf2UnO16wq/7j3KmWiPD9vm"
 [7] "tPnhNjKbBr6PbtAR+CAsSpxaVLMpA1PDydqsCQIDAQABAoIBAQDKI22QK3do0TTf"
 [8] "NrNBECarH1ZyZDC5rVXsSjUtyO+DZIRrAO5VPbm1MJaOAC4azD07Djt+Jg2tyD0a"
 [9] "ybIc48qDvL1Q8ETalCdSoZXzip3XdSORnAZvkr3BS5vxfJ2Dta/fok0mm/ggEVdJ"
[10] "lJ41qa0JEr/rwLGWyNExeMJrSLjXmt4S3fkZNJ12icCRKddeFyTL17LEf6lENXol"
[11] "e/SWuvB1+RhZb73eJVMPTJcoRXulJ0/pUD2QxLMn/YhvMVH8A13v9TipmS51mwLP"
[12] "FN8F9BNm2K6QXHgQLghjYbpDk1pRTzj+4Yr6dbWZipHSWWJy1WKMm93M+5VNuG6a"
[13] "tKGj/HQ1AoGBAPhhIxczFZxhd4qs6t09OkU2aEpGYcdMGEYFd7OUYhjUOhXHUMMC"
[14] "uUWAq2555VaUrKhlqovp+uTdMESop7Ac6gfSH0yG1rTLSiFCuOsNcBx1FKUgCh3Q"
[15] "OP0JugH6yOJuCwyT1DCoipGbq/sjhaUmb+sqwN+IhcQ6vCw4Qnp2emvfAoGBANy0"
[16] "zdG7PIL2i9Rub38+cR0/rFdZJFqWQXv/j1c+o+cAQfzsk6jPV5uR+St+HXyafMNu"
[17] "I7po1mvp7v1UJceFrynZGqdS0FNALmDAnySaPoyhqSjk+nB88MkSEcACr64Smumw"
[18] "5DHkU3hO+hhayCzPIsILiU67jXvIP3F5GabxNGUXAoGAGN+JZxJbkKyGDyIf5wXx"
[19] "puq66O1Bb3bkW2bCxP4QENJ3+qRaJx1HtnkbMdYNLG15GOgNezN0R6UK52VIXa+X"
[20] "lC7rqXs7VyGgi9IluIxA9OiYp6yctr2aZ2So9vfJVDuW6ayILFNEhS5ku6KkCJTf"
[21] "0loWtIv0cWE8ZOVBawggXFsCgYBWw612Ggl74rit1ox2lXGacgGqhRzJj/BGcv1C"
[22] "6xk8ItnOOKMD5h8mxYgTFQ06gvExUwcwrS4+VkThykbf3SozZWoZBXFoiP6ygocN"
[23] "uKWGW7dIoFvkBPoT0cqwlV3DLQVBgYz0IDLARSwEjwvKsdOUPTzJeunwE5T9YwI2"
[24] "ovRaGQKBgF0zysxImSvnC8jQFB5+jw5dCnP8gXDljZPDJhxwlkbNc85ikA27vSkQ"
[25] "+ql0YOsgka3DH4ISOpMGJXaCTkI86OXtLlG0HBjLgiiyYQnFieQ1xPB3PfCPKWHl"
[26] "G84TmLUw9uxC08jV0r7UfIDBxv7kNGDLJqyTmsCYON9EXbbt03ac"            
[27] "-----END RSA PRIVATE KEY-----"      

# 比较纯文本格式和PEM格式,不相同
> identical(paste0(ca.txt,"\n",collapse = ""),ca.pem)
[1] FALSE

# 比较纯文本格式和pkcs1格式,相同
> identical(paste0(ca.txt,"\n",collapse = ""),ca.pkcs1)
[1] TRUE

3.2 取读ca.key的公钥并输出
在ca.key文件中,不仅包括了私钥信息还包括了公钥信息。有2个种方法,可以获取公钥信息。一是使用上面的私钥对象,取出公钥,二是使用read_pubkey()函数进行读取。

首先使用刚刚生成的cakey对象,来获取公钥。


> cakey$pubkey
[2048-bit rsa public key]
md5: 87be025db1f33785aafa00aa83388a8b
sha256: c03bc0d35b4593ff81cde4545b1aa62f80e754545297f30669bdcce29a910a45

再使用read_pubkey()函数,来获取公钥。


> cakey_pub<-read_pubkey("./ca.key");cakey_pub # public
[2048-bit rsa public key]
md5: 87be025db1f33785aafa00aa83388a8b
sha256: c03bc0d35b4593ff81cde4545b1aa62f80e754545297f30669bdcce29a910a45

# 比较2个结果,相同
> identical(cakey_pub,cakey$pubkey)
[1] TRUE

还没有公钥文件,我们可以输出这个文件,用pkcs1格式


# 输出公钥文件
> write_pkcs1(cakey_pub,"./ca_pub.key")

# 读取输出的公钥文件
> read_pubkey("./ca_pub.key")
[2048-bit rsa public key]
md5: 87be025db1f33785aafa00aa83388a8b
sha256: c03bc0d35b4593ff81cde4545b1aa62f80e754545297f30669bdcce29a910a45

3.3 取读ca.crt证书文件
除了能读取秘钥,还可以进行证书的读取。


# 读取证书文件
> file<-"ca.crt"
> cacrt<-read_cert(file, der = is.raw(file))

# 查看证书对象
> cacrt
[x509 certificate] myca.com
md5: 916c490f78b0f068a9ea6f7b0ded5bd5
sha1: be2eed543b4188fdc08bee8dfb0adf403e7437bf

# 查看证书链式对象 
> read_cert_bundle(file)
[[1]]
[x509 certificate] myca.com
md5: 916c490f78b0f068a9ea6f7b0ded5bd5
sha1: be2eed543b4188fdc08bee8dfb0adf403e7437bf

接下来,查看证书的文件存储格式,证书的文件格式是以PEM格式进行存储的。


# 以PEM格式查看证书内容
> cacrt.pem<-write_pem(cacrt);cacrt.pem
[1] "-----BEGIN CERTIFICATE-----\nMIID7TCCAtWgAwIBAgIUcV2+3ipz02Qccfqe5rT1sSY43LYwDQYJKoZIhvcNAQEL\nBQAwgYUxCzAJBgNVBAYTAlpIMQswCQYDVQQIDAJCSjEQMA4GA1UEBwwHQkVJSklO\nRzEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMREwDwYDVQQDDAht\neWNhLmNvbTEhMB8GCSqGSIb3DQEJARYSYnNzcGlyaXRAZ21haWwuY29tMB4XDTIy\nMTEzMDA5NDA0M1oXDTIzMTEzMDA5NDA0M1owgYUxCzAJBgNVBAYTAlpIMQswCQYD\nVQQIDAJCSjEQMA4GA1UEBwwHQkVJSklORzEhMB8GA1UECgwYSW50ZXJuZXQgV2lk\nZ2l0cyBQdHkgTHRkMREwDwYDVQQDDAhteWNhLmNvbTEhMB8GCSqGSIb3DQEJARYS\nYnNzcGlyaXRAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\nAQEA1iLmJeJHYeVutw6Ui+V/tZs2SS4GFzTWRkoRmmt4Z+5jQMt/dv94WbjmKyvN\nNrXiNiGz1jZQsw2Bj+22rSKjGEh4Qipjpcc+AOfl99V3diH8YM/cwj6dNFKqqmpJ\nHtzDSbhOudPbwDsFugq3dyVsV1hMKrlEBetI7Qj/8kZSie1KL+QS00G+ISCHUes8\nf/eFHgd7sMXpOb65NJhAKZGSeT49V+IeF1M82VJEyV+x1p/C3ppAL9PTt3RFftTQ\nJjXW48tIfS3R85E0libyeQnlxM3slEf2UnO16wq/7j3KmWiPD9vmtPnhNjKbBr6P\nbtAR+CAsSpxaVLMpA1PDydqsCQIDAQABo1MwUTAdBgNVHQ4EFgQU55Mc/d8s7WlF\n0HaorBq64rcFJXIwHwYDVR0jBBgwFoAU55Mc/d8s7WlF0HaorBq64rcFJXIwDwYD\nVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAP6Vfs0SX8035Qo3nccOf\niemkfsMoH8Jme7TNT8sv19hxdVhtHw5pgPxsJfb5Upwp5RjQogdruPBXW86MVgSh\nxYptVH94L4QIPZFLvuPzTE1j03/44jm1mwvOGu7jf27Bb683Ltp6MoL9yoJylEYl\nFwYaowelmZnkAFArdy/QG/tgMuW3wh1ThACg1ZKDcnw+ncX5oAzJIa7ydAIUjyJO\nQpJvtrPfV23bGds3swICxZIPNLE7iAN5z9br1DZNJ+GoMrgCHlrvPilagY/LKzWu\nq9+IwP6mVY7egc+os7FQKQ3nFbGBBAE41m9HKP6Tw8kUhK8HcaViuFHbUOeftv8F\nhQ==\n-----END CERTIFICATE-----\n"

# 以pkcs1格式查看证书内容,报错。
> cacrt.pkcs1<-write_pkcs1(cacrt);cacrt.pkcs1
Error in write_pkcs1(cacrt) : PKCS1 pubkey format only supports RSA keys

# 以纯文件的方式读取证书文件
> cacrt.txt<-readLines(file);cacrt.txt
 [1] "-----BEGIN CERTIFICATE-----"                                     
 [2] "MIID7TCCAtWgAwIBAgIUcV2+3ipz02Qccfqe5rT1sSY43LYwDQYJKoZIhvcNAQEL"
 [3] "BQAwgYUxCzAJBgNVBAYTAlpIMQswCQYDVQQIDAJCSjEQMA4GA1UEBwwHQkVJSklO"
 [4] "RzEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMREwDwYDVQQDDAht"
 [5] "eWNhLmNvbTEhMB8GCSqGSIb3DQEJARYSYnNzcGlyaXRAZ21haWwuY29tMB4XDTIy"
 [6] "MTEzMDA5NDA0M1oXDTIzMTEzMDA5NDA0M1owgYUxCzAJBgNVBAYTAlpIMQswCQYD"
 [7] "VQQIDAJCSjEQMA4GA1UEBwwHQkVJSklORzEhMB8GA1UECgwYSW50ZXJuZXQgV2lk"
 [8] "Z2l0cyBQdHkgTHRkMREwDwYDVQQDDAhteWNhLmNvbTEhMB8GCSqGSIb3DQEJARYS"
 [9] "YnNzcGlyaXRAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC"
[10] "AQEA1iLmJeJHYeVutw6Ui+V/tZs2SS4GFzTWRkoRmmt4Z+5jQMt/dv94WbjmKyvN"
[11] "NrXiNiGz1jZQsw2Bj+22rSKjGEh4Qipjpcc+AOfl99V3diH8YM/cwj6dNFKqqmpJ"
[12] "HtzDSbhOudPbwDsFugq3dyVsV1hMKrlEBetI7Qj/8kZSie1KL+QS00G+ISCHUes8"
[13] "f/eFHgd7sMXpOb65NJhAKZGSeT49V+IeF1M82VJEyV+x1p/C3ppAL9PTt3RFftTQ"
[14] "JjXW48tIfS3R85E0libyeQnlxM3slEf2UnO16wq/7j3KmWiPD9vmtPnhNjKbBr6P"
[15] "btAR+CAsSpxaVLMpA1PDydqsCQIDAQABo1MwUTAdBgNVHQ4EFgQU55Mc/d8s7WlF"
[16] "0HaorBq64rcFJXIwHwYDVR0jBBgwFoAU55Mc/d8s7WlF0HaorBq64rcFJXIwDwYD"
[17] "VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAP6Vfs0SX8035Qo3nccOf"
[18] "iemkfsMoH8Jme7TNT8sv19hxdVhtHw5pgPxsJfb5Upwp5RjQogdruPBXW86MVgSh"
[19] "xYptVH94L4QIPZFLvuPzTE1j03/44jm1mwvOGu7jf27Bb683Ltp6MoL9yoJylEYl"
[20] "FwYaowelmZnkAFArdy/QG/tgMuW3wh1ThACg1ZKDcnw+ncX5oAzJIa7ydAIUjyJO"
[21] "QpJvtrPfV23bGds3swICxZIPNLE7iAN5z9br1DZNJ+GoMrgCHlrvPilagY/LKzWu"
[22] "q9+IwP6mVY7egc+os7FQKQ3nFbGBBAE41m9HKP6Tw8kUhK8HcaViuFHbUOeftv8F"
[23] "hQ=="                                                            
[24] "-----END CERTIFICATE-----"                                       

# 验证纯文本的证书与PEM格式,相同。
> identical(paste0(cacrt.txt,"\n",collapse = ""),cacrt.pem)
[1] TRUE

最后,可以把证书重写到一个新文件中,再读取,可得到完成一样的证书数据。


> write_pem(cacrt,"cacrt.crt.bak")
> read_cert("cacrt.crt.bak")
[x509 certificate] myca.com
md5: 916c490f78b0f068a9ea6f7b0ded5bd5
sha1: be2eed543b4188fdc08bee8dfb0adf403e7437bf

4. 获取网站证书并验证

如果我们想让自己的网站支持HTTPS,实现SSL/TLS协议时就需要用到证书;或者当我们想配置github的git的自动权限访问时,也需要使用用到证书;当我们在使用Linux,想进行无密码登陆时,这时也可以用证书。

利用openssl工具,我们可以获得各种网站的证书,查看网站的证书的相关信息,数字签名的信息,通过HTTPS传输的加密算法等信息,最后可以验证证书是否是合法的。

4.1 在浏览器网站证书
我们访问R的官方网站,https://www.r-project.org/,网站是HTTPS的,我们可以手动查看网站的证书。在证书中的,证书颁发者,SHA1,SHA256,有效期,公钥等的信息。

我们可以手动下载证书文件,在本地进行打开。

4.2 用R语言来下载证书
接下来,我们可以用R语言的程序,来获取证书信息,


# 证书下载
> cert <- download_ssl_cert("www.r-project.org")

查看当前证书,上级证书,一直到root证书。


> cert
[[1]]
[x509 certificate] *.r-project.org
md5: 11a9fee5a83206c063a203c97f71481b
sha1: 03c310e4971981154ada3a5df46206dadfb82172

[[2]]
[x509 certificate] Sectigo RSA Domain Validation Secure Server CA
md5: adab5c4df031fb9299f71ada7e18f613
sha1: 33e4e80807204c2b6182a3a14b591acd25b5f0db

[[3]]
[x509 certificate] USERTrust RSA Certification Authority
md5: 285ec909c4ab0d2d57f5086b225799aa
sha1: d89e3bd43d5d909b47a18977aa9d5ce36cee184c

4.3 查看当前证书的详细

取当前证书,看证书的信息。当前证书允许的域名。


# 取当前证书
> cert_data<-cert[[1]]

# 允许域名
> cert_data$alt_names
[1] "*.r-project.org" "r-project.org"  

# 查看cert_data的数据结构
> str(cert_data)
List of 8
 $ subject    : chr "CN=*.r-project.org"
 $ issuer     : chr "CN=Sectigo RSA Domain Validation Secure Server CA,O=Sectigo Limited,L=Salford,ST=Greater Manchester,C=GB"
 $ algorithm  : chr "sha256WithRSAEncryption"
 $ signature  : raw [1:256] b1 2f f9 a5 ...
 $ validity   : chr [1:2] "Oct 23 00:00:00 2022 GMT" "Nov 23 23:59:59 2023 GMT"
 $ self_signed: logi FALSE
 $ alt_names  : chr [1:2] "*.r-project.org" "r-project.org"
 $ pubkey     :List of 5
  ..$ type       : chr "rsa"
  ..$ size       : int 2048
  ..$ ssh        : chr "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQ/cx8HyMW9SCLJsC/UKaTh/RskQ33Leicy0prlBc2Dm3Tk/m1Dn7cpwGZ ..."
  ..$ fingerprint: 'hash' raw [1:32] a7 68 11 fb ...
  ..$ data       :List of 2
  .. ..$ e: 'bignum' raw [1:3] 01 00 01
  .. ..$ n: 'bignum' raw [1:257] 00 d0 fd cc ...

4.4 查看公钥信息
查看公钥信息,使用了RSA的2048位加密,查看公钥的二进制格式,就与网上在看到的公钥内容是一致的。


# 查看公钥为2048位的RSA加密
> cert_data$pubkey
[2048-bit rsa public key]
md5: 6b372d9b5c5759fbb28baf03c609730a
sha256: a76811fbe1608aeeb74f077b63e07c8fea82fdf4789c01c7b5b975a8958eb12b

# 公钥的ssh码
> cert_data$pubkey$ssh
[1] "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQ/cx8HyMW9SCLJsC/UKaTh/RskQ33Leicy0prlBc2Dm3Tk/m1Dn7cpwGZQrsS4ak1IaV5WroeJjWUzEiaJH5Ky4vJOGWJYXoXw5THDFxraaCk4CPd/cQuFkezY6iuEYORuNYoukV9xgXhfaGJN4K8Gan6Hi8syY6HqnOiSt887GUZckO7TQF3RishPlbLzx0G17inlhigDFtoFenG/x043EwkIFJ6pz1jA8h/Us29Rw1+853AwNZ/nOptaUFku6W3uXgf4TLYUn6NzPSKY6lJ34gpSoBVQIIU8hjz2Y3cwlIzgQnrw2qlzDmFmiZtjPTaMrvBzs5QHfsgOBHvc5j/"

# 查看公钥的二进制格式
> write_der(cert_data$pubkey)
  [1] 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a
 [29] 02 82 01 01 00 d0 fd cc 7c 1f 23 16 f5 20 8b 26 c0 bf 50 a6 93 87 f4 6c 91 0d f7 2d
 [57] e8 9c cb 4a 6b 94 17 36 0e 6d d3 93 f9 b5 0e 7e dc a7 01 99 42 bb 12 e1 a9 35 21 a5
 [85] 79 5a ba 1e 26 35 94 cc 48 9a 24 7e 4a cb 8b c9 38 65 89 61 7a 17 c3 94 c7 0c 5c 6b
[113] 69 a0 a4 e0 23 dd fd c4 2e 16 47 b3 63 a8 ae 11 83 91 b8 d6 28 ba 45 7d c6 05 e1 7d
[141] a1 89 37 82 bc 19 a9 fa 1e 2f 2c c9 8e 87 aa 73 a2 4a df 3c ec 65 19 72 43 bb 4d 01
[169] 77 46 2b 21 3e 56 cb cf 1d 06 d7 b8 a7 96 18 a0 0c 5b 68 15 e9 c6 ff 1d 38 dc 4c 24
[197] 20 52 7a a7 3d 63 03 c8 7f 52 cd bd 47 0d 7e f3 9d c0 c0 d6 7f 9c ea 6d 69 41 64 bb
[225] a5 b7 b9 78 1f e1 32 d8 52 7e 8d cc f4 8a 63 a9 49 df 88 29 4a 80 55 40 82 14 f2 18
[253] f3 d9 8d dc c2 52 33 81 09 eb c3 6a a5 cc 39 85 9a 26 6d 8c f4 da 32 bb c1 ce ce 50
[281] 1d fb 20 38 11 ef 73 98 ff 02 03 01 00 01

# 查看公钥数据
> cert_data$pubkey$data
$e
[b] 65537
$n
[b] 26382720270417477837617835499791330099049934775392664891485281047561411831161618531639849698257940022133596595793360566082157334663831597661390020187366330377887609444158710396573956877965613421020593308923784748020878445065836239835939589641288489663966645774920702533024654777130568392213769053338143063817255841711707909827551784702236553682744092755623610745991474611454202317512454804265930433899882101055065400009265523412830694180236095124621448935253985091450512509725554745453130660854770715808981111924477167623114187044856057832860089329518157485613424693402698364749754164433810264444699764245619172153599

4.5 验证证书是否真实有效
验证证书是否真实有效,ca_bundle()函数可以获得所有root证书的机构,通过比对当前证书的root机构与登记的机构比对,从而判断当前证书的真实性。


# 验证证书是否真实有效
> cert_verify(cert, ca_bundle())
[1] TRUE

# 查看root证书的机构的前6条
> head(ca_bundle())
[[1]]
[x509 certificate] GlobalSign Root CA
md5: 3e455215095192e1b75d379fb187298a
sha1: b1bc968bd4f49d622aa89a81f2150152a41d829c

[[2]]
[x509 certificate] GlobalSign
md5: 9414777e3e5efd8f30bd41b0cfe7d030
sha1: 75e0abb6138512271c04f85fddde38e4b7242efe

[[3]]
[x509 certificate] VeriSign Class 3 Public Primary Certification Authority - G3
md5: cd68b6a7c7c4ce75e01d4f5744619209
sha1: 132d0d45534b6997cdb2d5c339e25576609b5cc6

[[4]]
[x509 certificate] Entrust.net Certification Authority (2048)
md5: ee2931bc327e9ae6e8b5f751b4347190
sha1: 503006091d97d4f5ae39f7cbe7927d7d652d3431

[[5]]
[x509 certificate] Baltimore CyberTrust Root
md5: acb694a59c17e0d791529bb19706a6e4
sha1: d4de20d05e66fc53fe1a50882c78db2852cae474

[[6]]
[x509 certificate] AddTrust External CA Root
md5: 1d3554048578b03f42424dbf20730a3f
sha1: 02faf3e291435468607857694df5e45b68851868

4.6 导出密钥或证书
使用write_pem() 函数将钥匙或证书导出为标准的base64 PEM格式。对于私钥,可以设置一个密码。


# 查看证书的密文
> write_pem(cert_data)
[1] "-----BEGIN CERTIFICATE-----\nMIIGNzCCBR+gAwIBAgIQVDDlPXe+N3mjxP1zcGBexzANBgkqhkiG9w0BAQsFADCB\njzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD\nEy5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB\nMB4XDTIyMTAyMzAwMDAwMFoXDTIzMTEyMzIzNTk1OVowGjEYMBYGA1UEAwwPKi5y\nLXByb2plY3Qub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0P3M\nfB8jFvUgiybAv1Cmk4f0bJEN9y3onMtKa5QXNg5t05P5tQ5+3KcBmUK7EuGpNSGl\neVq6HiY1lMxImiR+SsuLyThliWF6F8OUxwxca2mgpOAj3f3ELhZHs2OorhGDkbjW\nKLpFfcYF4X2hiTeCvBmp+h4vLMmOh6pzokrfPOxlGXJDu00Bd0YrIT5Wy88dBte4\np5YYoAxbaBXpxv8dONxMJCBSeqc9YwPIf1LNvUcNfvOdwMDWf5zqbWlBZLult7l4\nH+Ey2FJ+jcz0imOpSd+IKUqAVUCCFPIY89mN3MJSM4EJ68Nqpcw5hZombYz02jK7\nwc7OUB37IDgR73OY/wIDAQABo4IDATCCAv0wHwYDVR0jBBgwFoAUjYxexFStiuF3\n6Zv5mwXhuAGNYeEwHQYDVR0OBBYEFAnIMghgCgq5FuZgZW2gz333Rr0yMA4GA1Ud\nDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr\nBgEFBQcDAjBJBgNVHSAEQjBAMDQGCysGAQQBsjEBAgIHMCUwIwYIKwYBBQUHAgEW\nF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAECATCBhAYIKwYBBQUHAQEE\neDB2ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29S\nU0FEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0MCMGCCsGAQUFBzAB\nhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTApBgNVHREEIjAggg8qLnItcHJvamVj\ndC5vcmeCDXItcHJvamVjdC5vcmcwggF/BgorBgEEAdZ5AgQCBIIBbwSCAWsBaQB3\nAK33vvp8/xDIi509nB4+GGq0Zyldz7EMJMqFhjTr3IKKAAABhAKZWJgAAAQDAEgw\nRgIhAJdfvjFXbRU053wGkFTCa6M/FZ9AQXpIWKw3XGmtclmPAiEA6FRxqIJ2qam2\naLj5lvj/YuiD+ohMvaeRL78TlAt1dSoAdgB6MoxU2LcttiDqOOBSHumEFnAyE4VN\nO9IrwTpXo1LrUgAAAYQCmViyAAAEAwBHMEUCIQCWAMENLlPBh73qMoqix/AIwr/g\niLrKwc4yKkcXNY49bQIgQWjhgFm/o/QL3NuoyaY5Gs0J7BWjJr4AHQn14cFmKAAA\ndgDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYQCmVh7AAAEAwBH\nMEUCIQCV0vEGrO3f/pH9ew1fNwFE40nrB17r/8XAwyiWI5cg7gIgZ3RQ3PKI1zFq\npiW86XgKgU9EnW1GjNzKJfxb4SMPuJkwDQYJKoZIhvcNAQELBQADggEBALEv+aVn\ndC0VLCw+CoBYt5cpWkwPfKpWewAC9fw2Q9womhmrN9+C51kX0JZpEE2V1oG5lahp\n5fUi5XwZRT+/1wNIz5GDLMbumY+m7dQp6NE+XApYSd/J+HnLoKAuVI+YosOtHhF/\n07cMNogiVhEldeOweo8Z8YxCmb/EzSY30wdHNNASf5s2TQ0tlZ1NzKTzt/gpOXDp\njgQJE4zXamym3qNGDumhbEWKozQqLVo2OOYgak8OkeDzar48MQdc3vvtO0B1heRh\nvZ2FezAFWDfHcldXJK2W/DOpprE+oIRjlYKztXG3r/aYpu59vMsAIhGWuC6Vg2Yx\nk8Umv/fhAjEe/xc=\n-----END CERTIFICATE-----\n"

本文尝试了使用openssl 的命令行工具,和R语言中的openssl包的秘钥和x509证书管理的函数,进行了秘钥生成,证书生成,证书管理,证书下载,证书验证等的功能尝试。里面有不少的密码学的内容,是需要我们先理解后再进行操作的。

唯一遗憾的就是不能直接用R语言进行证书的生成。openssl博大精深,一个包支持非常多的密码学的内容。

本文代码已上传到github: https://github.com/bsspirit/encrypt/blob/master/cert.r

转载请注明出处:
http://blog.fens.me/r-crypto-openssl-cert/

打赏作者