各個平臺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加密方式

最後

對於跨平臺聯合開發,記得除了在自己這個平臺驗證外,一定要在其他平臺也做相應的驗證,不要盲目自信。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章