
Daniel Becroft (Customer) asked a question.
Environment: 11.7.2
We need to enable encryption/decryption between C# and the Progress ABL, and have found some oddities between the implementations. The encryption model involves either side generating the encryption key based on a known seed value.
However, we've found that the GENERATE-PBE-KEY() function does not match the output of the PasswordDeriveBytes implementation from .NET, for keys larger than 128-bits. I've checked the example code from the Knowledge Base article[1], and it works for anything up to 128-bit key size. If I change the ABL code to use AES_CBC_192 or AES_CBC_256 encryption algorithm, the key values are generated differently:
Key size: 128 (AES_CBC_128) (from the example, and works)
ABL: ML06Y67hc5E4iqM0RiCXDQ==
C#: ML06Y67hc5E4iqM0RiCXDQ==
Key size: 192 (AES_CBC_192)
ABL: ML06Y67hc5E4iqM0RiCXDXW5Z1dAmcZi
C#: ML06Y67hc5E4iqM0RiCXDXW5Z1fhRcrH
Key size: 256 (AES_CBC_256)
ABL: ML06Y67hc5E4iqM0RiCXDXW5Z1dAmcZiuYcLkuu7DpM=
C#: ML06Y67hc5E4iqM0RiCXDXW5Z1fhRcrHLqG2HSv1/GM=
The difference is both cases starts after 26 characters (156 bits) - not sure if that is relevant. This applies to any of the _192 or _256 algorithms from the SYMMETRIC-SUPPORT list, not just the AES cipher.
[1] - https://knowledgebase.progress.com/articles/Article/000041878
Is this something that is known, or is there something else that needs to be adjusted to ensure the same input generates the same key across multiple applications/languages?
UPDATE: It appears that the core problem is that the neither the ABL implementation of GENERATE-PBE-KEY(), or the C# version of the PasswordDeriveBytes method, implement the PKCS1 algorithm correctly. Both allow for keys longer than accounted for. F
From RFC2898, section 5.1 (source: https://tools.ietf.org/html/rfc2898#section-5.1)
"The length of the derived key is bounded by the length of the hash function output, which is 16 octets for MD2 and MD5 and 20 octets for SHA-1."
This means that the GENERATE-PBE-KEY() function should error if requesting a key longer than 160-bits, rather than return a valid key. The same applies for C# (it uses a proprietary implementation to fill in the extra bytes).
This then leads to the question: what logic/algorithm is the OpenEdge implementation using to stretch the key to the requested length?
It is not using the same implementation as C# (as observed from the results), but it is using a deterministic algorithm (as the same code will produce the same key on different OpenEge installation and versions).
Just in case anyone comes across this and needs an answer. OpenEdge uses the OpenSSL encryption library under the hood. Specifically, the GENERATE-PBE-KEY() method returns the same output as OpenSSL's EVP_BytesToKey method. There's a C# version available here on Github (not my code).