2

I want to use the aes-128-ctr in Swift with the CryptoSwift library, however my resulting ciphertext is too long.

My IV is 16 bytes, salt 32 bytes and the aes plaintext is also 32 bytes, why is the resulting ciphertext 48 bytes, thus padded with another 16 bytes?

let salt: [UInt8] = Array("tkmlidnonknkqgvapjrpdcductebsozn".utf8) 
let derivedKey = try PKCS5.PBKDF2(password: password, salt: salt, iterations: numberOfIterations, variant: .sha256).calculate()
let iv: [UInt8] = Array("abcdefgthksdfghj".utf8)
let aesKey: [UInt8] = Array(derivedKey[..<16])
let aes = try AES(key: aesKey, blockMode: .CTR(iv: iv))
let ciphertext = try aes.encrypt(password)

here the password is the mentioned 32 bytes plaintext.

Additionally, is there any way to generate a random salt? I found that

let iv: [UInt8] = AES.randomIV(AES.blockSize)

generates a random IV, however how do I get such a salt?

jww
  • 97,681
  • 90
  • 411
  • 885
phoebus
  • 1,280
  • 1
  • 16
  • 36
  • 2
    It is best to avoid using CryptoSwift, amoung other things it is 500 to 1000 times slower than Common Crypto based implementations. Apple's Common Crypto is FIPS certified and as such has been well vetted, using CryptoSwift is taking a chance on correctness and security. – zaph Oct 28 '17 at 20:02

1 Answers1

2

According to the CryptoSwift documentation, it uses PKCS7 padding by default. Since CTR mode does not need padding, you can (and should) disable it by adding the padding: .noPadding to your AES() constructor call.

There are no special format requirements on the PBKDF2 salt (it can be literally any random string of bytes), so you should be able to use AES.randomIV() (or any other source of random bytes) to generate one.

(Internally, the CryptoSwift AES.randomIV() code seems to use RandomBytesSequence, but unfortunately that part of CryptoSwitf appears to be undocumented. The only usage example I could find, besides the randomIV() source code itself, is this test case. Which, BTW, looks like a really bad unit test — all it appears to be testing is that an AnyIterator<UInt8> actually returns UInt8 values. It's not even checking that the iterator actually returns the requested number of bytes, which it could totally fail to do, e.g. if opening /dev/urandom failed for some reason.)

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • 2
    Also, I'd like to note that I agree with zaph's comment above: if you have the option of using an officially certified crypto library, you probably should. It won't guarantee that your code will be secure, but it will ensure that any security holes in it are your own fault. ;) – Ilmari Karonen Oct 28 '17 at 20:32
  • thank you for your answer, that solved the problem and I will try switching to a certified library as recommended – phoebus Oct 28 '17 at 20:45
  • 1
    I find it bizarre that it should be necessary to set any kind of padding with CTR mode much less than set to `.noPadding`, that should be the default for CTR mode. I also find if bizarre that Apple has not updated Common Crypto or replaced it given the missing SHA-3, Argon2 and AES GCM mode not to mention the feud between the Crypto and the Swift groups. – zaph Oct 28 '17 at 21:17