我正在迅速实施AES加密。 Java和C#的加密解密工作正常。
我很快就得到了与实际结果不同的结果。 调试时,我注意到Java默认使用sign int。 因此,我实现了相同的方式,从而能够验证两个应用程序(Java和Swift)中的derivedKey是否相同。 但是在创建keyData和ivData时,它会丢失签名的数据。不确定是不是造成了问题。
我尝试了以下AES Encryption .net to swift中解释的代码
func decrypt(encryptedText: String, keys :String) -> String{
let encryptedData = encryptedText.data(using: .utf16LittleEndian)
let derivedKey = generateDerivedKey(keyString: keys)
let key = Array(derivedKey[0..<32])
let iv = Array(derivedKey[32..<48])
let keyData = Data(bytes: key, count: key.count)
let ivData = Data(bytes: iv, count: iv.count)
let decryptedData = testDeCrypt(data: encryptedData!, keyData: keyData, ivData: ivData, operation: kCCDecrypt)
return String(bytes: decryptedData, encoding: .unicode)!
}
func generateDerivedKey(keyString :String) -> [Int8] {
let salt: [UInt8] = [0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76]
var key = [UInt8](repeating: 0, count: 48)
CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), keyString, keyString.utf8.count, salt, salt.count, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1), 1000, &key, 48)
let derivedKey : [Int8] = key.map {Int8(bitPattern: $0)}
return derivedKey
}
func testDeCrypt(data: Data, keyData: Data, ivData: Data, operation: Int) -> Data {
assert(keyData.count == Int(kCCKeySizeAES128) || keyData.count == Int(kCCKeySizeAES192) || keyData.count == Int(kCCKeySizeAES256))
var decryptedData = Data(count: data.count)
var num_bytes_decrypted: size_t = 0
let operation = CCOperation(operation)
let algoritm = CCAlgorithm(kCCAlgorithmAES)
let options = CCOptions(kCCOptionPKCS7Padding)
let decryptedDataCount = decryptedData.count
let cryptoStatus = keyData.withUnsafeBytes {keyDataBytes in
ivData.withUnsafeBytes {ivDataBytes in
data.withUnsafeBytes {dataBytes in
decryptedData.withUnsafeMutableBytes {decryptedDataBytes in
CCCrypt(operation, algoritm, options, keyDataBytes, keyData.count, ivDataBytes, dataBytes, data.count, decryptedDataBytes, decryptedDataCount, &num_bytes_decrypted)
}
}
}
}
if cryptoStatus == CCCryptorStatus(kCCSuccess) {
decryptedData.count = num_bytes_decrypted
return decryptedData
} else {
return Data()
}
}
Java代码
public static String aesDecrypt(String text, String key) {
byte[] decValue = null;
try {
byte[] salt = new byte[] { 0x49, 0x76, 0x61, 0x6E, 0x20, 0x4D,
0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 };
SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec pbeKeySpec = new PBEKeySpec(key.toCharArray(), salt,
1000, 384);
Key secretKey = factory.generateSecret(pbeKeySpec);
byte[] keys = new byte[32];
byte[] iv = new byte[16];
System.arraycopy(secretKey.getEncoded(), 0, keys, 0, 32);
System.arraycopy(secretKey.getEncoded(), 32, iv, 0, 16);
SecretKeySpec secretSpec = new SecretKeySpec(keys, "AES");
AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try {
cipher.init(Cipher.DECRYPT_MODE, secretSpec, ivSpec);
} catch (InvalidKeyException e) {
} catch (InvalidAlgorithmParameterException e) {
}
org.apache.commons.codec.binary.Base64 decoder = new org.apache.commons.codec.binary.Base64();
byte[] decodedValue = decoder.decode(text.getBytes());
decValue = cipher.doFinal(decodedValue);
} catch (Exception e) {
}
if (decValue != null) {
return new String(decValue, Charset.forName("UTF_16LE"));
} else {
return null;
}
}
测试数据 密钥:“ ThisIsATestPassword444Encryption” 文字:“ TestStringToEncrypt”
Java输出 编码的密文文本:[97,47,77,79,118,111,79,70,47,87,90,67,81,98,51,74,83,88,97,68,84,105,72 ,71、67、121、122、86、81、116、106、104、117、78、108、118、49、48、65、77、69、53、114、43、120、104、89、120 ,50、98、80、66、50、77、87、80、103、110、117、118、118、97、78、106]
加密文本:a / MOvoOF / WZCQb3JSXaDTiHGCyzVQtjhuNlv10AME5r + xhYx2bPB2MWPgnuvvaNj
解密text.getbytes:[97,47,77,79,118,111,79,70,47,87,90,67,81,98,51,74,83,88,97,68,84 ,105、72、71、67、121、122、86、81、116、106、104、117、78、108、118、49、48、65、77、69、53、114、43、120、104 ,89、120、50、98、80、66、50、77、87、80、103、110、117、118、118、97、78、106]
解码后的解密文本:[107,-13、14,-66,-125,-123,-3、102、66、65,-67,-55、73、118,-125、78、33, -58、11、44,-43、66,-40,-31,-72,-39、111,-41、64、12、19,-102,-2,-58、22、49,-39 ,-77,-63,-40,-59,-113,-126,123,-81,-67,-93,99]
快速输出: encryptionText:a / MOvoOF / WZCQb3JSXaDTiHGCyzVQtjhuNlv10AME5r + xhYx2bPB2MWPgnuvvaNj
decryptedText:۽瑒왿᪰߆牷ྐྵ䐫徺ꋴ锏ݐ斑ﷃ翴㦦જ㤉ꄕ䞴櫘勐鼍ᐏ┓ീ学䥏㿖칵斗솽ᢼ铡鴷⤃ꗞ䛂䋗 쿠蒻⯨䍊䂷篥럟⤫俷违둘๔Ꞵ‵
Swift和Java加密匹配。
非常感谢您的帮助。
答案 0 :(得分:1)
Swift代码中最糟糕的两部分是:
#1
let encryptedData = encryptedText.data(using: .utf16LittleEndian)
和:
#2
return String(bytes: decryptedData, encoding: .unicode)!
在您的Java代码中,您将text
解码为Base-64,但是在您的Swift代码中,您仅获得了.utf16LittleEndian
的字节表示,这与Base-无关。 64。
您可能需要这样的东西:
guard let encryptedData = Data(base64Encoded: encryptedText) else {
print("Data is not a valid base-64")
return nil
}
(您的decrypt(encryptedText:keys:)
应该返回String?
而不是String
,因为解密可能会失败。)
在Java代码中,您使用new String(decValue, Charset.forName("UTF_16LE"))
将解密的字节转换为String。 UTF_16LE
代表UTF-16 Little Endian
。 Swift String.Encoding
中的等效项是utf16LittleEndian
。
该行应如下所示:
return String(bytes: decryptedData, encoding: .utf16LittleEndian)
使用generateDerivedKey(keyString:)
作为其返回类型时,[UInt8]
可以简化。 (您最好使用UInt8
来表示Swift中的中间字节类型。)
所有这些东西结合在一起,您的Swift代码应该是:
func decrypt(encryptedText: String, keys: String) -> String? { //### `String?` rather than `String`
//### Decode `encryptedText` as Base-64
guard let encryptedData = Data(base64Encoded: encryptedText) else {
print("Data is not a valid Base-64")
return nil
}
let derivedKey = generateDerivedKey(keyString: keys)
//### A little bit shorter, when `derivedKey` is of type `[UInt8]`
let keyData = Data(bytes: derivedKey[0..<32])
let ivData = Data(bytes: derivedKey[32..<48])
if let decryptedData = testDeCrypt(data: encryptedData, keyData: keyData, ivData: ivData, operation: kCCDecrypt) {
//### Use `utf16LittleEndian`
return String(bytes: decryptedData, encoding: .utf16LittleEndian)
} else {
//### return nil, when `testDeCrypt` fails
return nil
}
}
func generateDerivedKey(keyString: String) -> [UInt8] { //### `[UInt8]`
let salt: [UInt8] = [0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76]
var key = [UInt8](repeating: 0, count: 48)
CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), keyString, keyString.utf8.count, salt, salt.count, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1), 1000, &key, 48)
//### return the Array of `UInt8` directly
return key
}
func testDeCrypt(data: Data, keyData: Data, ivData: Data, operation: Int) -> Data? { //### make it Optional
assert(keyData.count == Int(kCCKeySizeAES128) || keyData.count == Int(kCCKeySizeAES192) || keyData.count == Int(kCCKeySizeAES256))
var decryptedData = Data(count: data.count)
var numBytesDecrypted: size_t = 0
let operation = CCOperation(operation)
let algoritm = CCAlgorithm(kCCAlgorithmAES)
let options = CCOptions(kCCOptionPKCS7Padding)
let decryptedDataCount = decryptedData.count
let cryptoStatus = keyData.withUnsafeBytes {keyDataBytes in
ivData.withUnsafeBytes {ivDataBytes in
data.withUnsafeBytes {dataBytes in
decryptedData.withUnsafeMutableBytes {decryptedDataBytes in
CCCrypt(operation, algoritm, options, keyDataBytes, keyData.count, ivDataBytes, dataBytes, data.count, decryptedDataBytes, decryptedDataCount, &numBytesDecrypted)
}
}
}
}
if cryptoStatus == CCCryptorStatus(kCCSuccess) {
decryptedData.count = numBytesDecrypted
return decryptedData
} else {
return nil //### returning `nil` instead of `Data()`
}
}
使用上面的新Swift代码,我可能会生成与您的Java代码相同的结果:
let test = "a/MOvoOF/WZCQb3JSXaDTiHGCyzVQtjhuNlv10AME5r+xhYx2bPB2MWPgnuvvaNj"
let keys = "ThisIsATestPassword444Encryption"
if let result = decrypt(encryptedText: test, keys: keys) {
print(result) //->TestStringToEncrypt
} else {
print("*Cannot decrypt*")
}
(我需要更新旧的Java环境以比较Java和Swift之间的中间结果,但这是另一回事了……)
答案 1 :(得分:0)
let rsaKeyValue = xmlRep["RSAKeyValue"]
let modulus = rsaKeyValue["Modulus"].element?.text
let exponent = rsaKeyValue["Exponent"].element?.text
var modBuffer: [UInt8] = [UInt8](Data(base64Encoded: modulus!)!)
let expBuffer: [UInt8] = [UInt8](Data(base64Encoded: exponent!)!)
if let prefix = modBuffer.first, prefix != 0x00 {
modBuffer.insert(0x00, at: 0)
}
let modulusEncoded: [UInt8] = modBuffer.encodeAsInteger()
let exponentEncoded: [UInt8] = expBuffer.encodeAsInteger()
let sequenceEncoded: [UInt8] = (modulusEncoded + exponentEncoded).encodeAsSequence()
let keyData = Data(bytes: sequenceEncoded)
let keySize = (modBuffer.count * 8)
let attributes: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits as String: keySize,
kSecAttrIsPermanent as String: false
]
var err : Unmanaged<CFError>?
let publicKey = SecKeyCreateWithData(keyData as CFData, attributes as CFDictionary, &err)
guard let tokenData = Authentication.getUserToken()?.data(using: .utf8) else { return }
let chunks = tokenData.toUInt8Array().chunked(into: 200)
var encryptedChunks = [[UInt8]]()
for chunk in chunks
{
var encryptionError: Unmanaged<CFError>?
let cipher = SecKeyCreateEncryptedData(publicKey!, .rsaEncryptionPKCS1, Data(bytes: chunk) as CFData, &encryptionError)
encryptedChunks.append([UInt8](cipher! as Data))
}
var str = "["
for chunk in encryptedChunks {
for byte in chunk {
str.append("\(byte),")
}
str.remove(at: String.Index(encodedOffset: str.count - 1))
str.append(";")
}
str.append("]")
let finalStr = str.replacingOccurrences(of: ";]", with: "]")
这是用于快速加密的扩展
internal extension Array where Element == UInt8 {
func encodeAsInteger() -> [UInt8] {
var tlvTriplet: [UInt8] = []
tlvTriplet.append(0x02)
tlvTriplet.append(contentsOf: lengthField(of: self))
tlvTriplet.append(contentsOf: self)
return tlvTriplet
}
func encodeAsSequence() -> [UInt8] {
var tlvTriplet: [UInt8] = []
tlvTriplet.append(0x30)
tlvTriplet.append(contentsOf: lengthField(of: self))
tlvTriplet.append(contentsOf: self)
return tlvTriplet
}
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}