I need to calculate the SHA 256 for my password.
i already know that I can user the common codec from apache but this is not allowed in where i am working
I tried to make a simple function to return the sha 256 from a plain text, which is:
public static String getSHA1(String plainText) {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
md.update(plainText.getBytes());
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < md.digest().length; i++) {
hexString.append(Integer.toHexString(0xFF & md.digest()[i]));
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
my problem is whatever the input is, the result is the same. i always got this result
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
I can calculate the sha 256 online using this website http://onlinemd5.com/
but i need to calculate it from my code.
your help is appreciated and lovely.
From the Javadoc for digest():
Completes the hash computation by performing final operations such as padding. The digest is reset after this call is made.
Call digest() once and put the results into a variable.
(By the way, had you searched for the digest, which is always a good idea whenever you get a fixed result, you would have seen that it's the SHA-256 digest for the empty string.)
Related
I am studying MD5 and also SHA with MessageDigest. Here is a code I have from class that implements MD5 with MessageDigest. I am having trouble understanding it.
So it gets the "instance" of MD5. I guess that is the MD5 algorithm? Then it updates the bytes. Why does it do this? Then it creates a variable bytes b with md.digest(), but I am not sure why it does this either? Then I think it uses the for statement to do the algorithm and maybe pad it (append 0?). If anyone could explain a little better, I'd appreciate!
try {
MessageDigest md = MessageDigest.getInstance("MD5"); // get the
// instance
// of md5
md.update(bytes); // get the digest updated
byte[] b = md.digest(); // calculate the final value
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0)
i += 256;
if (i < 16)
buf.append("0");
buf.append(Integer.toHexString(i));
}
message = buf.toString(); // output as strings
} catch (NoSuchAlgorithmException e) {
e.printStackTrace(); // when certain algorithm is down, output the
// abnormal condition
}
return message;
}
md.update(bytes) just puts the bytes through MD5. byte[] b = md.digest() gets out the result of the MD5 hash as a series of bytes.
Then the whole rest of the code is a dreadfully awkward way to convert bytes into a hexadecimal string.
Thanks the comments from everyone.
However, I have to explain this question.
I know that we shouldn't compare the result of encryption by using a fix random generator due to it may reduce the secure. However, I just want to do it in testing and I'll use a original mechanism of random in real running.
The case is that I need to login a server with account/password by the following steps:
Get info from server: a.b.com/get_cipher.cgi.
receive the response, parse it and get some info to create a cipher.
use the cipher to encrypt account/password and then compose the following URL a.b.com/login.cgi?encrypted={encrypted_account_password}
It's a complex process and I can't request the server to change the protocal. I want to test the whole login process. Thus, I tried to provide fake account/password and check if the generated url is correct without deciphering the result (if deciphering the result, it means that, in this test case, I need to decipher the the encrypted result, parse the url, and extract the related info, there are too much not related to the testing. Moreover, if I do some change in the login process, I may need to modify the deciphering and parsing process in the test cases.)
That means a hash function is not proper for me. (The original login process don't use any hash so that I don't want to test it in a test cases. Moreover, even thought I check the hash result is correct, it doesn't prove the login process is correct.)
=== The original question is as the following ===
I have a program which needs login. To void transfer the password in plain text on the network, I need to encipher it. In other word, the login process contains a ciphering phase.
Then, I want to write a test case for the whole login process. I think the encryption result of be the same if it use the same account and password.
Since it may use SecureRandom in the encryption process, I write a fake SecureRandom by Mockito as the following code:
private static final long RANDOM_SEED = 3670875202692512518L;
private Random generateRandomWithFixSeed() {
Random random = new Random(RANDOM_SEED);
return random;
}
private SecureRandom generateSecureRandomWithFixSeed() {
final Random random = generateRandomWithFixSeed();
final SecureRandom secureRandom = new SecureRandom();
final SecureRandom spySecureRandom = Mockito.spy(secureRandom);
Mockito.doAnswer(new Answer<Object>() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
byte[] bytes = (byte[]) args[0];
random.nextBytes(bytes);
return bytes;
}
})
.when(spySecureRandom)
.nextBytes(Matchers.<byte[]>anyObject());
return spySecureRandom;
}
#Test
public void test_SecureRandom_WithFixSeed() {
final SecureRandom secureRandom1 = generateSecureRandomWithFixSeed();
final SecureRandom secureRandom2 = generateSecureRandomWithFixSeed();
final byte[] bytes1 = new byte[20];
final byte[] bytes2 = new byte[20];
secureRandom1.nextBytes(bytes1);
secureRandom2.nextBytes(bytes2);
boolean isTheSameSeries = true;
for(int i = 0; i < 20; i++) {
isTheSameSeries &= (bytes1[i]==bytes2[i]);
}
assertThat(isTheSameSeries, is(true));
}
The generateRandomWithFixSeed() will new a Random with the same key, so that it will generate the same result. The generateSecureRandomWithFixSeed() uses Makito to detect the function call nextBytes() and always answer the result of the random. the test test_SecureRandom_WithFixSeed() also show two different SecureRandom instances generate the same results.
However, if I use generateSecureRandomWithFixSeed() in the cipher as the following, it can't always return the same result.
#Test
public void test_cipher() {
final SecureRandom secureRandomWithFixSeed = generateSecureRandomWithFixSeed();
final String pkcs = "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv7n+/uWHHVC7229QLEObeH0vUcOagavDukf/gkveqgZsszzGkZQaXfsrjdPiCnvjozCy1tbnLu5EInDy4w8B+a9gtK8KqsvlsfuaT9kRSMUS8CfgpWj8JcJwijmeZhjR52k0UBpWLfn3JmRYW8xjZW6dlOSnS0yqwREPU7myyqUzhk1vyyUG7wLpk7uK9Bxmup0tnbnD4MeqDboAXlQYnIFVV+CXywlAQfHHCfQRsGhsEtu4excZVw7FD1rjnro9bcWFY9cm/KdDBxZCYQoT/UW0OBbipoINycrmfMKt1r4mGE9/MdVoIEMBc54aI6sb2g5J2GtNCYfEu+1/gA99xY0+5B3ydH74cbqfHYOZIvu11Q7GnpZ6l8zTLlMuF/pvlSily76I45H0YZ3HcdQnf/GoKC942P6fNsynHEX01zASYM8dzyMxHQpNEx7fcXGi+uiBUD/Xdm2jwzr9ZEP5eEVlrpcAvr8c9S5ylE50lwR+Mp3vaZxPoLdSGZrfyXy4v97UZSnYARQBacmn6KgsIHIOKhYOxNgUG0jwCO/zrPvlbjiYTHQYLOCcldTULvXOdn51enJFGVjscGoZfRj6vZgyHVCUW4iip4iSbSKPcPbf0GMZuniS9qJ3Wybve0/xpppdOv1c40ez0NKQyQkEZRb+V0qfesatJKZd/hUGr+MCAwEAAQ==";
final byte bytePKCS[] = Base64.base64ToByteArray(pkcs);
final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(bytePKCS);
PublicKey pubKey = null;
try {
pubKey = KeyFactory.getInstance("RSA").generatePublic(pubKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
final String targetResultText = "NZqTzuNli92vuXEQNchGeF6faN/NBHykhfqBFcWzBHZhbgljZaWAcAzasFSm/odZZ6vBD2jK7J4oi5BmDjxNdEjkXyv3OZ2sOTLCfudgPwXcXmmhOwWHDLY02OX0X3RwBHzqWczqAd4dwslo59Gp5CT59GWXenJPL8wvG90WH2XAKOmHg5uEZj55ZvErRQ6StPVzLkiNCMPOhga7FZWK/rSEpT6BHDy3CibDZ0PNRtAW4wiYAr0Cw6brqiqkN301Bz6DzrV5380KDHkw26GjM8URSTFekwvZ7FISQ72UaNHhjnh1WgMIPf/QDbrEh5b+rmdZjzc5bdjyONrQuoj0rzrWLN4z8lsrBnKFVo+zVyUeqr0IxqD2aHDLyz5OE4fb5IZJHEMfYr/R79Zfe8IuQ2tusA02ZlFzGRGBhAkb0VygXxJxPXkjbkPaLbZQZOsKLUoIDkcbNoUTxeS9+4LWVg1j5q3HR9OSvmsF5I/SszvVrnXdNaz1IKCfVYkwpIBQ+Y+xI/K360dWIHR/vn7TU4UsGmWtwVciq0jWLuBN/qRE6MV47TDRQu63GzeV00yAM/xUM33qWNXCV1tbGXNZw8jHpakgflTY0hcjOFHPpq2UfJCyxiSBtZ0b7hw9Rvhi8VwYc243jXO9CvGq+J6JYvchvKHjq2+YKn1UB2+gs20=";
final String plainText = "a";
String resultText = "";
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey, secureRandomWithFixSeed);
final byte[] result = cipher.doFinal(plainText.getBytes());
resultText = Base64.byteArrayToBase64(result);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
assertThat(resultText, is(targetResultText));
}
aa
You shouldn't do what you're trying to do. That is not the point of encryption to be able to compare two encrypted values to determine if they're the same. I'm sure you CAN get this to work, but you'd effectively be disabling features and making everything you encrypt less secure in order to make them show up the same.
If you want to be able to compare the two values without decrypting the password, what you really want is a hash function. Specifically, take a look at using SHA1 at least, or SHA-256 (Better).
How to hash some string with sha256 in Java?
By design, a hash is one-way (e.g. You can't reverse the password without something like a Rainbow Table). However, its designed to be used exactly how you're describing, comparing the new value with the old.
If you really want to work with encrypted values, you should be decrypting the password value and comparing it against the plain-text. However, hashing follows best practices.
rather simple answer to your explanations, with only hash functions (no cipher needed):
1 share a secret between server and client. this must be done before. Any string does the job (you can see it as a password).
Client has P, Server has P
1bis better security: hash the P, at both sides: Client and Server have Ph
2 connection:
2a server create random R, and send to client
2b client make Ph x R (bit at bit for example) and hash it => (Ph x R)h
and sends it
2c server can do the same thing: (Ph x R)h and compares it
One weakness : if you get Ph at the server, you can spoof the client. To avoid that, you should use other functions.
Other option (more secure if you dont trust the server): use an asymetric key and RSA as in your original code.
I've found the reason.
I found that if I run the test case on Android 4.4, it can't work but it works on 4.1.2.
By more survey, it seems that Android use OpenSSL for encryption/description in newer version (AndroidOpenSSL).
In the file, external/conscrypt/src/main/java/org/conscrypt/OpenSSLCipherRSA.java
#Override
protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
engineInitInternal(opmode, key);
}
It shows that it use native OpenSSL library to encipher and don't use the given SecureRandom.
The solution is to provider the Provider when Cipher.getInstance().
#Test
public void test_cipher() {
private static final String PROVIDER_NAME = "BC";
final Provider provider = Security.getProvider(PROVIDER_NAME);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
}
How can I reverse this output from this method? (So that I get to see the plaintext)
I don't see any keys being used.
public String encrypt(String plaintext) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) {
}
try {
md.update(plaintext.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
}
byte raw[] = md.digest();
String hash = (new BASE64Encoder()).encode(raw);
return hash;
}
You can't. The SHA family are hash algorithms; that is, they are one-way cryptographic algorithms producing a hash or message digest. There is no way back. A hash is a fixed length result from a message of any length, with the design aim that it is computationally infeasible to find two messages that produce the same hash value; thus, to all intents, the hash can be seen as identifying the message. But you can't go back and retrieve the message from it.
Hashes are unkeyed. There are keyed constructs that can be made with them, for example a message authentication code or MAC.
The method is actually poorly named - this is not "encryption" per se.
I am writing android app that makes AES encryption/decryption of files. I want to be able to detect if incorrect password is specified and thus not matching key is derived for decryption.
I am using AES/CBC/PKCS7Padding with 256 bit key.
If I do cipher.doFinal() I can try/catch the BadPaddingException and it tells me that something is wrong and probably key was incorrect. But if I use CipherInputStream to read encrypted file, I get no feedback on correctness of padding. So if I deliberately specify incorrect password it decrypts file, then reports that everything is ok, however decrypted file is a total junk.
So my question is how to detect bad padding when using CipherInputStream?
Prepend some known header to your data. Decrypt it first and if it doesn't match what you expected, stop and return error.
Try and use GCM mode instead (Java 7 or Bouncy Castle provider). The trick with padding is that sometimes it is correct after the message has been altered (once in 256 times, approximately). GCM mode will add intergrity protection, so any alteration will result in an exception derived from BadPaddingException.
One thing though: you should prepend a (random) nonce when encrypting with GCM (actually a rule for CBC mode too, but the implications of using a non-random IV in CBC are less severe).
Note that you need to perform the final calculation to get a badpaddingexception, so don't forget to close or end the underlying stream. This is probably your current issue.
[EDIT]: this is not the answer, but the input could be used to generate a better CipherInputStream, see my other answer on this question.
I had the same issue, how to know if the key used to encrypt is the same that used to decrypt, because in my case I could decrypt the strings but it returned some garbage, and i need to know the encrypted string(its random) to get the correct value.
So what i have done is;
Decrypt the encrypted string.
Encrypt the String again using the correct key.
Decrypt the previous encrypted string.
Match if the original decrypted key equals the new decrypted key.
Cipher c = Cipher.getInstance(algorithm);
c.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] decValue = c.doFinal(encryptedData.getBytes());
decryptedValue = new String(decValue,"UTF-8");
//now i have the string decrypted in decryptedValue
byte[] encryptAgain = encrypt(decryptedValue);
String encryptAgaindecripted = new String(c.doFinal(encryptAgain),"UTF-8");
//if keys match then it uses the same key and string is valid
if (decryptedValue.equals(encryptAgaindecripted)){
//return valid
}
hope this helps someone.
I think bad padding is caught for some reason, this is from the CipherInputStream source:
private int getMoreData() throws IOException {
if (done) return -1;
int readin = input.read(ibuffer);
if (readin == -1) {
done = true;
try {
obuffer = cipher.doFinal();
}
catch (IllegalBlockSizeException e) {obuffer = null;}
catch (BadPaddingException e) {obuffer = null;}
if (obuffer == null)
return -1;
else {
ostart = 0;
ofinish = obuffer.length;
return ofinish;
}
}
try {
obuffer = cipher.update(ibuffer, 0, readin);
} catch (IllegalStateException e) {obuffer = null;};
ostart = 0;
if (obuffer == null)
ofinish = 0;
else ofinish = obuffer.length;
return ofinish;
}
Here is modified version of getMoreData() method in CipherInputStream, it maybe useful for someone who faced my problem:
private int getMoreData() throws IOException {
if (done) return -1;
int readin = input.read(ibuffer);
if (readin == -1) {
done = true;
try {
obuffer = cipher.doFinal();
}
catch (IllegalBlockSizeException e) {
throw new IOException(e);
}
catch (BadPaddingException e) {
throw new IOException(e);
}
if (obuffer == null)
return -1;
else {
ostart = 0;
ofinish = obuffer.length;
return ofinish;
}
}
try {
obuffer = cipher.update(ibuffer, 0, readin);
} catch (IllegalStateException e) {obuffer = null;};
ostart = 0;
if (obuffer == null)
ofinish = 0;
else ofinish = obuffer.length;
return ofinish;
}
I ran into this as well. I had a test that reliably fails a couple of times out of a thousand runs with AES/CBC/PKCS5Padding that is supported in Java.
To fix, you can do as suggested above and use bouncy castle.
However, I did a different fix and simply added a md5 content hash to the plain text before encrypting that I verify on decrypt. Simply append the content to the md5 hash and on decrypt grab the first 22 characters of the md5 hash and verify that the rest of the string has the same hash and throw an exception if it doesn't or return the plaintext (without md5 hash) if it does match. This will work regardless of the encryption algorithm. Probably with GCM mode this is indeed not needed though. Anyway, this way you can avoid extra dependencies on bouncy castle.
Is there a dead-simple native method in Java to encrypt/decrypt a string with a key? I don't really care what type of encryption (AES, DES, etc..), I just care that it's bound by with a key and not easily breakable.
Ideally, I would like it to be a one line solution like so:
String encryptedString = NativeEncryptionClass.encrypt("this is the data", "key123");
Thanks
Not sure you can do it in a [legiable] one-liner, but you can achieve simple symmetrical encryption relatively easily - take a look at the following example:
PrivateExample using DES
I've used the Bouncy Castle library to good effect in the past.
If by native you mean, not depending on platform specific libraries, maybe jasypt might be interesting for you.
May be you should try using simple XOR encryption
Ok, maybe it's not 'one line' but it seems easy enough:
make use of java's Cipher class. look here... (there are other examples on this page...)
http://download.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#BlowKeyEx
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SimpleMD5Example {
public static void main(String[] args) {
String passwordToHash = "0";
String generatedPassword = null;
try {
// Create MessageDigest instance for MD5
MessageDigest md = MessageDigest.getInstance("MD5");
// Add password bytes to digest
md.update(passwordToHash.getBytes());
// Get the hash's bytes
byte[] bytes = md.digest();
System.out.println(bytes);
// This bytes[] has bytes in decimal format;
// Convert it to hexadecimal format
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff), 16).substring(1));
}
// Get complete hashed password in hex format
generatedPassword = sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
System.out.println(generatedPassword);
}
}