package org.apereo.cas.util;
import com.google.common.base.Throwables;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.OctJwkGenerator;
import org.jose4j.jwk.OctetSequenceJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Base64;
import java.util.Map;
/**
* This is {@link EncodingUtils}
* that encapsulates common base64 calls and operations
* in one spot.
*
* @author Timur Duehr timur.duehr@nccgroup.trust
* @since 5.0.0
*/
public final class EncodingUtils {
/**
* JSON web key parameter that identifies the key..
*/
public static final String JSON_WEB_KEY = "k";
private static final Logger LOGGER = LoggerFactory.getLogger(EncodingUtils.class);
private EncodingUtils() {
}
/**
* Hex decode string.
*
* @param data the data
* @return the string
*/
public static String hexDecode(final String data) {
if (StringUtils.isNotBlank(data)) {
return hexDecode(data.toCharArray());
}
return null;
}
/**
* Hex encode string.
*
* @param data the data
* @return the string
*/
public static String hexEncode(final String data) {
try {
final char[] result = Hex.encodeHex(data.getBytes(StandardCharsets.UTF_8));
return new String(result);
} catch (final Exception e) {
return null;
}
}
/**
* Hex encode string.
*
* @param data the data
* @return the string
*/
public static String hexEncode(final byte[] data) {
try {
final char[] result = Hex.encodeHex(data);
return new String(result);
} catch (final Exception e) {
return null;
}
}
/**
* Hex decode string.
*
* @param data the data
* @return the string
*/
public static String hexDecode(final char[] data) {
try {
final byte[] result = Hex.decodeHex(data);
return new String(result);
} catch (final Exception e) {
return null;
}
}
/**
* Base64-encode the given byte[] as a string.
*
* @param data the byte array to encode
* @return the encoded string
*/
public static String encodeBase64(final byte[] data) {
return Base64.getEncoder().encodeToString(data);
}
/**
* Base64-decode the given string as byte[].
*
* @param data the base64 string
* @return the encoded array
*/
public static byte[] decodeBase64(final String data) {
return Base64.getDecoder().decode(data);
}
/**
* Base64-decode the given string as byte[].
*
* @param data the base64 string
* @return the encoded array
*/
public static byte[] decodeBase64(final byte[] data) {
return Base64.getDecoder().decode(data);
}
/**
* Base64-encode the given byte[] as a byte[].
*
* @param data the byte array to encode
* @return the byte[] in base64
*/
public static byte[] encodeBase64ToByteArray(final byte[] data) {
return Base64.getEncoder().encode(data);
}
/**
* Url encode a value via UTF-8.
*
* @param value the value to encode
* @return the encoded value
*/
public static String urlEncode(final String value) {
return urlEncode(value, StandardCharsets.UTF_8.name());
}
/**
* Url encode a value.
*
* @param value the value to encode
* @param encoding the encoding
* @return the encoded value
*/
public static String urlEncode(final String value, final String encoding) {
try {
return URLEncoder.encode(value, encoding);
} catch (final UnsupportedEncodingException e) {
throw Throwables.propagate(e);
}
}
/**
* Url decode a value.
*
* @param value the value to decode
* @return the decoded value
*/
public static String urlDecode(final String value) {
try {
return URLDecoder.decode(value, StandardCharsets.UTF_8.name());
} catch (final UnsupportedEncodingException e) {
throw Throwables.propagate(e);
}
}
/**
* Verify jws signature byte [ ].
*
* @param value the value
* @param signingKey the signing key
* @return the byte [ ]
*/
public static byte[] verifyJwsSignature(final Key signingKey, final byte[] value) {
try {
final String asString = new String(value, StandardCharsets.UTF_8);
final JsonWebSignature jws = new JsonWebSignature();
jws.setCompactSerialization(asString);
jws.setKey(signingKey);
final boolean verified = jws.verifySignature();
if (verified) {
final String payload = jws.getPayload();
LOGGER.trace("Successfully decoded value. Result in Base64-encoding is [{}]", payload);
return EncodingUtils.decodeBase64(payload);
}
return null;
} catch (final Exception e) {
throw Throwables.propagate(e);
}
}
/**
* Generate octet json web key of given size .
*
* @param size the size
* @return the key
*/
public static String generateJsonWebKey(final int size) {
final OctetSequenceJsonWebKey octetKey = OctJwkGenerator.generateJwk(size);
final Map<String, Object> params = octetKey.toParams(JsonWebKey.OutputControlLevel.INCLUDE_SYMMETRIC);
return params.get(JSON_WEB_KEY).toString();
}
/**
* Sign jws.
*
* @param key the key
* @param value the value
* @return the byte [ ]
*/
public static byte[] signJws(final Key key, final byte[] value) {
try {
final String base64 = EncodingUtils.encodeBase64(value);
final JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(base64);
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA512);
jws.setKey(key);
return jws.getCompactSerialization().getBytes(StandardCharsets.UTF_8);
} catch (final Exception e) {
throw Throwables.propagate(e);
}
}
}