How do I know the file type of a encrypted file - pgp

I am working on a file processing automation program. One of the function is to decrypt pgp file. I am using a code snippet written by maruthi pallamalli (
https://code.msdn.microsoft.com/windowsdesktop/Pretty-Good-Privacy-using-4f473c67#content) to do the decryption. However, I am having problem determiningenter code here the original file type dynamically so I can set the correct output file path.
public static void Decrypt(Stream inputStream, Stream privateKeyStream, string passPhrase, string **outputFile**)
{
try
{
PgpObjectFactory pgpF = null;
....
}
}

If a file is encrypted, you will not be able to determine the file type without decrypting it first.
The best way to deal with this depends on what your software is doing. If you can store the data in a trustworthy way, you can store the original file type outside of the encrypted data. You should only do this if there is no way for someone to tamper with this data.
If you can't store the file type in a trustworthy way, one option might be to store the file type and an HMAC of the file type and the encrypted data together. The HMAC lets you verify that the file type has not been tampered with, since you can only generate an HMAC if you know the secret key.

Related

Bad padding exception after encrypting a message with RSA SHA1 OAEP MGF1

I need to encrypt some message before sending it as request body in an API. I have to do this in Python and the library I used is Pycryptodome. From hereon, when I use the term API, I am referring to the API endpoint provided by the vendor and not the Pycryptodome API. The receiver(API vendor) shared the certificate (RSA 2048 bits) which I need to use to encrypt this message. This certificate is in binary format (DER) and has .cer as the extension. I need to import this using Pycryptodome and from the docs (https://pycryptodome.readthedocs.io/en/latest/src/public_key/rsa.html), I find that the import_key method accepts X.509 certificates in either binary or PEM encoding. The API documentation says I need to use RSA/NONE/OAEPWithSHA1AndMGF1Padding for encryption. This is my code.
def encrypt_message(message):
with open('/home/krishna/work/.certificates/random_certificate.cer', 'rb') as _file:
key_contents = _file.read()
recipient_key = RSA.import_key(key_contents)
cipher_rsa = PKCS1_OAEP.new(recipient_key)
return base64.b64encode(cipher_rsa.encrypt(message.encode())).decode()
I read the PKCS1_OAEP.py file, the default mask generation function is MGF1, default hash algorithm is SHA1. Hence, I did not specify these parameters in the new function in the above code. Also, I need to send this encrypted message as a base64 string (UTF-8). After reading the API documentation and the Pycryptodome documentation, I felt this code is sufficient for encryption. Also, this code is somewhat standard and is almost the same as the one in the Pycryptodome documentation. However, I get a decryption error and the vendor tells me this is due to "BAD PADDING EXCEPTION". This should not happen since I used OAEP for padding and the vendor confirmed they are using OAEP for padding as well. This is very hard for me to debug as I do not possess the vendor's private key.
So I tried generating my own pair of private and public keys (RSA-2048) and checked if I am able to decrypt my message. And duh, I am able to decrypt my message. Here is the code for encryption and decryption using my own keys.
def encrypt_message(message):
with open('my_pub.pem', 'rb') as _file:
pub = _file.read()
recipient_key = RSA.importKey(pub)
cipher_rsa = PKCS1_OAEP.new(recipient_key)
return base64.b64encode(cipher_rsa.encrypt(message.encode())).decode()
def decrypt_message(gibberish):
with open('my_priv.pem', 'rb') as _file:
priv = _file.read()
pvt_key = RSA.importKey(priv)
cipher_rsa = PKCS1_OAEP.new(pvt_key)
return cipher_rsa.decrypt(base64.b64decode(gibberish.encode())).decode()
So where I am going wrong? They key difference between this test and the actual API call is that my keys are generated in PEM format and have .pem as the extension. In the case of the API call, I have to use a .cer certificate in DER format. But I am assuming Pycryptodome is handling this for me (from the docs).
I have a few more questions regarding this.
What is NONE in RSA/NONE/OAEPWithSHA1AndMGF1Padding?
What is the difference between import_key() and importKey() in Pycryptodome? There are 2 methods and it does not look like importKey() has some documentation to it.
Can padding exceptions occur while using OAEP? From what I read from the internet, OAEP is the best method out there, not only in terms of adding randomness during encryption, but I also read that padding exceptions are very rare when this is used.
I really need to know what is going wrong here as I am dead clueless. Any suggestions or help will be appreciated.

How do I validate the Hmac using NodeJS?

I can successfully create an Hmac via NodeJS using the following code:
(slightly altered example from : https://nodejs.org/api/crypto.html#cryptocreatehmacalgorithm-key-options)
Crypto.createHmac('sha256', Crypto.randomBytes(16))
.update('I love cupcakes')
.digest('hex');
That results in a value like the following (hex-based string Hmac signature):
fb2937ca821264812d511d68ae06a643915931375633173ba64af9425f2ffd53
How do I use that signature to verify that the data was not altered? (using NodeJS, of course).
My Assumption
I'm assuming there is a method call where you supply the data and the signature and you get a boolean that tells you if the data was altered or not -- or something similar.
Another Solution?
Oh, wait, as I was writing that I started thinking...
Do I need to store the original random bytes I generated (Crypto.randomBytes(16)) and pass them to the receiver so they can just generate the HMac again and verify that the result is the same (fb2937ca821264812d511d68ae06a643915931375633173ba64af9425f2ffd53)?
If that is true that would be odd, because the parameter for Crypto.randomBytes(16) is named secret (in the official example)*. Seems like that needs to be kept secret??
Please let me know if there is a way to verify the signature on the receiving side & how I do that.
Official Documentation : A Bit Confusing
Here's the function as it is defined in the official docs:
crypto.createHmac(algorithm, key[, options])
In the function definition, you can see the second param is named key.
However, in the example they refer to it as secret
const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
.update('I love cupcakes')
.digest('hex');
console.log(hash);
Just posting the answer so if anyone in future sees this they will be able to have the definitive answer.
As the commentor (Topaco) pointed out, the simple answer is that:
The receiver who want wants to validate the Hmac simply needs to use the same key value & data and apply it to the method and retrieve the hash value.
const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
.update('I love cupcakes')
.digest('hex');
console.log(hash);
The original Hmac-creating party must provide three things for the verifying party:
data : (could be encrypted data from AES256, for example)
key : original key passed into the createHmac() method -- note: this item is called secret in the sample code by NodeJS (above).
hash :the (clearText) hash which the original creator generated when calling the createHmac() method.
With those three things the verifying party can now call the createHmac() method and determine if the hash they get matches the hash that the original hmac-creating party generated.
Doing this validates that the Data which was sent has not been corrupted or altered.
Additional Note On Key (secret)
I've come back after thinking about the Hmac a bit more.
It is required that both parties know the key (aka secret) but it does not mean that it should be exposed to others.
This must be kept secret (as the code implies) because if a nefarious type knew the value and could alter it, then they could also alter the data and generate a new key (secret) and pass it along as if the original creator sent it along (MITM - man in the middle attack).
So, the point here is that yes, both parties have to know the key (secret) value, but it should not be shared where it might be discovered by nefarious types.
Instead, it will have to be agreed upon or based upon a secret password, etc.

File encryption in Laravel and sudo users

I understand I can encrypt and store the contents of files (csv mainly) using the techniques explained here and here.
However, I am looking for a way to prevent anyone from accessing these files, even users with sudo access to the server. The only one (or group of people) who should be able to access the encrypted files would be those who have a password or encryption key chosen by me. Is this possible?
By default the file will show encrypted data, hence even if the file anyone get cant seen data. however you can also put key protectection using class from Encrypt directly or using spatie crypt
Here LOOK Spatie link
You can also use the default crypt like this
use Illuminate\Encryption\Encrypter;
//Keys and cipher used by encrypter(s)
$fromKey = base64_decode("from_key_as_a_base_64_encoded_string");
$toKey = base64_decode("to_key_as_a_base_64_encoded_string");
$cipher = "AES-256-CBC"; //or AES-128-CBC if you prefer
//Create two encrypters using different keys for each
$encrypterFrom = new Encrypter($fromKey, $cipher);
$encrypterTo = new Encrypter($toKey, $cipher);
//Decrypt a string that was encrypted using the "from" key
$decryptedFromString = $encrypterFrom->decryptString("gobbledygook=that=is=a=from=key=encrypted=string==");
//Now encrypt the decrypted string using the "to" key
$encryptedToString = $encrypterTo->encryptString($decryptedFromString);

Problems decrypting data in node.js (RSA PKCS 1.5)

I am having great difficulty implementing some encryption for a node.js project. I am using node-rsa which in turn uses the built in node crypto module.
My code appears to encrypt the data just fine and I can decrypt it. Unfortunately, the system I am sending the data to cannot. Having hit a bit of a wall I've tried decryption some data generated the other end. That also fails.
What is unusual in this case is that the data has to be encrypted using the PRIVATE key and decrypted using the PUBLIC key. As stupid as this is, I had no say in the decision to use this mechanism and it is already in wide use in a UK pubic transport ticketing system. So there is no possibility of doing anything different.
The specification [only] says:
The payload data (Appendix A) is encrypted using the TIS private key,
using 1024Bit RSA PKCS#1v1.5. (This is a freely available public
standard). This protects a payload of up to 116 bytes, or 928Bits,
creating a 128 byte or 1024Bit encrypted output. The RSA encryption
algorithm adds a header of length 12 bytes to the payload before
encryption to improve security. For decryption purposes, this header
should be removed to get the correct payload.
The format of this header is: 0x00 [10 non-zero bytes which are
padding] 0x00 [content]. This is often done automatically by
encryption/decryption software.
Here is an example public key:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDriuvWAKiTKFgmjHjHYjWK4IZ6
W1UOdrntxFAGT1szZlbKJfWGeBOPSk6MnW6AeX54zEta74Dnoj4MBT+MlekVQ2zp
G3qIZpp4DR+kF6eVRlguUg9l/Fgr9ZrFgkumCKIx/ccc6rvZcNvPnOVdPCBVoMRr
3X59WlLmH4d+RAivAQIDAQAB
-----END PUBLIC KEY-----
I've derived this from the Modules / Exponent listed below... I think it is correct...?
Which is [supposedly] valid to decode this encrypted data:
1f876b22ea8af4341c4198347aabf1b1ba40649ad6918bbe26ebfcf4633786a2669ee499d796cf438a76ff0d4f6efc43f605994330e6fb88c8117eea6aad1a12c2525940f7b9946b3f6cbd674e2740070400ae6f2cf1ed6d36f610822a23d5a8a4717ecf671bf0530200f75a269951020be9f69a992d423f55eb6fefe6caa449
I get the following error:
decryptData error Error: Error during decryption (probably incorrect key). Original error: Error: error:0407006A:rsa routines:RSA_padding_check_PKCS1_type_1:block type is not 01
I hate to say it, but I am now completely stumped. If anyone is able to decrypt that data using the supplied key and can explain how I would be very grateful.
Just to save the usual response to this sort of question that I see whenever anyone else has asked a similar question in the past. Please do not comment if all you want to say is the process is wrong. That is not helpful in any way. Just to confirm, whilst encryption with the private key is unusual, it is not impossible....It is supported by the RSA specification.
There are several ticket retailers who are encrypting their data this way and several scanning equipment manufacturers who are producing equipment that decrypts in this way. It's out there, it's working.
The only issue seems to be that there is some small mismatch between the encrypted data I am seeing from node-rsa (node.js crypto library) and the example data I have been given.
This is the original format the keys were given to me.....
Appendix D - Example Security Keys for Tickets
All example tickets are encrypted using the following fixed 1024Bit RSA key
(Never use these keys in production, you must generate your own key pair for this purpose as this private key cannot be considered secure and is for testing only)
Modulus = 16540368155253773454125654483794538435594869143015457768150677916704644349481001621163 93533906833356026635527060528398017212524170789714748325265707476885395169247950736258 76338137535298120673942399072260833758038152595105311260002268650951968659366409471762 707986435753824060971148933772149012757770173722369
= HEX [00eb8aeb d600a893 2858268c 78c76235 8ae0867a 5b550e76 b9edc450 064f5b33 6656ca25 f5867813 8f4a4e8c 9d6e8079 7e78cc4b 5aef80e7 a23e0c05 3f8c95e9 15436ce9 1b7a8866 9a780d1f a417a795 46582e52 0f65fc58 2bf59ac5 824ba608 a231fdc7 1ceabbd9 70dbcf9c e55d3c20 55a0c46b dd7e7d5a 52e61f87 7e4408af 01]
Public Exponent = 65537
= HEX [010001]
Private Exponent = 23262061627321059848127951748956201956280865601289878122136319690902346303487555417896 45421978315004119428666694674801184773156427997741861134011936129888508204465790901818 10860126020371138225614906842567831455763314175530505369901364910691824152015094858350 72189773434923487177372245370361799421231555208773
= HEX [21205394 b0590501 3a8c895a ff2797c2 255ba45f adf1afce ec5a9caa 96848c11 0b89b896 f44774f0 c5119103 1f246071 e209515b c3ad4c66 6bf582d3 72312f2b 7250fe61 f6abed7f e219c08d c3985ae1 3f6b6db2 0e3c040b df7a817d 14a5a6f1 20d94047 08512132 aca00baa 29805440 4ad5dec2 1bd544bb 8938c74b 2904e645]
Just to confirm... I was given incorrect data.

mongodb, node.js and encrypted data

I'm working on a project which involves a lot of encrypted data. Basically, these are JSON objects serialized into a String, then encrypted with AES256 into a Cyphertext, and then have to be stored in Mongo.
I could of course do this the way described above, which will store the cyphertext as String into a BSON document. However, this way, if for some reason along the way the Cyphertext isn't treated properly (for instance, different charset or whatever reason), the cyphertext is altered and I cannot rebuild the original string anymore. With millions of records, that's unacceptable (it's also slow).
Is there a proper way to save the cyphertext in some kind of native binary format, retrieve it binary and then return it to the original string? I'm used to working with strings, my skills with binary format are pretty rusty. I'm very interested in hearing your thoughts on the subject.
Thanks everyone for your input,
Fabian
yes :)
var Binary = require('mongodb').Binary;
var doc = {
data: new Binary(new Buffer(256))
}
or with 1.1.5 of the driver you can do
var doc = {
data: new Buffer(256)
}
The data is always returned as a Binary object however and not a buffer. The link to the docs is below.
http://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html

Resources