package com.xiaopeng.map.utils; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang.RandomStringUtils; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.util.io.pem.PemReader; import java.io.*; import java.math.BigInteger; import java.security.*; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.*; import java.util.UUID; /** * @author chenjl * @date 2020/6/3 */ public class VehicleCodec { static { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); } /** * 获得一个UUID * * @return String UUID */ public static String getUUID() { String s = UUID.randomUUID().toString(); // 去掉“-”符号 return s.substring(0, 8) + s.substring(9, 13) + s.substring(14, 18) + s.substring(19, 23) + s.substring(24); } /** * 生成序列号 * @return */ public static String generateSn() { return String.join("-", RandomStringUtils.randomAlphanumeric(4), RandomStringUtils.randomAlphanumeric(4), RandomStringUtils.randomAlphanumeric(4), RandomStringUtils.randomAlphanumeric(4)).toUpperCase(); } /** * Encode binary data to base64 * * @param value * The binary data * @return The base64 encoded String */ public static String encodeBASE64(byte[] value) { return new String(Base64.encodeBase64(value)); } /** * Decode a base64 value * * @param value * The base64 encoded String * @return decoded binary data * @throws UnsupportedEncodingException */ public static byte[] decodeBASE64(String value) { try { return Base64.decodeBase64(value.getBytes("utf-8")); } catch (UnsupportedEncodingException ex) { throw new IllegalArgumentException(ex); } } /** * ECDSA签名 * @param data 明文 * @param ecPrivateKey EC私钥 * @return 签名byte[] * @throws Exception */ public static String sign(byte[] data, ECPrivateKey ecPrivateKey) throws Exception { Signature signature = Signature.getInstance("SHA256withECDSA", "BC"); signature.initSign(ecPrivateKey); signature.update(data); return encodeBASE64(signature.sign()); } /** * ECDSA 验签 * @param data 明文 * @param sign 签名byte[] * @param ecPublicKey EC公钥 * @return 通过-true,失败-false * @throws Exception */ public static boolean verify(byte[] data, String sign, ECPublicKey ecPublicKey) throws Exception { Signature signature = Signature.getInstance("SHA256withECDSA", "BC"); signature.initVerify(ecPublicKey); signature.update(data); return signature.verify(decodeBASE64(sign)); } /** * 根据X和Y,得到EC公钥 * @param publicKeyXBase64 * @param publicKeyYBase64 * @return * @throws NoSuchAlgorithmException * @throws InvalidParameterSpecException * @throws InvalidKeySpecException */ public static ECPublicKey getECPublicKeyFromPoint(String publicKeyXBase64, String publicKeyYBase64) throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException { byte[] xkeyBytes = decodeBASE64(publicKeyXBase64); byte[] ykeyBytes = decodeBASE64(publicKeyYBase64); KeyFactory keyFactory = KeyFactory.getInstance("ECDSA"); ECPoint pubPoint = new ECPoint(new BigInteger(1, xkeyBytes), new BigInteger(1, ykeyBytes)); AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC"); parameters.init(new ECGenParameterSpec("secp256k1")); ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); ECPublicKeySpec pubSpec = new ECPublicKeySpec(pubPoint, ecParameters); return (ECPublicKey) keyFactory.generatePublic(pubSpec); } /** * 获取ECPrivateKey对象 * @param privateKeyBase64 * @return * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ public static ECPrivateKey getECPrivateKey(String privateKeyBase64) throws NoSuchAlgorithmException, InvalidKeySpecException { byte[] keyBytes = decodeBASE64(privateKeyBase64); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("EC"); return (ECPrivateKey) keyFactory .generatePrivate(pkcs8KeySpec); } /** * 从KEY文件解析KeyPair * @param pemFile * @return * @throws IOException */ public static KeyPair parsePEMFile(File pemFile) throws IOException { if (!pemFile.isFile() || !pemFile.exists()) { throw new FileNotFoundException(String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath())); } PemReader reader = new PemReader(new FileReader(pemFile)); PEMKeyPair pemKeyPair; try (PEMParser pemParser = new PEMParser(reader)) { reader.readPemObject(); pemKeyPair = (PEMKeyPair) pemParser.readObject(); return new JcaPEMKeyConverter().getKeyPair(pemKeyPair); } catch (Exception e) { //ignore } return null; } /** * Write a byte array as hexadecimal String. */ public static String byteToHexString(byte[] bytes) { return String.valueOf(Hex.encodeHex(bytes)); } /** * Build an hexadecimal MD5 hash for a String * * @param value * The String to hash * @return An hexadecimal Hash * @throws Exception */ public static String hexMD5(String value) { try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); messageDigest.reset(); messageDigest.update(value.getBytes("utf-8")); byte[] digest = messageDigest.digest(); return byteToHexString(digest); } catch (Exception ex) { throw new IllegalArgumentException(ex); } } /** * VIN 转UUID * @param vin 车架号 * @param salt1 盐1 * @param salt2 盐2 * @return */ public static String vinToUUID(String vin, String salt1, String salt2) { return hexMD5(hexMD5(vin + salt1) + salt2).toUpperCase(); } /** * 将字节数组转换成16进制字符串 */ public static String encodeHexStr(final byte[] bytes){ if (bytes == null) { return null; } char[] digital = "0123456789ABCDEF".toCharArray(); char[] result = new char[bytes.length * 2]; for (int i = 0; i < bytes.length; i++) { result[i * 2] = digital[(bytes[i] & 0xf0) >> 4]; result[i * 2 + 1] = digital[bytes[i] & 0x0f]; } return new String(result); } /** * 检查是否VIN * @param vin * @return */ public static boolean isVin(String vin) { return vin.length() == 17 && vin.charAt(0) == 'L'; } }