[问题与总结] 数据结构与算法之加密解密

目录

 

1.BASE64Encoder / BASE64Decoder 报错java:sun.misc程序包不存在

2.java.security.InvalidKeyException: Illegal key size

3.Python 与 Java 算法对照


1.BASE64Encoder / BASE64Decoder 报错java:sun.misc程序包不存在

JDK1.8 包括小于1.8的版本可以使用,但JDK1.8可能IDE还是会提示Access restriction.

Access restriction: The constructor 'BASE64Encoder()' is not API (restriction on required library 'D:\Environment\Java\jdk1.8.0_131\jre\lib\rt.jar')
Access restriction: The constructor 'BASE64Decoder()' is not API (restriction on required library 'D:\Environment\Java\jdk1.8.0_131\jre\lib\rt.jar')

其实从JDK1.8开始,SUN公司就已经建议不再使用 sun.misc.BASE64Encodersun.misc.BASE64Decoder了,推荐使用 java.util.Base64 工具类来将其替换.

//原代码
new sun.misc.BASE64Encoder().encode(encrypted);
//替换为
java.util.Base64.getEncoder().encodeToString(encrypted);

//原代码
byte[] encrypted1 = new sun.misc.BASE64Decoder().decodeBuffer(text);
//替换为
byte[] encrypted1 = java.util.Base64.getDecoder().decode(text);

此外,还可以通过引入Apache提供的commons-codec.jar解决.

//原代码
new sun.misc.BASE64Encoder().encode(encrypted);
//替换为
org.apache.commons.codec.binary.Base64.encodeBase64String(encrypted);

//原代码
byte[] encrypted1 = new sun.misc.BASE64Decoder().decodeBuffer(text);
//替换为
byte[] encrypted1 = org.apache.commons.codec.binary.Base64.decodeBase64(text);

2.java.security.InvalidKeyException: Illegal key size

之前在公司开发的时候,一直可以正常的加密解密,但在自己更新了JDK后,发现加密时始终抛出InvalidKeyException.

java.lang.Exception: Operator password encrypt error.
	at com.xxx.framework.codec.PwdEncryptor.encryptoptpwd(PwdEncryptor.java:16)
Caused by: java.security.InvalidKeyException: Illegal key size
	at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
	at javax.crypto.Cipher.implInit(Cipher.java:805)
	at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
	at javax.crypto.Cipher.init(Cipher.java:1396)
	at javax.crypto.Cipher.init(Cipher.java:1327)
	at com.xxx.framework.codec.Encryptor.encrypt(Encryptor.java:25)
	at com.xxx.framework.codec.PwdEncryptor.encryptoptpwd(PwdEncryptor.java:11)

分析是JDK版本问题,但收集信息后发现问题并不是那么简单,故在此记录留痕.

在我们安装的JRE目录下有这样一个文件夹:%JAVE_HOME%\jre\lib\security(%JAVE_HOME%是自己电脑的Java路径,),其中包含有两个.jar文件:“local_policy.jar ”和“US_export_policy.jar”,也就是我们平时说的jar包,这两个jar包就是我们JCE中的核心类库了。JRE中自带的“local_policy.jar ”和“US_export_policy.jar”是支持128位密钥的加密算法,而当我们要使用256位密钥算法的时候,已经超出它的范围,无法支持,所以才会报:“java.security.InvalidKeyException: Illegal key size or default parameters”的异常。

解决问题分两种情况,首先进入%JAVE_HOME%/jre/lib/security/ 目录.

1.若目录里面存在的是 policy 文件夹:

说明此版本为JVM启用 无限制强度管辖策略 有了一种新的更简单的方法。请在当前文件夹中查找文件 java.security,使用文本编辑器打开java.security,并找到定义java安全性属性crypto.policy的行,它可以有两个值limited 或 unlimited - 默认值是limited。

默认情况下,您应该能找到一条注释掉的行:

#crypto.policy=unlimited
您可以通过取消注释该行来启用无限制,删除#:

crypto.policy=unlimited
然后重新启动指向JVM的Java应用程序即可。

2.若目录里面没有policy 文件夹,存在的是local_policy.jar,US_export_policy.jar两个jar包:

去官方下载JCE无限制权限策略文件。

jdk 5: http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-plat-419418.html#jce_policy-1.5.0-oth-JPR

jdk6: http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

JDK7的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK8的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html 

下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
将两个jar文件放到%JAVE_HOME%\jre\lib\security目录下覆盖原来文件即可。

————————————————
以上内容原文链接:https://blog.csdn.net/zhuwangxiangbie/article/details/105124612

了解更多加密解密算法内容,可访问:https://blog.csdn.net/dafeige8/article/details/75637058

3.Python 与 Java 算法对照

以AES加密算法为例,其Java代码实现如下:

public class Encryptor {
    /**
     * 加密因子
     */
    private static final String cryptKey = "Zz2aAhN86By947mNh+QfQs4+iiYzvXdBpuIWcrHaIQQ=";

    /**
     * 向量(增强算法)
     */
    private static final String cryptIV = "5IjGHGqTqHuaff4prjyMGg==";
    
    public static String encryptPassword(String data) throws Exception{
        return base64Encode(aesEncryptToBytes(data, cryptKey)); 
    }
    
    private static String base64Encode(byte[] bytes) {
        return new sun.misc.BASE64Encoder().encode(bytes);
    }

    private static byte[] base64Decode(String base64Code) throws Exception {
        if (base64Code == null)
            return null;
        return new sun.misc.BASE64Decoder().decodeBuffer(base64Code);
    }

    private static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        byte[] key = base64Decode(encryptKey);
        byte[] iv = base64Decode(cryptIV);
        SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec _iv = new IvParameterSpec(iv);// 使用EBC模式,需要一个向量iv,可增加加密算法的强度
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//算法/模式/补码方式
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, _iv);
        return cipher.doFinal(content.getBytes("utf-8"));
    }

    private static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey)
        throws Exception {
        byte[] key = base64Decode(decryptKey);
        byte[] iv = base64Decode(cryptIV);
        SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec _iv = new IvParameterSpec(iv);// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, _iv);
        byte[] decryptBytes = cipher.doFinal(encryptBytes);
        return new String(decryptBytes);
    }

    public static void main(String[] args) {
        try {
            String pwd = encryptPassword("test1234");
            System.out.println(pwd);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Python 标准库不支持加密算法,可以安装PyCrypto模块来实现常见的加密解密,具体代码实现如下:

由于 PyCrypto 已经超过三年无人维护,安装过程踩无数坑(我只安装成功一次,还修改了vc底层).因此 Github 上的开发者 Varbin 在该项目的 Github issue 里呼吁开发们不要再使用 PyCrypto ,而应该将 PyCrypto 替换为 PyCryptoDome。对于使用 PyCrypto 的已有项目而言,PyCryptodome 保持了与 PyCrypto 相当高的兼容性并且处于良好的维护状态,可放心更换。对于要使用 Python 加密库的项目,建议开发者使用 PyCryptoDome.(详参链接:https://www.jianshu.com/p/fdc5a5854b04)

# coding=utf-8
# AES AES/CBC/PKCS5|Zero

import base64
from Crypto.Cipher import AES

# 加密因子
AES_SECRET_KEY = b"Zz2aAhN86By947mNh+QfQs4+iiYzvXdBpuIWcrHaIQQ=\n"
# 向量(增强算法)
IV = b"5IjGHGqTqHuaff4prjyMGg==\n"


def ByteToHex(bins):
    """
    Convert a byte string to it's hex string representation e.g. for output.
    """
    return ''.join(["%02X" % x for x in bins]).strip()


'''
采用AES对称加密算法
'''
# str不是16的倍数那就补足为16的倍数. ZeroPadding

'''
    在PKCS5Padding中,明确定义Block的大小是8位
    而在PKCS7Padding定义中,对于块的大小是不确定的,可以在1-255之间
    PKCS #7 填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。
    假定块长度为 8,数据长度为 9,
    数据: FF FF FF FF FF FF FF FF FF
    PKCS7 填充: FF FF FF FF FF FF FF FF FF 01 01 01 01 01 01 01   ?应该是填充01

    python3:填充bytes(这个说法不对,AES的参数是字符串,不是byte)
    length = 16 - (len(data) % 16)
    data += bytes([length])*length

    python2:填充字符串
    length = 16 - (len(data) % 16)
    data += chr(length)*length

    pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
    unpad = lambda s : s[0:-ord(s[-1])]
'''
def ZeroPadding(value, bs):
    while len(value) % bs != 0:
        value += '\0'
    return str.encode(value)  # 返回bytes


# 对于python,不需要zerounpadding?  去掉尾部的\0
def PKCS7Padding(value, bs):
    pad = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)  # PKS7
    return str.encode(pad(value))  # 返回bytes


def PKCS7UnPadding(value):
    # value = value[:-value[-1]]
    unpad = lambda s: s[0:-ord(s[-1])]  # 获得数据的长度,截取
    return unpad(value)


# 加密方法
def encrypt_oracle(text=str):
    key = base64.decodebytes(AES_SECRET_KEY)
    iv = base64.decodebytes(IV)
    # 初始化加密器
    aes = AES.new(key, AES.MODE_CBC, iv)
    bs = AES.block_size
    pad2 = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)  # PKS7

    # 先进行aes加密
    # encrypt_aes = aes.encrypt(add_to_16(text))
    # Zeropadding
    # encrypt_aes = aes.encrypt(add_to_16(text))
    # Pkcs7 padding
    encrypt_aes = aes.encrypt(str.encode(pad2(text)))
    # 转为hex
    print(ByteToHex(encrypt_aes))  # 转为字符串 71462668992DB7B3FE76ABFE22376CF6
    # 用base64转成字符串形式
    encrypted_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8')  # 执行加密并转码返回bytes
    # zeropadding:   UR5c4C1iW5mIdxrv5rxo4w==     Pkcs7/Pkcs7: jE7BUAKWpdJWb2ulcFWd/g==
    # 和js的 结果相同 http://tool.chacuo.net/cryptaes
    return encrypted_text


# 解密方法
def decrypt_oralce(text=str):
    key = base64.decodebytes(AES_SECRET_KEY)
    iv = base64.decodebytes(IV)
    # 初始化加密器
    aes = AES.new(key, AES.MODE_CBC, iv)
    # 优先逆向解密base64成bytes
    base64_decrypted = base64.decodebytes(text.encode(encoding='utf-8'))
    #
    decrypted_text = str(aes.decrypt(base64_decrypted), encoding='utf-8')  # 执行解密密并转码返回str
    unpad = lambda s: s[0:-ord(s[-1])]
    # PADDING = '\0'
    # print decrypted_text.rstrip(PADDING)  #zeropadding只见诶去掉结尾\0
    return unpad(decrypted_text)


if __name__ == '__main__':
    en = encrypt_oracle('2323@#dFCSD.?')
    decrypt_oralce(en)

 

你可能感兴趣的:(Python,Java,数据结构与算法)