Problem:
for reasons behind scope of this document, i need to use passwords in scripts/custom keywords directly. BUT, this is security breach once i’ll go to git repository.
Solution:
encrypt passwords and store master key far, far away from git repository.
I created custom keyword based on discussions on Stack Overflow.
Also i was able to call keyword from another keyword looking at definition in Katalon files:
keyword definition:
package com.swre
import java.security.AlgorithmParameters
import java.security.GeneralSecurityException
import java.security.NoSuchAlgorithmException
import java.security.spec.InvalidKeySpecException
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec
import com.kms.katalon.core.annotation.Keyword
import groovy.json.JsonSlurper
import internal.GlobalVariable
public class encryption {
def createSecretKey(char[] password, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512")
PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength)
SecretKey keyTmp = keyFactory.generateSecret(keySpec)
return new SecretKeySpec(keyTmp.getEncoded(), "AES")
}
def base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes)
}
def base64Decode(String property) throws IOException {
return Base64.getDecoder().decode(property)
}
@Keyword
def encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException {
SecretKeySpec key = createSecretKey(((new JsonSlurper().parseText((new File(GlobalVariable.masterPasswordFile)).text))["masterPassword"]).toCharArray(), new String("12345678").getBytes(), 40000, 128)
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
pbeCipher.init(Cipher.ENCRYPT_MODE, key)
AlgorithmParameters parameters = pbeCipher.getParameters()
IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class)
byte[] cryptoText = pbeCipher.doFinal(property.getBytes("UTF-8"))
byte[] iv = ivParameterSpec.getIV()
return base64Encode(iv) + ":" + base64Encode(cryptoText)
}
@Keyword
def decrypt(String string) throws GeneralSecurityException, IOException {
def retStr
try{
// println "************************ Try"
SecretKeySpec key = createSecretKey(((new JsonSlurper().parseText((new File(GlobalVariable.masterPasswordFile)).text))["masterPassword"]).toCharArray(), new String("12345678").getBytes(), 40000, 128)
String iv = string.split(":")[0]
String property = string.split(":")[1]
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)))
retStr = new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8")
} catch (Exception e){
// println "************************ Catch\n${e}"
retStr = string
}
return retStr
}
}
i’m using global variable GlobalVariable.masterPasswordFile to store masterPassword filepath, this is content of master password file:
{
"masterPassword": "MyMasterPwd"
}
examples of usage from script:
def codeMeText="Hesl0NaZ4k0d0van13"
def cStr = CustomKeywords.'com.swre.encryption.encrypt'(codeMeText)
println CustomKeywords.'com.swre.encryption.encrypt'(codeMeText)
println CustomKeywords.'com.swre.encryption.decrypt'(cStr)
Example of usage from another Custom Keyword: (DB connection keyword in my case)