简体   繁体   中英

iOS CryptoSwift AES Encryption to Python Decryption works - but not the inverse

I am using CryptoSwift 1.4.1, iOS 15.2, PyCryptodome 3.12.0, and XCode 13.2.1 to encrypt small string messages that I send to a Raspberry Pi Linux Device over BLE. It works when iOS encrypts the message and sends it to the Raspberry Pi. The Pi can successfully decrypt it. Now I want to do the inverse, encrypt a message on the Pi and have the iOS App read and decrypt it. This, however is not working and the decrypted value is the not the message I encrypted on the Pi.

Working iOS encryption:

func aesEncrypt(stringToEncrypt: String, key: Array<UInt8>, iv: Array<UInt8>) throws -> String {
    let data = stringToEncrypt.data(using: String.Encoding.utf8)
    let encrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .noPadding).encrypt((data?.bytes)!)
    return encrypted.toHexString()
}

let ivString = "4198816658388141"
let keyString = "9004786896524916"

let key = [UInt8](keyString.utf8)
let iv = [UInt8](ivString.utf8)

let encryptedSsid = try! aesEncrypt(stringToEncrypt: ssid!, key: key, iv: iv)

Working Raspberry Pi decryption in Python:

KEY = b'9004786896524916'
IV = b'4198816658388141'
MODE = AES.MODE_CFB

def decrypt(key, iv, encrypted_text):
    logger.info(f"Encrypted: {encrypted_text}")
    aes = AES.new(key, MODE, iv, segment_size=128)
    encrypted_text_bytes = binascii.a2b_hex(encrypted_text)
    decrypted_text = aes.decrypt(encrypted_text_bytes).decode("utf-8")
    logger.info(f"Decrypted: {decrypted_text}")
    return decrypted_text

I tried to encrypt a message on the Pi with the following code:

KEY = b'9004786896524916'
IV = b'4198816658388141'
MODE = AES.MODE_CFB

def encrypt(key, decrypted_text):
    # Create cipher object and encrypt the data
    logger.info(f"Decrypted: {decrypted_text}")
    cipher = AES.new(key, MODE, segment_size=128)  # Create a AES cipher object with the key using the mode CBC
    #encrypted_text = cipher.encrypt(pad(decrypted_text, AES.block_size))  # Pad the input data and then encrypt
    encrypted_text = cipher.encrypt(decrypted_text)  # Pad the input data and then encrypt
    logger.info(f"Encrypted: {encrypted_text}")
    return encrypted_text
    ...
    encrypt(KEY, returnString('utf-8'))

However, the iOS App fails to decrypt it properly with this method:

func aesDecrypt(stringToDecrypt: String, key: Array<UInt8>, iv: Array<UInt8>) throws -> String {
    let data = stringToDecrypt.data(using: String.Encoding.utf8)
    let decrypted = try AES(key: key, blockMode: CFB(iv: iv), padding: .noPadding).decrypt((data?.bytes)!)
    return decrypted.toHexString()
}
let ivString = "4198816658388141"
let keyString = "9004786896524916"

let key = [UInt8](keyString.utf8)
let iv = [UInt8](ivString.utf8)
var message = try! aesDecrypt(stringToDecrypt: charString, key: key, iv: iv)

How can I get decryption to work properly in the iOS App when a message is encrypted on the Pi? Thanks.

In the encrypt() method the IV is not considered. As in aesEncrypt() , the IV must be passed and used when creating the AES object.
Furthermore there are bugs in the encoding: The plaintext must be UTF8 encoded and the ciphertext must be hex encoded:

def encrypt(key, iv, plaintext):
    cipher = AES.new(key, MODE, iv, segment_size=128)  
    plaintext_bytes = plaintext.encode("utf-8")
    ciphertext = cipher.encrypt(plaintext_bytes)
    ciphertext_hex = binascii.b2a_hex(ciphertext)  
    return ciphertext_hex

This function is the counterpart to decrypt() , ie it can be used to decrypt the ciphertext generated with encrypt() .


In the iOS code I see two bugs, both concerning the encoding:

The ciphertext must not be UTF8 encoded, but hex decoded, ie the line:

let data = stringToDecrypt.data(using: String.Encoding.utf8)

must be modified accordingly.

Also, the decrypted data must not be hex encoded, but UTF-8 decoded, ie the line:

return decrypted.toHexString()

must be modified accordingly.

Since I'm not familiar with iOS, I won't make any suggestions on how to change this.


Regarding security: A static IV is insecure. Instead, the IV should be randomly generated for each encryption. Since the (non-secret IV) is needed for decryption, it is passed along with the ciphertext (typically concatenated).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM