Decryption result not consistent - java

I have two instances of my service that does the encryption and decryption running in cloud. The decryption fails sometimes with 'decryption failed' error. I guess this is because each instance has its own Aead instance. How can i solve this issue?
public class Utils {
private static final Logger log = LoggerFactory.getLogger(Utils.class);
private Aead aead;
private static Utils utils;
private Utils() {
try {
AeadConfig.register();
KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
aead = AeadFactory.getPrimitive(keysetHandle);
} catch (GeneralSecurityException e) {
log.error(String.format("Error occured: %s",e.getMessage())).log();
}
}
public static Utils getInstance() {
if(null == utils) {
utils = new Utils();
}
return utils;
}
public String encrypt(String text) throws GeneralSecurityException, UnsupportedEncodingException {
byte[] plainText = text.getBytes("ISO-8859-1");
byte[] additionalData = null;
byte[] cipherText = aead.encrypt(plainText,additionalData);
String output = Base64.getEncoder().encodeToString(cipherText);
return output;
}
public String decrypt(String text) throws GeneralSecurityException, UnsupportedEncodingException {
byte[] cipherText = Base64.getDecoder().decode(text);
byte[] additionalData = null;
byte[] decipheredData = aead.decrypt(cipherText,additionalData);
String output = new String(decipheredData,"ISO-8859-1");
return output;
}
#Test
public void encrypt() throws IOException, GeneralSecurityException {
String encryptedText = cryptographicUtils.encrypt("Hello World");
assertThat(encryptedText, Matchers.notNullValue());
}
#Test
public void decrypt() throws IOException, GeneralSecurityException {
String encryptedText = cryptographicUtils.encrypt("Hello 123456");
String decrypedText = cryptographicUtils.decrypt(encryptedText);
assertThat(decrypedText, Matchers.is("Hello 123456"));
}
I am getting consistent result if only one instance is running...

I will have to use the same keyset to encrypt and decrypt. I am able to resolve the issue by storing the keyset in a physical location and use it to create Aead instance. With this change all instances of my service able to decrypt string successfully

Looks like a thread safety issue. Try making the getInstance synchronized. Also, protect access to private Aead aead
Multiple threads can be altering the state of aead if you're not careful.
Consider a queue to do your work, or synchronize access to what is interacting with aead.

Related

When encoding the password, always return null value

I want to encode my password using an encryption key. but I got a null value, when printing the encoded password. I have attached my code below:
public class FirstJava {
private static final Long ENCRYPTION_KEY = 29190210908917L;
public static String encrypt(String strToEncrypt, byte[] key) {
if (strToEncrypt == null)
return strToEncrypt;
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
final SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes()));
} catch (Exception exception) {
System.out.println("ERROR");
}
return null;
}
public static void main(String[] args) {
String password = "12345678";
byte[] arr = String.valueOf(ENCRYPTION_KEY).getBytes();
String passwordEnc = encrypt(password,arr);
System.out.println("passwordEnc============= "+passwordEnc);
}
}
AES only supports key sizes of 16, 24 or 32 bytes. Your key length is 14, add 2 more digits to your key and it will work.
private static final Long ENCRYPTION_KEY = 2919021090891712L; //16 bytes

MAC doFinal gives different value for same data

I am facing an issue with the following code
public static void main(String[] args) throws NoSuchAlgorithmException {
String key = "test";
SecretKeySpec secretKeySpec = new
SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
Mac mac = Mac.getInstance("HmacSHA512");
try {
if (null != mac) {
mac.init(secretKeySpec);
}
} catch (InvalidKeyException e) {
}
IntStream.range(1, 12).parallel().forEach(d->{
final byte[] bytes = "somestring".getBytes(StandardCharsets.UTF_8);
final byte[] doFinal= mac.doFinal(bytes);
String digest = Base64.getEncoder().encodeToString(doFinal);
LOGGER.info("digest -- {} ", digest);
});
}
Even the string is the same but digests generated using a mac.doFinal is different. This is just a showcase of the issue. I have used the same code in my spring reactive application where mac is a bean and digest generated every time when user make a request which is a concurrent request where also i have seen these weird behavior.

Is there a way investigate an "invalid Assertion" received when attempting OAuth 2.0 JWT Bearer Token Flow in Salesforce

I have written a java client as per Salesforce's OAuth JWT Bearer Token Flow but the response is "Invalid Assertion". The Certificate I have uploaded to the Salesforce organisation is self-signed and the claim I am sending consists of the client_id (the OAuth connected app's consumer key), the email address/user name of the user (which is also the email declared in the certificate and the user is already successfully using the Salesforce REST API via user/password OAuth flow), an expiry time and the audience is set to https://login.salesforce.com (aud). I can see the 'Digital Signature' has been loaded correctly in Salesforce and that my code correctly signs it. My Oauth scope in Salesforce has been set to:
Access and manage your data (api)
Provide access to your data via the Web (web)
Perform requests on your behalf at any time (refresh_token, offline_access)
I get the same response when I POST the JWT directly to /services/oauth2/token form, as below:
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=k5ARCVFd1VgfOuM...
I include the header:
"Content-Type","application/x-www-form-urlencoded"
The JWT is generated using:
import com.payliquid.model.config.OAuthCredentials;
import org.apache.commons.codec.binary.Base64;
import org.joda.time.DateTime;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.cert.CertificateException;
public class JWTGenerator {
public static final String HEADER = "{\"alg\":\"RS256\"}";
public static final String CLAIM_TEMPLATE = "'{'\"iss\": \"%s\", \"prn\": \"%s\", \"aud\": \"%s\", \"exp\": \"%s\"'}'";
public static final String ALGORITHM = "SHA256withRSA";
private String audience;
private KeyStore keystore;
public JWTGenerator(String authServerURL, KeyStore keystore) {
this.audience = authServerURL;
this.keystore = keystore;
}
public String generateToken(OAuthCredentials oAuthCredentials, String clientId) {
final String certPassword = oAuthCredentials.getPassword();
final String principal = oAuthCredentials.getUserName();
final String certAlias = oAuthCredentials.getSecurityToken().get();
try {
StringBuilder jwTokenBuilder = new StringBuilder();
appendEncodedHeader(jwTokenBuilder);
appendSeparator(jwTokenBuilder);
final String joinedClaim = String.format(CLAIM_TEMPLATE, getClaimElements(clientId, principal));
appendEncodedClaim(jwTokenBuilder, joinedClaim);
PrivateKey privateKey = getPrivateKey(certPassword, certAlias);
String signedPayload = signPayload(jwTokenBuilder, privateKey);
appendSeparator(jwTokenBuilder);
jwTokenBuilder.append(signedPayload);
return jwTokenBuilder.toString();
} catch (Exception e) {
throw new OAuthRuntimeSystemException("Could not generate JWT Token", e);
}
}
private PrivateKey getPrivateKey(String certPassword, String certAlias) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
PrivateKey privateKey = loadPrivateKey(certAlias, certPassword);
if (privateKey == null) {
throw new OAuthRuntimeSystemException("Could not generate JWT Token as no private key available with " + certAlias);
}
return privateKey;
}
private String[] getClaimElements(String iss, String prn) {
return new String[]{
iss,
prn,
audience,
getExpirationTime()};
}
private String getExpirationTime() {
return new DateTime().plusMinutes(1).toDate().getTime() + "";
}
private void appendSeparator(StringBuilder token) {
token.append(".");
}
private PrivateKey loadPrivateKey(String certAlias, String privateKeyPassword) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
return (PrivateKey) keystore.getKey(certAlias, privateKeyPassword.toCharArray());
}
private String signPayload(StringBuilder token, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
Signature signature = Signature.getInstance(ALGORITHM);
signature.initSign(privateKey);
signature.update(getBytesInCharSet(token.toString()));
return encode(signature.sign());
}
private void appendEncodedClaim(StringBuilder token, String claim) throws UnsupportedEncodingException {
token.append(encode(claim));
}
private void appendEncodedHeader(StringBuilder token) throws UnsupportedEncodingException {
token.append(encode(HEADER));
}
private String encode(String payload) throws UnsupportedEncodingException {
final byte[] bytes = getBytesInCharSet(payload);
return encode(bytes);
}
private byte[] getBytesInCharSet(String s) throws UnsupportedEncodingException {
return s.getBytes("UTF-8");
}
private String encode(byte[] bytes) {
return Base64.encodeBase64URLSafeString(bytes);
}
}
Is there a way to get more information as to why the assertion failed or is there more I need to do to the JWT or the Salesforce Connected App or User to get this to work?

Encrypting PE file with Java

I'm trying to make a file crypter in Java, and it's working perfectly with txt files, however when I try to encrypt an .exe file, the file is getting f*** up. I had write a simple hello world program in C++ which is printing "hello world" on the command prompt, I call it f(for sake of simplicity). The problem is that when I encrypt the file, and then decrypt it, it's corrupted I mean I can't run it I'm getting message that the file isn't compatible with the 64 architecture. Here is my Java code:
The main class(the program starts from here:
public class Main {
public static void main(String[] args) {
try{
FileLoader fl = new FileLoader("C:\\..\\f.exe");
fl.encrypt();
SecretKey key = fl.get_key();
FileLoader dk = new FileLoader("C:\\..\\encrypted.exe", key);
dk.decrypt();
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
The FileHandler is the class which I'm using to work with files
public class FileLoader {
private String fileName;
private byte[] b_file_data;
private String s_file_data;
private List<String> l_file_data;
private Path path;
private SecretKey key;
public FileLoader(String file_name) throws IOException {
this.fileName = file_name;
this.b_file_data = read_file_bytes();
path = Paths.get(this.fileName);
this.l_file_data = s_read_file_lines();
}
public FileLoader(String file_name, SecretKey key) throws IOException {
this.fileName = file_name;
this.key = key;
this.b_file_data = read_file_bytes();
path = Paths.get(this.fileName);
this.l_file_data = s_read_file_lines();
}
public SecretKey get_key(){
return this.key;
}
private byte[] read_file_bytes() throws IOException{
Path path = Paths.get(this.fileName);
return Files.readAllBytes(path);
}
public void write_to_file(byte[] Bytes) throws IOException{
Path path = Paths.get(this.fileName);
Files.write(path, Bytes);
}
public byte[] get_file_bytes() {
return this.b_file_data;
}
private List<String> s_read_file_lines() throws IOException {
Charset charset = Charset.forName("ISO-8859-1");
return Files.readAllLines(this.path, charset);
}
public List<String> get_file_lines() {
return this.l_file_data;
}
public String get_data_string(){
return get_file_lines().toString();
}
public void encrypt() throws Exception {
DES algorithm = new DES(read_file_bytes());
key = algorithm.get_key();
byte[] encrypted = algorithm.get_encrypted_data();
FileOutputStream out = new FileOutputStream(new File("encrypted.exe"));
out.write(encrypted);
}
public void decrypt() throws Exception {
DES algorithm = new DES(read_file_bytes());
key = algorithm.get_key();
byte[] decrypted = algorithm.get_decrypted_data();
FileOutputStream out = new FileOutputStream(new File("decrypted.exe"));
out.write(decrypted);
}
}
The DES class it is just implementing the cryptography algorithm
public class DES {
private KeyGenerator keyGen;
private SecretKey secretKey;
private Cipher cipher;
private byte[] bytes_to_encrypt;
private byte[] encrypted_bytes;
private byte[] decrypted_bytes;
public DES(byte[] bytes_to_encrypt) {
this.bytes_to_encrypt = bytes_to_encrypt;
generate_key();
init_cipher();
encrypt_text();
}
private void generate_key(){
try{
keyGen = KeyGenerator.getInstance("DES");
}catch(Exception e){
System.out.println(e.toString());
}
keyGen.init(56);
secretKey = keyGen.generateKey();
}
private void init_cipher(){
try{
cipher = Cipher.getInstance("DES");
}catch(Exception e){
System.out.println(e.toString());
}
}
private void encrypt_text(){
try{
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
encrypted_bytes = cipher.doFinal(bytes_to_encrypt);
}catch(Exception e){
System.out.println(e.toString());
}
}
private void decrypt_text(){
try{
cipher.init(Cipher.DECRYPT_MODE, secretKey);
decrypted_bytes = cipher.doFinal(encrypted_bytes);
}catch(Exception e){
System.out.println(e.toString());
}
}
public byte[] get_encrypted_data(){
return this.encrypted_bytes;
}
public byte[] get_decrypted_data(){
decrypt_text();
return this.decrypted_bytes;
}
public byte[] get_original_data(){
return this.bytes_to_encrypt;
}
public SecretKey get_key(){
return this.secretKey;
}
}
Since I'm encrypting the PE as any other file, I think I'm messing with the sections, however I have no idea how to correct it. Any help is appreciated. I apologize for the bad looking code

What is the C# equivalent of the Java SecretKeySpec

I have following code written in Java
Mac mac = Mac.getInstance("HmacSHA1");
String secretKey ="sKey";
String content ="Hello";
byte[] secretKeyBArr = secretKey.getBytes();
byte[] contentBArr = content.getBytes();
SecretKeySpec secret_key = new SecretKeySpec(secretKeyBArr,"HmacSHA1");
byte[] secretKeySpecArr = secret_key.getEncoded();
mac.init(secret_key);
byte[] final = mac.doFinal(contentBArr);
I want to make same example in C#. So, I wrote following code
HMACSHA1 hmacsha1 = new HMACSHA1();
string secretKey = "sKey";
string content = "Hello";
byte[] secretKeyBArr = Encoding.UTF8.GetBytes(secretKey);
byte[] contentBArr = Encoding.UTF8.GetBytes(content);
hmacsha1.Key = secretKeyBArr;
byte[] final = hmacsha1.ComputeHash(contentBArr);
Final results are not equal. secretKeyBArr and contentBArr are byte array and their values are same in both example. What is unknown is SecretKeySpec passed to mac.init(). So, what is equivalent same class in C#?
The results are identical, but Java uses signed bytes while C# uses unsigned bytes by default.
Furthermore, SecretKeySpec itself normally does not change the underlying data. You need to e.g. put a DES key specification in a SecretKeyFactory to make sure that the parity bits are set correctly (in the resulting SecretKey). So there is no need for an equivalent as the class itself does very little except wrapping the data.
I'm implementing a credit card payment method form a provider (cardinity) that doesn't provide a .net implementation. I'm looking for similar stuff and end-up writing my own as my google skills seem to be ....
What I need is the base64 string of javax.crypto.mac
I am supporting the following methods:
enum EncryptionMethods
{
None=0,
HMACSHA1,
HMACSHA256,
HMACSHA384,
HMACSHA512,
HMACMD5
}
I have implemented the code you have above, the SecretKeySpec and the Mac the following way (you need System.Security.Cryptography.ProtectedData):
internal class Protected
{
private Byte[] salt = Guid.NewGuid().ToByteArray();
protected byte[] Protect(byte[] data)
{
try
{
return ProtectedData.Protect(data, salt, DataProtectionScope.CurrentUser);
}
catch (CryptographicException)//no reason for hackers to know it failed
{
return null;
}
}
protected byte[] Unprotect(byte[] data)
{
try
{
return ProtectedData.Unprotect(data, salt, DataProtectionScope.CurrentUser);
}
catch (CryptographicException)//no reason for hackers to know it failed
{
return null;
}
}
}
internal class SecretKeySpec:Protected,IDisposable
{
readonly EncryptionMethods _method;
private byte[] _secretKey;
public SecretKeySpec(byte[] secretKey, EncryptionMethods encryptionMethod)
{
_secretKey = Protect(secretKey);
_method = encryptionMethod;
}
public EncryptionMethods Method => _method;
public byte[] SecretKey => Unprotect( _secretKey);
public void Dispose()
{
if (_secretKey == null)
return;
//overwrite array memory
for (int i = 0; i < _secretKey.Length; i++)
{
_secretKey[i] = 0;
}
//set-null
_secretKey = null;
}
~SecretKeySpec()
{
Dispose();
}
}
internal class Mac : Protected,IDisposable
{
byte[] rawHmac;
HMAC mac;
public Mac(SecretKeySpec key, string data)
{
switch (key.Method)
{
case EncryptionMethods.HMACMD5:
mac = new HMACMD5(key.SecretKey);
break;
case EncryptionMethods.HMACSHA512:
mac = new HMACSHA512(key.SecretKey);
break;
case EncryptionMethods.HMACSHA384:
mac = new HMACSHA384(key.SecretKey);
break;
case EncryptionMethods.HMACSHA256:
mac = new HMACSHA256(key.SecretKey);
break;
case EncryptionMethods.HMACSHA1:
mac = new HMACSHA1(key.SecretKey);
break;
default:
throw new NotSupportedException("not supported HMAC");
}
rawHmac = Protect( mac.ComputeHash(Cardinity.ENCODING.GetBytes(data)));
}
public string AsBase64()
{
return System.Convert.ToBase64String(Unprotect(rawHmac));
}
public void Dispose()
{
if (rawHmac != null)
{
//overwrite memory address
for (int i = 0; i < rawHmac.Length; i++)
{
rawHmac[i] = 0;
}
//release memory now
rawHmac = null;
}
mac?.Dispose();
mac = null;
}
~Mac()
{
Dispose();
}
}
I have implemented this in an OAuthSigner class the following way:
public override string ComputeSignature(string plainTextToEncode, string consumerSecret)
{
var key = PercentEncode(consumerSecret) + "&";
try
{
using (var secretKey = new SecretKeySpec(key.GetBytes(), EncryptionMethods.HMACSHA1))
using (Mac mac = new Mac(secretKey, plainTextToEncode))
{
return mac.AsBase64();
}
}
finally
{
key = null;//free memory, remove sensitive data
}
}
Then, it's not what you ask for but I need a helper method as I am sending my text to a web service that goes like this and I include it as some might copy the code:
public static String PercentEncode(string textToEncode)
{
return string.IsNullOrEmpty(textToEncode)
?""
: UrlEncoder.Default.Encode(Cardinity.ENCODING.GetString(Cardinity.ENCODING.GetBytes(textToEncode)))
.Replace("+", "%20").Replace("*", "%2A")
.Replace("%7E", "~");
}
The class UrlEncoder comes from System.Text.Encodings.Web, you may have to add a reference.
The class named Cardinity implements a "short-cut" to the Encoding that I use for Cardinity
public abstract class Cardinity
{
...
public static String API_BASE = "https://api.cardinity.com";
public static String API_VERSION = "v1";
public static String VERSION = "0.1";
public static String ENCODING_CHARSET = "UTF-8";
public static Encoding ENCODING => Encoding.UTF8;
}
as Java uses string.GetBytes a lot, I have added an extension method for this that I call above in the key.GetBytes(), here is the extension code:
public static byte[] GetBytes(this string sender)=>
Cardinity.ENCODING.GetBytes(sender);
My test method, I have copied the values from Cardinity API passes without any issues.
private OAuthSigner signer;
public HmacOAuthSigner_Test()
{
signer = new HmacOAuthSigner();
}
[TestMethod]
public void Test_HmacOAuthSigner_ComputeSignature_DefaultText()
{
var expects = "PxkffxyQh6jsDNcgJ23GpAxs2y8=";
var test_data = "justsomerandommessage";
var secretkey = "yvp0leodf231ihv9u29uuq6w8o4cat9qz2nkvs55oeu833s621";
var actual = signer.ComputeSignature(test_data, secretkey);
Assert.AreEqual(expects, actual, $"Expecting {test_data} to return {expects} received {actual}");
}
The whole implementation of the HmacOAuthSigner is here, it implements an abstract class with the PercentEncode method in it.
public class HmacOAuthSigner : OAuthSigner
{
public override string ComputeSignature(string signatureBaseString, string consumerSecret)
{
var key = PercentEncode(consumerSecret) + "&";
var secretKey = new SecretKeySpec(key.GetBytes(), EncryptionMethods.HMACSHA1);
using (Mac mac = new Mac(secretKey, signatureBaseString))
{
return mac.AsBase64();
}
}
public override string GetSignatureMethod()
{
return "HMAC-SHA1";
}
}
and the abstract class that I use as a contract for all the implementations:
public abstract class OAuthSigner
{
/// <summary>
/// Signature method used
/// </summary>
/// <returns>a string that tells the implementation method</returns>
public abstract string GetSignatureMethod();
/// <summary>
/// computes the signature that is used with the encryption based on the keys provided by cardinity
/// </summary>
/// <param name="signatureBaseString">The secret string that services as a base</param>
/// <param name="consumerSecret">The consumer key as specified in the API settings</param>
/// <returns>signature string computed by the provided parameters using the signature method</returns>
public abstract string ComputeSignature(String signatureBaseString, String consumerSecret);
/// <summary>
/// Encode a string into a format expected by Cardinity
/// </summary>
/// <param name="textToEncode">The text that is to be encoded</param>
/// <returns>web encoded string ready for using to send to Cardinity</returns>
public static String PercentEncode(string textToEncode)
{
return string.IsNullOrEmpty(textToEncode)
?""
: UrlEncoder.Default.Encode(Cardinity.ENCODING.GetString(Cardinity.ENCODING.GetBytes(textToEncode)))
.Replace("+", "%20").Replace("*", "%2A")
.Replace("%7E", "~");
}
}

Categories

Resources