2

I am trying to Implement AES encryption in python.
I am referring a java code sample in order to accomplish this.
In Java, the 256 bit secret (using the given key) is generated using

Key secretKey = new SecretKeySpec(Base64.decodeBase64(GIVEN_KEY), "AES");

I am trying to do the same in python using the following snippet

secret = hashlib.sha256(GIVEN_KEY.encode()).digest()

But the string encoded with python implementation is not being able to get decrypted. Is the above snippets similar, or is there anything I am missing?

Hrishi
  • 1,424
  • 1
  • 13
  • 29

1 Answers1

2

In Java the Base64 decoded value of GIVEN_KEY is used as key, in Python, the SHA256 hash of GIVEN_KEY. Both are not the same.

The counterpart in Python would be something like:

import base64
...
secret = base64.b64decode(GIVEN_KEY.encode()) # by default UTF8 encoded

EDIT: In the linked code (p. 31) the key is Base64url encoded without padding:

QOahfcdo98NLjYJuhP4-VKigx51NkUETsKlIu9uXZFY

which can be recognized by the character - and the length which is not divisible by 4.

This corresponds Base64url decoded to the byte sequence

40e6a17dc768f7c34b8d826e84fe3e54a8a0c79d4d914113b0a948bbdb976456

which represents a 32 bytes key (AES-256) and can be tested e.g. here.

In Python you can Base64url decode with urlsafe_b64decode. However, a padded Base64url encoded value is expected, so that the padding has to be added first, e.g. with the repad method from here.

import base64

# from https://stackoverflow.com/a/9024884/9014097
def repad(data):
    return data + "=" * (-len(data)%4)

GIVEN_KEY = 'QOahfcdo98NLjYJuhP4-VKigx51NkUETsKlIu9uXZFY'

secret = base64.urlsafe_b64decode(repad(GIVEN_KEY).encode()) 
print(secret.hex()) # 40e6a17dc768f7c34b8d826e84fe3e54a8a0c79d4d914113b0a948bbdb976456
Topaco
  • 40,594
  • 4
  • 35
  • 62
  • If this doesn't solve the problem, it would be best to post both codes. – Topaco Aug 06 '20 at 06:05
  • Base64 decoding won't solve it, the char length of GIVEN_KEY is not necessarily a multiple of 4. the `SecretKeySpec` is doing some kind of key derivation. – Hrishi Aug 06 '20 at 07:13
  • `SecretKeySpec` creates a `SecretKey` based on the passed `byte[]`, it does not change the underlying data, [here](https://docs.oracle.com/javase/8/docs/api/javax/crypto/spec/SecretKeySpec.html). If its length does not match a valid AES key (16, 24, 32 bytes), an exception is thrown later (i.e. during encryption/decryption). Probably your problem is somewhere else. I can only recommend you to post both codes. – Topaco Aug 06 '20 at 07:38
  • _...the char length of GIVEN_KEY is not necessarily a multiple of 4..._ With padding the length should actually be a multiple of 4. Maybe during the encoding of the key a Base64 variant is applied that doesn't pad. Apache's [`Base64.decodeBase64`](https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64.html#decodeBase64-java.lang.String-) decodes Base64 and Base64url encoded strings. While `Base64.encodeBase64String` pads, `Base64.encodeBase64URLSafeString` does not. Maybe you should check which Base64 variant was used to encode the key. – Topaco Aug 06 '20 at 09:08
  • See the Sample Java code for AES encryption section in [this doc](https://enterprise.smsgupshup.com/help/in/EnterpriseAPIDocument.pdf) (page number 31) , I am trying to recreate this in python. – Hrishi Aug 06 '20 at 09:21
  • The Java code indeed uses a Base64url encoded key without padding, which has to be decoded accordingly in the Python code, see the EDIT section in my answer. – Topaco Aug 06 '20 at 10:02
  • That's some progress. I tried this method. Now I am no longer getting the key lengith issue. But the remote service is still not able to decrypt the string I am encrypting. Let me share the python code as well for your reference. – Hrishi Aug 06 '20 at 11:17
  • 1
    @Hrishi - This question here is answered. Please ask a new question and post both codes in the question (and not just as links in comments). Thanks. – Topaco Aug 06 '20 at 11:40