使用rsa进行http传输加密

? 版权声明:本文为博主原创文章,转载请注明出处

[TOC]

1. RSA算法

RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。

今天只有短的RSA钥匙才可能被强力方式破解。但在分布式计算和量子计算机理论日趋成熟的今天,RSA加密安全性收到了挑战和质疑。

RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解缺及其困难,因此可以将乘积公开作为加密密钥。

2. HTTPS

2.1 HTTPS优点

1. 使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器。

2. HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比HTTP协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。

3. HTTPS是现行框架下最安全的解决方案,虽然不是觉得安全,但它增加了中间人攻击的成本。

2.2 HTTPS缺点

1. SSL的专业证书需要购买,功能越强大的证书费用越高

2. 相同的网络环境下,HTTPS协议会使页面的加载时间延长50%,增加10%-20%的耗电。此外,HTTPS协议还会影响缓存,增加数据开销和功耗。

3. HTTPS协议的安全性是有范围的,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。

4. 最关键的是,SSL证书的信用链体系并不安全。特别是在某些国家可以控制CA根证书的情况下,中间人攻击一样可行。

3. RSA传输加密实现

综上所述(其实主要是因为HTTPS购买SSL证书需要花钱),可在某些关键数据传输过程中进行RSA加密。比如:登录时对登录密码进行加密。

3.1 所需插件

3.1.1 JS插件

BigInt.js - 用于生成一个大整数(这是RSA算法的需要)

Barrett.js - RSA算法所需要用到的一个支持文件

RSA_Stripped.js - RSA的主要算法

下载密码:bhiq

3.1.2 所需JAR

bcprov-jdk15on
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.58</version>
</dependency>

3.1.3 代码

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.study</groupId>
    <artifactId>webrsa</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- bcprov-jdk15on -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.58</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <target>1.7</target>
                    <source>1.7</source>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
RSAUtils.java
package com.study.webrsa.utils;

import java.io.ByteArrayOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * RSA加解密工具类
 *
 */
public class RSAUtils {

    public static final String SECURITY = "RSA"; // 加密方式
    public static final String ALGORITHM = "MD5withRSA"; // 加密算法
    public static final String PUBLIC_KEY = "RSAPublicKey"; // 公钥
    public static final String PRIVATE_KEY = "RSAPrivateKey"; // 私钥

    /**
     * 获取密钥
     */
    public static Map<String, Object> getKey() {

        Map<String, Object> map = null;
        try {
            // 生成实现指定算法的KeyPairGenerator对象,用于生成密钥对
            KeyPairGenerator keyPairGenerator =
                    KeyPairGenerator.getInstance(SECURITY, new BouncyCastleProvider());
            keyPairGenerator.initialize(1024); // 初始化密钥长度
            KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 生成密钥对
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); // 获取公钥
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); // 获取私钥

            // 保存到map中
            map = new HashMap<String, Object>();
            map.put(PUBLIC_KEY, rsaPublicKey);
            map.put(PRIVATE_KEY, rsaPrivateKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;

    }

    /**
     * 利用私钥进行解密
     *
     * @param privateKey
     *                      私钥
     * @param str
     *                      密文
     * @return
     */
    public static String decrypt(RSAPrivateKey privateKey, String str) {

        try {
            System.out.println("密文为:" + str);
            // 获取实现指定转换的Cipher对象
            Cipher cipher = Cipher.getInstance("RSA/NONE/NoPadding", new BouncyCastleProvider());
            cipher.init(Cipher.DECRYPT_MODE, privateKey); // 用密钥初始化此Cipher对象

            int blockSize = cipher.getBlockSize(); // 返回块的大小
            byte[] bytes = hexStringToBytes(str); // 将十六进制转换为二进制
            int j = 0;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            while (bytes.length - j * blockSize > 0) { // 将二进制数据分块写入ByteArrayOutputStream中
                baos.write(cipher.doFinal(bytes, j * blockSize, blockSize));
                j++;
            }

            // 将二进制数据转换为字符串
            byte[] bs = baos.toByteArray();
            StringBuilder sb = new StringBuilder();
            sb.append(new String(bs));
            String pwd = sb.reverse().toString();
            System.out.println("明文为:" + pwd);
            return pwd;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 将十六进制字符串转换为二进制数组
     *
     * @param hexString
     *                  十六进制字符串
     * @return
     */
    private static byte[] hexStringToBytes(String hexString) {

        if (hexString == null || "".equals(hexString)) {
            return null;
        }

        hexString = hexString.toUpperCase(); // 全部转换为大写字符
        int length = hexString.length() / 2; // 获取十六进制数据个数
        char[] hexChars = hexString.toCharArray(); // 将十六进制字符串转换为字符数组
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2; // 开始位置
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    private static byte charToByte(char ch) {

        return (byte) "0123456789ABCDEF".indexOf(ch);

    }

}
login.jsp
<%@page import="java.util.Map"%>
<%@page import="java.security.interfaces.RSAPrivateKey"%>
<%@page import="java.security.interfaces.RSAPublicKey"%>
<%@page import="com.study.webrsa.utils.RSAUtils"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>用户登录</title>

    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<%
    // 获取密钥对
    Map<String, Object> map = RSAUtils.getKey();
    // 获取公钥
    RSAPublicKey rsaPublicKey = (RSAPublicKey) map.get(RSAUtils.PUBLIC_KEY);
    // 获取私钥
    RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) map.get(RSAUtils.PRIVATE_KEY);
    // 保存私钥到session中,便于后台进行解密
    session.setAttribute("rsaKey", rsaPrivateKey);
    // 保存公钥到request中,便于页面加密
    String publicExponent = rsaPublicKey.getPublicExponent().toString(16);
    String publicModulus = rsaPublicKey.getModulus().toString(16);
    request.setAttribute("publicExponent", publicExponent);
    request.setAttribute("publicModulus", publicModulus);
%>
<body>
    <div class="container-fluid">
        <form action="login" method="post" class="col-md-6 col-md-offset-3"
            onsubmit="return cmdEncrypt();">
            <div class="form-group">
                <label for="loginName">登录名</label>
                <input type="text" id="loginName" name="loginName" class="form-control"
                    placeholder="请输入用户名...">
            </div>
            <div class="form-group">
                <label for="loginPwd">登录密码</label>
                <input type="password" id="loginPwd" name="loginPwd" class="form-control"
                    placeholder="请输入登录密码...">
            </div>
            <button type="submit" class="btn btn-primary">登录</button>
        </form>
    </div>
</body>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    <script type="text/javascript" src="resources/rsa/BigInt.js"></script>
    <script type="text/javascript" src="resources/rsa/Barrett.js"></script>
    <script type="text/javascript" src="resources/rsa/RSA_Stripped.js"></script>
    <script type="text/javascript">

        // 提交前对密码进行加密
        function cmdEncrypt() {

            setMaxDigits(131);
            var pwd = $("#loginPwd").val(); // 获取原始密码
            var key = new RSAKeyPair("${publicExponent}", "", "${publicModulus}");
            pwd = encryptedString(key, pwd); // 对密码进行加密
            $("#loginPwd").val(pwd);
            return true;

        }

    </script>
</html>
LoginServlet.java
package com.study.webrsa.servlet;

import java.io.IOException;
import java.security.interfaces.RSAPrivateKey;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.study.webrsa.utils.RSAUtils;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        doPost(req, resp);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        // 设置编码格式
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");

        // 获取前台参数
        String loginName = req.getParameter("loginName");
        String loginPwd = req.getParameter("loginPwd");

        // 获取私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) req.getSession().getAttribute("rsaKey");

        // 对密码进行解密
        loginPwd = RSAUtils.decrypt(privateKey, loginPwd);

        // 校验
        if (true) {
            req.setAttribute("username", loginName);
            System.out.println("用户[" + loginName + "]用密码[" + loginPwd + "]登录本系统");
            req.getRequestDispatcher("/success.jsp").forward(req, resp);
        }

    }

}
success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录成功</title>
</head>
<body>
    <center>
        <h1>欢迎您,${username }</h1>
    </center>
</body>
</html>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>

</web-app>

4. 注意事项

4.1 setMaxDigits()

setMaxDigits(),到底应该传值多少?

在JS文件中给出公式为:n * 2 / 16。其中n为密钥长度。
    如果n为1024,则值应为 1024 * 2 / 16 = 128。

经过测试,传128后台解密会报错;正确的值应该大于128。

个人喜好的公式是:n * 2 / 16 + 3
即  密钥长度若为1024,其值为 131
    密钥长度若为2048,其值为 259

4.2 解密方式

在网上百度的代码,解密方式一般如下所示:
// 获取实现指定转换的Cipher对象
Cipher cipher = Cipher.getInstance("RSA/NONE/NoPadding", new BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, privateKey); // 用密钥初始化此Cipher对象

int blockSize = cipher.getBlockSize(); // 返回块的大小
byte[] bytes = new BigInteger(str, 16).toByteArray();
int j = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (bytes.length - j * blockSize > 0) { // 将二进制数据分块写入ByteArrayOutputStream中
    baos.write(cipher.doFinal(bytes, j * blockSize, blockSize));
    j++;
}
用上述方式,偶尔会报错如下所示:
java.lang.IllegalArgumentException: Bad arguments
    at javax.crypto.Cipher.doFinal(Cipher.java:2185)
    at com.study.webrsa.utils.RSAUtils.decrypt(RSAUtils.java:76)
    at com.study.webrsa.servlet.LoginServlet.doPost(LoginServlet.java:43)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1087)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
后发现问题就出现在toByteArray()上面,因为在用上面的三个JS进行加密时,偶尔得出的密文会比正确的密文多出一个byte,里面是o。

因此可使用如下方式:
// 获取实现指定转换的Cipher对象
Cipher cipher = Cipher.getInstance("RSA/NONE/NoPadding", new BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, privateKey); // 用密钥初始化此Cipher对象

int blockSize = cipher.getBlockSize(); // 返回块的大小
byte[] bytes = hexStringToBytes(str); // 将十六进制转换为二进制
int j = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (bytes.length - j * blockSize > 0) { // 将二进制数据分块写入ByteArrayOutputStream中
    baos.write(cipher.doFinal(bytes, j * blockSize, blockSize));
    j++;
}

/**
 * 将十六进制字符串转换为二进制数组
 *
 * @param hexString
 *                  十六进制字符串
 * @return
 */
private static byte[] hexStringToBytes(String hexString) {

    if (hexString == null || "".equals(hexString)) {
        return null;
    }

    hexString = hexString.toUpperCase(); // 全部转换为大写字符
    int length = hexString.length() / 2; // 获取十六进制数据个数
    char[] hexChars = hexString.toCharArray(); // 将十六进制字符串转换为字符数组
    byte[] d = new byte[length];
    for (int i = 0; i < length; i++) {
        int pos = i * 2; // 开始位置
        d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
    }
    return d;
}

private static byte charToByte(char ch) {

    return (byte) "0123456789ABCDEF".indexOf(ch);

}

参考:

JS加密Java解密报rsa bad argument

HTTPS优缺点、原理解析:我们的网站该不该做HTTPS?

更好的markdown体验:https://www.zybuluo.com/chy282/note/975080


时间: 2024-10-28 19:04:38

使用rsa进行http传输加密的相关文章

iOS中使用RSA对数据进行加密解密

RSA算法是一种非对称加密算法,常被用于加密数据传输.如果配合上数字摘要算法, 也可以用于文件签名. 本文将讨论如何在iOS中使用RSA传输加密数据. 本文环境 mac os openssl-1.0.1j, openssl需要使用1.x版本, 推荐使用[homebrew](http://brew.sh/)安装. Java 8 RSA基本原理 RSA使用"秘匙对"对数据进行加密解密.在加密解密数据前,需要先生成公钥(public key)和私钥(private key). 公钥(publ

使用X.509数字证书加密解密实务(三)-- 使用RSA证书结合对称加密技术加密长数据

本文全部源代码下载:/Files/chnking/EncryptLongData.rar 一.  使用证书结合对称加密算法加.解密长数据 上一章节讨论了如何使用RSA证书加密数据,文中提到:“Dotnet的RSA实现有个特点,它必须要在明文中添加一些随机数,所以明文不能把128字节占满,实际测试,明文最多为117字节,留下的空间用来填充随机数”.也就是说对于1024位密钥的RSA来说,一次只能加密128字节的数据,对于Dotnet的RSA实现更是只能加密117个字节的数据. 这就引出一个问题,超

Python使用rsa模块实现非对称加密与解密

Python使用rsa模块实现非对称加密与解密 1.简单介绍: RSA加密算法是一种非对称加密算法 是由已知加密密钥推导出解密密钥在计算上是不可行的"密码体制.加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的. RSA密钥至少为500位长,一般推荐使用1024位.RSA密钥长度随着保密级别提高,增加很快. 由于RSA的特性,一个1024位的密钥只能加密117位字节数据,当数据量超过117位字节的时候,程序就会抛出异常. --来自大佬 2.代码实现: 来一段大佬的代码

面试官:怎么设计大文件、大数据场景下的传输加密方案?

某年某月某一天,冷冽寒风中,姚小毛走进了某家公司,开始了新一轮的面试. 一阵寒暄后. 面试官:"你好,看你的项目经验中有做过数据加密的工作,你是使用什么加密算法加解密的?" 姚小毛:"嗯,我是采用的 非对称加密 + 对称加密 的混合加密算法." 面试官:"为什么要用混合加密的方式?" 姚小毛:"非对称加密跟对称加密都各有优缺点. 非对称安全性好点,由发送方跟接收方分别持有公钥.私钥. 但是缺点是在做大数据量的加密传输时,传输速度会比较慢

RSA,JAVA私钥加密,C#公钥解密

做这个东西在坑里爬了3天才爬出来,记录下供园友参考.C#程序员一枚,项目需要和Java做数据交互,对方甩了段密文和一个CER证书给我,然后我要对其密文进行解密. RSA 非对称加密,对方用私钥加密,我用公钥解密.关于证书的一点说明:证书类型有两种 .pfx 和 .cer ,其中 .pfx 证书既包含公钥也包含私钥, 而 .cer 证书只包含公钥. C#默认RSA只支持公钥加密,私钥解密.而现在的需求正好相反,因此想要直接用C#内置加密类肯定是行不通的.而且C#和Java的RSA加密并不互通.经过

rsa实现js前台加密java后台解密

前段时间咱老大吩咐我写一个rsa前台加密到后台用java解密.(说实话这之前我还真没用过) 不过没办法啊,这是任务,于是研究了一下.圆满完成任务了,下面共享下实现思路: 准备工作:其实鄙人也没那么强啦,第三方包是必须的 bcprov-jdk15on-148.jar commons-codec-1.7.jar commons-lang-2.4.jar log4j-1.2.15.jar slf4j-api-1.6.1.jar package com.web.utils; import java.io

小饼-带你爬那些年爬过的RSA坑 iOS RAS加密 以及与 .NET 之间的通信问题

背景 首先最近我们在做一个APP 但是我们数据交互都是明文的=- = 这咋办勒,傻子也知道加密一下咯.可是加密也有问题 对称加密的话,人家破解你的应用就能知道了.所以用到了非对称加密并且每个APP生成不同的RSA密钥对. 初步实现 实现再iOS上面实现RSA加密并不难,因为iOS中有openssl 和 系统自带的 security.framework.我这里选择了openSSL 因为我比较懒 =- = 发现别人已经写好了 直接就用了呗.security.framework其实也不错的,就是我还不

Android与Server端的传输加密

1.必须找一个在Android和JDK上通用的加密算法,后面发现了http://www.cnblogs.com/hjtdlx/p/3926141.html这篇文章,试了一下,是可以用的. 2.Android和Server端的传输采用JSON格式,除了加密还要校验是否被修改.传输格式: {params:xxx,sign:xxx} 其中,params为经过DES3加密的json数据,sign为原json数据md5值.这样,在收到数据后先进行DES解密,然后将解密后的json数据进行MD5,和传过来的

MAC系统用RSA 对数据进行加密解密

创建密钥对 在终端中一次输入下面的脚本 openssl genrsa -out private_key.pem 1024 openssl req -new -key private_key.pem -out rsaCertReq.csr openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt openssl x509 -outform der -in rsaCert.crt