Using PyCrypto with Spring Crypto/Spring Security Default Encoders
Spring Crypto Encryptor DetailsThe Spring Crypto module is amazing. Secure defaults using standard interfaces really make it a pleasure to use, and with it being full tested and vetted, it also gives a develoepr the warm fuzzy feelings of nice Java security implentation.
The standard interface is through the org.springframework.security.crypto.encrypt.Encryptors class, defined (in version 3.2.0 here (the class API to which this blog post was written in July 2016). Spring Crypto uses AES256 encryption behind the scenes in its out of the box class setup; it's as easy as:
In the above code snippet, the password variable is a passcode, with the salt variable used to create the AES key. It uses 256 bit encryption with the standard calls (depending on your JRE/Java Cryptography Extension (JCE) Setup, make sure to download the appropriate extension). The default AESBytesEncryptor setup generates a 256 bit key (32 bytes) from a salted iteration done 1024 times. Another thing to note here, is that the salt variable is decoded from a 16 character Hex string and the default Java implementation is "AES/CBC/PKCS5Padding". The PKCS#5 padding is defined in its own RFC, and it is how to deal with byte arrays that are not an integer multiple of a given byte length (16).
Here is the relevant code in the AESBytesEncryptor class:
With the default text encoder, it uses a random 16 byte Initialization Vector (IV), prepended to the encrypted text hex output String. What this means is that the same string encoded multiple times will result in different outputs.
As you can see, the same string "foo" encrypted multiple times results in different encrypted outputs. This is because the initialization vector IV. In the AESBytesEncryptor class, the encrypt method has the following lines of code:
The perceptive reader will also note the ternary switch statement with the byte-concatination; if the NULL_IV_GENERATOR is used, then the encrypted text is returned directly. The concept in the Spring Crypto world is 'queryable encryption'. The Encryptor class has the 'queryableText' encryptor, which uses the null IV concept. The encrypted text is 'queryable', because it returns the same string output each time for the same input string.
Produces the following identical hex strings:
Two little more snippets of code to fully understand how the spring-crypto module details work. The input String is encoded with UTF-8 before being encrypted, and then a hex encoding/decoding is applied.
Here is the encoding call from the HexEncodingTextEncryptor class:
With the decryption decoding in a similar manner. That is the overview of the Spring Security/Spring Crypto implementation details.
PyCrypto Implementation DetailsNow that we understand the encodings, paddings and encryption algorithms presented in the spring-crypto library, the super powerful and fully configurable pycrypto/pycryptodome library can easily be setup to encrypt/decrypt the same hex strings. The below snippets use python 3.5 and pycryptodome as the PyCrypto implementation.
Here is the linked implementation in the custom AES256 implementation AesCrypt256 python class (source too long to embed).
With the random initialization vector example usage specified:
And the example output:
And to run the sample code with the null/16-byte \x00 vector: