Decrypting AES GCM 256 with pgcrypto (PostgresQL) - postgresql

I am trying to decrypt a message with pgcrypto that is encrypted with AES GCM 256.
Specifications of the encryption:
Encryption algorithm AES
Key [secret of listener] (64-character-long hexadecimal string in configuration)
Key length 256 bits (32 bytes)
Block mode GCM
Padding None
Initialization vector In HTTP header (X-Initialization-Vector)
Authentication tag In HTTP header (X-Authentication-Tag)
So I receive a:
body
key
iv_header
auth_tag
I tried the below
with base as (
select
'F8E2F759E528CB69375E51DB2AF9B53734E393' as body,
'000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F' as key,
'3D575574536D450F71AC76D8' as iv_header,
'19FDD068C6F383C173D3A906F7BD1D83' as auth_tag
),
out as (
select
decrypt_iv(
convert_to(concat(decode(body,'hex'),decode(auth_tag,'hex')),'LATIN1'),
decode(key, 'hex'),
decode(iv_header, 'hex'),
'aes/pad:none'
)
from base
)
select * from out
I keep getting the error decrypt_iv error: Data not a multiple of block size while I would expect to get the encoded message {"type": "PAYMENT"}
I expect that something goes wrong in the decoding and concatenating of body and auth_tag, but can't figure out what.
Some notes on what/why I did that
I concat the auth_tag to the body as several sources describe it that way.
I use the convert_to function as it seems the only way to concatenate two bytea values
I manage to decrypt this message in other languages (i.e. Snowflake or Python)
If anyone sees what I am doing wrong or has some directions it is highly appreciated.

pgcrypto only says it supports cbc and ecb. I'm not a cryptographer, but I don't think either of those is the same thing as GCM. So I don't think you can do this with pgcrypto. I don't know why it leads to the exact error you get, but it also doesn't surprise me.
If I really needed to do this inside the database, I think I do it by writing a function using pl/python3u.

Related

Ionic 3 Native AES256 encrypted data is not 24 byte format

We are developing and using the Ionic 3 Native AES 256 algorithm to encrypt the data, the out put of encrypted data is not valid format of ciphertext format(24 byte). so that we can't able to decrypt in java programme side. also our middleware team using AES/GCM/NoPadding but ionic native plugin using AES/CBC/PKCS5PADDING so that we could not able to decrypt the data in java based middleware side. please advise, how do we handle this.
ionic docs : https://ionicframework.com/docs/v3/native/aes256/
As commented in your first question regarding this topic
(ionic v3 AES 256 algorithm to using encrypted not able to decrypt in java AES/GCM/noPadding algorithm) I run the ionic encryption with these data:
password = "test#123"
plaintext = "Test1234"
and received a Base64-encoded ciphertext string like "izMYpAIMvsCKIVjiNztsrA=="
(as the encryptionKey & iv is generated with random elements your results will differ).
Decoding this ciphertext string back to a byte array I get a (byte array) length of 16 and NOT 24 (it has to be always a multiple of 16) so your encryption isn't running well when getting a length of 24!
Second: there is no way to work with different AES modes - ionic does only support CBC mode that has to be used on your middleware decryption as well. If you need to use an authenticated encryption like "GCM" mode you have to use an additional library.

Decrypting AES GCM with Python without Authentication Tag

I will start with a disclaimer that I am out of my depth here. A colleague was showing me a decryption routine he wrote with pycryptodomex. He had an encrypted file, a key, and a nonce (extracted from the file). He was able to decrypt the file contents in a very straight forward way.
c = Crypto.Cipher.AES.new(key, AES.MODE_GCM, nonce)
c.decrypt(encrypted_data)
You can see a similar implementation in the pycryptodome test for GCM:
cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
pt = get_tag_random("plaintext", 16 * 100)
ct = cipher.encrypt(pt)
cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
pt2 = cipher.decrypt(ct)
Unfortunately, pycryptdomex is an additional dependency that I would need to carry around and I am looking to avoid this. I have a base installation of Anaconda, which brings with it the pyCrypto and pyCA/cryptography packages. It appears that pycryptodomex is a fork of pyCrytpo, which didn't have a stable GCM implementation to begin with. When I look at the implementation for PyCA/cryptography, it looks straight forward:
cipher = Cipher(algorithms.AES(key), modes.GCM(nonce), backend=default_backend())
d = cipher.decryptor()
But when we want to decrypt content we have to call finalize_with_tag and produce an authentication tag:
d.update(encrypted_data) + d.finalize_with_tag(tag)
Unfortunately, I don't have an authentication tag nor do I know where to find it. I can't set the value to None as there is a minimum length requirement. I'm also not sure why I need to produce an authentication tag in the first place for AES GCM decryption with PyCA/Cryptography but I do not need to produce a tag when decrypting with the pycryptodomex. I'm ultimately looking for clarity on the following:
Is it possible to implement AES/GCM decryption with the Anaconda PyCA/cryptography package if I only have access to the key, nonce, and encrypted data?
Why do I need to provide an authentication tag for decryption with one implementation and not the other?
Is pycryptodomex doing something under the hood to determine the tag?
GCM without authentication tag is equivalent to CTR mode. (except the + 1 difference in starting counter value)
Calling decrypt does not verify the tag (as far as I know). You can test this yourself by altering the ciphertext just one byte. It will decrypt just fine (to a plaintext that is off by one byte). Use decrypt_and_verify (see test_invalid_mac test).
See 2.
Apologies as I can't reply to comments. Is it possible to derive the tag from the decrypted data after decryption? This PR associated with PyCA/cryptography seems to imply the exact scenario considered here.
According to the GCM spec (section 7.2: “Algorithm for the
Authenticated Decryption Function”), the tag itself is not needed
until the ciphertext has been decrypted.
Does calling d.update(encrypted_data) decrypt data successfully and d.finalize() is only needed to verify the integrity of the data?

IPhone Decryption with private key -Data Encrypted in Java

Can anyone help with the code how to decrypt with private key ,As in server side they are using OAEP encryption method .I tried decrypting using private key but the decrypted text is Null,I am getting the Error code as -9809 as decryption code result
When you say "with a private key" I assume you mean you're using SecKeyDecrypt() for asymmetric encryption rather than CommonCryptor for symmetric encryption.
SecKeyDecrypt() does not support OAEP. It only supports PKCS1 v1.5 padding (kSecPaddingPKCS1). It can also technically handle ASN.1 padding + PKCS1 padding, but this isn't usually relevant to decryption. You should have noticed this when you passed the SecPadding parameter. What did you pass?
That error number is errSSLCrypto which is a generic "something went wrong in crypto" message.

What are those "garbage" 16 bytes at the beginning of an unencrypted EncryptedData tag from an encrypted ws-security SOAP message? (WCF)

I'm inspecting a WCF request message in order to implement part of the WS-Security standard to have iPhone <-> WCF intercommunication (I'm using certificate security over basicHttpBinding).
After reading the standard xmlenc-core I could decrypt both the SignedInfo and the Body tags, but I see 16 bytes at the beginning of both unencrypted tags from which I have no idea.
I create a sample application according to the standard in order to send request from the iPhone to a self hosted WCF but it continues responding "An error occurred when verifying security for the message".
The only thing I don't know how to implement are those 16 bytes, does anybody knows what to use on those 16 bytes?
Thanks
When using Triple-DES and AES the cipher-text is prefixed by the IV. So when decrypting, you should use the first 16 bytes of the value as the IV and then perform the AES-CBC decryption on the remaining bytes. My guess is that you have forgotten this and thus are decrypting the IV also (which will yield garbage).

Compatible encryption between C# and PHP, ColdFusion, Ruby, Python

We're developing a service that will accept a POST request. Some of the POST data will need to be encrypted before the POST as it will be stored in hidden fields on a form.
The application is written in C#, but we want third party clients to be able to easily integrate with it. We find that most clients use PHP, Classic ASP or VB.Net.
The third parties should only be doing the encryption. We'd do the decryption. There is no two-way communication.
What are the most compatible combinations of encryption algorithm, padding mode and other options?
Assuming that you have a safe way of sharing a key (whether RSA encryption of it, retrieval over an SSH or HTTPS link, or callling the other developer on a secured phone line), any of the major modern encryptions (like AES, as mentioned by #Ed Haber) would be suitable. I would second his suggestion of AES. There should be libraries for PHP, VB, Ruby, etc.
However, remember that with "no two-way communication" you will have to find an out-of-channel method for securely getting the symmetric key to the encrypting party.
If you mean that it should be impossible for third-parties to decrypt data, then you will want to use an asymmetric encryption algorithm such as RSA. This will the third-party to encrypt data with your public key, and then only you can decrypt the data with your private key, which you do not disclose. There should be implementations of RSA available for all the languages you mentioned.
If you don't care if the third-party can decrypt the data, then AES is the way to go. You will have one key which you share with the third-parties. This key is used both for encryption and decryption.
I would use AES for the bulk data encryption and RSA for encrypting the AES Key.
If the data is small enough then just encrypt the whole thing with RSA.
Ed Haber said
I would use AES for the bulk data
encryption and RSA for encrypting the
AES Key. If the data is small enough
then just encrypt the whole thing with
RSA.
I think this is a good solution. What I would do is have your application publish an API for getting a public RSA key. When I third party wants to send you something it gets the public key. It then generates a session key to do the actual encryption using a block cipher, (ie AES), and sends the key to you by encrypting with your public key. You decrypt the session key with your private key. The third party then encrypts the data it wants to send you with AES (using a padding scheme that you also publish) and sends it to you. You decrypt it using the session key.
There are some problems with the method above. Since you are not sending any information (other than publishing your public key, you cannot control how the session key is generated. This means that third parties can use very insecure ways to of generating the session key and you will never know. A second problem is everyone who wants to send you data has to pad data for AES in the same way you do. So you will have to make sure every one co-ordinates. The second issue isn't to big, but the first could be a problem especially if you don't trust the third parties all that much to generate really good session keys from a good cryptographically secure random number generator
You could very easily implement your own XOR key-based bit encryption. With a little thought and ingenuity, you can come up with something that's more than suitable for you application.
Here's a PHP example:
function XOREncryption($InputString, $KeyPhrase){
$KeyPhraseLength = strlen($KeyPhrase);
for ($i = 0; $i < strlen($InputString); $i++){
$rPos = $i % $KeyPhraseLength;
$r = ord($InputString[$i]) ^ ord($KeyPhrase[$rPos]);
$InputString[$i] = chr($r);
}
return $InputString;
}
ColdFusion has the encrypt and decrypt functions capable of handling a range of algorithms and encodings, including the AES recommended above.
Information at: http://www.cfquickdocs.com/cf8/?getDoc=encrypt#Encrypt
Quick example code:
Key = generateSecretKey( 'AES' , 128 )
EncryptedText = encrypt( Text , Key , 'AES' , 'Hex' )
Text = decrypt( EncryptedText , Key, 'AES' , 'Hex' )
Similar functionality is available with this library for PHP:
http://www.chilkatsoft.com/p/php_aes.asp
...and Java, Python, Ruby, and others...
http://www.example-code.com/java/crypt2_aes_matchPhp.asp
http://www.example-code.com/python/aes_stringEncryption.asp
Sounds like RSA is the algorithm for you.
Why not have your server exposed over HTTPS? That way, any client which can handle HTTPS can consume the service securely.