各个平台DES加密方式的实现

背景

前段时间在跟后台联调敏感数据的加密和解密时遇到了一些问题,设备使用的是android平台提供的des加密方式,后台使用的javax提供的des加密方式和PHP提供加密方式,在对接过程中就出现了同一段字符,在前后端解密得到的字符串不一样,最后经过一段时间的调试,得到了结果一致的实现方式,下面记录下来。

实现平台

java平台

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.util.Base64;
 
public class DESUtil {
 
    private static final String KEY = "test";
    private static final String DES = "DES";
    private static final String DES_P = "DES/ECB/PKCS5Padding";
    private static final String CHARSET = "UTF-8";
 
 
    /**
     * 进行DES加密
     *
     * @param string String 需要加密的字符串
     * @return String 加密字符串
     */
    public static String encryptByDes(String string) {
        return encryptByDes(string, KEY);
    }
 
 
    /**
     * DES 解密
     *
     * @param string String 加密串
     * @return String 明文
     */
    public static String decryptByDes(String string) {
        return decryptByDes(string, KEY);
    }
 
 
    /**
     * 进行DES加密
     *
     * @param string
     * @param key
     * @return
     */
    private static String encryptByDes(String string, String key) {
        try {
            if (string != null && string.length() > 0) {
                byte[] tmpOriginalStr = string.getBytes(CHARSET);
                // 创建一个密匙工厂
                SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
                // 创建一个DESKeySpec对象
                DESKeySpec dks = new DESKeySpec(key.getBytes());
                // 将DESKeySpec对象转换成SecretKey对象
                SecretKey secretKey = keyFactory.generateSecret(dks);
                // 用密匙初始化Cipher对象
                Cipher cipher = Cipher.getInstance(DES_P);
                // Cipher对象实际完成加密操作
                cipher.init(Cipher.ENCRYPT_MODE, secretKey);
                // 真正开始加密操作
                byte[] encryptStr = cipher.doFinal(tmpOriginalStr);
                if (encryptStr != null) {
                    return Base64.getEncoder().encodeToString(encryptStr);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
 
    /**
     * DES 解密
     *
     * @param string
     * @param key
     * @return
     */
    private static String decryptByDes(String string, String key) {
        try {
            if (string != null && string.length() > 0) {
                // 创建一个密匙工厂
                SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
                // 创建一个DESKeySpec对象
                DESKeySpec dks = new DESKeySpec(key.getBytes(CHARSET));
                // 将DESKeySpec对象转换成SecretKey对象
                SecretKey secretKey = keyFactory.generateSecret(dks);
                // 用密匙初始化Cipher对象
                Cipher cipher = Cipher.getInstance(DES_P);
                // Cipher对象实际完成解密操作
                cipher.init(Cipher.DECRYPT_MODE, secretKey);
                // 真正开始解密操作
                byte[] decryptBytes = cipher.doFinal(Base64.getDecoder().decode(string));
                if (decryptBytes != null) {
                    return new String(decryptBytes, CHARSET);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

android平台

/**
 * DES 工具类
 */
public class DESUtil {
    @IntDef({Cipher.ENCRYPT_MODE, Cipher.DECRYPT_MODE})
    @interface DESType {}

    /**
     * Des加密/解密
     *
     * @param content  字符串内容
     * @param password 密钥
     * @param type     加密:{@link Cipher#ENCRYPT_MODE},解密:{@link Cipher#DECRYPT_MODE}
     * @return 加密/解密结果
     */
    public static String des(String content, String password, @DESType int type) {
        try {
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            @SuppressLint("GetInstance") Cipher cipher = Cipher.getInstance("DES");
            cipher.init(type, keyFactory.generateSecret(desKey), random);

            if (type == Cipher.ENCRYPT_MODE) {
                byte[] byteContent = content.getBytes("utf-8");
                return parseByte2HexStr(cipher.doFinal(byteContent));
            } else {
                byte[] byteContent = parseHexStr2Byte(content);
                return new String(cipher.doFinal(byteContent));
            }
        } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException |
                UnsupportedEncodingException | InvalidKeyException | NoSuchPaddingException |
                InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * des加密
     *
     * @param plainText 待加密字符串
     * @return 加密后的字符串
     */
    public static String encryptByDes(String plainText){

        return EncryptionClient.encryptByDes(plainText);
    }

    /**
     * des解密
     *
     * @param cipherText 待解密字符串
     * @return 解密后的字符串
     */
    public static String decryptByDes(String cipherText) throws Exception{

        return EncryptionClient.decryptByDes(cipherText);
    }

}

ios平台

#pragma mark- 加密算法
 
+(NSString *) encryptUseDES:(NSString *)plainText key:(NSString *)key{
 
    NSString *ciphertext = nil;
    NSData *textData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [textData length];
    unsigned char buffer[1024];
    memset(buffer, 0, sizeof(char));
    size_t numBytesEncrypted = 0;
 
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmDES,
                                          kCCOptionPKCS7Padding | kCCOptionECBMode,
                                          [key UTF8String],
                                          kCCKeySizeDES,
                                          nil,
                                          [textData bytes],
                                          dataLength,
                                          buffer,
                                          1024,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
        ciphertext = [GTMBase64 stringByEncodingData:data];
    }
    return ciphertext;
}

#pragma mark- 解密算法
 
+(NSString *)decryptUseDES:(NSString *)cipherText key:(NSString *)key{
 
    NSString *plaintext = nil;
    NSData *cipherdata = [GTMBase64 decodeString:cipherText];
    unsigned char buffer[1024];
    memset(buffer, 0, sizeof(char));
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES,
                                          kCCOptionPKCS7Padding | kCCOptionECBMode,
                                          [key UTF8String],
                                          kCCKeySizeDES,
                                          nil,
                                          [cipherdata bytes],
                                          [cipherdata length],
                                          buffer,
                                          1024,
                                          &numBytesDecrypted);
    if(cryptStatus == kCCSuccess) {
        NSData *plaindata = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted];
        plaintext = [[NSString alloc]initWithData:plaindata encoding:NSUTF8StringEncoding];
    }
    return plaintext;
}

Web前端

import CryptoJS from "crypto-js"
KEY = 'test'
function encodeData(data) {
    if (data) {
        let key = CryptoJS.enc.Utf8.parse(KEY);
        return CryptoJS.DES.encrypt(data, key, {
            padding: CryptoJS.pad.Pkcs7,
            mode: CryptoJS.mode.ECB
        }).toString()
    } else {
        return ""
    }
}
function decodeData(data) {
    if (data) {
        try {
            let key = CryptoJS.enc.Utf8.parse(KEY);
            return CryptoJS.DES.decrypt(data, key, {
                padding: CryptoJS.pad.Pkcs7,
                mode: CryptoJS.mode.ECB
            }).toString(CryptoJS.enc.Utf8)
        } catch (e) {
            return "decode failure"
        } finally {
        }
    } else {
        return ""
    }
}

C#平台

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace SenseKeeperV3_guest_sample
{
        /// <summary>
        /// 类名称   :CryptTools
        /// 类说明   :加解密算法
        /// 完成日期 :
        /// </summary>
        public static class CryptTools
        {
          
            private static string inlineKey = "test";
            #region DES加密字符串
            ///// <summary>
            /////
            ///// 注意:密钥必须为8位
            ///// </summary>
            /// <summary>
            /// 加密字符串
            /// </summary>
            /// <param name="p_strInput">明码</param>
            /// <returns>加密后的密码</returns>
            public static string DesEncryptFixKey(string p_strInput,string key)
            {
                byte[] byKey = null;
                byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
                try
                {
                    byKey = System.Text.Encoding.UTF8.GetBytes(key.Substring(0, 8));
                    DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                    des.Mode = CipherMode.ECB;
                    byte[] inputByteArray = Encoding.UTF8.GetBytes(p_strInput);
                    MemoryStream ms = new MemoryStream();
                    CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write);
                    cs.Write(inputByteArray, 0, inputByteArray.Length);
                    cs.FlushFinalBlock();
                    return Convert.ToBase64String(ms.ToArray());
                }
                catch (System.Exception ex)
                {
                    throw (ex);
                }
            }
            #endregion
            #region DES解密字符串
            //const string m_strEncryptKey = "kinghuns"; zh注释
            /// <summary>
            /// 解密字符串
            /// </summary>
            /// <param name="this.inputString">加了密的字符串</param>
            /// <param name="decryptKey">密钥</param>
            public static string DesDecryptFixKey(string p_strInput,string key)
            {
                byte[] byKey = null;
                byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
                byte[] inputByteArray = new Byte[p_strInput.Length];
                try
                {
                    byKey = System.Text.Encoding.UTF8.GetBytes(key.Substring(0, 8));
                    DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                    des.Mode = CipherMode.ECB;
                    inputByteArray = Convert.FromBase64String(p_strInput);
                    MemoryStream ms = new MemoryStream();
                    CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write);
                    cs.Write(inputByteArray, 0, inputByteArray.Length);
                    cs.FlushFinalBlock();
                    System.Text.Encoding encoding = new System.Text.UTF8Encoding();
                    return encoding.GetString(ms.ToArray());
                }
                catch (System.Exception ex)
                {
                    throw (ex);
                }
            }
            #endregion
             
            #region DES加密字符串
            ///// <summary>
            /////
            ///// 注意:密钥必须为8位
            ///// </summary>
            /// <summary>
            /// 加密字符串,使用内部默认秘钥
            /// </summary>
            /// <param name="p_strInput">明码</param>
            /// <returns>加密后的密码</returns>
            public static string DesEncryptFixKey(string p_strInput)
            {
                return DesEncryptFixKey(p_strInput,inlineKey);
            }
            #endregion
             
            #region DES解密字符串
            //const string m_strEncryptKey = "kinghuns"; zh注释
            /// <summary>
            /// 解密字符串,使用内部默认秘钥
            /// </summary>
            /// <param name="this.inputString">加了密的字符串</param>
            /// <param name="decryptKey">密钥</param>
            public static string DesDecryptFixKey(string p_strInput)
            {
                return DesDecryptFixKey(p_strInput,inlineKey);
            }
            #endregion
  
            public static String md5(String s)
            {
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] bytes = System.Text.Encoding.UTF8.GetBytes(s);
                bytes = md5.ComputeHash(bytes);
                md5.Clear();
                string ret = "";
                for (int i = 0; i < bytes.Length; i++)
                {
                    ret += Convert.ToString(bytes[i], 16).PadLeft(2, '0');
                }
                return ret.PadLeft(32, '0');
            }
        }
}

jni层实现

参考:Android 平台更加安全的DES加密方式

最后

对于跨平台联合开发,记得除了在自己这个平台验证外,一定要在其他平台也做相应的验证,不要盲目自信。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容