0


在线支付系列【3】支付安全之对称和非对称加密

有道无术,术尚可求,有术无道,止于术。

文章目录

前言

支付

和金钱挂钩,

支付安全

显得尤为重要,微信、支付宝等第三方支付公司,为了确保支付安全问题,都下足了不少功夫,其底层还是和

信息安全

密切挂钩,所以在这之前,我们需要了解各种安全机制,才能更好地了解支付流程和安全性问题。

信息安全

信息安全

是一个很广泛的概念,涉及计算机和网络系统的各个方面。从总体上来讲,信息安全有5个基本要素∶

  1. 机密性∶确保信息不暴露给未授权的实体或进程。
  2. 完整性∶只有得到允许的人才能够修改数据,并能够判别数据是否已被篡改。
  3. 可用性∶得到授权的实体在需要时可访问数据。
  4. 可控性∶可以控制授权范围内的信息流向和行为方式。
  5. 可审查性∶对出现的安全问题提供调查的依据和手段。

加密机制

数据加密

即对明文(未经加密的数据)按照某种加密算法(数据的变换算法)进行处理,而形成难以理解的密文(经加密后的数据)。即使密文被截获,截获方也无法或难以解码,从而防止泄露信息。

按照加密密钥和解密密钥的异同,有两种密钥体制,分别是

对称密码体制

非对称密码体制

核心概念

1、明文

加密前的消息叫

明文

(plain text)。比如小明给小红发送一封情书没有加密,只要被截取,那么会直接看到明文的内容信息。连篇的土味情话被看到,盗信者直呼辣眼睛😭😭😭
在这里插入图片描述
2、密文

加密后的文本叫

密文

(cipher text)。为了防止别人看到,小明对情书内容进行加密,加密后内容变成了不可读的内容,就算被窃取,盗信者也无法看懂其内容。
在这里插入图片描述

3、密钥

拥有

钥匙

的人,使用

钥匙

将明文变为密文,使用

钥匙

将密文解析为明文,这把

钥匙

叫做

秘钥

(key)。

在这里插入图片描述

4、加密

使用

秘钥

,将明文变为密文的过程叫做

加密

(encrypt)。

5、解密

使用

秘钥

,将密文还原为明文的过程叫做

解密

(decrypt)。

6、加密算法

加密算法是一种密码学算法,就是指将明文变成密文的加密技术。所有的加密算法都是公开的,而算法使用的

密钥

则必须保密。

对称加密

对称加密

加密和解密采用相同的密钥。因为只使用一个密钥,密钥必须保密,一旦被窃取,消息会被破解。其优点是运算速度快。

它要求发送方和接收方在安全通信之前,商定一个

密钥

。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信的安全性至关重要。

工作流程

  1. 小明使用某种加密算法生成一个秘钥,并将这个秘钥给小红。
  2. 小明使用秘钥将情书进行加密,变为密文,并发送给小红。
  3. 小红收到情书后,使用秘钥将密文还原为明文。在这里插入图片描述

非对称加密

非对称加密

公钥

私钥

两个概念,私钥自己拥有,不能给别人,公钥公开。比对称加密安全,但是运算速度更慢。

工作流程

  1. 小红使用某种加密算法生成一对密钥(公钥和私钥),并将这个公钥给小明。
  2. 得到公钥的小明使用该密钥对机密信息进行加密后再发送给小红。
  3. 小红用自己的专用私钥对加密后的信息进行解密。在这里插入图片描述 在传输过程中,即使攻击者截获了传输的密文,并得到了公钥,也无法破解密文,因为只有小红的私钥才能解密密文。

JCE

JCE

Java Cryptography Extension

三个单词的缩写,译为Java 加密扩展,是JDK 1.4 提供的一个用于加密、密钥生成算法等功能的扩展包。

在这里插入图片描述
接下来我们使用

JCE

实现对称、非对称加解密。

对称加解密

1. 创建密钥

创建密钥需要创建一个

javax.crypto.KeyGenerator

密钥生成器对象,

KeyGenerator

提供对称密钥生成器的功能,使用此类的

getInstance 

方法获取实例对象。

KeyGenerator 

对象可重复使用,也就是说,在生成密钥后,可以重复使用同一个

KeyGenerator

对象来生成更多的密钥。

KeyGenerator.getInstance()

方法返回指定算法的密钥生成器对象,三个重载方法说明如下:

// 返回生成指定算法的秘密密钥的 KeyGenerator 对象。// algorithm:密钥算法的标准名称publicstaticfinalKeyGeneratorgetInstance(String algorithm)throwsNoSuchAlgorithmException// 返回生成指定算法的秘密密钥的 KeyGenerator 对象。// algorithm:密钥算法的标准名称// provider:提供者的名称publicstaticfinalKeyGeneratorgetInstance(String algorithm,String provider)throwsNoSuchAlgorithmException,NoSuchProviderException// 返回生成指定算法的秘密密钥的 KeyGenerator 对象。// algorithm:密钥算法的标准名称// provider:提供者对象publicstaticfinalKeyGeneratorgetInstance(String algorithm,Provider provider)throwsNoSuchAlgorithmException

该方法需要两个重要参数:算法名称、服务提供者。

加密服务提供者

简称

CSP

java.security.Provider

是所有安全服务提供程序的基类。在进行加解密运算时,需要指定一个

CSP

JDK

默认安装并配置了一个或多个提供程序,也可以注册第三方或自定义服务提供者(例如第三方加密机)。如果没有指定该参数,会从可用的提供者中选取第一个。

通过以下代码,可以获取当前

JDK

环境所有提供者:

Provider[] providers =Security.getProviders();for(Provider provider : providers){String name = provider.getName();double version = provider.getVersion();System.out.println(name +": "+ version);}// 输出结果SUN: 1.8SunRsaSign: 1.8SunEC: 1.8SunJSSE: 1.8SunJCE: 1.8SunJGSS: 1.8SunSASL: 1.8XMLDSig: 1.8SunPCSC: 1.8SunMSCAPI: 1.8

算法名称:密钥算法的标准名称。常用的对称算法有:

AES、3DES、SM1(国密JDK不支持)、SM4(国密)

等。
算法名称秘钥长度加密强度性能版权DES56弱快美国3DES168中慢美国IDEA128强中瑞士AES128 192 256强快美国SM1128强中国SM4128强中国
创建了秘钥生成器后,还需要调用

init 

方法进行初始化。常用方法:

// 初始化此密钥生成器,使其具有确定的密钥大小。// 参数:keysize  密钥长度。这是特定于算法的一种规格,是以位数为单位指定的。publicfinalvoidinit(int keysize)
密钥长度

是一个重要的参数,每种算法都有其支持的长度,长度越长的情况下,暴力破解的时间就越长。长度单位为位

(bit)

生成对称密钥代码如下:

// 获取密钥生成器,指定算法为AESKeyGenerator keyGenerator =KeyGenerator.getInstance("AES");// 初始化
keyGenerator.init(128);// 生成公钥SecretKey secretKey = keyGenerator.generateKey();// 打印秘钥:LDDoCClZOvP9ZncFM19jZg==byte[] keyEncoded = secretKey.getEncoded();System.out.println(Base64.getEncoder().encodeToString(keyEncoded));

2. 加密

在上一步骤中,我们生成了一个

Base64

编码的秘钥字符串:

LDDoCClZOvP9ZncFM19jZg==

,接下来我们使用该秘钥进行加密。

加解密时,需要使用

JCE

中的

javax.crypto.Cipher

对象。此类为加密和解密提供密码功能。它构成了

Java Cryptographic Extension 

(JCE) 框架的核心。

调用

getInstance

方法获取该对象实例,该方法需要一个字符串参数。

// 返回实现指定转换的 Cipher 对象。此方法从首选 Provider 开始遍历已注册安全提供者列表。// 参数:transformation - 转换的名称,例如 DES/CBC/PKCS5Padding。publicstaticfinalCiphergetInstance(String transformation)
transformation 

翻译过来是转换的意思,可以理解为一个转换规则,由三部分组成

算法/加密模式/填充规则

算法就是标准的算法名称,之间我们已经介绍过了。

加密模式

主要有以下两种:

  • **ECB(电码本模式)**,将明文分成若干小段, 然后对每小段进行加密
  • **CBC(密码分组链接模式)**,先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再使用密钥进行加密
填充规则

:在分组密码中,当数据长度不符合分组长度时,需要按一定的方式,将尾部明文分组进行填充,这种将尾部分组数据填满的方法称为填充(Padding)。

填充规则

主要有以下几种:

  • NOPADDING:即不填充,要求明文的长度,必须是加密算法分组长度的整数倍。
  • ANSIX9.23:在填充字节序列中,最后一个字节填充为需要填充的字节长度,其余字节填充0。
  • PKCS5PADDING:在填充字节序列中,每个字节填充为需要填充的字节长度。

以下列举了几种算法对应的转换名称:
算法转换名称AESAES/CBC/NoPaddingAESAES/CBC/PKCS5PaddingAESAES/ECB/NoPaddingAESAES/ECB/PKCS5PaddingDESDES/CBC/NoPaddingDESDES/CBC/PKCS5PaddingDESDES/ECB/NoPaddingDESDES/ECB/PKCS5Padding
通过以上知识,加密代码如下:

// 原文String message ="爱老虎油~";// Base64编码的秘钥字符串String keyBase64 ="LDDoCClZOvP9ZncFM19jZg==";// 获取Cipher 对象Cipher cipher =Cipher.getInstance("AES/ECB/PKCS5Padding");// 将秘钥字符串转为秘钥对象SecretKey keySpec =newSecretKeySpec(Base64.getDecoder().decode(keyBase64),"AES");// 初始化,设置为加密模式,并传入秘钥
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);// 加密运算byte[] cipherData = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));// 打印密文:SJ+6fnHAWt9ui7Pq3AlFmg==System.out.println("密文:"+Base64.getEncoder().encodeToString(cipherData));

3. 解密

解密

就比较简单了,使用秘钥,调用

Cipher 

对象进行解密即可,代码如下:

// 解密// 密文String enBase64Message="SJ+6fnHAWt9ui7Pq3AlFmg==";// Base64编码的秘钥字符串String enKeyBase64 ="LDDoCClZOvP9ZncFM19jZg==";// 获取Cipher 对象Cipher deCipher =Cipher.getInstance("AES/ECB/PKCS5Padding");// 将秘钥字符串转为秘钥对象SecretKey deKeySpec =newSecretKeySpec(Base64.getDecoder().decode(enKeyBase64),"AES");// 初始化,设置解密模式,并传入秘钥
        deCipher.init(Cipher.DECRYPT_MODE, deKeySpec);// 解密运算byte[] bytes = deCipher.doFinal(Base64.getDecoder().decode(enBase64Message));// 打印明文System.out.println("明文:"+newString(bytes));

执行结果如下:

密文:SJ+6fnHAWt9ui7Pq3AlFmg==
明文:爱老虎油~

非对称加解密

1. 创建密钥

使用

KeyPairGenerator.getInstance()

获取一个秘钥生成器,参数类型和对称秘钥一样,区别在于算法名称不一样。

常见的非对称加密算法有:

  • RSA:性能比较快,如果想要较高的加密难度,需要很长的秘钥。
  • ECC:基于椭圆曲线提出。是目前加密强度最高的非对称加密算法。
  • SM2:同样基于椭圆曲线问题设计。最大优势就是国家认可和大力支持。

代码如下

// 获取非对称密钥生成器KeyPairGenerator keyPairGenerator =KeyPairGenerator.getInstance("RSA");// 初始化
        keyPairGenerator.initialize(512);// 生成秘钥对KeyPair keyPair = keyPairGenerator.generateKeyPair();// 获取内部密钥对PrivateKey privateKey = keyPair.getPrivate();// 私钥PublicKey publicKey = keyPair.getPublic();// 公钥// 打印秘钥:System.out.println("公钥:"+Base64.getEncoder().encodeToString(publicKey.getEncoded()));System.out.println("私钥:"+Base64.getEncoder().encodeToString(privateKey.getEncoded()));

执行结果

公钥:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL8SAEW1o3lMg4XVQi29n7XqQ02ei0voeKcXvj+bVH1Fu+8W9CzSLpnlHHQgL9bl8Kly/5/y0TgE+NBxsrdfZo8CAwEAAQ==
私钥:MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvxIARbWjeUyDhdVCLb2ftepDTZ6LS+h4pxe+P5tUfUW77xb0LNIumeUcdCAv1uXwqXL/n/LROAT40HGyt19mjwIDAQABAkEAm4TsYdERaSbFGsbVIePpPimadHAqkzN6GQ8zVBR7NaaEeeFjZ/XX/FmNTvrKp2IXN5p0d0LZDOUPq3UL/nzpQQIhAP3JnMQBa9yeb3NzmCguaDwty8175sEDsB/NJLrULuehAiEAwLxrkZItOaoFRV6c78qPsHQGKSTQQBAFS2vycehW4C8CIQDH6wwM8zmunzgYcFTKQlRmI4VKJ3JNVcRmKMnoSsFwQQIgTob2lPMn9gyt5RuteY3giZZcRDs5lkBwx9ANkheF/gUCIAwBGYCzZHNsEr6PIfImrwxRLs/MFPbbQAHpUQaLaWL9

2. 公钥加密

使用公钥对原文数据进行加密。

// 使用公钥加密// 原文String message ="爱老虎油~";// Base64编码的公钥字符串String publicKeyBase64 ="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMEC2gOpKGTzCdJ4flb6Oj9QmbwVANmwLn0zBkZINepGEeWnvORxlteakSK03O2XgtHSGyW4r520KBtvKEcdFAECAwEAAQ==";// 获取Cipher 对象Cipher cipher =Cipher.getInstance("RSA/ECB/PKCS1Padding");// 将公钥字符串转为公钥对象X509EncodedKeySpec bobPubKeySpec =newX509EncodedKeySpec(Base64.getDecoder().decode(publicKeyBase64));KeyFactory keyFactory =KeyFactory.getInstance("RSA");PublicKey publicKeyByValue = keyFactory.generatePublic(bobPubKeySpec);// 初始化,设置为加密模式,并传入公钥
        cipher.init(Cipher.ENCRYPT_MODE, publicKeyByValue);// 加密运算byte[] cipherData = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));// 打印密文:mMzlg+65E1QKJi+zOVdyzbYrq526fOd7ir0Zlkbvo2q37iGvrMiq/y9P4teBtPe9PRJF7HCsmezZ3/M0aiQbyw==System.out.println("密文:"+Base64.getEncoder().encodeToString(cipherData));

3. 私钥解密

使用私钥对密文数据进行解密。

// 使用私钥解密// 密文String enBase64Message ="mMzlg+65E1QKJi+zOVdyzbYrq526fOd7ir0Zlkbvo2q37iGvrMiq/y9P4teBtPe9PRJF7HCsmezZ3/M0aiQbyw==";// Base64编码的私钥字符串String privateKeyBase64 ="MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAwQLaA6koZPMJ0nh+Vvo6P1CZvBUA2bAufTMGRkg16kYR5ae85HGW15qRIrTc7ZeC0dIbJbivnbQoG28oRx0UAQIDAQABAkEAmQgjx6dFadTxQrlaoqe/qxfC7MdSZ0czdP0RyoPSi64k942Rj46in5zDw60SynysVvMmVinxPPFS+6rv5kIWaQIhAPMXt8l7jPGmF6pYTmE2cx9OjB4Q9q8uhfIKZc0E7T9HAiEAy0JkNwSVxK76I9mFZpoRSfH37xAqLyUKhdCRAn5fBncCIQDGw3Pg6Ia750SeYgnkbrL+vCjRRKmPX4jh+SJ32jlqbQIgIXe6FpELtAn3qAV+AKnnpNxRraxktcSMmgIAjn+OV/sCIFlpFzkKXkW2cTv6oVHbFkqgrDPhTAXbshsa/U301Oac";// 获取Cipher 对象Cipher deCipher =Cipher.getInstance("RSA/ECB/PKCS1Padding");// 将私钥字符串转为私钥对象PKCS8EncodedKeySpec privateKeySpec =newPKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyBase64));KeyFactory privateKeyFactory =KeyFactory.getInstance("RSA");PrivateKey privateKeyByValue = privateKeyFactory.generatePrivate(privateKeySpec);// 初始化,设置解密模式,并传入私钥
        deCipher.init(Cipher.DECRYPT_MODE, privateKeyByValue);// 解密运算byte[] bytes = deCipher.doFinal(Base64.getDecoder().decode(enBase64Message));// 打印明文: 明文:爱老虎油~System.out.println("明文:"+newString(bytes));
标签: 安全 网络

本文转载自: https://blog.csdn.net/qq_43437874/article/details/128641715
版权归原作者 云烟成雨TD 所有, 如有侵权,请联系我们删除。

“在线支付系列【3】支付安全之对称和非对称加密”的评论:

还没有评论