RSA加密

 # 1.RSA格式

密钥格式:PKCS#1 ,PKCS#8

PKCS#1形式的密钥专指RSA的密钥,如果一个ECC的密钥就无法用PKCS#1形式来表达。那么有没有一个通过的机构既可以表示RSA密钥,又可以表示ECC的密钥呢?有,这个就是PKCS#8形式的密钥。 

PKCS#1和PKCS#8私钥生成方式不一样

获取PKCS#1

```
    public  static  PrivateKey  getPKCS1Key(byte[] privateKeyBytes )  throws Exception{
        // 取得私钥  for PKCS#1
        RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure((ASN1Sequence) ASN1Sequence.fromByteArray(privateKeyBytes));
        RSAPrivateKeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(), asn1PrivKey.getPrivateExponent());
        KeyFactory keyFactory=  KeyFactory.getInstance("RSA");
        PrivateKey priKey= keyFactory.generatePrivate(rsaPrivKeySpec);
        return priKey;
    }
```

PKCS#8

证书有三种类型:X.509证书、PKCS#7证书、PKCS#12证书 

X.509只包含公钥,没有私钥,这种证书一般公开发布,可用于放在客服端使用,用于加密、验签。 

PKCS#12就定义了这样一种证书,它既包含了公钥有包含了私钥。典型的入pfx、p12证书就是PKCS#12证书。 

PKCS#7就定义了这样一个证书链的类型结构。典型如p7b后缀名的证书就是这样的格式。 (java不支持PKCS#7)

X509证书使用

```
 @Test
    public void testVerifyZhangsanCert() throws Exception {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        FileInputStream inStream = new FileInputStream("H:/certtest/zhangsan.cer");
        X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(inStream);
        System.out.println(certificate.getPublicKey().getClass());
        Signature signature = Signature.getInstance(certificate.getSigAlgName());
        signature.initVerify(getRootPublicKey());
        signature.update(certificate.getTBSCertificate());
        boolean legal = signature.verify(certificate.getSignature());
        System.out.println(legal);
    }
```

PKCS#12使用要导入

```
public class P12Application {
    public static void main(String[] args) throws Exception {
        //从文件中解析
        try (FileInputStream is = new FileInputStream("apiclient.p12")) {
            System.out.println(P12Info.parse(is, "证书密码"));
        }

        //从Base64加密串中解析
        String p12Base64 = "xxxyyyzzz";
        byte[] base64byte = Base64.getDecoder().decode(p12Base64);
        try (ByteArrayInputStream is = new ByteArrayInputStream(base64byte)) {
            System.out.println(P12Info.parse(is, "证书密码"));
        }
    }

    @Data
    @Builder
    private static class P12Info {
        /**
         * 证书序列号.
         */
        private final String serialNo;

        /**
         * 证书秘钥.
         */
        private final PrivateKey privateKey;

        /**
         * 公钥.
         */
        private final PublicKey publicKey;

        public static P12Info parse(InputStream is, String passwd) throws Exception {
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(is, passwd.toCharArray());
            String keyAlias = null; 
            //解析证书,必须有别名
            Enumeration<String> aliases = ks.aliases();
            if (aliases.hasMoreElements()) {
                keyAlias = aliases.nextElement();
            }
            //解析私钥
            PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, passwd.toCharArray());
            Certificate cert = ks.getCertificate(keyAlias);
            BigInteger serialNumber = ((X509CertImpl) cert).getSerialNumber();
            //证书一般都使用16进制表示
            String certSn = serialNumber.toString(16);
           
            //设置证书序列号和私钥
            return P12Info.builder()
                    .serialNo(certSn)
                    .privateKey(privateKey)
                    .publicKey(cert.getPublicKey())
                    .build();
        }
    }
}
```

两种证书解析方式不一样

**RSA加密的填充方式**

[RSA](https://so.csdn.net/so/search?q=RSA&spm=1001.2101.3001.7020)加密常用的填充模式有三种:`RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING, RSA_NO_PADDING。` 

java本身只支持NoPadding和PKCS5Padding 

1.RSA_PKCS1_PADDING 填充模式,最常用的模式

要求:
输入:必须 比 RSA 钥模长(modulus) 短至少11个字节, 也就是 RSA_size(rsa) – 11
如果输入的明文过长,必须切割, 然后填充

输出:和modulus一样长

根据这个要求,对于512bit的密钥, block length = 512/8 – 11 = 53 字节

2.RSA_PKCS1_OAEP_PADDING
输入:RSA_size(rsa) – 41

输出:和modulus一样长

3.for RSA_NO_PADDING  不填充

输入:可以和RSA钥模长一样长,如果输入的明文过长,必须切割, 然后填充

```
在实际做任何形式加密之前,需要有公钥和私钥两个密钥对。幸运的是,Java提供了非常简单的方法,请看示例代码:

public static KeyPair generateKeyPair() throws Exception {
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    generator.initialize(2048, new SecureRandom());
    KeyPair pair = generator.generateKeyPair();

    return pair;
}
```

# 常见签名算法SHA1WithRSA、MD5withRSA生成签名以及验签

```
  //用私钥给入参加签
                Signature sign = Signature.getInstance("SHA1WithRSA");
                sign.initSign(privatekey);
                sign.update(param.getBytes());
 
                signature = sign.sign();
```

*

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值