package com.commafeed.backend.security;

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Arrays;

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.ejb.Singleton;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.commafeed.backend.dao.UserService;

// http://www.javacodegeeks.com/2012/05/secure-password-storage-donts-dos-and.html
@Singleton
public class PasswordEncryptionService {

	private static final Logger log = LoggerFactory
			.getLogger(UserService.class);

	public boolean authenticate(String attemptedPassword,
			byte[] encryptedPassword, byte[] salt) {
		// Encrypt the clear-text password using the same salt that was used to
		// encrypt the original password
		byte[] encryptedAttemptedPassword = null;
		try {
			encryptedAttemptedPassword = getEncryptedPassword(
					attemptedPassword, salt);
		} catch (Exception e) {
			// should never happen
			log.error(e.getMessage(), e);
		}

		// Authentication succeeds if encrypted password that the user entered
		// is equal to the stored hash
		return Arrays.equals(encryptedPassword, encryptedAttemptedPassword);
	}

	public byte[] getEncryptedPassword(String password, byte[] salt) {
		// PBKDF2 with SHA-1 as the hashing algorithm. Note that the NIST
		// specifically names SHA-1 as an acceptable hashing algorithm for
		// PBKDF2
		String algorithm = "PBKDF2WithHmacSHA1";
		// SHA-1 generates 160 bit hashes, so that's what makes sense here
		int derivedKeyLength = 160;
		// Pick an iteration count that works for you. The NIST recommends at
		// least 1,000 iterations:
		// http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
		// iOS 4.x reportedly uses 10,000:
		// http://blog.crackpassword.com/2010/09/smartphone-forensics-cracking-blackberry-backup-passwords/
		int iterations = 20000;

		KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations,
				derivedKeyLength);

		SecretKey key = null;
		try {
			SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
			key = f.generateSecret(spec);
		} catch (Exception e) {
			// should never happen
			log.error(e.getMessage(), e);
		}

		return key.getEncoded();
	}

	public byte[] generateSalt() {
		// VERY important to use SecureRandom instead of just Random
		SecureRandom random = null;
		try {
			random = SecureRandom.getInstance("SHA1PRNG");
		} catch (NoSuchAlgorithmException e) {
			// should never happen
			log.error(e.getMessage(), e);
		}

		// Generate a 8 byte (64 bit) salt as recommended by RSA PKCS5
		byte[] salt = new byte[8];
		random.nextBytes(salt);

		return salt;
	}

}

@@ -2117,21 +2117,20 @@
 %0D%0A%09%09
-SecretKey key
+byte%5B%5D bytes
  = n
@@ -2213,16 +2213,26 @@
 m);%0D%0A%09%09%09
+SecretKey 
 key = f.
@@ -2250,24 +2250,54 @@
 ret(spec);%0D%0A
+%09%09%09bytes = key.getEncoded();%0D%0A
 %09%09%7D catch (E
@@ -2377,18 +2377,16 @@
 ;%0D%0A%09%09%7D%0D%0A
-%0D%0A
 %09%09return
@@ -2386,32 +2386,21 @@
 %09return 
-key.getEncoded()
+bytes
 ;%0D%0A%09%7D%0D%0A%0D
@@ -2501,29 +2501,23 @@
 om%0D%0A
-%09%09SecureRandom random
+%0D%0A%09%09byte%5B%5D salt
  = n
@@ -2534,16 +2534,29 @@
 y %7B%0D%0A%09%09%09
+SecureRandom 
 random =
@@ -2599,118 +2599,11 @@
 );%0D%0A
-%09%09%7D catch (NoSuchAlgorithmException e) %7B%0D%0A%09%09%09// should never happen%0D%0A%09%09%09log.error(e.getMessage(), e);%0D%0A%09%09%7D%0D%0A
 %0D%0A
+%09
 %09%09//
@@ -2662,31 +2662,25 @@
 SA PKCS5%0D%0A%09%09
-byte%5B%5D 
+%09
 salt = new b
@@ -2688,16 +2688,17 @@
 te%5B8%5D;%0D%0A
+%09
 %09%09random
@@ -2712,24 +2712,130 @@
 tes(salt);%0D%0A
+%09%09%7D catch (NoSuchAlgorithmException e) %7B%0D%0A%09%09%09// should never happen%0D%0A%09%09%09log.error(e.getMessage(), e);%0D%0A%09%09%7D
 %0D%0A%09%09return s

fix findbugs warnings