I am currently working on my final project for school. It´s a client management system, and on the login, I have decided to include an encryption feature so that clients can store their credentials without having to worry about their passwords being out in the open.
I have found this code online, and, since I'm still new on programming, I was wondering if you could give me a little bit of help regarding the meaning of the code.
I know what it does, I just need a little bit of explanation on how it does it.
Here is the code:
package Login;
import java.security.MessageDigest;
public class Encrypter {
public static void main(String[] args) {
String password = "password";
String algorithm = "SHA";
byte[] plainText = password.getBytes();
MessageDigest md = null;
try {
md = MessageDigest.getInstance(algorithm);
} catch (Exception e) {
e.printStackTrace();
}
md.reset();
md.update(plainText);
byte[] encodedPassword = md.digest();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < encodedPassword.length; i++) {
if ((encodedPassword[i] & 0xff) < 0x10) {
sb.append("0");
}
sb.append(Long.toString(encodedPassword[i] & 0xff, 16));
}
System.out.println("Plain : " + password);
System.out.println("Encrypted: " + sb.toString());
}
}
Related
It was hard for me to explain in the title, but I would like to create a program which takes certain text, say hello0, hash it in sha256, and see if it has two leading zeros. If so, print hash. If not, make it hello1, then hello2 and so on until two leading zeros are found. Here is a few ways I found on how to create my sha256 hash from text:
import java.security.MessageDigest;
public class sha
{
public static void main(String[] args)throws Exception
{
int yeah = 40;
String password = "previousblock14currentblock" + yeah;
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes());
byte byteData[] = md.digest();
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("Hex format : " + sb.toString());
StringBuffer hexString = new StringBuffer();
for (int i=0;i<byteData.length;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
System.out.println("Hex format : " + hexString.toString());
}
}
When you run the code you receive Hex format : 0a0a30b1031fa60b8fa9478a070b03333df75017fd61c1b1c7e16bd929831ef5. This has one leading zero but I want two. I don't know what to do next, but i believe I set everything up correctly. How would I go about creating a while or if statement, each time adding yeah by 1? Would this be the best way of doing it?
The issue is that when I create a while loop the sha256 hash wont update, so it always prints 0a0a30b1031fa60b8fa9478a070b03333df75017fd61c1b1c7e16bd929831ef5. I'm wondering if I'm doing something wrong and wanted to see how someone else would do it.
thank you for your help.
public class Sha {
private static String byteArrayToHexString(byte[] array) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; i++) {
sb.append(Integer.toString((array[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
final int MAX_PASS_ATTEMPTS = 40000;
final String PASS_PREFIX = "previousblock14currentblock";
MessageDigest md = MessageDigest.getInstance("SHA-256");
for (int i = 0; i < MAX_PASS_ATTEMPTS; i++) {
String password = PASS_PREFIX + i;
md.reset();
md.update(password.getBytes());
byte[] hash = md.digest();
//System.out.println(byteArrayToHexString(hash));
if (hash[0] == 0 && hash[1] == 0) {
System.out.println("Password: " + password);
System.out.println("Hash: " + byteArrayToHexString(hash));
return;
}
}
System.out.println("No luck after " + MAX_PASS_ATTEMPTS + " tries.");
}
}
By the way, this is the great resource to learn about Java control flow statements.
In my existing system, i have hashed the password with the following algorithm in php.
$userId = "testusername";
$password = "testpassword";
echo md5(sha1($userId).sha1($password));
what will be the equivalent method in Java for the above, because i was migrating php to java.
when i tried to search in google, they are talking about MessageDigest method.
In PHP i have used the inbuild md5() and sha1() function
in java, i found the following, but still, its not equivalent.
public static String sha1(String input) {
StringBuilder sb = null;
try{
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.reset();
md.update(input.getBytes());
byte[] bytes = md.digest();
sb = new StringBuilder();
for(int i=0; i< bytes.length ;i++)
{
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
}catch(RuntimeException | NoSuchAlgorithmException e){
throw new RuntimeException(e.getMessage());
}
return sb.toString();
}
public static String md5(String input) {
StringBuilder sb = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(input.getBytes());
byte[] bytes = md.digest();
sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
} catch (RuntimeException | NoSuchAlgorithmException e) {
throw new RuntimeException(e.getMessage());
}
return sb.toString();
}
}
You can try bellow example :
class Main {
public static void main(String[] a) throws UnsupportedEncodingException, NoSuchAlgorithmException {
String output, input = "ml";
MessageDigest md = MessageDigest.getInstance("md5");
byte[] digest = md.digest(input.getBytes("UTF-8"));
BigInteger bigInt = new BigInteger(1, digest);
output = bigInt.toString(16);
System.out.println(""+output);
}
}
In the same way you also can generate sha1 just pass "sha1" in MessageDigest.getInstance(); function.
sha1($userId)+sha1($password) completely wrong. To do string concatenation in PHP you need sha1($userId).sha1($password)
The result you're seeing in PHP is actually md5(8) or c9f0f895fb98ab9159f51fd0297e236d. This is because the SHA1 of $password begins with an 8. The rest of the hash is thrown away.
This can not be used as a secure hashing function because there are too many collisions. For example, a password of 12345 has the same hash. You should require users to reset their passwords and use a standard password hashing mechanism instead.
I have an API documentation that requires encrypting a key to authenticate,
I managed to build and compile their sample code, but the results on windows are different than linux.
When I run and test from Windows, all seems to be correct and works with the API.
That same test on Linux outputs a different result. I need it working on Linux since that's the main server.
I am using & running the same jar file on both environments.
This is the key I am trying to encrypt (it's a dynamic key):
2136230$486B91E1BEA5D082BA3601CD803585CE$20140409$20140409$$ABCDEFGH$Reserved$CTC
This is the correct output on Windows (it's obviously quite longer):
F7BE2B7E0CEAD9D09135FCF2A8AEB11E2937D26B33CCBC9B8132A29A3534040C9737B2A8E3F271A9DF6454696CF890F7886223AE9C86F81EF58E41AEAA3D34A80F7089154E64F4FD36E75C25A7C2DA7FF03D21F57DA950F5
This is the wrong output from Linux:
F66D4CE1238B30EE54ABC74966D7AC3064FEA3ADFB9D37548E41509CE4FED9CB1D146651B491F2433169999A85F73DAF9ACD07A090DF3D85477BE4201ADC9E1A0181EA7CB763050A
What is causing this and how to correct it ?
This is the source code of the program to use as we received from the API company:
public class DESUtil
{
private static final String Algorithm = "DESede/ECB/PKCS5Padding";// DESede/ECB/PKCS5Padding;DESede
private static final String DESede = "DESede";
public static byte[] encrypt(byte[] keybyte, byte[] src)
throws NoSuchAlgorithmException, NoSuchPaddingException, Exception
{
SecretKey deskey = new SecretKeySpec(keybyte, DESede);
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.ENCRYPT_MODE, deskey);
return c1.doFinal(src);
}
public static byte[] decrypt(byte[] keybyte, byte[] src)
throws NoSuchAlgorithmException, NoSuchPaddingException, Exception
{
SecretKey deskey = new SecretKeySpec(keybyte, DESede);
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.DECRYPT_MODE, deskey);
return c1.doFinal(src);
}
public static String byte2hex(byte[] b)
{
StringBuffer hs = new StringBuffer();
String stmp = "";
for (int n = 0; n <b.length; n++)
{
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1)
hs.append("0").append(stmp);
else
hs.append(stmp);
}
return hs.toString().toUpperCase(Locale.getDefault());
}
public static byte[] hex2byte(String hexStr)
{
if (hexStr.length() % 2 != 0)
{
AppLogger.error("hex2bytes's hexStr length is not even.");
return null;
}
byte[] toBytes = new byte[hexStr.length() / 2];
for (int i = 0, j = 0; i <hexStr.length(); j++, i = i + 2)
{
int tmpa = Integer.decode(
"0X" + hexStr.charAt(i) + hexStr.charAt(i + 1)).intValue();
toBytes[j] = (byte) (tmpa & 0XFF);
}
return toBytes;
}
public static void main(String[] args)
{
Security.addProvider(new com.sun.crypto.provider.SunJCE());
final byte[] rawKey = "db90e7eb".getBytes();
final byte[] keyBytes = new byte[24];
for (int i = 0; i <rawKey.length; i++)
{
keyBytes[i] = rawKey[i];
}
for (int i = rawKey.length; i <keyBytes.length; i++)
{
keyBytes[i] = (byte)0;
}
String szSrc = "20926330$AD75B1697FB5EB6345B2D412124030D2$10086$10086$10.164.111$ABCDEFGH$Reserved$CTC";
System.out.println("string before encrypt:" + szSrc);
byte[] encoded = null;
try
{
encoded = encrypt(keyBytes, szSrc.getBytes());
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("string after encrypt::" + byte2hex(encoded));
byte[] srcBytes = null;
try
{
srcBytes = decrypt(keyBytes, encoded);
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("string before decode: :" + (new String(srcBytes)));
}
}
Almost certainly your use of szSrc.getBytes() which uses the platform's default character encoding.
Try szSrc.getBytes("ISO-8859-1") as a starter if it's working on Windows, but if this string comes from an external service you should determine the encoding scheme dynamically (eg. if it comes through a Servlet use httpRequest.getCharacterEncoding()).
Can someone figure out why the output of these (php and java) snippets of code don't return the same SHA512 for the same input?
$password = 'whateverpassword';
$salt = 'ieerskzcjy20ec8wkgsk4cc8kuwgs8g';
$salted = $password.'{'.$salt.'}';
$digest = hash('sha512', $salted, true);
echo "digest: ".base64_encode($digest);
for ($i = 1; $i < 5000; $i++) {
$digest = hash('sha512', $digest.$salted, true);
}
$encoded_pass = base64_encode($digest);
echo $encoded_pass;
This is the code on the android application:
public String processSHA512(String pw, String salt, int rounds)
{
try {
md = MessageDigest.getInstance("SHA-512");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("No Such Algorithm");
}
String result = hashPw(pw, salt, rounds);
System.out.println(result);
return result;
}
private static String hashPw(String pw, String salt, int rounds) {
byte[] bSalt;
byte[] bPw;
String appendedSalt = new StringBuilder().append('{').append(salt).append('}').toString();
try {
bSalt = appendedSalt.getBytes("ISO-8859-1");
bPw = pw.getBytes("ISO-8859-1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unsupported Encoding", e);
}
byte[] digest = run(bPw, bSalt);
Log.d(LCAT, "first hash: " + Base64.encodeBytes(digest));
for (int i = 1; i < rounds; i++) {
digest = run(digest, bSalt);
}
return Base64.encodeBytes(digest);
}
private static byte[] run(byte[] input, byte[] salt) {
md.update(input);
return md.digest(salt);
}
The library for base64 encoding is this: base64lib
This java code is actually some modified code I found around another question in StackOverflow.
Although the Android code is running fine it doesn't match with the output from the php script. It doesn't even match the first hash!
Note 1: On php hash('sha512',$input, $raw_output) returns raw binary output
Note 2: On java I tried to change the charset (UTF-8, ASCII) but it also didn't work.
Note 3: The code from the server can not be changed, so I would appreciate any answer regarding how to change my android code.
The first hash should be the same on the server and in Java. But then in the loop what gets appended to the digest is password{salt} in the PHP code, but only {salt} in the Java code.
For the lazy ones, one example better than a thousand words ;). I finally understood what was happening. The method update appends bytes to the digest, so when you append $password.{$salt} is the same as doing mda.update(password bytes) and the mda.digest("{$salt}" bytes. I do that answer because I was going crazy finding why it was not working and it was all in this answer.
Thanks guys.
This is the example that works in a Java Server:
public static String hashPassword(String password, String salt) throws Exception {
String result = password;
String appendedSalt = new StringBuilder().append('{').append(salt).append('}').toString();
String appendedSalt2 = new StringBuilder().append(password).append('{').append(salt).append('}').toString();
if(password != null) {
//Security.addProvider(new BouncyCastleProvider());
MessageDigest mda = MessageDigest.getInstance("SHA-512");
byte[] pwdBytes = password.getBytes("UTF-8");
byte[] saltBytes = appendedSalt.getBytes("UTF-8");
byte[] saltBytes2 = appendedSalt2.getBytes("UTF-8");
byte[] digesta = encode(mda, pwdBytes, saltBytes);
//result = new String(digesta);
System.out.println("first hash: " + new String(Base64.encode(digesta),"UTF-8"));
for (int i = 1; i < ROUNDS; i++) {
digesta = encode(mda, digesta, saltBytes2);
}
System.out.println("last hash: " + new String(Base64.encode(digesta),"UTF-8"));
result = new String(Base64.encode(digesta));
}
return result;
}
private static byte[] encode(MessageDigest mda, byte[] pwdBytes,
byte[] saltBytes) {
mda.update(pwdBytes);
byte [] digesta = mda.digest(saltBytes);
return digesta;
}
I am trying to store the password into the database in the encrypted form with the help of JSP and Servlets. How I can do that?
Self-written algorithms are a security risk, and painful to maintain.
MD5 is not secure.
Use the bcrypt algorithm, provided by jBcrypt (open source):
// Hash a password
String hashed = BCrypt.hashpw(password, BCrypt.gensalt());
// Check that an unencrypted password matches or not
if (BCrypt.checkpw(candidate, hashed))
System.out.println("It matches");
else
System.out.println("It does not match");
If you use Maven, you can get the library by inserting the following dependency in your pom.xml (if a newer version is available please let me know):
<dependency>
<groupId>de.svenkubiak</groupId>
<artifactId>jBCrypt</artifactId>
<version>0.4.1</version>
</dependency>
Try something like this to encrypt your data.
MessageDigest md = MessageDigest.getInstance("MD5");
......
synchronized (md) {
md.reset();
byte[] hash = md.digest(plainTextPassword.getBytes("CP1252"));
StringBuffer sb = new StringBuffer();
for (int i = 0; i < hash.length; ++i) {
sb.append(Integer.toHexString((hash[i] & 0xFF) | 0x100).toUpperCase().substring(1, 3));
}
String password = sb.toString();
}
You can also use something like below. Below is a crypt method which takes a string input and will return and encrypted string. You can pass password to this method.
public static String crypt(String str) {
if (str == null || str.length() == 0) {
throw new IllegalArgumentException(
"String to encrypt cannot be null or zero length");
}
StringBuffer hexString = new StringBuffer();
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes());
byte[] hash = md.digest();
for (int i = 0; i < hash.length; i++) {
if ((0xff & hash[i]) < 0x10) {
hexString.append("0"
+ Integer.toHexString((0xFF & hash[i])));
} else {
hexString.append(Integer.toHexString(0xFF & hash[i]));
}
}
} catch (NoSuchAlgorithmException e) {
}
return hexString.toString();
}