在 swift 中使用 TripleDes 和 MD5

2024-04-10

我有一个使用 TripleDes 和 MD5 的 Java 代码算法。这是我的java代码:

 private String _encrypt(String message, String secretKey) throws Exception {

        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
        byte[] keyBytes = Arrays.copyOf(digestOfPassword, 16);

        SecretKey key = new SecretKeySpec(keyBytes, "DESede/ECB/PKCS7Padding");
        Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS7Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] plainTextBytes = message.getBytes("utf-8");


        byte[] buf = cipher.doFinal(plainTextBytes);
        byte [] base64Bytes = Base64.encodeBase64(buf);
        String base64EncryptedString = new String(base64Bytes);

        return base64EncryptedString;
    }

我想在 swift 中使用 TripleDes 和 MD5,我将此 java 代码转换为 swift 但 swift 中存在问题,因为在 java 中使用 16 字节,而 swift 使用 24 字节。如何解决java和swift编码之间的差异? 这是我的快速代码:

    func myEncrypt(encryptData:String) -> String?{

            let myKeyData : NSData = ("Fanava@Wrapper!1395" as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData
            let myRawData : NSData = encryptData.data(using: String.Encoding.utf8)! as NSData


   let mykeydatamd5 = Data(bytes: myKeyData.bytes, count: 24) // this key convert to 24 bytes but does not hash to md5 

  let mykeydatamd5 = Data(bytes: myKeyData.md5().bytes, count: 24) // this line converted key to md5(), 24byte, but it 


            let buffer_size : size_t = myRawData.length + kCCBlockSize3DES
            let buffer = UnsafeMutablePointer<NSData>.allocate(capacity: buffer_size)
            var num_bytes_encrypted : size_t = 0

            let operation: CCOperation = UInt32(kCCEncrypt)
            let algoritm:  CCAlgorithm = UInt32(kCCAlgorithm3DES)
            let options:   CCOptions   = UInt32(kCCOptionECBMode | kCCOptionPKCS7Padding)
            let keyLength        = size_t(kCCKeySize3DES)

            let Crypto_status: CCCryptorStatus =  CCCrypt(operation, algoritm, options, mykeydatamd5.bytes  , keyLength, nil, myRawData.bytes, myRawData.count, buffer, buffer_size, &num_bytes_encrypted)

            if UInt32(Crypto_status) == UInt32(kCCSuccess){

                let myResult: NSData = NSData(bytes: buffer, length: num_bytes_encrypted)

                free(buffer)

                return myResult.base64EncodedString(options: [])
            }else{
                free(buffer)

                return nil
            }
        }

以下是可以轻松修改 TrippleDES 的示例代码:

来自子集 SO 文档部分

用于具有随机 IV 的 CBC 模式下的 AES 加密 (Swift 3+)

iv 是加密数据的前缀

aesCBC128Encrypt将创建一个随机 IV 并添加到加密代码的前缀。
aesCBC128Decrypt将在解密期间使用前缀 IV。

输入是数据,键是数据对象。如果需要在调用方法中进行转换和/或转换,则需要使用 Base64 等编码形式。

密钥的长度应恰好为 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。如果使用其他密钥大小,则会抛出错误。

PKCS#7 填充 https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7默认设置。

此示例需要 Common Crypto
项目必须有一个桥接头:
#import <CommonCrypto/CommonCrypto.h>
添加Security.framework到项目。

这是示例,而不是生产代码。

enum AESError: Error {
    case KeyError((String, Int))
    case IVError((String, Int))
    case CryptorError((String, Int))
}

// The iv is prefixed to the encrypted data
func aesCBCEncrypt(data:Data, keyData:Data) throws -> Data {
    let keyLength = keyData.count
    let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
    if (validKeyLengths.contains(keyLength) == false) {
        throw AESError.KeyError(("Invalid key length", keyLength))
    }

    let ivSize = kCCBlockSizeAES128;
    let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
    var cryptData = Data(count:cryptLength)

    let status = cryptData.withUnsafeMutableBytes {ivBytes in
        SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
    }
    if (status != 0) {
        throw AESError.IVError(("IV generation failed", Int(status)))
    }

    var numBytesEncrypted :size_t = 0
    let options   = CCOptions(kCCOptionPKCS7Padding)

    let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
        data.withUnsafeBytes {dataBytes in
            keyData.withUnsafeBytes {keyBytes in
                CCCrypt(CCOperation(kCCEncrypt),
                        CCAlgorithm(kCCAlgorithmAES),
                        options,
                        keyBytes, keyLength,
                        cryptBytes,
                        dataBytes, data.count,
                        cryptBytes+kCCBlockSizeAES128, cryptLength,
                        &numBytesEncrypted)
            }
        }
    }

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        cryptData.count = numBytesEncrypted + ivSize
    }
    else {
        throw AESError.CryptorError(("Encryption failed", Int(cryptStatus)))
    }

    return cryptData;
}

// The iv is prefixed to the encrypted data
func aesCBCDecrypt(data:Data, keyData:Data) throws -> Data? {
    let keyLength = keyData.count
    let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
    if (validKeyLengths.contains(keyLength) == false) {
        throw AESError.KeyError(("Invalid key length", keyLength))
    }

    let ivSize = kCCBlockSizeAES128;
    let clearLength = size_t(data.count - ivSize)
    var clearData = Data(count:clearLength)

    var numBytesDecrypted :size_t = 0
    let options   = CCOptions(kCCOptionPKCS7Padding)

    let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
        data.withUnsafeBytes {dataBytes in
            keyData.withUnsafeBytes {keyBytes in
                CCCrypt(CCOperation(kCCDecrypt),
                        CCAlgorithm(kCCAlgorithmAES128),
                        options,
                        keyBytes, keyLength,
                        dataBytes,
                        dataBytes+kCCBlockSizeAES128, clearLength,
                        cryptBytes, clearLength,
                        &numBytesDecrypted)
            }
        }
    }

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        clearData.count = numBytesDecrypted
    }
    else {
        throw AESError.CryptorError(("Decryption failed", Int(cryptStatus)))
    }

    return clearData;
}

用法示例:

let clearData = "clearData0123456".data(using:String.Encoding.utf8)!
let keyData   = "keyData890123456".data(using:String.Encoding.utf8)!
print("clearData:   \(clearData as NSData)")
print("keyData:     \(keyData as NSData)")

var cryptData :Data?
do {
    cryptData = try aesCBCEncrypt(data:clearData, keyData:keyData)
    print("cryptData:   \(cryptData! as NSData)")
}
catch (let status) {
    print("Error aesCBCEncrypt: \(status)")
}

let decryptData :Data?
do {
    let decryptData = try aesCBCDecrypt(data:cryptData!, keyData:keyData)
    print("decryptData: \(decryptData! as NSData)")
}
catch (let status) {
    print("Error aesCBCDecrypt: \(status)")
}

示例输出:

clearData:   <636c6561 72446174 61303132 33343536>
keyData:     <6b657944 61746138 39303132 33343536>
cryptData:   <92c57393 f454d959 5a4d158f 6e1cd3e7 77986ee9 b2970f49 2bafcf1a 8ee9d51a bde49c31 d7780256 71837a61 60fa4be0>
decryptData: <636c6561 72446174 61303132 33343536>

Notes:
CBC 模式示例代码的一个典型问题是它将随机 IV 的创建和共享留给了用户。该示例包括 IV 的生成、加密数据的前缀以及在解密期间使用前缀 IV。这将临时用户从必要的细节中解放出来CBC mode https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29.

为了安全起见,加密数据还应该进行身份验证,此示例代码没有提供身份验证,以便较小并允许与其他平台更好的互操作性。

还缺少从密码中导出密钥的密钥,建议PBKDF2 https://en.wikipedia.org/wiki/PBKDF2使用的是文本密码作为密钥材料。

有关强大的生产就绪多平台加密代码,请参阅RNC加密器 https://github.com/RNCryptor.

如果需要,可以将此函数修改为 3DES。

对于 PBKDF2 加密 **基于密码的密钥派生 2 (Swift 3+)

基于密码的密钥派生既可用于从密码文本派生加密密钥,也可用于保存密码以进行身份​​验证。

可以使用多种哈希算法,包括本示例代码提供的 SHA1、SHA256、SHA512。

rounds 参数用于使计算变慢,以便攻击者必须在每次尝试上花费大量时间。典型的延迟值在 100ms 到 500ms 之间,如果性能不可接受,可以使用更短的值。

此示例需要 Common Crypto
项目必须有一个桥接头:
#import <CommonCrypto/CommonCrypto.h>
添加Security.framework到项目。

参数:

password     password String  
salt         salt Data  
keyByteCount number of key bytes to generate
rounds       Iteration rounds

returns      Derived key


func pbkdf2SHA1(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
    return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA1), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}

func pbkdf2SHA256(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
    return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}

func pbkdf2SHA512(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
    return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA512), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}

func pbkdf2(hash :CCPBKDFAlgorithm, password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
    let passwordData = password.data(using:String.Encoding.utf8)!
    var derivedKeyData = Data(repeating:0, count:keyByteCount)

    let derivationStatus = derivedKeyData.withUnsafeMutableBytes {derivedKeyBytes in
        salt.withUnsafeBytes { saltBytes in

            CCKeyDerivationPBKDF(
                CCPBKDFAlgorithm(kCCPBKDF2),
                password, passwordData.count,
                saltBytes, salt.count,
                hash,
                UInt32(rounds),
                derivedKeyBytes, derivedKeyData.count)
        }
    }
    if (derivationStatus != 0) {
        print("Error: \(derivationStatus)")
        return nil;
    }

    return derivedKeyData
}

用法示例:

let password     = "password"
//let salt       = "saltData".data(using: String.Encoding.utf8)!
let salt         = Data(bytes: [0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61])
let keyByteCount = 16
let rounds       = 100000

let derivedKey = pbkdf2SHA1(password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
print("derivedKey (SHA1): \(derivedKey! as NSData)")

示例输出:

derivedKey (SHA1): <6b9d4fa3 0385d128 f6d196ee 3f1d6dbf>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 swift 中使用 TripleDes 和 MD5 的相关文章

随机推荐

  • 如何将 Enum 绑定到 bit 或 int 的 DbType?

    我正在使用 Linq2Sql 并希望将对象字段 枚举 绑定到数据库中的 bit 或 int 类型 例如 我想在我的模型中有一个性别字段 我已经编辑了 DBML 并将类型更改为指向我的枚举 我想使用相同的想法为性别创建单选按钮 我想我已经弄清
  • 在 logback 中记录并行线程

    我将尝试对我的 Selenium 框架进行简要描述 以便我可以解释我的问题 I use 硒2 当前版本2 3 1 测试NG 5 14 我设置 testng xml 文件来并行运行测试套件中的测试 只有 2 个实例 出于记录目的 我使用log
  • Chrome 中忽略 window.open 宽度

    我想创建一个固定大小的弹出窗口 但是在 Chrome 中宽度属性被忽略 但在 FF 中工作正常 这是我的代码 window open width 300 生成的弹出窗口大于给定的宽度 有什么建议么 这似乎是 Chrome 中的一些奇怪的怪癖
  • 如何从 unicode 字符串中获取正确的元素?

    我想使用索引从 unicode 字符串中获取特定字母 但是 它并没有按预期工作 Example var handwriting 1234567890 var normal abcdefghijklmnopqrstuvwxyzABCDEFGH
  • 在shiny R中输入向量然后使用它

    在 Shiny R 中 我想要一种简单的方法来将向量作为 ui R 中的用户输入 然后想在 server R 中的函数中使用它 我是闪亮的新手 请帮忙 这里有一些简单的方法可以帮助您入门 祝您好运 请记住 下次发布一些代码 否则你肯定会被否
  • 创建像 ASP.NET MVC 3 ViewBag 这样的类?

    我有一种情况 我想做一些类似于 ASP NET MVC 3 ViewBag 对象所做的事情 其中 属性是在运行时创建的 或者是在编译时 无论如何 我想知道如何创建具有这种行为的对象 我创建了这样的东西 public class MyBag
  • 如何使用 mpsc 通道在线程之间创建环形通信?

    我想生成 n 个能够与环形拓扑中的其他线程通信的线程 例如线程 0 可以向线程 1 发送消息 线程 1 可以向线程 2 发送消息 等等 线程 n 可以向线程 0 发送消息 这是我想用 n 3 实现的示例 use std sync mpsc
  • c中的联合初始化

    我想知道联合变量是否会像结构变量一样被初始化 include
  • Typescript:在单独的文件中定义类及其方法

    是否可以在一个文件中声明一个类并在单独的文件中定义其方法 我有一些课程a lot方法 如果我能把它们分散一点那就太好了 简短回答 Typescript 不支持将类定义拆分为多个文件 解决方法 您可以定义一个包含类成员的接口 以及两个实现该接
  • 有谁遇到过“encodeURIComponent(string)”的跨浏览器问题

    我需要动态地从一些自定义字符串值创建 URL 我有疑问encodeURIComponent string https developer mozilla org en JavaScript Reference Global Objects
  • 体系结构 x86_64 的未定义符号:GCC

    我在我的 mac pro 上安装了 gcc 5 3 0 我想使用以下命令编译 c 程序 gcc main c o matrix mcmodel medium lm 但是我收到了这个错误 Undefined symbols for archi
  • Rails 资产管道和摘要价值

    有谁知道资产消化价值到底是怎么计算的吗 如果我有两个 JS 文件 其中包含各种其他包含的 JS 脚本 那么如果内部脚本都没有更改 每个文件是否会维护相同的摘要哈希 或者每次运行 asset precompile 操作时都会计算新的摘要值 接
  • 在 RStudio 中网络抓取 VIN 号码的品牌/型号/年份

    我目前正在开展一个项目 需要查找制造商 型号和 VIN 编号年份 我有 300 个不同 VIN 号码的列表 检查每个单独的 VIN 号码并将制造商 型号和年份手动输入到 Excel 中是非常低效且乏味的 我尝试使用带有 SelectorGa
  • 不使用循环打印 1 到 1000 [重复]

    这个问题在这里已经有答案了 我在 C 编程上下文中看到这个问题 我检查了一个解决方案 我的一位朋友给了我这段代码 它工作完美 但我无法理解它的逻辑以及它是如何工作的 我向他询问了这个问题 但他也不知道该程序实际上是如何工作的 我认为他也从某
  • 如何在 Play Framework 2.0 中使用 Evolutions?

    对于 1 x 版本 我们可以使用play evolutions apply 在 play 2 0 beta 中如何做到这一点 Evolution apply 在应用程序启动时自动运行 Play 2 0 rc1 缺少的是生成进化脚本并从 SB
  • 在 RSpec 请求规范中的每个请求之前设置标头

    如何在其中设置标题before each像下面这样 RSpec describe Users API type request do before each do host example org set a header for all
  • 更新对象时出现 HibernateOptimisticLockingFailureException

    我在更新对象时遇到以下异常 HibernateOptimisticLockingFailureException 类 用户 的对象 带有标识符 25614 乐观锁定失败 嵌套异常 是 org hibernate StaleObjectSta
  • Snowflake 中具有多个 JSON 对象的横向展平数组

    我有一个包含多个 JSON 对象的数组 表中任何 JSON 数组的最大元素数为 8 这是数组原始值的示例 variants id 12388362846279 inventory quantity 10 sku sku1 id 123883
  • 是否可以从命令行运行 Smalltalk 脚本?

    我发现了一个 可能过时且不正确 2004 年的博客文章 http www ianbicking org where smalltalk went wrong html它声称不可能从命令行运行 Smalltalk 脚本 从那时起有什么变化吗
  • 在 swift 中使用 TripleDes 和 MD5

    我有一个使用 TripleDes 和 MD5 的 Java 代码算法 这是我的java代码 private String encrypt String message String secretKey throws Exception Me