Java开发中的加密、解密、签名、验签,密钥,证书,这篇就够了

先说一下两个重要的工具

  • OpenSSL:OpenSSL整个软件包大概可以分成三个主要的功能部分:SSL协议库libssl、应用程序命令工具以及密码算法库libcrypto。它使用标准的文件格式(PEM/CER/CRT/PKCS等)存储密钥和证书信息。
  • keytool:是密钥和证书管理工具。它出自于Java体系,它使用KeyStore来管理密钥和证书。

两者都是可以用来生成加密密钥的工具,keytool出自Java体系,它可以直接操作KeyStore,而OpenSSL不支持直接操作KeyStore。实际情况有可能是这样的,使用OpenSSL生成了密钥或证书,然后使用keytool将其导入到KeyStore以便在Java环境中使用。

当然OpenSSL还具备其他功能比如作为SSL的客户端和服务器,这是keytool所不具备的。

采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。——百度百科

  • 加密和解密使用同样的密钥
  • 计算速度快,适用于对大量数据加密处理
  • 安全性取决于算法,也取决于密钥的管理,一旦密钥泄漏,数据则暴露无遗

基于上述的特点,在一些需要高效实时传输的加密通讯场景中,比如使用VPN或者代理进行通讯时,可以使用对称加密。另外在同一个系统内部不同模块,比如前后端,从前端输入的敏感信息,可以使用对称加密算法进行加密后将密文传到后端,避免传输过程中明文被截获,因为同系统内部之间密钥管理相对容易,而对于共享密钥有泄漏风险的其他任何场景,则不适合使用对称加密算法进行加密。

算法

描述

DES(Data Encryption Standard)

数据加密标准,速度较快,适用于加密大量数据

3DES(Triple DES)

基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高

AES(Advanced Encryption Standard)

高级加密标准,速度快,安全级别高,支持128、192、256、512位密钥的加密

Blowfish

速度快且安全,而且没有专利和商业限制。了解更多>>[1]

可以看到,以上的方法使用起来并不友好,参数、返回等大量存在byte[],不便于理解,中间结果不便于查看和传输,比如如果需要将encryptedData返回给下游系统,那么还得使用Base64进行处理,基于此,我对在上述接口基础上进一步进行封装,使其使用起来更贴近日常使用场景。

这里补充一下,在实际项目开发过程中,还真遇见不少同学对Base64理解有误的情况,对于以上处理和转换过程理解有难度的同学,[2]

虽然AES支持128、192或 256的密钥长度,但是当我们使用192或256位长度的密钥时,会收到这个异常:java.security.InvalidKeyException: Illegal key size or default parameters

原因是JRE中自带的local_policy.jarUS_export_policy.jar是支持128位密钥的加密算法,而当我们要使用192或256位密钥算法的时候,已经超出它支持的范围。

解决方案:去官方下载JCE无限制权限策略文件。

下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt

  • 如果安装了JRE,将两个jar文件放到%JRE_HOME%\\lib\\security目录下覆盖原来的文件。
  • 如果安装了JDK,还要将两个jar文件也放到%JDK_HOME%\\jre\\lib\\security目录下覆盖原来文件。

AES128和AES256主要区别是密钥长度不同(分别是128bits,256bits)、加密处理轮数不同(分别是10轮,14轮),后者强度高于前者,当前AES是公认的较为安全的对称加密算法。

非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 ——百度百科

  • 也称公开密钥加密,算法需要两个密钥,其中一个可以公开,并且通过公开的密钥无法推导出对应的私钥
  • 算法复杂度相对对称加密算法高,所以计算相对较慢
  • 密钥的保密性较好,因为公钥可以公开,免去了交换密钥的需求

由于安全性较好,并且密钥可以公开,无交换过程泄密的风险,因此非对此密钥算法被广泛使用,比如SSH、HTTPS、电子证书、数字签名、加密通讯等领域。

报文签名验签

1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法,RSA算法从被发明至今一直是最广为使用的\”非对称加密算法\”。其他场景的算法还有Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)。

在开始介绍具体使用之前,补充两个知识点:

  1. 如果你对非对称密钥的编码规则和数据格式定义不清楚,可以先看一下这篇文章[3],这里摘抄重点:

openssl有多种形式的密钥,openssl提供PEM和DER两种编码方式对这些密钥进行编码,并提供相关指令可以使用户在这两种格式之间进行转换。

DER

DER就是密钥的二进制表述格式

PEM

PEM格式就是对DER编码转码为base64字符格式。通过base64解码可以还原DER格式。

PEM 是明文格式,可以包含证书或者是密钥;其内容通常是以类似 “—–BEGIN …—–” 开头 “—–END …—–” 为结尾的这样的格式进行描述的。 因为DER是纯二进制格式,对人不友好,所以一般都用PEM进行存储。

  1. RSA非对称加解密算法填充方式(Padding)[4],同样摘抄重点:

RSA加密常用的填充模式有三种:RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING, RSA_NO_PADDING。

与对称加密算法DES,AES一样,RSA算法也是一个块加密算法( block cipher algorithm),总是在一个固定长度的块上进行操作。但跟AES等不同的是,block length是跟key length有关的。

每次RSA加密的明文的长度是受RSA填充模式限制的,但是RSA每次加密的块长度就是key length。

genrsa命令

OpenSSL> genrsa –help usage: genrsa [args] [numbits] -des encrypt the generated key with DES in cbc mode -des3 encrypt the generated key with DES in ede cbc mode (168 bit key) -aes128, -aes192, -aes256 encrypt PEM output with cbc aes -camellia128, -camellia192, -camellia256 encrypt PEM output with cbc camellia -out file output the key to \’file-passout arg output file pass phrase source-f4 use F4 (0x10001) for the E value-3 use 3 for the E value

示例:

//生成2048位的RSA私钥openssl genrsa -out pkcs1_private.pem 2048 rsa命令 usage: rsa [-ciphername] [-check] [-in file] [-inform fmt][-modulus] [-noout] [-out file] [-outform fmt] [-passin src][-passout src] [-pubin] [-pubout] [-sgckey] [-text]-check Check consistency of RSA private key-in file Input file (default stdin)-inform format Input format (DER, NET or PEM (default))-modulus Print the RSA key modulus-noout Do not print encoded version of the key-out file Output file (default stdout)-outform format Output format (DER, NET or PEM (default PEM))-passin src Input file passphrase source-passout src Output file passphrase source-pubin Expect a public key (default private key)-pubout Output a public key (default private key)-sgckey Use modified NET algorithm for IIS and SGC keys-text Print in plain text in addition to encoded

在Java环境中,需要注意两个问题,需要借助上述命令来解决,我们以两个小例子说明。

首先在 /tmp 目录下简单生成一个私钥:

尝试读取RSA.pem并生成PrivateKey对象

运行之后发现会报这个异常:java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

问题原因:Java自带的security包不支持直接读取PEM格式文件。

解决方法:需要将PEM格式转为DER格式再进行读取。

好了,继续读取RSA.der并尝试生成PrivateKey对象

运行之后发现会报另一个异常:java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence

问题原因:OpenSSL生成的私钥是PKCS#1格式的,而Java自带的security包使用PKCS8EncodedKeySpec来实现私钥,私钥信息是以PKCS#8标准定义的,我们从下面这个类的构造方法说明可以很明显看到。

解决方法:OpenSSL生成密钥之后在Java环境中使用要先转为PKCS#8格式。

关于PKCS#1与PKCS#8,简单理解两者都是非对称加密私钥信息的标准定义,区别是PKCS#1是针对RSA算法的,而PKCS#8是通用的,两者在格式定义上有些许区别。

继续读取RSA_pkcs8.der并尝试生成PrivateKey对象

搞定!

上面我们使用了openssl工具生成RSA非对称密钥对,以字符串或标准文件格式存储密钥并处理加解密,在实际Java项目开发中,经常会使用keystore来管理密钥,对此我们可以使用 keytool 工具来进行密钥生成,或将其他文件格式的密钥导入keystore

正式介绍keytool之前我们先来解释几个概念,对下文keytool的使用理解有帮助。

我们先来看一个小场景,A要告诉B一个秘密:

上面流程在正常情况下没问题,可以保证数据加密传输,即使被第三方截获,没有B的私钥也解密不了。然而在复杂的网络环境下,情况有可能是这样的:

上述过程就是典型的中间人攻击场景,A和B的通讯链路中多了一个中间人X,而AB却完全无感知。在上述流程第4步之后,A持有的是X的公钥,X持有的是B的公钥,而实际上A需要的是B的公钥,但A却不知道,并且它以为自己持有的就是B的公钥,所以接下来A还是正常的使用这个公钥加密并发送数据,这样A和B之间的通讯信息就完全被X获取并且可以随意篡改。

在实际的网络环境中,我们无法阻止X的存在,那如何解决上述中间人攻击问题?通过分析上述流程,我们不难发现,A要获取B的公钥,但实际却收到了X的公钥,然鹅,它却无法辨识出来这个公钥不是B的,而证书,可以帮助我们解决这个关键问题。

数字证书是数字凭据,它提供有关实体标识的信息以及其他支持信息。数字证书是由权威证书颁发机构(Certificate Authority,简称CA)颁发的,由该权威机构担保证书信息的有效性。数字证书包含证书中所标识的实体的公钥,由于证书将公钥与申请者匹配,并且该证书的真实性由颁发机构保证,因此,数字证书为如何找到用户的公钥并知道它是否有效这一问题提供了解决方案。

常见的证书有三种:

  1. 带有私钥的证书:由PublicKey Cryptography Standards #12,即PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式,以 pfx 作为证书文件后缀名,PKCS#12可以增加加密保护,有助于传输证书及对应的私钥。
  2. 二进制编码的证书:由X.509公钥证书格式标准定义,证书中没有私钥,包含DER编码二进制格式的公钥,以 cer 作为证书文件后缀名。
  3. Base64编码的证书:由X.509公钥证书格式标准定义,证书中没有私钥,包含BASE64编码格式的公钥,也是以 cer 作为证书文件后缀名。

密钥库是存储一个或多个密钥条目的文件,每个密钥条目以一个别名标识,它包含密钥和证书相关信息。

在Java中,keystore中每种类型的条目都实现 KeyStore.Entry 接口,主要有三种基本的实现:

  1. KeyStore.PrivateKeyEntry

此类型的条目保存一个加密的PrivateKey,可以选择用受保护格式存储该私钥,以防止未授权访问。它还随附一个相应公钥的证书链。 2. KeyStore.SecretKeyEntry 此类型的条目保存一个加密的SecretKey,可以选择用受保护格式存储该密钥,以防止未授权访问。 3. KeyStore.TrustedCertificateEntry 此类型的条目包含一个属于另一方的单个公钥证书(Certificate)。它被称为可信证书,因为keystore的所有者相信证书中的公钥确实属于该证书所标识的身份。

另外,平时我们有时也会看到truststore,从其文件格式来看它和keystore其实是一个东西,只是为了方便管理将其分开,keystore一般保存的是私钥,用来加解密或者做签名,而truststore中保存的是一些可信任的证书,主要是在Java在代码中以HTTPS方式调用时对被访问者进行认证的,以确保它是可信任的。

接下来我们使用keytool工具来生成密钥和证书。

下面我们使用该命令生成一对非对称密钥并将公钥包装到X.509 V3自签名证书中,密钥条目别名和密钥库文件名均为java-and-more,密钥库类型为pkcs12,并按提示输入对应内容:

注意PKCS12不支持设置密钥库条目密码,默认它与密钥库密码一致,如果创建默认类型(JKS)的密钥库,可以通过-keypass参数指定密钥条目密码。

keytool -list 命令 查看密钥库内容:

keytool -exportcert 命令 导出密钥库条目证书

keytool -printcert 命令 打印证书内容

从keystore文件导出的证书、密钥都是DER格式,可以使用openssl工具转换成PEM格式

再从证书中导出公钥信息

注意:无法使用命令直接从keystore导出私钥信息,需要使用代码实现。以下示例使用Java从 PKCS12证书中提取私钥和公钥

这个过程涉及到3个命令:

  • keytool -certreq
  • keytool -gencert
  • keytool -importcert

分别对应以下3个步骤:

  1. 机构A使用certreq命令生成一个证书签名请求文件CSR (certificate sign request)并将其发送给机构B
  2. 机构B接收到这个请求后,使用gencert命令签发证书,会生成一个证书或者证书链
  3. 机构A接收到响应,使用importcert命令将签发证书导入到keystore中

下面以Alice.keystore签名的证书导入到密钥库Bob.keystore为例演示上述过程:

先生成两个keystore文件

生成证书签名请求文件CSR,即将条目别名为 Alice 的公钥和一些个人信息从密钥库 Alice.keystore 文件中导出,作为证书请求文件

签发证书,使用密钥库Bob.keystore中别名为 Bob 条目的私钥为 cert.csr 签发证书,并保存到 Bob-to-Alice.crt 文件中

导入签发证书到密钥库,将签发证书 Bob-to-Alice.crt 更新到已存在别名 Alice 的密钥库 Alice.keystore 文件中

这是因为在更新被签发证书之前,一定要先将签发证书的机构的信任证书导入到密钥库文件,即将密钥库Bob.keystore的证书以其相应的别名导入到密钥库Alice.keystore中。

导出Bob.keystore的信任证书:

将信任证书Bob.crt以其别名Bob导入到密钥库Alice.keystore

再将签发证书Bob-to-Alice.crt以别名Alice导入到密钥库Alice.keystore:

对比最开始生成的密钥库Alice.keystore的证书信息可发现,别名为Alice条目的证书链已由单个Alice.keystore自签名的证书变为2个证书,分别是Bob.keystore签名的及Alice.keystore的自签名证书。

至此,我们已经基本把对称加密和非对称加密从原理、场景、工具和代码等多方面进行了介绍。

接下来我们补充一个在日常开发中也会广泛应用到的算法:信息摘要算法,也叫散列函数、哈希函数。不同于上述两种算法,信息摘要算法并不算是一种加密算法,它有以下几个特点反而让它在某些场景下非常适用:

  1. 固定输入得到固定输出,且不同输入得到相同输出的概率极低
  2. 理论上不能从散列计算之后的值逆向推导出原始明文
  3. 无论输入的数据长度多少,得到的输出值长度是固定的(不同的哈希算法长度不一样)

设想这种场景,我们要在数据库中保存用户密码,首先肯定不能保存明文,既然要使用密文保存,那使用对称加密还是非对称加密呢?结合实际场景和安全性考虑,两种都不合适!因为这两种都要考虑密钥的管理,如果密钥泄漏那密码则有被破解的风险。在这种场景下,我们可以使用单向散列函数来解决这个问题,这样即使算法和密文都泄漏,也无法逆向计算出明文。

当然散列函数还有更多用途,比如文件一致性校验、数字签名等。

常见的哈希算法有:MD5、sha1、sha2(sha224、sha256、sha384、sha512),其中sha1加密后的长度是160字节,sha2加密之后的密文长度和shaxxx的数字相同,比如sha256加密之后,密文长度为256字节。

关于哈希算法的更详细介绍可以看一下这篇文章,最常用的三种哈希算法[5]

终于写到这里了,良心力作,码字不易,欢迎收藏。

[1]

https://baike.baidu.com/item/Blowfish/1677776: https://link.juejin.cn?target=https%3A%2F%2Fbaike.baidu.com%2Fitem%2FBlowfish%2F1677776

[2]

https://www.jianshu.com/p/c5147a3eaf07: https://link.juejin.cn?target=https%3A%2F%2Fwww.jianshu.com%2Fp%2Fc5147a3eaf07

[3]

https://www.jianshu.com/p/78886e480bef: https://link.juejin.cn?target=https%3A%2F%2Fwww.jianshu.com%2Fp%2F78886e480bef

[4]

https://blog.csdn.net/makenothing/article/details/88429511: https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fmakenothing%2Farticle%2Fdetails%2F88429511

[5]

https://blog.csdn.net/zhanxiao5287/article/details/90300222: https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fzhanxiao5287%2Farticle%2Fdetails%2F90300222

来源:https://juejin.cn/post/6882404615443185678

想要加密源代码,这九款软件值得一试!保护源代码安全加密很重要

随着数字化进程的加速,源代码作为软件开发的核心资产,其安全性显得尤为重要。一旦源代码被泄露,可能导致知识产权被盗、商业机密外泄甚至企业核心竞争力丧失。为此,源代码加密成为了保护代码安全的有效措施。以下是九款值得一试的源代码加密软件,它们可以有效帮助开发者和企业保障代码的机密性和安全性。

安秉源代码加密软件是一款专为企业设计的源代码保护解决方案,采用先进的透明加密技术,在不影响开发人员日常工作的前提下,自动对源代码进行加密处理。支持多种操作系统和常见的开发语言(如Java、C++、Python等),并与SVN、Git等主流版本控制系统无缝对接,同时依然可以进行版本比对与合并。此外,安秉还提供了细粒度的权限管理和实时监控功能,确保源代码在传输、存储和使用过程中的安全。

GitGuardian专注于代码泄露检测和防护,特别适用于分布式开发环境。它能够实时扫描代码库和开发人员的提交日志,检测潜在的安全隐患,比如敏感信息的暴露或未经加密的源码,并快速采取修复措施。

Veracrypt是一款免费且开源的文件加密工具,非常适合本地开发者使用。它能够为存储源代码的文件夹创建加密卷,并支持多种加密算法,例如AES和Serpent,从而确保源代码即使被窃取也无法解密。

Azure DevOps提供了一个集成的版本控制和存储管理系统,其内置的代码保护功能可以对源代码进行加密存储,同时支持细粒度的权限控制。通过结合Azure Key Vault,用户还可以进一步确保敏感数据的安全,并自动化加密密钥的管理。

ESET Endpoint Encryption是一款高度灵活的加密工具,适用于个人开发者和小型团队。其特性包括文件级和文件夹级加密、密钥管理以及与多平台的兼容性,能够为本地存储的源代码提供强有力的保护。

VMProtect通过将代码转换为虚拟机代码运行的方式,对源代码进行深度保护。其核心功能是加密和混淆执行逻辑,使得代码即使被破解,也难以被解析和复现,是防止逆向工程的利器。

Cloakware提供了全面的代码保护解决方案,包含加密、混淆和反调试功能。它支持多种编程语言,并内置了AI驱动的威胁检测功能,可以实时监控代码运行状态,从而提升代码的安全性。

CodeSecure是Checkmarx推出的源代码安全扫描与保护工具。它不仅可以对代码进行加密,还能够在开发阶段自动扫描安全漏洞并提供修复建议,从而确保代码在加密的同时保持高质量。

Dotfuscator是专门为.NET开发者设计的代码混淆工具。它通过对代码逻辑的重构和加密,极大地增加了逆向工程的难度。该工具还支持运行时检查机制,防止未经授权的代码运行。

源代码加密并非只是保护数据的一种手段,它更是开发者和企业维护核心竞争力的关键环节。无论是通过混淆技术、加密存储,还是实时监控和权限管理,这九款工具都能为源代码安全提供强有力的保障。在选择合适的加密工具时,应根据团队规模、技术栈以及具体需求,找到最匹配的解决方案。保护代码安全,从现在开始!

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。