java加解密算法
最近在搞报文加解密的一些业务,一路总是坑坑洼洼的。
首先,部分内容是从别的地方搬运过来的。https://www.oschina/question/2534721_2143246?sort=default
知识点1:
sonarLint对加密算法使用的一些规范:
Encryption algorithms should be used with secure mode and padding scheme
Vulnerability
Blocker
java:S5542
To perform secure cryptography, operation modes and padding scheme are essentials and should be used correctly according to the encryption algorithm:
For block cipher encryption algorithms (like AES), the GCM (Galois Counter Mode) mode that works internally with zero/no padding scheme, is recommended. At the opposite, these modes and/or schemes are highly discouraged:
Electronic Codebook (ECB) mode is vulnerable because it doesn't provide serious message confidentiality: under a given key any given plaintext block always gets encrypted to the same ciphertext block.
Cipher Block Chaining (CBC) with PKCS#5 padding (or PKCS#7) is vulnerable to padding oracle attacks.
RSA encryption algorithm should be used with the recommended padding scheme (OAEP)
Noncompliant Code Example
Cipher c0 = Cipher.getInstance("AES"); // Noncompliant: by default ECB mode is chosen
Cipher c1 = Cipher.getInstance("AES/ECB/NoPadding"); // Noncompliant: ECB doesn't provide serious message confidentiality
Cipher c3 = Cipher.getInstance("Blowfish/ECB/PKCS5Padding"); // Noncompliant: ECB doesn't provide serious message confidentiality
Cipher c4 = Cipher.getInstance("DES/ECB/PKCS5Padding"); // Noncompliant: ECB doesn't provide serious message confidentiality
Cipher c6 = Cipher.getInstance("AES/CBC/PKCS5Padding"); // Noncompliant: CBC with PKCS5 is vulnerable to oracle padding attacks
Cipher c7 = Cipher.getInstance("Blowfish/CBC/PKCS5Padding"); // Noncompliant: CBC with PKCS5 is vulnerable to oracle padding attacks
Cipher c8 = Cipher.getInstance("DES/CBC/PKCS5Padding"); // Noncompliant: CBC with PKCS5 is vulnerable to oracle padding attacks
Cipher c9 = Cipher.getInstance("AES/CBC/PKCS7Padding"); // Noncompliant: CBC with PKCS7 is vulnerable to oracle padding attacks
Cipher c10 = Cipher.getInstance("Blowfish/CBC/PKCS7Padding"); // Noncompliant: CBC with PKCS7 is vulnerable to oracle padding attacks
Cipher c11 = Cipher.getInstance("DES/CBC/PKCS7Padding"); // Noncompliant: CBC with PKCS7 is vulnerable to oracle padding attacks
Cipher c14 = Cipher.getInstance("RSA/NONE/NoPadding"); // Noncompliant: RSA without OAEP padding scheme is not recommanded
Compliant Solution
// Recommended for block ciphers
Cipher c5 = Cipher.getInstance("AES/GCM/NoPadding"); // Compliant
// Recommended for RSA
Cipher c15 = Cipher.getInstance("RSA/None/OAEPWithSHA-1AndMGF1Padding"); // Compliant
Cipher c16 = Cipher.getInstance("RSA/None/OAEPWITHSHA-256ANDMGF1PADDING"); // Compliant
See
OWASP Top 10 2017 Category A6 - Security Misconfiguration
MITRE, CWE-327 - Use of a Broken or Risky Cryptographic Algorithm
CERT, MSC61-J. - Do not use insecure or weak cryptographic algorithms
SANS Top 25 - Porous Defenses
知识点2:
3DES加密还有细分,你这里用的是DESede/CBC/NoPadding,
DESede表示加密方式是3DES,
CBC表示加密模式,这个模式不好解释常用的还有ECB
NoPadding表示填充模式,java中常用的还有PKCS5Padding
解释完了,怎么解决呢?
你要问对方3DES使用了什么加密模式,什么填充方式,然后你选择对应的解密模式和填充算法
常用的有:DESede/ECB/PKCS5Padding,DESede/ECB/NoPadding,DESede/CBC/PKCS5Padding,DESede/CBC/NoPadding,
加密模式没有太大的问题,主要是填充方式,如果对方不是PKCS5Padding或者不是兼容的方式那么,你必须要选择NoPadding,然后手动将他填充的去掉,就是你上面说的无法正常显示的字符
再说一下3DES加密过程:
3DESkey有24个字节,通过java内置算法会得到三个key用来给原数据三次加密,所以为什么是叫3DES
然后原数据按每8个字节分组,所以这里就产生了填充的问题,如果你的原数据不是8的整数倍字节,就需要填充满8的倍数,填充的字节就是填充模式决定的,PKCS5Padding的填充模式比较邪,他的算法是如果还缺5个字节,那么用0x05填充5个,如果还缺4个字节那么用0x04填充4个,以此类推,如果缺1个那么用0x01填充1个,注意,如果你的数据正好是8的倍数,那么他还会神奇的再填充8个0x08。
知识点3:
首先,加解密是有iv向量的,所以是cbc模式,至于padding的方式,可以先用NoPadding ,这样解密得到的结果是不会错的,只不过会多一些加密时的补位,根据解密结果byte[] 补位的数据 判断补位方式是PKCS7Padding。
通过分析Nopadding模式得到的byte[] 发现密文是有错误的,重新要了密文,解决了问题
至于java 里支持PKCS7Padding 需要引用 bcprov-jdk16-144.jar 来添加支持。
在代码添加 Security.addProvider(new com.sun.crypto.provider.SunJCE());
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
代码。 然后Cipher cipher = Cipher.getInstance(Algorithm); 可以写成Cipher cipher = Cipher.getInstance(Algorithm,"BC"); 。
知识点4:
对于3des加密算法,加密key的长度问题,长度要求24个字符,真实业务中也有可能少于24或大于24。不同情况的处理方式:
=24:
private static SecretKeySpec getSecretKey1(final String key) {
return new SecretKeySpec(key.getBytes(), KEY_ALGORITHM);
}
>24:
private static SecretKeySpec getSecretKey(final String key) {
//返回生成指定算法密钥生成器的KeyGenerator 对象
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
kg.init(168, new SecureRandom(key.getBytes()));
//生成一个密钥
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
// 转换为DESede专用密钥
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
return null;
}
<24:
忘了,找不到了。
终极知识点5:
更多推荐
java加解密算法
发布评论