【ios】【android】3DES_CBC_PKCS5Padding加密、解密问题(附完整代码)

问题一:加密结果不一致

一、问题描述

实现了android的蓝牙对接后开始着手ios的蓝牙对接,出现了ios加密结果与在线加密的结果一致,而android的加密结果与甲方公司的结果一致的问题。

1.android部分代码如下:
	public byte[] get3DesEncCodeCBC(byte[] byteS, byte[] key, byte[] iv) {
        byte[] byteFina = null;
        Cipher cipher;
        try {
            SecretKey desKey = new SecretKeySpec(key, "DESede");
            IvParameterSpec desIV = new IvParameterSpec(iv);
            cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            cipher.init(cipher.ENCRYPT_MODE, desKey, desIV);
            byteFina = cipher.doFinal(byteS);
        } catch (Exception error) {
            error.printStackTrace();
        } finally {
            cipher = null;
        }
        return byteFina;
    }
2.ios部分代码如下:
	public static func CBCMain(op: Int, key: String, iv: String, content: String) -> String? {
        // op传1位加密,0为解密
        // CCOperation(kCCEncrypt)加密 1
        // CCOperation(kCCDecrypt) 解密 0
        var ccop = CCOperation();
        // Key
        let keyData: NSData = (key as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData;
        let keyBytes = UnsafeRawPointer(keyData.bytes);
        let keyLength = size_t(kCCKeySize3DES);
        // 可选的初始化向量
        let ivData: NSData = (iv as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData;
        let ivDataBytes = UnsafeRawPointer(ivData.bytes);
        // 加密或解密的内容
        if op == 1 {
            ccop = CCOperation(kCCEncrypt);
        } else {
            ccop = CCOperation(kCCDecrypt);
        }
        let data: NSData = (content as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData;
        let dataLength = size_t(data.length);
        let dataBytes = UnsafeRawPointer(data.bytes);
        // 返回数据
        let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES);
        let cryptPointer = UnsafeMutableRawPointer(cryptData!.mutableBytes);
        let cryptLength = size_t(cryptData!.length);
        // 特定的几个参数
        let operation: CCOperation = UInt32(ccop);
        let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES);
        let options: CCOptions = UInt32(kCCOptionPKCS7Padding);
        var numBytesCrypted :size_t = 0;
        let cryptStatus = CCCrypt(operation, // 加密还是解密
                                  algoritm, // 算法类型
                                  options,  // 密码块的设置选项
                                  keyBytes, // 秘钥的字节
                                  keyLength, // 秘钥的长度
                                  ivDataBytes, // 可选初始化向量的字节
                                  dataBytes, // 加解密内容的字节
                                  dataLength, // 加解密内容的长度
                                  cryptPointer, // output data buffer
                                  cryptLength,  // output data length available
                                  &numBytesCrypted); // real output data length
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            cryptData!.length = Int(numBytesCrypted);
            if op == 1  {
                // 返回加密的数据
                let hexStr = DataUtils.nsDataToHex(data: cryptData!);
                return hexStr;
            } else {
                // 返回解密的数据
                let hexStr = DataUtils.nsDataToHex(data: cryptData!);
                return hexStr;
            }
        }
        return nil;
    }
二、问题解决

重新看了一遍android加密调用部分的代码,使用了十六进制字符串转byte数组的方法:
在这里插入图片描述
由于是对蓝牙数据进行加密,所以传入的字符串为十六进制,在ios代码中使用:

(content as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData;

是错误的,改为十六进制字符串的转换方法:

let keyData: NSData = Data.init(hex: key) as NSData;

最终获取到了正确的加密结果。

问题二:解密结果不一致

一、问题描述

在解决完加密结果不一致的问题后,发现ios的解密结果也与android结果不一致。

二、问题解决

在着手解决加密结果不一致的问题时,有篇文章中写到android对key的处理,若key为16字节,则会将前8字节拼接到key末尾,组成24字节的key,而ios存在16字节与24字节两种长度的key值,若传入的key为16字节,则会直接使用16字节的key。所以在key传入时,对其做长度的判断,若为16字节则进行拼接即可解决。

ios部分代码如下:
	public static func decryptionCBC(key: String, iv: String, content: String) -> String? {
        // 密钥处理
        var keyStr = [String]();
        if key.length() == 32 {
            keyStr.append(key);
            keyStr.append(key.substr(index: 0, length: 16));
        }
        let keyData: NSData = Data.init(hex: keyStr.joined()) as NSData;
        let keyBytes = UnsafeRawPointer(keyData.bytes);
        let keyLength = size_t(kCCKeySize3DES);
        // 可选的初始化向量
        let ivData: NSData = Data.init(hex: iv) as NSData;
        let ivDataBytes = UnsafeRawPointer(ivData.bytes);
        // 加密或解密的内容
        let ccop = CCOperation(kCCDecrypt);
        let data = Data.init(hex: content) as NSData;
        let dataLength = size_t(data.length);
        let dataBytes = UnsafeRawPointer(data.bytes);
        // 返回数据
        let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES);
        let cryptPointer = UnsafeMutableRawPointer(cryptData!.mutableBytes);
        let cryptLength = size_t(cryptData!.length);
        // 特定的几个参数
        let operation: CCOperation = UInt32(ccop);
        let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES);
        let options: CCOptions = UInt32(kCCOptionPKCS7Padding);
        var numBytesCrypted :size_t = 0;
        let cryptStatus = CCCrypt(operation, // 加密还是解密
                                  algoritm, // 算法类型
                                  options,  // 密码块的设置选项
                                  keyBytes, // 秘钥的字节
                                  keyLength, // 秘钥的长度
                                  ivDataBytes, // 可选初始化向量的字节
                                  dataBytes, // 加解密内容的字节
                                  dataLength, // 加解密内容的长度
                                  cryptPointer, // output data buffer
                                  cryptLength,  // output data length available
                                  &numBytesCrypted); // real output data length
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            cryptData!.length = Int(numBytesCrypted);
            let hexStr = DataUtils.nsDataToHex(data: cryptData!);
            return hexStr;
        }
        return nil;
    }

附一:测试通过后的IOS SWIFT 3DES加密解密代码

	/**
     - CBC算法加密
     - parameter key: 密钥
     - parameter iv: 偏移量
     - parameter content: 加密数据
     - returns: string
     */
    public static func encryptionCBC(key: String, iv: String, content: String) -> String? {
        // 密钥处理
        var keyStr = [String]();
        if key.length() == 32 {
            keyStr.append(key);
            keyStr.append(key.substr(index: 0, length: 16));
        }
        let keyData: NSData = Data.init(hex: keyStr.joined()) as NSData;
        let keyBytes = UnsafeRawPointer(keyData.bytes);
        let keyLength = size_t(kCCKeySize3DES);
        // 可选的初始化向量
        let ivData: NSData = Data.init(hex: iv) as NSData;
        let ivDataBytes = UnsafeRawPointer(ivData.bytes);
        // 加密或解密的内容
        let ccop = CCOperation(kCCEncrypt);
        let data = Data.init(hex: content) as NSData;
        let dataLength = size_t(data.length);
        let dataBytes = UnsafeRawPointer(data.bytes);
        // 返回数据
        let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES);
        let cryptPointer = UnsafeMutableRawPointer(cryptData!.mutableBytes);
        let cryptLength = size_t(cryptData!.length);
        // 特定的几个参数
        let operation: CCOperation = UInt32(ccop);
        let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES);
        let options: CCOptions = UInt32(kCCOptionPKCS7Padding);
        var numBytesCrypted :size_t = 0;
        let cryptStatus = CCCrypt(operation, // 加密还是解密
                                  algoritm, // 算法类型
                                  options,  // 密码块的设置选项
                                  keyBytes, // 秘钥的字节
                                  keyLength, // 秘钥的长度
                                  ivDataBytes, // 可选初始化向量的字节
                                  dataBytes, // 加解密内容的字节
                                  dataLength, // 加解密内容的长度
                                  cryptPointer, // output data buffer
                                  cryptLength,  // output data length available
                                  &numBytesCrypted); // real output data length
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            cryptData!.length = Int(numBytesCrypted);
            let hexStr = DataUtils.nsDataToHex(data: cryptData!);
            return hexStr;
        }
        return nil;
    }

	/**
     - CBC算法解密
     - parameter key: 密钥
     - parameter iv: 偏移量
     - parameter content: 加密数据
     - returns: string
     */
    public static func decryptionCBC(key: String, iv: String, content: String) -> String? {
        // 密钥处理
        var keyStr = [String]();
        if key.length() == 32 {
            keyStr.append(key);
            keyStr.append(key.substr(index: 0, length: 16));
        }
        let keyData: NSData = Data.init(hex: keyStr.joined()) as NSData;
        let keyBytes = UnsafeRawPointer(keyData.bytes);
        let keyLength = size_t(kCCKeySize3DES);
        // 可选的初始化向量
        let ivData: NSData = Data.init(hex: iv) as NSData;
        let ivDataBytes = UnsafeRawPointer(ivData.bytes);
        // 加密或解密的内容
        let ccop = CCOperation(kCCDecrypt);
        let data = Data.init(hex: content) as NSData;
        let dataLength = size_t(data.length);
        let dataBytes = UnsafeRawPointer(data.bytes);
        // 返回数据
        let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES);
        let cryptPointer = UnsafeMutableRawPointer(cryptData!.mutableBytes);
        let cryptLength = size_t(cryptData!.length);
        // 特定的几个参数
        let operation: CCOperation = UInt32(ccop);
        let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES);
        let options: CCOptions = UInt32(kCCOptionPKCS7Padding);
        var numBytesCrypted :size_t = 0;
        let cryptStatus = CCCrypt(operation, // 加密还是解密
                                  algoritm, // 算法类型
                                  options,  // 密码块的设置选项
                                  keyBytes, // 秘钥的字节
                                  keyLength, // 秘钥的长度
                                  ivDataBytes, // 可选初始化向量的字节
                                  dataBytes, // 加解密内容的字节
                                  dataLength, // 加解密内容的长度
                                  cryptPointer, // output data buffer
                                  cryptLength,  // output data length available
                                  &numBytesCrypted); // real output data length
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            cryptData!.length = Int(numBytesCrypted);
            let hexStr = DataUtils.nsDataToHex(data: cryptData!);
            return hexStr;
        }
        return nil;
    }

附二:测试通过后的ANDROID 3DES加密解密代码

一、Des3Utils.java
	/**
     * CBC算法加密
     *
     * @param key
     * @param content
     * @return
     */
    public static String encryptionCBC(String key, String iv, String content) {
        Des3EncryptUtils des = new Des3EncryptUtils();
        byte[] bye = des.get3DesEncCodeCBC(DataUtils.hexStrToByteArray(content), DataUtils.hexStrToByteArray(key), DataUtils.hexStrToByteArray(iv));
        return HexUtils.toString(bye).trim();
    }

	/**
     * CBC算法解密
     *
     * @param key
     * @param content
     * @return
     */
    public static byte[] decryptionCBC(String key, String iv, String content) {
        Des3EncryptUtils des = new Des3EncryptUtils();
        return des.get3DesDesCodeCBC(DataUtils.hexStrToByteArray(content), DataUtils.hexStrToByteArray(key), DataUtils.hexStrToByteArray(iv));
    }
二、DataUtils.java
	/**
     * 16进制字符串转byte数组
     *
     * @param hexStr
     * @return
     */
    public static byte[] hexStrToByteArray(String hexStr) {
        if (hexStr == null) {
            return null;
        }
        if (hexStr.length() == 0) {
            return new byte[0];
        }
        byte[] byteArray = new byte[hexStr.length() / 2];
        for (int i = 0; i < byteArray.length; i++) {
            String subStr = hexStr.substring(2 * i, 2 * i + 2);
            byteArray[i] = ((byte) Integer.parseInt(subStr, 16));
        }
        return byteArray;
    }
三、Des3EncryptUtils.java
    /**
     * CBC算法加密(带向量)
     *
     * @param byteS
     * @return
     */
    public byte[] get3DesEncCodeCBC(byte[] byteS, byte[] key, byte[] iv) {
        byte[] byteFina = null;
        Cipher cipher;
        try {
            SecretKey desKey = new SecretKeySpec(key, "DESede");
            IvParameterSpec desIV = new IvParameterSpec(iv);
            cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            cipher.init(cipher.ENCRYPT_MODE, desKey, desIV);
            byteFina = cipher.doFinal(byteS);
        } catch (Exception error) {
            error.printStackTrace();
        } finally {
            cipher = null;
        }
        return byteFina;
    }

    /**
     * CBC算法解密(带向量)
     *
     * @param byteS
     * @return
     */
    public byte[] get3DesDesCodeCBC(byte[] byteS, byte[] key, byte[] iv) {
        byte[] byteFina = null;
        Cipher cipher;
        try {
            SecretKey desKey = new SecretKeySpec(key, "DESede");
            IvParameterSpec desIV = new IvParameterSpec(iv);
            cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            cipher.init(cipher.DECRYPT_MODE, desKey, desIV);
            byteFina = cipher.doFinal(byteS);
        } catch (Exception error) {
            error.printStackTrace();
        } finally {
            cipher = null;
        }
        return byteFina;
    }
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布熬夜了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值