Skip to content

Instantly share code, notes, and snippets.

@monzou
Last active December 19, 2015 02:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monzou/5886251 to your computer and use it in GitHub Desktop.
Save monzou/5886251 to your computer and use it in GitHub Desktop.
Security Utilities
public final class AESProtector {
private static final Configuration CONFIGURATION;
static {
try {
CONFIGURATION = ConfigurationLoader.load(Configuration.class, "aes-security-policy.yml", "default-aes-security-policy.yml");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static final String CHARSET = "UTF-8";
private static final String ALGORITHM = "AES";
/**
* 文字列を暗号化します。
*
* @param value 文字列
* @param salt ソルト
* @return 暗号化された文字列
*/
public static String encrypt(String value, String salt) {
checkNotNull(value);
checkNotNull(salt);
try {
SecretKey key = generateKey();
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
String valueToEncrypt = null;
String encryptedValue = value;
for (int i = 0; i < CONFIGURATION.iterationCount; i++) {
valueToEncrypt = salt + encryptedValue;
encryptedValue = new BASE64Encoder().encode(cipher.doFinal(valueToEncrypt.getBytes(CHARSET)));
}
return encryptedValue;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException
| UnsupportedEncodingException e) {
throw new |RuntimeException(e);
}
}
/**
* 文字列を復号化します。
*
* @param encryptedValue 暗号化された文字列
* @param salt ソルト
* @return 復号化された文字列
*/
public static String decrypt(String encryptedValue, String salt) {
checkNotNull(encryptedValue);
checkNotNull(salt);
SecretKey key = generateKey();
Cipher cipher;
try {
cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
String decryptedValue = encryptedValue;
for (int i = 0; i < CONFIGURATION.iterationCount; i++) {
decryptedValue = new String(cipher.doFinal(new BASE64Decoder().decodeBuffer(decryptedValue)), CHARSET);
decryptedValue = decryptedValue.substring(salt.length());
}
return decryptedValue;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IOException | IllegalBlockSizeException
| BadPaddingException e) {
throw new |RuntimeException(e);
}
}
private static SecretKey generateKey() {
try {
return new SecretKeySpec(CONFIGURATION.secret.getBytes(CHARSET), ALGORITHM);
} catch (UnsupportedEncodingException e) {
throw new |RuntimeException(e);
}
}
private static class Configuration {
public String secret;
public int iterationCount;
}
private AESProtector() {
}
}
public final class Bytes2 {
/**
* 16 進に変換します。
*
* @param data データ
* @return 変換された文字列
*/
public static String toHex(byte[] data) {
StringBuilder sb = new StringBuilder();
for (byte b : data) {
sb.append(toHex(b));
}
return sb.toString();
}
/**
* 16 進に変換します。
*
* @param b データ
* @return 変換された文字
*/
public static String toHex(byte b) {
String s = Integer.toHexString(0xff & b);
if (s.length() == 1) {
s = "0" + s;
}
return s;
}
private Bytes2() {
}
}
public final class Hasher {
/**
* SHA-256 によりハッシュ化します。
*
* @param value ハッシュ化する値
* @return ハッシュ化された値
*/
public static String hash(String value) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(checkNotNull(value).getBytes());
return Bytes2.toHex(md.digest());
} catch (NoSuchAlgorithmException e) {
throw new |RuntimeException(e);
}
}
private Hasher() {
}
}
public final class Passwords {
private static final Configuration CONFIGURATION;
static {
try {
CONFIGURATION = ConfigurationLoader.load(Configuration.class, "password-policy.yml", "default-password-policy.yml");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static final char[] ALPHABET_CHARS = "abcdefghijklmnopqrstuvwxyz".toCharArray();
private static final char[] NUMBER_CHARS = "0123456789".toCharArray();
private static final int RANDOM_PASSWORD_CHAR_LENGTH = 8;
/**
* パスワードをハッシュ化します。
* <p>
* ユーザーコードと固定のソルトをハッシュしてソルトにした後, ストレッチングします。
*
* @param userCode ユーザーコード
* @param password パスワード
* @return ハッシュ化されたパスワード
*/
public static String hash(String userCode, String password) {
checkNotNull(userCode);
checkNotNull(password);
String salt = Hasher.hash(CONFIGURATION.salt + userCode);
String hashed = null;
for (int i = 0; i < CONFIGURATION.stretchCount; i++) {
hashed = Hasher.hash(hashed + salt + password);
}
return hashed;
}
/**
* ランダムパスワードを生成します。
*
* @return パスワード
*/
public static String generateRandomPassword() {
return generateRandomPassword(RANDOM_PASSWORD_CHAR_LENGTH);
}
/**
* ランダムパスワードを生成します。
*
* @param passwordCharLength パスワードの文字数
* @return パスワード
*/
public static String generateRandomPassword(int passwordCharLength) {
char[] password = new char[passwordCharLength];
for (int i = 0; i < passwordCharLength; i++) {
double d = Math.random();
if (i < 2) {
// 最初の2文字はアルファベット
int index = (int) (d * ALPHABET_CHARS.length) % ALPHABET_CHARS.length;
password[i] = ALPHABET_CHARS[index];
} else {
// 2文字目以降は数字
int index = (int) (d * NUMBER_CHARS.length) % NUMBER_CHARS.length;
password[i] = NUMBER_CHARS[index];
}
}
return new String(password);
}
private static class Configuration {
public String salt;
public int stretchCount;
}
private Passwords() {
}
}
public final class RandomSaltGenerator {
private static final int DEFAULT_LENGTH = 8;
/**
* ランダムなソルトを生成します。
*
* @return ソルト
*/
public static String generate() {
return generate(DEFAULT_LENGTH);
}
/**
* ランダムなソルトを生成します。
*
* @param length ソルトの長さ
* @return ソルト
*/
public static String generate(int length) {
byte[] salt = new byte[length];
SecureRandom sr;
try {
sr = SecureRandom.getInstance("SHA1PRNG");
sr.nextBytes(salt);
return Bytes2.toHex(salt);
} catch (NoSuchAlgorithmException e) {
throw new |RuntimeException(e);
}
}
private RandomSaltGenerator() {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment