Camel PGP crypto and symmetric keys - java

My question is how does camel pgp actually work and if my deduction is correct at all, I'm not a java programmer so please note that some of the following text might make no sense.
Does it encrypt the payload with a symmetric key, then encrypts the symmetric key with a public key and sends both to the destination (e.g. ftp server) which then decrypts the symmetric key (session key) and then decrypts the payload with it ? Or does it encrypt the payload with pub key and thats it ? Besides, is any of the keys generated every message ? In other words, lets say we have 20 files in a directory, camel processes them one by one, does this mean that the symmetric key will be generated 20 times or it's only generated once and then reused?
I am trying to find out the best solution to encrypt the messages, it seems it's sufficient to use a symmetric key only (AES) as I can transfer it through a safe channel once and that's it, however the implementation appears to be painful in comparison to PGP (I have to implement a Java tool to generate, save to file and load AES keys, play with initialization vector, HMAC etc.), but on the other hand if the latter creates a different key each time it would be inefficient in my case.

In OpenPGP, you've got two choices, Apache Camel allows both of them:
Hybrid Cryptography
A session key (a new one generated each time) is encrypted using public/private (asymmetric) cryptography. This session key is then used for encrypting the actual information using symmetric cryptography.
This approach combines the advantages of public/private and symmetric cryptography: it enables the advanced key management features of OpenPGP, but does not suffer from the enormous costs of encrypting large amounts of data using public/private key cryptography.
Generating new, random session keys each time is very cheap, as those are mostly a random block of data, and do not involve complex calculations as for public/private key pairs.
Using GnuPG (and probably all other implementations), this approach is used by default when using gpg --encrypt. If you specify the recipient's public key, and no passphrase, you will be using this approach.
Symmetric Encryption
OpenPGP also allows directly generating the session key from a passphrase, which is directly used for symmetric encryption. This disables OpenPGP's key management features. Direct symmetric encryption is rarely used with OpenPGP, but might be handy sometimes.
Using GnuPG, this is achieved by calling gpg --symmetric. If you encrypt (and do not sign), but are asked for a passphrase, you will probably be using symmetric cryptography.
In OpenPGP, public/private key cryptography is never used to encrypt input directly.

Related

Passing username and password securely between 2 backend systems endcrypted

What will be the most secure way in java to Pass username and password encrypted between 2 backend systems written in Java behind the vpn?
The goal will be that if the username and password encrypted being captured by someone, it could never be decrypted.
Theoritically speaking, asymmetric encryption tools are used for transporting confidential data. Every node/client will has a pair of keys that one of them is private and only known by itself, and the other one is public and should be known by everbody that wants to send confidential data to that particular node. The thing is, if a payload data is encrypted with the public key of the client X, it can only be decrypted with the private key of the client X.
Protocols like SSL, TLS, etc. are some widely used implementations of that concept.
assuming you can control both servers in an un-monitored manner(or at least not monitored by the intruder) and could implement any code on both servers then:
you can write your own made up protocol and its encryption algorithms on both systems and use it to share your data between your two systems.
this way the intruder would have no clue what the captured data even is or how to interpret them.
since you said 'Never be decrypted' your protocol could use an encryption key which is already defined on both servers and is not exchanged between them(over a handshake for example) and could use an encryption algorithm which doesn't store any encryption key validation in the transmitted data(like padding or hash etc) and of course shouldn't exchange the encryption algorithm.
it is worth noting that ssl/tls or any other protocol which expose their encryption algorithm and exchange encryption keys used are bad ideas to reach your goal since these protocols are prone to be deciphered if certain portions of their traffic are captured.
The SHA (Secure Hash Algorithm) is one of the popular cryptographic hash functions. A cryptographic hash can be used to make a signature for a text or a data file.
The SHA-256 algorithm generates an almost-unique, fixed-size 256-bit (32-byte) hash. This is a one-way function, so the result cannot be decrypted back to the original value.
Currently, SHA-2 hashing is widely used as it is being considered as the most secure hashing algorithm in the cryptographic arena.
A few library like Guava or Apache commons codec provide the functions.
In your case, I suggest you send the Username in clear text, but send the password use the SHA encrypted, since it cannot be decrypted, in another backend system, you have save the enrypted String somewhere safe like Database, when the password send over, you just need to see the encrypted string match.
This is nice tutorial article talk about SHA in java:
https://www.baeldung.com/sha-256-hashing-java

Manually generate a PGP message

This is an extension of this question: OpenPGP Encryption Using BouncyCastle Lightweight API
My problem is as follows:
I have to generate a PGP encrypted message from a plain text. Because of the key sizes in question the only options I had was to either install the Unlimited Strength policy files or use the lightweight API. Given that I needed the solution to be portable I decided to use the lightweight API.
All solutions that I have found to use the lightweight API use the PGPEncryptedDataGenerator and open a stream to encrypt it (code samples in the other link) however the AES encryption for it uses CFB mode whereas I need to do it in CBC mode.
My Current Approach:
I generated a random 256 bit key and 128 bit initialization vector and used it to encrypt the plaintext. Then I encrypted the key with the public key using RSA. I first wrote the encrypted key and then the encrypted text in a stream, signed it using a private key, created PGPLiteralDataPackets out of it and then compressed and armoured it.
However when I try to decrypt it using gpg, it recognized the private key I signed it with and then it gives me a set of non printable ascii characters, which means that it does not recognize the encrypted part even though the public key is present in its keyring.
This means that I am not constructing the message properly. I would like to know how to construct a PGP message manually using bouncy castle so that the encrypted message created by me will be recognized and decrypted.

Send a Secret key over JAVA DataOutputStream

I am developing a FTP tool using symmetric key + RSA. I want to send my secret key to the server over dataoutputstream.How can I do this? I tried following,
Client:
SecretKey secretKey = en_de_cryptor.returnSecretKey();
String encodedKey = Base64.encode(secretKey.getEncoded());
dout.writeUTF(secretKey.toString());
Server:
String secretKey = din.readUTF();
byte[] decodedKey = Base64.decode(secretKey);
But I couldn't get the decode key. How can I solve this and get the secret key at server side.
As most other people have pointed out you have a problem which you are sending the most important part of an asymmetric key in clear text where the secret key can be intercepted. Sure you could encrypt the key, but that introduces other encryption problems to solve. If you use symmetric encryption algorithm to encrypt the key you have a key agreement problem to solve. How will each side agree on a key in a secure manner so that a 3rd party can't intercept it?
At some level you are re-solving problems SSL has already solved. Why not just use it? Also SSL has been battle tested and security experts have gone over it for 25 years. To develop your own version means you may fall into similar pitfalls that have already been encountered by SSL developers.
But, if you must re-implement you are going to need to change your algorithm. The most secure way to protect the private key is to never send it over the network in the first place. Asymmetric encryption allows you to trade messages between the client and server without the key agreement problem symmetric algorithms have.
Here's an algorithm that will get around the key agreement problem:
Have the server generate an asymmetric key. Two options:
Generate an asymmetric key one time (ie at server startup) and all connections use the same key.
Generate an asymmetric key for each client when they connect making it more secure.
When the client connects transfer the server's public key to the client
The client will generate a secret key for a symmetric algorithm (How do you pick the algorithm? SSL solved this too).
Client encrypts this secret key using the server's public key
The client transfers the encrypted secret key to the server.
The server decrypts the message using its private key to obtain the symmetric secret key.
Now the server and client can exchange any encrypted message using symmetric encryption and a 3rd party can't listen in.
While even if you did this you still are open to man in the middle attacks where a 3rd party listener could trick the client and server to send unencrypted data through the 3rd party as the client trades messages with the client and server. Just a simple example of how implementing this stuff yourself could lead to you creating something less secure than just using SSL.
If you do send encrypted payloads around you'll want to ditch DataInputStream and go with straight binary streams so you don't need to convert binary payloads to UTF strings with Base64Encoding.
omg, don't do that! base64 doesn't give you any security. use encryption, not encoding
you send secretKey.toString (which is not encoded) instead of encodedKey

Is a pre-shared key safe between Android and another java application?

I have an Android application that communicates with another java application. For the data encryption i use the javax.crypto library to encrypt and decrypt the data with a pre-shared key.
According to this question it's possible to get the source code from an APK file. So if somebody is able to read the source code of my application, he's also able to read/manipulate the encrypted data.
It's probably true, so is there a way to prevent this (additional measures, other security method)? Don't know if it have extra value but here is my encryption code:
private static String IV = "AAAAAAAAAAAAAAAA";
private static String ENCRYPTION_KEY = "0123456789abcdef";
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key = new SecretKeySpec(ENCRYPTION_KEY.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(input.getBytes("UTF-8"));
EDIT:
Communication is send and recieving by NFC. My main issue is, if someone has the key he's able to read and write (abused) information to the other side (the NFC reader)
The pre-shared key is not safe!
For someone with just little java reverse engineering skills it is a job of five minutes to decompile your APK file and extracting the key. Once this has been done your crypto is effectively useless.
The standard approach to fix this is to use a key agreement algorithm. You can for example use the Diffie-Hellman key exchange to quickly and secure generate a common secret between two devices: Wikipedia on Diffie-Hellman
Build a hash from the generated common secret and use this as your AES encryption key for this session is a lot more secure and doesn't take much work.
If NFC is your transport layer you need bidirectional data exchanges for Diffie-Hellman to work. Therefore Android Beam will not be usable for you. You can however do bidirectinal data-transfer using host based card emulation on one phone and reader/writer mode on the other.
Using encryption when transmitting data over NFC is a good idea by the way, also the communication range is limited to some few centimeters, you can still sniff the communication from a few meters distance. NFC doesn't do any encryption for you.
A last word of warning: Cryptography is hard to do in practice. Before you send out anything of value over a cryptographic link please make sure that you have a good understanding of what you do. I recommend reading this book which is a good and practical introduction of cryptography: Bruce Schneider - Cryptography Engineering

Confused about how Android Encryption works

Okay, I am working on an application and I want to store a file on the user's SD Card, but I want the file encrypted. I've researched several sites that use the DES encryption to encrypt files and data, but I am confused about something. All the examples I'm seen use a line like this:
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
The problem I am having is that I get my key to encrypt and obviously I need the same key to decrypt. But its seems like a paradox because if I store my key in a file or in a database, can't someone get the key and decrypt my file? Maybe I am missing something, but is there a way to generate a key using a supplied pass phrase? And why would someone not want to use a passkey if they must store the generated key somewhere else?
I think there are two cases:
You trust the user - let the key be dependent on some input (password / passphrase). and encrypt / decrypt the data with it.
You don't trust the user - then you're in trouble, you might obfuscate the encryption / decryption algorithm, but as long as the mechanism + key is stored on the device, you will have this problem.
This applies to both symmetric and asymmetric encryption.
First of all, please don't use DES. It has been broken from many years. Use AES instead.
The problem I am having is that I get
my key to encrypt and obviously I need
the same key to decrypt.
If you use symmetric cryptography techniques this is it. Otherwise have a look to asimmetric encryption.
But its seems like a paradox because
if I store my key in a file or in a
database, can't someone get the key
and decrypt my file?
Yes, someone could do it.
Maybe I am missing something, but is there a way to generate a key using a supplied pass phrase?
You don't use a the key using a passphrase. Usually you do the following things:
key generation
encrypt the key generated with a symmetric key derived from a passphrase
And why would someone not want to use
a passkey if they must store the
generated key somewhere else?
There could be several reasons. For example you can store the key in a removable device, and you want simply connect it to your computer for retrieving the key, without entering the passphrase.
Having a passphrase has its disadvantage too: passphrase must be remembered, can be guessed, if it's too long probably you'll write it down (and that's pretty the same thing then storing it in a file )
EDIT:
to generate a key from a password have a look at PBKDF2 (related post).
Yeah, it is possible to use a pass-phrase to encrypt.
But first, dump DES. Use AES-128.
Accept the pass-phrase from the user and and generate the hash using SHA-256 or SHA-512. Trim the hash to 128 bits for AES-128. Refer this post.
Java AES and using my own Key
Use a salt when you can.
Regarding the storage of password part. Store the hash and not the password. This way you can prevent the attacker from generating the key. Ask the user to enter strong password. And don't forget that your salt must be very strong too.
So, in the end, you store only the hash of the password. The password is not stored and the key to decrypt will not be stored(It will be generated at run-time)
Hope it helps.

Categories