liujie
2026-05-12 0bcfca6b2561d096a2ce26e2e7200cd0768b2b6d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
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';
    }
 
 
}