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).
Related
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();
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);
Is there a way to load a crypted file (that is a jar file), decrypted it (so obtains the real byte array) and use it without create a file on filesystem and launch it?
byte[] jarBytes=Decrypter.decrypt("my\\encrypted\\jar\\file");
//use jarBytes to execute an application without create a real File with this bytes...
Sure.
The input stream can come from a resource (i.e., on the classpath). The bytes can be manipulated as required.
See this post for an example of loading the jar from a directory. Your version would be almost identical, except for where the bytes come from originally, and with an additional transformation step.
If anybody is that interested in your code they'll either just a) reverse-engineer your class loader, or b) just use your class loader as-is and not worry about reverse-engineering the encrypted code... but good luck anyway :)
Like this?
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decValue = c.doFinal(data);
I am trying to implement a PKI verification scheme, where a message string is signed with a private key on server, the signature is stored on the client along with the message string. The client then verifies the signature using a public key.
The restrictions of my environment are, the server is Google App Engine and the client is a Java program. I have played with Java-only and Python-only solutions of PKI verification and got them to work, however when doing one operation in Python and another in Java is posing problem, mainly due to Key file format restrictions and my limited understanding of cryptography terminology.
One of the biggest limitations is crypto support in GAE. The only library supported is PyCrypto and this library can't read public/private keys stored in PEM, DER or X509 formats. As far as I could find, only M2Crypto supports reading from these files, but it can't be used inside GAE because it's a wrapper around openssl, so not a pure python solution. Even if I could find a way to translate the public/private keys from PEM/DER/X509 to the format that PyCrypto understands, that will work for me. But I couldn't find any way to do it. Any ideas there?
I found one possible solution in the form of tlslite. tlslite could read a private key from PEM file and create a signature. Here is the code.
from tlslite.utils.cryptomath import bytesToBase64
from tlslite.utils.keyfactory import parsePEMKey
s = open('private.pem').read()
key = parsePEMKey(s)
doc = 'Sample text'
bytes = array('B')
bytes.fromstring(doc)
print bytesToBase64(key.sign(bytes))
The corresponding Java code I used to verify the signature is.
String signAlgo = "SHA1WithRSAEncryption";
// read public key from public.der
byte[] encodedKey = new byte[294]; // shortcut hardcoding
getAssets().open("public.der").read(encodedKey);
// create public key object
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pk = kf.generatePublic(publicKeySpec);
// read signature (created by python code above)
byte[] encodedSig = new byte[345];
getAssets().open("signature.txt").read(encodedSig);
byte[] decodedSig = Base64.decodeBase64(encodedSig);
// Do verification
Signature verifyalg = Signature.getInstance(signAlgo);
verifyalg.initVerify(pk);
verifyalg.update(message.getBytes());
Log.d(TAG, "Verif : "+verifyalg.verify(decodedSig));
The verification fails.
I suspected if the tlslite is using different algorithm for signature creation than what the java code expects.
So I tried to find that out.
On python side
print key.getSigningAlgorithm()
gave me
pkcs1-sha1
on Java side, I tried to find all supported algorithms with this code:
Set<String> algos = java.security.Security.getAlgorithms("Signature");
for(String algo : algos) {
Log.d(TAG, algo);
}
That gave me
MD4WithRSAEncryption
RSASSA-PSS
SHA1withDSA
SHA1withRSA/ISO9796-2
1.2.840.113549.1.1.10
SHA512withRSA/PSS
MD5withRSA/ISO9796-2
DSA
SHA512WithRSAEncryption
SHA224withRSA/PSS
NONEWITHDSA
SHA256withRSA/PSS
SHA224WithRSAEncryption
SHA256WithRSAEncryption
SHA1withRSA/PSS
SHA1WithRSAEncryption
SHA384withRSA/PSS
SHA384WithRSAEncryption
MD5WithRSAEncryption
I tried all the SHA1 values on the Java side. But none helped to verify the signature generated by tlslite with pkcs1-sha1 algo. Any idea about this mapping?
These are different operations. In Python, you need to use hashAndSign. The default happens to be SHA1 hash.
Keyczar should work fine on App Engine, and is available in both Java and Python flavours.
I have a properties file in java, in which I store all information of my app, like logo image filename, database name, database user and database password.
I can store the password encrypted on the properties file. But, the key or passphrase can be read out of the jar using a decompiler.
Is there a way to store the db pass in a properties file securely?
There are multiple ways to manage this. If you can figure out a way to have a user provide a password for a keystore when the application starts up the most appropriate way would be to encrypt all the values using a key, and store this key in the keystore. The command line interface to the keystore is by using keytool. However JSE has APIs to programmatically access the keystore as well.
If you do not have an ability to have a user manually provide a password to the keystore on startup (say for a web application), one way to do it is to write an exceptionally complex obfuscation routine which can obfuscate the key and store it in a property file as well. Important things to remember is that the obfuscation and deobfuscation logic should be multi layered (could involve scrambling, encoding, introduction of spurious characters etc. etc.) and should itself have at least one key which could be hidden away in other classes in the application using non intuitive names. This is not a fully safe mechanism since someone with a decompiler and a fair amount of time and intelligence can still work around it but is the only one I know of which does not require you to break into native (ie. non easily decompilable) code.
You store a SHA1 hash of the password in your properties file. Then when you validate a users password, you hash their login attempt and make sure that the two hashes match.
This is the code that will hash some bytes for you. You can easily ger bytes from a String using the getBytes() method.
/**
* Returns the hash value of the given chars
*
* Uses the default hash algorithm described above
*
* #param in
* the byte[] to hash
* #return a byte[] of hashed values
*/
public static byte[] getHashedBytes(byte[] in)
{
MessageDigest msg;
try
{
msg = MessageDigest.getInstance(hashingAlgorithmUsed);
}
catch (NoSuchAlgorithmException e)
{
throw new AssertionError("Someone chose to use a hashing algorithm that doesn't exist. Epic fail, go change it in the Util file. SHA(1) or MD5");
}
msg.update(in);
return msg.digest();
}
No there is not. Even if you encrypt it, somebody will decompile the code that decrypts it.
You could make a separate properties file (outside the jar) for passwords (either direct DB password or or key passphrase) and not include that properties file with the distribution. Or you might be able to make the server only accept that login from a specific machine so that spoofing would be required.
In addition to encrypting the passwords as described above put any passwords in separate properties file and on deployment try to give this file the most locked down permissions possible.
For example, if your Application Server runs on Linux/Unix as root then make the password properties file owned by root with 400/-r-------- permissions.
Couldn't you have the app contact a server over https and download the password, after authenticating in some way of course?