package com.englishtown.bitbucket.hook;
import com.atlassian.sal.api.pluginsettings.PluginSettings;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
* Service to encrypt/decrypt git user passwords
*/
public class DefaultPasswordEncryptor implements PasswordEncryptor {
private SecretKey secretKey;
public static final String ENCRYPTED_PREFIX = "encrypted:";
public static final String SETTINGS_CRYPTO_KEY = "crypto.key";
@Override
public void init(PluginSettings pluginSettings) {
try {
String keyBase64;
Object value = pluginSettings.get(SETTINGS_CRYPTO_KEY);
if (value == null || value.toString().isEmpty()) {
KeyGenerator gen = KeyGenerator.getInstance("AES");
secretKey = gen.generateKey();
keyBase64 = Base64.getEncoder().encodeToString(secretKey.getEncoded());
pluginSettings.put(SETTINGS_CRYPTO_KEY, keyBase64);
} else {
keyBase64 = value.toString();
byte[] data = Base64.getDecoder().decode(keyBase64);
secretKey = new SecretKeySpec(data, 0, data.length, "AES");
}
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
protected byte[] runCipher(byte[] data, boolean encrypt) {
try {
int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
Cipher cipher = getCipher(mode);
return cipher.doFinal(data);
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(e);
} catch (BadPaddingException e) {
throw new RuntimeException(e);
}
}
private Cipher getCipher(int mode) {
try {
// Create Cipher
Cipher cipher = Cipher.getInstance("AES");
// Initialize Cipher with key
cipher.init(mode, secretKey);
return cipher;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean isEncrypted(String password) {
if (password == null || password.isEmpty()) {
return false;
}
return password.startsWith(ENCRYPTED_PREFIX);
}
@Override
public String encrypt(String password) {
if (isEncrypted(password)) {
return password;
}
try {
byte[] encryptedData = runCipher(password.getBytes("UTF-8"), true);
return ENCRYPTED_PREFIX + Base64.getEncoder().encodeToString(encryptedData);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
@Override
public String decrypt(String password) {
if (!isEncrypted(password)) {
return password;
}
try {
byte[] encryptedData = Base64.getDecoder().decode(password.substring(ENCRYPTED_PREFIX.length()));
byte[] clearData = runCipher(encryptedData, false);
return new String(clearData, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}