Java how to encrypt text file using a specific public key? - java

I was given a public key id, and being asked to use this public key id to encrypt a .txt file. I can find a reference on how to perform this, but in C# language using Bouncycastle and nothing with Java.
The specific public key id is provided by the encrypted-file recipient. Decryption is done by the encrypted-file recipient, therefore I have no concern on any decryption or private key id, if these info are essential which is beyond my knowledge for time being.
I am using Java and very new with encryption, please direct me to any LATEST java application examples or tutorial that encrypt a text file using specific public key id given instead of generated ones. Thanks!

You can use „raw“ Bouncy Castle for Java or one of several wrappers around the API. For using Bouncy Castle you need to understand the OpenPGP RFC (rfc4880).
Alternatively you can use existing wrappers like e.g. Bouncy GPG:
final String original_message = "I love deadlines. I like the whooshing sound they make as they fly by. Douglas Adams";
// Most likely you will use one of the KeyringConfigs.... methods.
// These are wrappers for the test.
KeyringConfig keyringConfigOfSender = Configs
.keyringConfigFromResourceForSender();
ByteArrayOutputStream result = new ByteArrayOutputStream();
try (
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(result, 16384 * 1024);
final OutputStream outputStream = BouncyGPG
.encryptToStream()
.withConfig(keyringConfigOfSender)
.withStrongAlgorithms()
.toRecipients("recipient#example.com", "sender#example.com")
.andSignWith("sender#example.com")
.binaryOutput()
.andWriteTo(bufferedOutputStream);
// Maybe read a file or a webservice?
final ByteArrayInputStream is = new ByteArrayInputStream(original_message.getBytes())
) {
Streams.pipeAll(is, outputStream);
// It is very important that outputStream is closed before the result stream is read.
// The reason is that GPG writes the signature at the end of the stream.
// This is triggered by closing the stream.
// In this example outputStream is closed via the try-with-resources mechanism of Java
}
result.close();
byte[] chipertext = result.toByteArray();

Related

Encrypt user passwords when uploading code and decrypt during run-time

Have to begin moving in-house, local machine only Java framework into a private but online repo for staff only, however, the current framework requires a properties class which includes sensitive information (usernames, passwords etc) to login to the database and other technology the framework uses.
As a result, pushing the latest framework will include all of said individuals usernames/passwords, which is a security concern.
I've been asked to "Encrypt the password so when it's uploaded it's hidden" and then "Decrypt the password during runtime, so that information can be used to execute the code, as without the login data, the framework will not work".
While there is much better solutions (ie just don't upload the properties class, rework framework to not need the properties class etc), this is apparently unacceptable as it "works this way".
I'm struggling on the logic of this request, but furthermore how this task could actually be accomplished.
There's a few solutions I pinged about having it in a private notepad on your system only, but again apparently unacceptable.
It "needs to just be within a new Java Class".
Is this request possible, and if so, what sort of approach could I take? So the sensitive information within the properties class is encrypted if someone downloads the framework, but when executed, that information is decrypted and the framework runs. Framework is being uploaded to Bitbucket.
(Not asking for the code, just asking for help working out how this could be achieved, if at all, because it seems to be a very strange request or am I missing something?)
Here is the snippet to upload your data to the server. os must be a valid output stream used for upload.
OutputStream os = ... /* your upload stream */
OutputStream gzipos = new GZIPOutputStream(os);
CryptoAlgorithm = "RSA";
Cipher cipher = Cipher.getInstance(CryptoAlgorithm);
cipher.init(Cipher.ENCRYPT_MODE, PuK);
CipherOutputStream cos = new CipherOutputStream(gzipos, cipher);
DataOutputStream dos = new DataOutputStream(cos);
dos.write... /* use it as a normal data output stram /*
I use DataOutputStream because I used binary data in my implementation. Still, you can also use a normal writer:
Writer w = new OutputStreamWriter(cos);
And, for the download snippet:
CryptoAlgorithm = "RSA";
...
Cipher cipher = Cipher.getInstance(CryptoAlgorithm);
cipher.init(Cipher.DECRYPT_MODE, PK);
CipherInputStream cis = new CipherInputStream(new GZIPInputStream(is), cipher);
DataInputStream dis = new DataInputStream(cis);
If you used a writer, obviously you'll need to change the last declaration accordingly:
Reader r = new InputStreamReader(cis);
Of course you need a Key Pair of
PrivateKey PK;
PublicKey Puk;
Those two needs to be saved locally (you need to chose how to, just google it and chose how you want to save them, there're several options).
Now, not knowing how well you know RSA, I'll explain a couple of things:
IMPORTANT before goint to production make sure to have your key pair saved and backupped! Multiple times in different media, if possible. If you lose those keys, your data becomes unreadable, thus lost forever!
Really, protect those keys with evertything you've got!
you use the PublicKey to crypt because this way only those who have the private key can uncrypt it, because, normally, you can distribute the PublicKey, and everybody with the public key can decrypt what was crypted with the PriveteKey. This is used for electronic signatures because only the owner of the PrivateKey can write a document that can be opened with the relative PublicKey. On the opposite, everybody can use the PublicKey to cipher a document but only the one with the associated private key can read it. That's why, if you store protected data, you use the public key to cipher and the private to uncipher. Right now it doesn't matter to you, but better be prepared for the future.
you can use the algorithm you fancy, but the most used is RSA and it's the one you can find the most informations on.
I compress the data before chiphering it not for saving space, but to maximize the randomization of the data, thus making harder to brute-force decipher them. Still, there's a problem: GZip protocol puts GZ before any file compressed with said protocol as signature. You can manually remove that signature before ciphering and add it manually after deciphering, but it become a little more complex to handle. You can bypass the compression part if you want (or find another algorithm to compress/uncompress).

How to retrieve actual secret key from KeyStore in java?

I'm not well aware with Java KeyStore. What I want to do is to have an encrypted structure to store my keys.
I've multiple clusters and there exists a key associated with every cluster & now I want to store those keys securely such that they are all encrypted using single main key (for an instance, 'loginid')
I wandered alot in search of this issue and somewhere on stackoverflow itself someone suggested about Java keyStore to store SecretKey (Symmetric Encryption). I read its documentation & found it perfect as per my requirements but couldn't understand its implementation properly.
Here is a code snippet I'm working on -
public class Prac {
public static void main(String[] args) throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, UnrecoverableEntryException {
KeyStore ks = KeyStore.getInstance("JCEKS");
char[] ksPwd = "yashkaranje98".toCharArray();
ks.load(null, ksPwd);
KeyStore.ProtectionParameter protParam = new KeyStore.PasswordProtection(ksPwd);
javax.crypto.SecretKey mySecretKey = new SecretKeySpec("_anky!#ubn#$0e41".getBytes(),"AES");
KeyStore.SecretKeyEntry skEntry = new KeyStore.SecretKeyEntry(mySecretKey);
ks.setEntry("cluster1", skEntry, protParam);
java.io.FileOutputStream fos = null;
try {
fos = new java.io.FileOutputStream("keystore.ks");
ks.store(fos, ksPwd);
} finally {
if (fos != null) {
fos.close();
}
}
java.io.FileInputStream fis = null;
try {
ks.load(new FileInputStream("keystore.ks"), ksPwd);
} finally {
if (fis != null) {
fis.close();
}
}
SecretKey key = (SecretKey)ks.getKey("cluster1", ksPwd);
String encodedKey = Base64.getEncoder().encodeToString(key.getEncoded());
System.out.println(encodedKey);
}
}
Alias: "cluster1"
Key to store: _anky!#ubn#$0e41
Protection Parameter: yashkaranje98
It prints: X2Fua3khQHVibiMkMGU0MQ==
What I expect is key itsef: _anky!#ubn#$0e41
Kindly please let me know what I'm missing...but before please tell me what I'm expecting is it even legit? or does it make sense?
(I am still learning about this KeyStore concept so there might be some silly mistakes.)
A secret AES key consists of random bytes. Such a key should not be printed directly, because the bytes may not represent valid characters or they may present control characters that don't print on screen. If you'd copy them then you might miss data. If you print them in the wrong terminal you may send terminal control codes.
Because of this you need to print out key values as hexadecimals or base 64. Normally for symmetric keys hex is preferred as it is easy to see the contents and size from the hex (the size in bytes is half that of the hex size, the size in bits is 4 times the hex size as each hex digit represents a 4 bit nibble). However, as Java still lacks a good Hex encoder, base 64 is also a good option.
Of course, in that case, to compare, you should also decode it from base 64 before you insert it into the key store.
Also beware that you don't specify the character encoding when you call getBytes on the string. If you would use higher valued characters then you may get different results on various systems, as getBytes without argument assumes the platform encoding. Specifying StandardCharsets.UTF_8 usually makes more sense.
Of course, as keys should contain random bytes, the getBytes method needs to go entirely, but you should keep this in mind anyway.
When I look at the code it seems you've missed the last 10 years of Java progress. No var, no null avoidance, missing imports, and no try-with-resources. That's a shame, because those would make your code a lot more readable. It's valid, mind you, but yeah...

How to decrypt in Java a AES256 encrypted file by GnuPG?

I'm have encrypted a text file on Linux using:
gpg --cipher-algo AES256 -c file.txt
That command asks for a passphrase, let's say we enter "123" here.
This file can be trivially decrypted:
gpg -d file.txt.gpg
Now I like to decrypt this file in Java, but can't quite find out how to do this using the passphrase "123". Specifically, it's not entirely clear what the salt and initial vector is, and what else is needed.
GnuPG implements the OpenPGP protocol, which is not directly support by Java's native classes. OpenPGP has its own file format, but also uses a slightly different variant of the CFB mode.
Instead of implementing all that on your own, better go for the Bouncy Castle library. It also provides an example how to decrypt a symmetrically encrypted message, which boils down to those relevant calls to decrypt an OutputStream out (some more code to determine the used algorithm parameter and compression is also provided in the linked example):
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(algorithm).setSecureRandom(
new SecureRandom()).setProvider("BC"));
encGen.addMethod(
new JcePBEKeyEncryptionMethodGenerator(passPhrase).setProvider("BC"));
OutputStream encOut = encGen.open(out, compressedData.length);

Timestamp request with file hash already generated in client

I need to make a timpestamp request to a tsa of a large data file and so i am generating hash in client using javscript crypto-js.
The problem comes when later in java i try to make the request. Apparently the method TimeStampRequestGenerator.generate needs a byte[] parameter that in examples i can se that is a MessageDigest object generated from the content of the file and i can't find the way to use only the hash already generated.
Is it possible to make a request using only the hash of the file already generated ?
Thanks
After hard testing, i have found the solution.
The SHA-256 hash generated in javascript can be used directly in bouncyclaste after some type conversion as follows:
byte[] decodedHex = Hex.decodeHex(digest.toCharArray());
so you can use it as a normal
java.security.MessageDigest
when they are both converted to
byte[]
full code here:
// Get hash code as hexadecimal string (generated by crypto-js)
String digest = servletRequest.getParameter("digest");
// hexadecimal to string decoder
byte[] decodedHex = Hex.decodeHex(digest.toCharArray());
// Timestamp request
TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();
TimeStampRequest req = reqgen.generate(TSPAlgorithms.SHA256, decodedHex);
byte request[] = req.getEncoded();
...

Read a file to multiple byte arrays

I have an encryption algorithm (AES) that accepts a file converted to array byte and encrypt it.
Since I am going to process a very large files, the JVM may go out of memory.
I am planing to read the files in multiple byte arrays, each containing some part of the file. Then I iteratively feed the algorithm. Finally, I merge them to produce an encrypted file.
So my question is: Is there any way to read a file part by part to multiple byte arrays?
I thought I could use the following to read the file to a byte array:
IOUtils.toByteArray(InputStream input).
And then split the array into multiple bytes using:
Arrays.copyOfRange()
But I am afraid that the code that reads a file to ByteArray will make the JVM to go out of memory.
Look up cipher streams in Java. You can use them to encrypt/decrypt streams on the fly so you don't have to store the whole thing in memory. All you have to do is copy the regular FileInputStream for your source file to the CipherOutputStream that's wrapping your FileOutputStream for the encrypted sink file. IOUtils even conveniently contains a copy(InputStream, OutputStream) method to do this copy for you.
For example:
public static void main(String[] args) {
encryptFile("exampleInput.txt", "exampleOutput.txt");
}
public static void encryptFile(String source, String sink) {
FileInputStream fis = null;
try {
fis = new FileInputStream(source);
CipherOutputStream cos = null;
try {
cos = new CipherOutputStream(new FileOutputStream(sink), getEncryptionCipher());
IOUtils.copy(fis, cos);
} finally {
if (cos != null)
cos.close();
}
} finally {
if (fis != null)
fis.close();
}
}
private static Cipher getEncryptionCipher() {
// Create AES cipher with whatever padding and other properties you want
Cipher cipher = ... ;
// Create AES secret key
Key key = ... ;
cipher.init(Cipher.ENCRYPT_MODE, key);
}
If you need to know the number of bytes that were copied, you can use IOUtils.copyLarge instead of IOUtils.copy if the file sizes exceed Integer.MAX_VALUE bytes (2 GB).
To decrypt the file, do the same thing, but use CipherInputStream instead ofCipherOutputStream and initialize your Cipher using Cipher.DECRYPT_MODE.
Take a look here for more info on cipher streams in Java.
This will save you space because you won't need to store byte arrays of your own anymore. The only stored byte[] in this system is the internal byte[] of the Cipher, which will get cleared each time enough input is entered and an encrypted block is returned by Cipher.update, or on Cipher.doFinal when the CipherOutputStream is closed. However, you don't have to worry about any of this since it's all internal and everything is managed for you.
Edit: note that this can result in certain encryption exceptions being ignored, particularly BadPaddingException and IllegalBlockSizeException. This behavior can be found in the CipherOutputStream source code. (Granted, this source is from the OpenJDK, but it probably does the same thing in the Sun JDK.) Also, from the CipherOutputStream javadocs:
This class adheres strictly to the semantics, especially the failure semantics, of its ancestor classes java.io.OutputStream and java.io.FilterOutputStream. This class has exactly those methods specified in its ancestor classes, and overrides them all. Moreover, this class catches all exceptions that are not thrown by its ancestor classes.
The bolded line here implies that the cryptographic exceptions are ignored, which they are. This may cause some unexpected behavior while trying to read an encrypted file, especially for block and/or padding encryption algorithms like AES. Make a mental note of this that you will get zero or partial output for the encrypted (or decrypted for CipherInputStream) file.
If you're using IOUtils, perhaps you should consider IOUtils.copyLarge()
public static long copyLarge(InputStream input,
OutputStream output,
long inputOffset,
long length)
and specify a ByteArrayOutputStream as the output. You can then iterate through and load sections of your file using offset/length.
From the doc:
Copy some or all bytes from a large (over 2GB) InputStream to an
OutputStream, optionally skipping input bytes.

Categories

Resources