如何像android密码一样快速加密?

sab*_*eer 2 encryption swift

嗨,我正在 android 和 swift 中开发应用程序,在 android 中使用加密

 public static String Encrypt(String text, String key)
        throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    byte[] keyBytes= new byte[16];
    byte[] b= key.getBytes("UTF-8");
    int len= b.length;
    if (len > keyBytes.length) len = keyBytes.length;
    System.arraycopy(b, 0, keyBytes, 0, len);
    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
    cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec);

    byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
    BASE64Encoder encoder;
    encoder = new BASE64Encoder();
    return encoder.encode(results);
}
Run Code Online (Sandbox Code Playgroud)

和服务器端使用 RIJnadal 算法来获取它,但快速端我使用的是 Cryptoswift 库

        let key = privateKey // length == 3

    let iv = "0123456789" // lenght == 16

    let s = string
    let enc = try! s.aesEncrypt(key, iv: iv)
    let dec = try! enc.aesDecrypt(key, iv: iv)
    print(s) //string to encrypt
    print("enc:\(enc)") //2r0+KirTTegQfF4wI8rws0LuV8h82rHyyYz7xBpXIpM=
    print("dec:\(dec)") //string to encrypt
    print("\(s == dec)") //true
Run Code Online (Sandbox Code Playgroud)

它产生错误块大小和初始化向量必须是相同的长度!怎么修

zap*_*aph 5

Rijndael 和 AES 的区别在于 AES 是一个子集。AES 的块大小为 128 位(16 字节),密钥大小为 128、192 和 256 位。

下面是一些使用 Common Crypto 和硬件加密引擎的 Swift 代码示例,请注意,使用硬件加密引擎比纯代码实现快 500 到 1000 倍:

将 Security.framework 添加到项目
将 #import 添加到桥接头。

斯威夫特 2.x:

func testCrypt(data data:[UInt8], keyData:[UInt8], ivData:[UInt8], operation:Int) -> [UInt8]? {
    let cryptLength  = size_t(data.count+kCCBlockSizeAES128)
    var cryptData    = [UInt8](count:cryptLength, repeatedValue:0)

    let keyLength             = size_t(kCCKeySizeAES128)
    let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
    let options:  CCOptions   = UInt32(kCCOptionPKCS7Padding)

    var numBytesEncrypted :size_t = 0

    let cryptStatus = CCCrypt(CCOperation(operation),
        algoritm,
        options,
        keyData, keyLength,
        ivData,
        data, data.count,
        &cryptData, cryptLength,
        &numBytesEncrypted)

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        cryptData.removeRange(numBytesEncrypted..<cryptData.count)

    } else {
        print("Error: \(cryptStatus)")
    }

    return cryptData;
}
Run Code Online (Sandbox Code Playgroud)

弃用文档部分的示例:

CBC 模式下的 AES 加密与随机 IV (Swift 3+)

iv 是加密数据的前缀

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

输入是数据,键是数据对象。如果需要在调用方法中转换为和/或来自编码形式(如 Base64)。

密钥的长度应该正好是 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。如果使用其他密钥大小,则会引发错误。

默认情况下设置PKCS#7 填充

此示例需要 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;
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

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)")
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

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>
Run Code Online (Sandbox Code Playgroud)

注意:
CBC 模式示例代码的一个典型问题是它将随机 IV 的创建和共享留给用户。此示例包括 IV 的生成、加密数据的前缀并在解密期间使用前缀 IV。这将临时用户从CBC 模式所需的细节中解放出来。

为了安全起见,加密的数据也应该有身份验证,这个示例代码没有提供,为了小并且允许其他平台更好的互操作性。

还缺少来自密码的密钥的密钥派生,建议使用PBKDF2,将文本密码用作密钥材料。

有关强大的生产就绪多平台加密代码,请参阅RNCryptor