我在ios AESCrypt的node.js中解密消息时打破了前缀

时间:2016-10-28 11:26:12

标签: android ios node.js encryption

我在ios中使用https://github.com/Gurpartap/AESCrypt-ObjC

print(AESCrypt.encrypt("Start of messsage this ultra long message about how to AES encrypt in node js, message cryptrd with ios AESCrypt! finish", password: "pass"))
  

print is =   " DB6bpsjaoOTuBL / tb0KR81zOD9gQTmiRjP6Jk3H6WB06rKA513d3VEVvD7fJ4Ap54JRB + e0Vcj7IRPZeB1iauc71udvsUIt59gdds / AP6 + qGKLjVBRpo9mD3xcHkZRuSBGjEnjjdfn8vpDER7oBg9ArQL6vvdc5bb3FtJ4wUdRI ="

和Android

 MessageDigest digest = MessageDigest.getInstance("SHA-256");
    digest.update(password.getBytes("UTF-8"));
    byte[] keyBytes = new byte[32];
    System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);

    cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
    key = new SecretKeySpec(keyBytes, "AES");
    spec = getIV();
}

public AlgorithmParameterSpec getIV()
{
    byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
    IvParameterSpec ivParameterSpec;
    ivParameterSpec = new IvParameterSpec(iv);

    return ivParameterSpec;
}

public String encrypt(String plainText) throws Exception
{
    cipher.init(Cipher.ENCRYPT_MODE, key, spec);
    byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
    String encryptedText = new String(Base64.encode(encrypted, Base64.DEFAULT), "UTF-8");

    return encryptedText;
}

但是当我尝试在node.js服务器中解密时我有问题 - 解密的消息已经崩溃了前缀

bFQAG_V] UCCCQW

  

message =" bFQAG_V] UCCCQWe这个关于如何AES的超长消息   在节点js中加密,使用ios AESCrypt消息加密!光洁度"

尝试了不同的设置,但没有尝试

这是我在node.js上的代码

var crypto = require('crypto');
var iv = new Buffer(16);

var encrypt = function(data, key) {
    var decodeKey = crypto.createHash('sha256').update(key, 'utf-8').digest();
    var cipher = crypto.createCipheriv('aes-256-cbc', decodeKey, iv);
    return cipher.update(data, 'utf8', 'base64') + cipher.final('base64');
};

var decrypt = function(data, key) {
    var encodeKey = crypto.createHash('sha256').update(key).digest();
    var cipher = crypto.createDecipheriv('AES-256-CBC', encodeKey, iv);
  var text =  cipher.update(data, 'base64', 'utf8')+ cipher.final('utf8')
    return text;
};

var data = 'DB6bpsjaoOTuBL/tb0KR81zOD9gQTmiRjP6Jk3H6WB06rKA513d3VEVvD7fJ4Ap54JRB+e0Vcj7IRPZeB1iauc71udvsUIt59gdds/AP6+qGKLjVBRpo9mD3xcHkZRuSBGjEnjjdfn8vpDER7oBg9ArQL6vvdc5bb3FtJ4wUdRI='
var key = 'pass';
var decipher = decrypt(data, key);

1 个答案:

答案 0 :(得分:0)

很多代码都缺失了,所以只能猜测:

node.js代码将IV作为加密数据的前缀,这是一种常用方法,并且在解密之前不会删除16字节的IV。

如果是这种情况,请将IV前缀拆分并将其用作解密的IV。

弃用文档部分的示例:

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

iv以加密数据为前缀

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

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

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

PKCS#7 padding默认设置。

此示例需要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>

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

为了安全起见,加密数据也应该具有身份验证,这个示例代码不会提供这样的代码,因为它很小并且可以为其他平台提供更好的互操作性。

同样缺少密钥的密钥派生密钥,建议使用PBKDF2文本密码作为密钥材料使用。

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