Skip to content

Commit

Permalink
发布1.5版本
Browse files Browse the repository at this point in the history
  • Loading branch information
xiangyuecn committed Jun 8, 2022
1 parent 3675451 commit a07ce38
Show file tree
Hide file tree
Showing 4 changed files with 427 additions and 135 deletions.
188 changes: 145 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,67 @@
**[源GitHub仓库](https://github.com/xiangyuecn/RSA-java)】 | 【[Gitee镜像库](https://gitee.com/xiangyuecn/RSA-java)】如果本文档图片没有显示,请手动切换到Gitee镜像库阅读文档。**

# :open_book:RSA-java的帮助文档

本项目核心功能:支持`Java`环境下`PEM``PKCS#1``PKCS#8`)格式RSA密钥对导入、导出。

底层实现采用PEM文件二进制层面上进行字节码解析,简单轻巧0依赖;附带实现了一个含有RSA加密解密操作测试控制台程序(双击`Start.bat`即可运行,前提装了JDK)。
你可以只copy `RSA_PEM.java` 文件到你的项目中使用(建好package目录或者修改一下package),只需这一个文件你就拥有了通过PEM格式密钥简单快速创建`RSA Cipher`的能力。也可以clone整个项目代码双击`Start.bat`即可直接测试。

底层实现采用PEM文件二进制层面上进行字节码解析,简单轻巧0依赖;附带实现了一个RSA封装操作类(`RSA_Util.java`),和一个测试控制台程序(`Test.java`,双击`Start.bat`即可运行,前提装了JDK)。

你可以只copy `RSA_PEM.java` 文件到你的项目中使用(建好package目录或者修改一下package),只需这一个文件你就拥有了通过PEM格式密钥简单快速创建`RSA Cipher`的能力。clone整个项目代码双击`Start.bat`即可观摩效果,经目测看起来没什么卵用的文件都svn:ignore掉了(svn滑稽。
**如需功能定制,网站、App、小程序开发等需求,请加本文档下面的QQ群,联系群主(即作者),谢谢~**

【C#版】:[RSA-csharp](https://github.com/xiangyuecn/RSA-csharp),本Java项目从C#版移植。


[](?)

## 特性

- 通过`XML格式`密钥对创建RSAPublicKey、RSAPrivateKey、Cipher
- 通过`PEM格式`密钥对创建RSAPublicKey、RSAPrivateKey、Cipher
- 通过指定密钥位数创建RSA(生成公钥、私钥)
- RSA加密、解密
- RSA签名、验证
- 导出`XML格式`公钥、私钥
- 导出`PEM格式`公钥、私钥
- `PEM格式`秘钥对和`XML格式`秘钥对互转


[](?)

## 如何加密、解密、签名、校验
得到了RSA_PEM后,加密解密就异常简单了,没那么多啰嗦难懂的代码:
``` java
//先解析pem,公钥私钥都行,如果是xml就用 RSA_PEM.FromXML("<RSAKeyValue><Modulus>....</RSAKeyValue>")
RSA_PEM pem=RSA_PEM.FromPEM("-----BEGIN XXX KEY-----..此处意思意思..-----END XXX KEY-----");

//直接创建RSA操作类
RSA_Util rsa=new RSA_Util(pem);
//RSA_Util rsa=new RSA_Util(2048); //也可以直接生成新密钥,rsa.ToPEM()得到pem对象

//加密
String enTxt=rsa.Encode("测试123");

//解密
String deTxt=rsa.Decode(enTxt);

//签名
String sign=rsa.Sign("SHA1", "测试123");

//校验签名
boolean isVerify=rsa.Verify("SHA1", sign, "测试123");

//导出pem文本
String pemTxt=rsa.ToPEM(false).ToPEM_PKCS8(false);

System.out.println(pemTxt+"\n"+enTxt+"\n"+deTxt+"\n"+sign+"\n"+isVerify);
//****更多的实例,请阅读 Test.java****
//****更多功能方法,请阅读下面的详细文档****
```



[](?)

## 【QQ群】交流与支持

Expand All @@ -27,6 +71,18 @@



[](?)

[](?)

[](?)

[](?)

[](?)

[](?)

# :open_book:文档

## 【RSA_PEM.java】
Expand All @@ -38,9 +94,9 @@

### 静态方法

**static RSA_PEM FromPEM(String pem)**:用PEM格式密钥对创建RSA,支持PKCS#1、PKCS#8格式的PEM,出错将会抛出异常。pem格式如:`-----BEGIN XXX KEY-----....-----END XXX KEY-----`
`RSA_PEM` **FromPEM(String pem)**:用PEM格式密钥对创建RSA,支持PKCS#1、PKCS#8格式的PEM,出错将会抛出异常。pem格式如:`-----BEGIN XXX KEY-----....-----END XXX KEY-----`

**static RSA_PEM FromXML(String xml)**:将XML格式密钥转成PEM,支持公钥xml、私钥xml,出错将会抛出异常。xml格式如:`<RSAKeyValue><Modulus>....</RSAKeyValue>`
`RSA_PEM` **FromXML(String xml)**:将XML格式密钥转成PEM,支持公钥xml、私钥xml,出错将会抛出异常。xml格式如:`<RSAKeyValue><Modulus>....</RSAKeyValue>`


### 构造方法
Expand All @@ -54,60 +110,93 @@

### 实例属性

byte[]**Key_Modulus**(模数n,公钥、私钥都有)、**Key_Exponent**(公钥指数e,公钥、私钥都有)、**Key_D**(私钥指数d,只有私钥的时候才有);有这3个足够用来加密解密。
`byte[]`**Key_Modulus**(模数n,公钥、私钥都有)、**Key_Exponent**(公钥指数e,公钥、私钥都有)、**Key_D**(私钥指数d,只有私钥的时候才有);有这3个足够用来加密解密。

byte[]**Val_P**(prime1)、**Val_Q**(prime2)、**Val_DP**(exponent1)、**Val_DQ**(exponent2)、**Val_InverseQ**(coefficient); (PEM中的私钥才有的更多的数值;可通过n、e、d反推出这些值(只是反推出有效值,和原始的值大概率不同))。
`byte[]`**Val_P**(prime1)、**Val_Q**(prime2)、**Val_DP**(exponent1)、**Val_DQ**(exponent2)、**Val_InverseQ**(coefficient); (PEM中的私钥才有的更多的数值;可通过n、e、d反推出这些值(只是反推出有效值,和原始的值大概率不同))。

int**keySize()**(密钥位数)
`int` **keySize()**密钥位数

boolean**hasPrivate()**(是否包含私钥)
`boolean` **hasPrivate()**是否包含私钥


### 实例方法

**RSAPublicKey getRSAPublicKey()**:得到公钥Java对象。
`RSAPublicKey` **getRSAPublicKey()**:得到公钥Java对象。

**RSAPrivateKey getRSAPrivateKey()**:得到私钥Java对象,如果此PEM不含私钥会直接报错。
`RSAPrivateKey` **getRSAPrivateKey()**:得到私钥Java对象,如果此PEM不含私钥会直接报错。

**String ToPEM(boolean convertToPublic, boolean privateUsePKCS8, boolean publicUsePKCS8)**:将RSA中的密钥对转换成PEM格式。convertToPublic:等于true时含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响 。**privateUsePKCS8**:私钥的返回格式,等于true时返回PKCS#8格式(`-----BEGIN PRIVATE KEY-----`),否则返回PKCS#1格式(`-----BEGIN RSA PRIVATE KEY-----`),返回公钥时此参数无效;两种格式使用都比较常见。**publicUsePKCS8**:公钥的返回格式,等于true时返回PKCS#8格式(`-----BEGIN PUBLIC KEY-----`),否则返回PKCS#1格式(`-----BEGIN RSA PUBLIC KEY-----`),返回私钥时此参数无效;一般用的多的是true PKCS#8格式公钥,PKCS#1格式公钥似乎比较少见。
`String` **ToPEM(boolean convertToPublic, boolean privateUsePKCS8, boolean publicUsePKCS8)**:将RSA中的密钥对转换成PEM格式。convertToPublic:等于true时含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响 。**privateUsePKCS8**:私钥的返回格式,等于true时返回PKCS#8格式(`-----BEGIN PRIVATE KEY-----`),否则返回PKCS#1格式(`-----BEGIN RSA PRIVATE KEY-----`),返回公钥时此参数无效;两种格式使用都比较常见。**publicUsePKCS8**:公钥的返回格式,等于true时返回PKCS#8格式(`-----BEGIN PUBLIC KEY-----`),否则返回PKCS#1格式(`-----BEGIN RSA PUBLIC KEY-----`),返回私钥时此参数无效;一般用的多的是true PKCS#8格式公钥,PKCS#1格式公钥似乎比较少见。

**String ToPEM_PKCS1(boolean convertToPublic)**:ToPEM方法的简化写法,不管公钥还是私钥都返回PKCS#1格式;似乎导出PKCS#1公钥用的比较少,PKCS#8的公钥用的多些,私钥#1#8都差不多。
`String` **ToPEM_PKCS1(boolean convertToPublic)**:ToPEM方法的简化写法,不管公钥还是私钥都返回PKCS#1格式;似乎导出PKCS#1公钥用的比较少,PKCS#8的公钥用的多些,私钥#1#8都差不多。

**String ToPEM_PKCS8(boolean convertToPublic)**:ToPEM方法的简化写法,不管公钥还是私钥都返回PKCS#8格式。
`String` **ToPEM_PKCS8(boolean convertToPublic)**:ToPEM方法的简化写法,不管公钥还是私钥都返回PKCS#8格式。

**String ToXML(boolean convertToPublic)**:将RSA中的密钥对转换成XML格式,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响。
`String` **ToXML(boolean convertToPublic)**:将RSA中的密钥对转换成XML格式,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响。


## 如何加密、解密、签名、校验
得到了RSA_PEM后,加密解密就异常简单了,没那么多啰嗦难懂的代码。
``` java
RAS_PEM pem=RSA_PEM.FromPEM("-----BEGIN XXX KEY-----..此处意思意思..-----END XXX KEY-----");

//通过公钥构造加密Cipher
Cipher enc = Cipher.getInstance("RSA");
enc.init(Cipher.ENCRYPT_MODE, pem.getRSAPublicKey());
byte[] en = enc.doFinal("测试123".getBytes("utf-8"));

//通过私钥构造解密Cipher
Cipher dec = Cipher.getInstance("RSA");
dec.init(Cipher.DECRYPT_MODE, pem.getRSAPrivateKey());
byte[] de = dec.doFinal(en);
String deTxt=new String(de,"utf-8");//测试123

//通过私钥构造签名对象
Signature signature=Signature.getInstance("SHA1WithRSA");
signature.initSign(pem.getRSAPrivateKey());
signature.update("测试123".getBytes("utf-8"));
byte[] signBytes=signature.sign();

//通过公钥构造签名校验对象
Signature signVerify=Signature.getInstance("SHA1WithRSA");
signVerify.initVerify(pem.getRSAPublicKey());
signVerify.update("测试123".getBytes("utf-8"));
boolean isVerify=signVerify.verify(signBytes);
```

更多的实例,请阅读`Test.java`

## 【RSA_Util.java】
这个文件依赖`RSA_PEM.java`,封装了加密、解密、签名、验证、秘钥导入导出操作。

### 构造方法

**RSA_Util(int keySize)**:用指定密钥大小创建一个新的RSA,会生成新密钥,出错抛异常。

**RSA_Util(String pemOrXML)**:通过`PEM格式``XML格式`密钥,创建一个RSA,pem或xml内可以只包含一个公钥或私钥,或都包含,出错抛异常。`XML格式`如:`<RSAKeyValue><Modulus>...</RSAKeyValue>`。pem支持`PKCS#1``PKCS#8`格式,格式如:`-----BEGIN XXX KEY-----....-----END XXX KEY-----`

**RSA_Util(RSA_PEM pem)**:通过一个pem对象创建RSA,pem为公钥或私钥,出错抛异常。


### 实例属性

`RSAPublicKey` **publicKey**:RSA公钥。

`RSAPrivateKey` **privateKey**:RSA私钥,仅有公钥时为null。

`int` **keySize()**:密钥位数。

`boolean` **hasPrivate()**:是否包含私钥。


### 实例方法

`String` **ToXML(boolean convertToPublic)**:导出`XML格式`秘钥对,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响。

`RSA_PEM` **ToPEM(boolean convertToPublic)**:导出RSA_PEM对象(然后可以通过RSA_PEM.ToPEM方法导出PEM文本),如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响。

`String` **Encode(String str)**:加密操作,支持任意长度数据,出错抛异常。

`byte[]` **Encode(byte[] data)**:加密数据,支持任意长度数据,出错抛异常。

`String` **Decode(String str)**:解密字符串(utf-8),出错抛异常。

`byte[]` **Decode(byte[] data)**:解密数据,出错抛异常。

`String` **Sign(String hash, String str)**:对str进行签名,并指定hash算法(如:SHA256 大写)。

`byte[]` **Sign(String hash, byte[] data)**:对data进行签名,并指定hash算法(如:SHA256 大写)。

`boolean` **Verify(String hash, String sign, String str)**:验证字符串str的签名是否是sign,并指定hash算法(如:SHA256 大写)。

`boolean` **Verify(String hash, byte[] sign, byte[] data)**:验证data的签名是否是sign,并指定hash算法(如:SHA256 大写)。






[](?)

[](?)

[](?)

[](?)

[](?)

[](?)


# :open_book:图例
Expand All @@ -122,6 +211,13 @@ RSA工具(非开源):




[](?)

[](?)

[](?)

# :open_book:知识库

请移步到[RSA-csharp](https://github.com/xiangyuecn/RSA-csharp)阅读知识库部分,知识库内包含了详细的PEM格式解析,和部分ASN.1语法;然后逐字节分解PEM字节码教程。
Expand All @@ -131,6 +227,12 @@ RSA工具(非开源):
本库的代码整理未使用IDE,RSA_PEM.java copy过来的,Test.java直接用的文本编辑器编写,*.java文件全部丢到根目录,没有创建包名目录,源码直接根目录裸奔,简单粗暴;这样的项目结构肉眼看去也算是简洁,也方便copy文件使用。


[](?)

[](?)

[](?)

# :star:捐赠
如果这个库有帮助到您,请 Star 一下。

Expand Down
27 changes: 15 additions & 12 deletions RSA_PEM.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ public class RSA_PEM {
public byte[] Key_D;

//以下参数只有私钥才有 https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.rsaparameters?redirectedfrom=MSDN&view=netframework-4.8
/**prime1**/
/**prime1,只有私钥的时候才有**/
public byte[] Val_P;
/**prime2**/
/**prime2,只有私钥的时候才有**/
public byte[] Val_Q;
/**exponent1**/
/**exponent1,只有私钥的时候才有**/
public byte[] Val_DP;
/**exponent2**/
/**exponent2,只有私钥的时候才有**/
public byte[] Val_DQ;
/**coefficient**/
/**coefficient,只有私钥的时候才有**/
public byte[] Val_InverseQ;

private RSA_PEM() {}
Expand All @@ -59,14 +59,17 @@ public RSA_PEM(RSAPublicKey publicKey, RSAPrivateKey privateKeyOrNull) {
public RSA_PEM(byte[] modulus, byte[] exponent, byte[] d, byte[] p, byte[] q, byte[] dp, byte[] dq, byte[] inverseQ) {
Key_Modulus=modulus;
Key_Exponent=exponent;
Key_D=BigL(d, modulus.length);

int keyLen = modulus.length / 2;
Val_P=BigL(p, keyLen);
Val_Q=BigL(q, keyLen);
Val_DP=BigL(dp, keyLen);
Val_DQ=BigL(dq, keyLen);
Val_InverseQ=BigL(inverseQ, keyLen);
if(d!=null){
Key_D=BigL(d, modulus.length);

int keyLen = modulus.length / 2;
Val_P=BigL(p, keyLen);
Val_Q=BigL(q, keyLen);
Val_DP=BigL(dp, keyLen);
Val_DQ=BigL(dq, keyLen);
Val_InverseQ=BigL(inverseQ, keyLen);
}
}
/***
* 通过公钥指数和私钥指数构造一个PEM,会反推计算出P、Q但和原始生成密钥的P、Q极小可能相同
Expand Down
Loading

0 comments on commit a07ce38

Please sign in to comment.