All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.tinypass.client.common.SecurityUtil Maven / Gradle / Ivy
package com.tinypass.client.common;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
class SecurityUtil {
private static final String HMAC_DELIMITER = "~~~";
private static final String CIPHER_ALGORITHM = "AES/ECB/NoPadding";
private static final String SECRET_KEY_ALGORITHM = "AES";
private static final String HMAC_ALGORITHM = "HmacSHA256";
private static final int BLOCK_SIZE = 16;
private static final int KEY_SIZE = 32;
private static final char KEY_PADDING = 'X';
private static final Base64.Encoder base64Encoder = Base64.getUrlEncoder().withoutPadding();
private static byte[] removePadding(byte[] source) {
byte lastByte = source[source.length - 1];
int paddingLength = (lastByte > 0 && lastByte <= BLOCK_SIZE) ? lastByte : 0;
return Arrays.copyOf(source, source.length - paddingLength);
}
private static byte[] addPadding(byte[] source) {
int rem = source.length % BLOCK_SIZE;
int padding = rem != 0 ? BLOCK_SIZE - rem : 0;
byte[] result = Arrays.copyOf(source, source.length + padding);
Arrays.fill(result, source.length, source.length + padding, (byte) padding);
return result;
}
private static String hmac(String value, String key) throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance(HMAC_ALGORITHM);
mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), HMAC_ALGORITHM));
return base64Encoder.encodeToString(mac.doFinal(value.getBytes(StandardCharsets.UTF_8)));
}
private static String prepareKey(String source) {
if (source.length() > KEY_SIZE) {
return source.substring(0, KEY_SIZE);
}
return source + String.join("", Collections.nCopies(KEY_SIZE - source.length(), String.valueOf(KEY_PADDING)));
}
private static byte[] useCipher(byte[] source, String key, int mode)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(mode, new SecretKeySpec(prepareKey(key).getBytes(StandardCharsets.UTF_8), SECRET_KEY_ALGORITHM));
return cipher.doFinal(source);
}
static String encrypt(String key, String value)
throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
byte[] bytes = addPadding(value.getBytes(StandardCharsets.UTF_8));
String encrypted = base64Encoder.encodeToString(useCipher(bytes, key, Cipher.ENCRYPT_MODE));
return encrypted + HMAC_DELIMITER + hmac(encrypted, key);
}
static String decrypt(String key, String value)
throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
String[] parts = value.split(HMAC_DELIMITER);
if (parts.length > 2)
throw new IllegalArgumentException("Invalid message. We've found data after HMAC");
String data = parts[0];
if (parts.length > 1 && !hmac(data, key).equals(parts[1]))
throw new IllegalArgumentException("Could not parse message: invalid HMAC");
return new String(removePadding(useCipher(Base64.getUrlDecoder().decode(data), key, Cipher.DECRYPT_MODE)), StandardCharsets.UTF_8);
}
}