First, you should never be using CBC mode for a number of reasons, including no tamper detection, and potential issues with padding attacks, such as ones that have hit TLS in the past.
Instead, you should be using a more modern encryption mode that does integrity checking by default. NimCrypto isn't something I'd recommend; its maintainers don't seem to have too deep an understanding of cryptography (or perhaps don't care much about people building secure systems on top of their library). They only support one modern mode, and they implement it incorrectly. They seem not to be in a hurry to fix this. Meanwhile, Nim ships working with OpenSSL out of the box. OpenSSL has GCM built in, which is the default symmetric cipher suite for AES. On most platforms, OpenSSL will use hardware accelerated code for this. However, Nim's standard libraries don't expose it directly. I've wrapped some of the AES bits in OpenSSL for my own needs, which you're welcome to use if you like: <https://github.com/crashappsec/nimutils> I've not tried to make it ready for anyone else, so there's no documentation at this point, but here's some sample code: import nimutils, strutils, options var encCtx: GcmCtx decCtx: GcmCtx nonce: string ct: string pt = "This is a test between disco and death" key = "0123456789abcdef" gcmInitEncrypt(encCtx, key) gcmInitDecrypt(decCtx, key) echo "Initial pt: ", pt for i in 1 .. 10: ct = encCtx.gcmEncrypt(pt) nonce = encCtx.gcmGetNonce() pt = decCtx.gcmDecrypt(ct, nonce).get("<error>") echo "Nonce: ", nonce.hex() echo "CT: " echo ct.strDump() echo "Decrypted: ", pt Run Alternately, I believe someone in the community maintains a good wrapping of libSodium; the SecretBox abstraction there.