This question is in the specific context of the Java class java.security.KeyStore and its load(InputStream stream, char[] password) method which can accept null values for password to bypass integrity checking.
What are the risks involved with loading and querying a keystore without checking its integrity? The keystore will be queried for the user's private key which will be used to sign a document for non-repudiation. The certificate queried will be further validated against a copy stored in a database at the time the user registered himself and the (supposedly exact same) cert.
Well the main risk is that anyone who can read the file can also modify it. So someone could replace the file you read with a different keystore that has the same names for the keys but contains a different private key, so you end up signing documents with the wrong private key and none of them will pass verification.
Also, anyone with access to the file gains access to the private key and can sign documents as if they came from your app.
Related
I have a java program that has a method:
static void verifyAndDecrypt(PGPPublicKey publicKeyIn, PGPSecretKeyRingCollection privateKey, String password, InputStream toBeDecrypted, OutputStream outputStream)
It uses bouncy castle to decrypt and verify a file. The output is written to outputStream.
In production I have run into the scenario of receiving files with signatures that the java code is able to decrypt, but not do signature verification on.
Lets call such a production file prodFile.txt.gpg.
That file is thus encrypted with our public key, and signed with the senders private key.
(I have yet to figure out why it fails, these files are able to be verified using GnuPG)
I have added the option of being lenient and just log a warning when signature fails.
My question is, how do I write unit tests for this?
I could (and have locally on my machine) write a test that takes prodFile.txt.gpg and call verifyAndDecrypt() on it, given that I pass in our secret key and password, and asserts that the file is decrypted, and when the signature verification fails logs a warning.
But I can't check in this code, since it would leave password and private keys in the repo.
So my question is,
How do I create a file testFile.txt.gpg that replicates the above scenario?
I could create key pairs for testing, but I don't know how to force the failing of the signature in the same way as with prodFile.txt.gpg.
I am also wondering if it's possible to "unpack" the content of prodFile.txt.gpg so that I have the cleartext file: prodFile.txt and the corresponding signature that I have problem with. And from there make a modification to prodfile.txt so that the signature doesn't match, then encrypt it with the public key of a keypair for testing purposes while using the "bad" signature. But I can't seem to find a way to do this. I suspect the gpg command won't let me do something like this.
The plain text is signed using java.security.Signature. Below is the code used to sign the plain text
public String getSignature(String plainText) throws Exception
{
KeyStore keyStore = loadKeyStore(); // A local method to read the keystore file from file system.
PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD.toCharArray());
Signature privateSignature = Signature.getInstance(SIGNATUREALGO);
privateSignature.initSign(privateKey);
privateSignature.update(plainText.getBytes("UTF-8"));
byte[] signature = privateSignature.sign();
return String.valueOf(signature);
// KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD and SIGNATUREALGO are all constant Strings
}
Note 1: I found online a way to verify the signature using the public key Java Code Examples for java.security.Signature#verify(). But this is not what I require.
Note 2: I also found a ways to encrypt and decrypt as mentioned here RSA Signing and Encryption in Java. But the use case I have in hand is to get the original plain text from a signed data. Is that possible?
No, you can't retrieve the original content from just the signature.
The signature alone does not contain enough information to restore the original clear text, no matter what keys you have access to.
The basic idea of a signature is to send it together with the clear text. That means the clear text will be visible, but the signature can be used to verify that the message was written (or at least signed) by who claims to have done so and has not been tampered with since then.
Signing something is different from encrypting it. The two often uses the same or related technologies and both fall under cryptography.
I have a problem and I have no idea how to solve it.
I load an encrypted password (SSHA) from a text file and I need add a user with this password from the source code in Java.
Example from file:
e1NTSEF9Ukd6ZEZyanZBZlJGMGs3eGFDOGZxQ3U3QlozcUZXRGJoeWIyS0E9PQ==
Real password: 123
Example code not work as I want:
String encryptedPSWD = "e1NTSEF9Ukd6ZEZyanZBZlJGMGs3eGFDOGZxQ3U3QlozcUZXRGJoeWIyS0E9PQ==";
attributes.add(new BasicAttribute("userPassword","{SSHA}"+encryptedPSWD);
It not work, because we can send only real value password?
And is the problem that this is one-sided encryption and LDAP will also not be able to decrypt it?
The error number and text from the LDAP server would be instructive; but, in a general case, there are two things that stand out:
(1) Assuming the user already has a password, you are modifying an existing attribute, not adding an attribute. If you attempt to add a value to a single valued attribute that's already got a value, or if you attempt to add a value to a multi-value attribute that is already present, you would get ldap error 20. To modify an existing attribute would look something like this:
LDAPModificationSet attributes = new LDAPModificationSet();
LDAPAttribute attrUserPassword = new LDAPAttribute("userPassword", "{SSHA}"+encryptedPSWD);
attributes.add(LDAPModification.REPLACE, attrUserPassword);
(2) Some directories do not allow using "pre-encoded" passwords as a default. This is because password policies cannot be applied to an unknown password (i.e. how do I know this password is at least eight characters, contains a special character, and does not contain a dictionary word?). The Oracle Unified Directory servers that I manage return error 53 in this case, along with text saying "Pre-encoded passwords are not allowed for the password attribute userPassword.", but other directory servers may return use a different code (53 is a pretty generic code that just means something in the server config prevented the action from being completed). How to sort it depends on the LDAP server -- mine have a allow-pre-encoded-passwords Boolean within the password policy. I generally set it to "true", bulk import users, then return the setting to 'false' to prevent app developers from circumventing our password policies.
i try to find the good way for the best technology/method for hidden password in a file, but without use external jar or library.
Actually i use one object that represent a list of user name and password. Convert my list in a xml (only in memory) and after that, i store in a file with AES.
Use only java 7, no external library.
Is a good/secure method?
If this operation is no good, is possible to create dynamically xml encrypted?
thanks
You can use a FileOutputStream wrapped in a CipherOutputStream.
It's not really secure to save passwords encrypted with AES because:
1) Where do you store the key? If you store it in the server, if an attacker violates the server and finds the key, he will have complete acces to the users information.
2) Do you really need to know the users' passwords? In many application, for security reasons, it's better to keep only the hash of the password. The username can be stored in plaintext and you can also add a salt to the password to enforce it. You can do that with some algorithms offered by Java7 platform. In this way, even if someone enters your server, he can't use users login informations without breaking the hash function.
Here's an example that worked for me:
public byte[] getHash(String password, byte[] salt, String algorithm) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest digest = MessageDigest.getInstance(algorithm);//The String rapresents the alg you want to use: for example "SHA-1" or "SHA-256"
digest.reset();
digest.update(salt);
return digest.digest(password.getBytes("UTF-8"));
}
You can also look at this link for a more complete example: https://www.owasp.org/index.php/Hashing_Java
I know id file contains Private and Public Key. Public Key is inside Certificate under Id File and Private Key is inside id file but not in the certificate.
The Question is how can i get those keys through my java code . I need to encrypt and decrypt mails .
Public keys can be found in the Domino Directory. You don't need to do anything special to encrypt emails. The Notes APIs will do that for you automatically.
Decryption is another story. The whole point of a private key is that it is private. The private key in your current ID file is available to you after you type in your password, but you can't access any other private key. Private keys are encrypted using a password-derived key and if there was any way to get around that encryption, it would not be private!
So, if you are trying to decrypt messages sent to users, the only way to do that is to switch the current ID to that user's ID file, using that user's password.
Easiest way is to create a shared certificate across all users and add that to your Java code.
The following sample shows you how to create a self-signed certificate.
http://www-10.lotus.com/ldd/ddwiki.nsf/dx/Connecting_to_a_Domino_server_over_SSL_in_Java_using_a_self_signed_certificate._