SPAKE2+

一、用处

  1. SPAKE2+: an ECC-based pairing algorithm protocol, mutually authenticate two entities.
  2. The NIST P-256 curve shall be used.

二、过程

1、Vehicle OEM Server:generate password, w0, L

Vehicle OEM Server 应该在配对前生成w0,L并存入车辆,以便在车辆断网时配对也可以继续。

(1)Scrypt = f(password, salt, cost, r, p, dkLen)

password: 随机数(可选:8个十进制数字组成的字符串)(The password is UTF-8 encoded).
salt: 随机生成的字母字符串。(16个随机字母组成的字符串)
cost:cost parameter Nscrypt: 4096 or higher(可选:32768)
r: block size,8
p: parallelization parameter, 1
dkLen: Output length, 80
Scrypt代码见下方

(2)z0: scrypt的左40字节;z1:scrypt的右40字节。

(3)w0=(z0 mod (n-1)) + 1; w1=(z1 mod (n-1))+1

n:the order of base point G as defined for NIST P-256

(4) L=w1 × G

2、Vehicle

The Vehicle OEM Server provides salt, L, w0 to the vehicle.(数据传输应保持安全和完整)
Y = y × G + w0 × N
Z = y × (X - w0 × M)
V = y × L
(x,y均为随机数,并且无法从X,Y获取x,y)
(X, Y shall not be the point at infinity and shall be on the chosen curve. A new y shall be generated, and a new Y shall be calculated until the requirements for Y are fulfilled before continuing the protocol.)
(M,N is a point on the used elliptic curve,算法见下方)

3、Device/owner

The password should be provided to the owner through the Vehicle OEM account,protected by the login credentials known only by the owner.
X = x × G + w0 × M
Z = x × (Y - w0 × N)
V = w1 × (Y - w0 × N)

4、Shared key

Vehicle 和 device交换X、Y后经计算得:
Z = xyG
V = xyw1

Both vehicle and device then shall calculate the shared secret K as follows:
K = SHA-256(len(X) || X || len(Y) || Y || len(Z) || Z || len(V) || V || len(w0) || w0)
where len(str) denotes the length of a string in bytes, represented as an 8-byte little-endian number.
The shared secrets CK and SK are derived from K:
CK = K [0:128]
SK = K [128:128] 3
The LONG_TERM_SHARED_SECRET is derived based on Listing 18-9.

5、认证

The verification of the derived keys shall be done by calculating a check value on either side which are mutually exchanged and verified.
The vehicle shall calculate the verification value M[1] as
K1=HKDF(CK, “ConfirmationKeys” || TLV 5Bh || TLV 5Ch, [0:128]), where ConfirmationKeys is a defined static string (see Listing 18-6).
M[1]=C-MAC(K1, X) using K1 as secret key, using CMAC-AES-128 as defined in [RFC4493] and shall send it over to the device.
The device shall verify M[1] using the received M[1] from the vehicle and, if successful, shall
calculate the verification value M[2] as
K2=HKDF(CK, “ConfirmationKeys” || TLV 5Bh || TLV 5Ch, [128:128]) (see Listing 18-6)
M[2]=C-MAC(K2, Y) using K2 as secret key, using CMAC-AES-128 as defined in [RFC4493] and shall send it over to the vehicle. 31
The protocol succeeds when the vehicle successfully validates M[2].

6、相关参数代码

计算Scrypt

private static byte[] scrypt(byte[] password, byte[] salt, int cost,
                                 int blocksize, int parallel, int length)
            throws GeneralSecurityException {

        if (cost < 2 || (cost & (cost - 1)) != 0) {
            throw new IllegalArgumentException(
                    "Cost must be a power of 2 greater than 1");
        }

        if (cost > Integer.MAX_VALUE / 128 / blocksize) {
            throw new IllegalArgumentException("Parameter cost is too large");
        }

        if (blocksize > Integer.MAX_VALUE / 128 / parallel) {
            throw new IllegalArgumentException(
                    "Parameter blocksize is too large");
        }

        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(password, "HmacSHA256"));

        byte[] key = new byte[length];

        byte[] b1 = new byte[128 * blocksize * parallel];
        byte[] xy = new byte[256 * blocksize];
        byte[] v1 = new byte[128 * blocksize * cost];

        pbkdf2(mac, salt, 1, b1, parallel * 128 * blocksize);

        for (int i = 0; i < parallel; i++) {
            smix(b1, i * 128 * blocksize, blocksize, cost, v1, xy);
        }

        pbkdf2(mac, b1, 1, key, length);

        return key;
    }
protected static void pbkdf2(Mac mac, byte[] salt, int iterations,
                                 byte[] key, int length) throws GeneralSecurityException {
        int len = mac.getMacLength();

        byte[] u1 = new byte[len];
        byte[] t1 = new byte[len];
        byte[] block = new byte[salt.length + 4];

        int limit = (int) Math.ceil((double) length / len);
        int r = length - (limit - 1) * len;

        System.arraycopy(salt, 0, block, 0, salt.length);

        for (int i = 1; i <= limit; i++) {
            block[salt.length + 0] = (byte) (i >> 24 & 0xff);
            block[salt.length + 1] = (byte) (i >> 16 & 0xff);
            block[salt.length + 2] = (byte) (i >> 8 & 0xff);
            block[salt.length + 3] = (byte) (i >> 0 & 0xff);

            mac.update(block);
            mac.doFinal(u1, 0);
            System.arraycopy(u1, 0, t1, 0, len);

            for (int j = 1; j < iterations; j++) {
                mac.update(u1);
                mac.doFinal(u1, 0);

                for (int k = 0; k < len; k++) {
                    t1[k] ^= u1[k];
                }
            }

            System.arraycopy(t1, 0, key, (i - 1) * len, (i == limit ? r : len));
        }
    }
w0 = Computation_w(scrypt, 0);
w1 = Computation_w(scrypt, 40);
protected BigInteger Computation_w(byte[] data, int offset) {
    BigInteger zx;
    if (data[offset] < 0) {
        byte[] byte41 = new byte[41];
        byte41[0] = 0;
        System.arraycopy(data, offset, byte41, 1, 40);
        zx = new BigInteger(byte41);
    } else {
        byte[] byte40 = new byte[40];
        System.arraycopy(data, offset, byte40, 0, 40);
        zx = new BigInteger(byte40);
    }
    BigInteger wx = zx.mod(n);
    return wx.add(new BigInteger("1"));
}

protected ECPoint Computation_L() {
    L = G.multiply(w1).normalize();
    log.info("L: " + L);
    return L;
}

private static void smix(byte[] b1, int bi, int round, int cpu, byte[] v1, byte[] xy) {
        int xi = 0;
        int yi = 128 * round;
        System.arraycopy(b1, bi, xy, xi, 128 * round);
        for (int i = 0; i < cpu; i++) {
            System.arraycopy(xy, xi, v1, i * (128 * round), 128 * round);
            blockMixSalsa8(xy, xi, yi, round);
        }
        for (int i = 0; i < cpu; i++) {
            int j = integerify(xy, xi, round) & (cpu - 1);
            blockxor(v1, j * (128 * round), xy, xi, 128 * round);
            blockMixSalsa8(xy, xi, yi, round);
        }
        System.arraycopy(xy, xi, b1, bi, 128 * round);
    }
    
private static void blockMixSalsa8(byte[] by, int bi, int yi, int round) {

   byte[] x1 = new byte[64];
    System.arraycopy(by, bi + (2 * round - 1) * 64, x1, 0, 64);
    for (int i = 0; i < 2 * round; i++) {
        blockxor(by, i * 64, x1, 0, 64);
        salsa(x1);
        System.arraycopy(x1, 0, by, yi + (i * 64), 64);
    }
    for (int i = 0; i < round; i++) {
        System.arraycopy(by, yi + (i * 2) * 64, by, bi + (i * 64), 64);
    }
    for (int i = 0; i < round; i++) {
        System.arraycopy(by, yi + (i * 2 + 1) * 64, by, bi + (i + round) * 64, 64);
    }
}
    
 private static void salsa(byte[] b1) {

    int[] base32 = new int[16];
    for (int i = 0; i < 16; i++) {
        base32[i] = (b1[i * 4 + 0] & 0xff) << 0;
        base32[i] |= (b1[i * 4 + 1] & 0xff) << 8;
        base32[i] |= (b1[i * 4 + 2] & 0xff) << 16;
        base32[i] |= (b1[i * 4 + 3] & 0xff) << 24;
    }

    int[] x1 = new int[16];
    System.arraycopy(base32, 0, x1, 0, 16);

    for (int i = 8; i > 0; i -= 2) {
        x1[4] ^= r1(x1[0] + x1[12], 7);
        x1[8] ^= r1(x1[4] + x1[0], 9);
        x1[12] ^= r1(x1[8] + x1[4], 13);
        x1[0] ^= r1(x1[12] + x1[8], 18);
        x1[9] ^= r1(x1[5] + x1[1], 7);
        x1[13] ^= r1(x1[9] + x1[5], 9);
        x1[1] ^= r1(x1[13] + x1[9], 13);
        x1[5] ^= r1(x1[1] + x1[13], 18);
        x1[14] ^= r1(x1[10] + x1[6], 7);
        x1[2] ^= r1(x1[14] + x1[10], 9);
        x1[6] ^= r1(x1[2] + x1[14], 13);
        x1[10] ^= r1(x1[6] + x1[2], 18);
        x1[3] ^= r1(x1[15] + x1[11], 7);
        x1[7] ^= r1(x1[3] + x1[15], 9);
        x1[11] ^= r1(x1[7] + x1[3], 13);
        x1[15] ^= r1(x1[11] + x1[7], 18);
        x1[1] ^= r1(x1[0] + x1[3], 7);
        x1[2] ^= r1(x1[1] + x1[0], 9);
        x1[3] ^= r1(x1[2] + x1[1], 13);
        x1[0] ^= r1(x1[3] + x1[2], 18);
        x1[6] ^= r1(x1[5] + x1[4], 7);
        x1[7] ^= r1(x1[6] + x1[5], 9);
        x1[4] ^= r1(x1[7] + x1[6], 13);
        x1[5] ^= r1(x1[4] + x1[7], 18);
        x1[11] ^= r1(x1[10] + x1[9], 7);
        x1[8] ^= r1(x1[11] + x1[10], 9);
        x1[9] ^= r1(x1[8] + x1[11], 13);
        x1[10] ^= r1(x1[9] + x1[8], 18);
        x1[12] ^= r1(x1[15] + x1[14], 7);
        x1[13] ^= r1(x1[12] + x1[15], 9);
        x1[14] ^= r1(x1[13] + x1[12], 13);
        x1[15] ^= r1(x1[14] + x1[13], 18);
    }

    for (int i = 0; i < 16; ++i) {
        base32[i] = x1[i] + base32[i];
    }

    for (int i = 0; i < 16; i++) {
        b1[i * 4 + 0] = (byte) (base32[i] >> 0 & 0xff);
        b1[i * 4 + 1] = (byte) (base32[i] >> 8 & 0xff);
        b1[i * 4 + 2] = (byte) (base32[i] >> 16 & 0xff);
        b1[i * 4 + 3] = (byte) (base32[i] >> 24 & 0xff);
    }
}

private static int integerify(byte[] b1, int bi, int round) {
    bi += (2 * round - 1) * 64;
    int n = (b1[bi + 0] & 0xff) << 0;
    n |= (b1[bi + 1] & 0xff) << 8;
    n |= (b1[bi + 2] & 0xff) << 16;
    n |= (b1[bi + 3] & 0xff) << 24;

    return n;
}

private static void blockxor(byte[] s1, int si, byte[] d1, int di, int length) {
	for (int i = 0; i < length; i++) {
	    d1[di + i] ^= s1[si + i];
	}
}

NIST P-256(SECP256r1) curve parameters:
M= 04
88 6e 2f 97 ac e4 6e 55 ba 9d d7 24 25 79 f2 99
3b 64 e1 6e f3 dc ab 95 af d4 97 33 3d 8f a1 2f
5f f3 55 16 3e 43 ce 22 4e 0b 0e 65 ff 02 ac 8e
5c 7b e0 94 19 c7 85 e0 ca 54 7d 55 a1 2e 2d 20
N=
04
d8 bb d6 c6 39 c6 29 37 b0 4d 99 7f 38 c3 77 07
19 c6 29 d7 01 4d 49 a2 4b 4f 98 ba a1 29 2b 49
07 d6 0a a6 bf ad e4 50 08 a6 36 33 7f 51 68 c6
4d 9b d3 60 34 80 8c d5 64 49 0b 1e 65 6e db e7

	static final ECPoint G;
    static final ECPoint M;
    static final ECPoint N;
    static final BigInteger n;

    static {
        SecP256R1Curve Curve = new SecP256R1Curve();

        byte[] Gx = {(byte) 0x6b, (byte) 0x17, (byte) 0xd1, (byte) 0xf2, (byte) 0xe1, (byte) 0x2c, (byte) 0x42, (byte) 0x47, (byte) 0xf8, (byte) 0xbc, (byte) 0xe6, (byte) 0xe5, (byte) 0x63, (byte) 0xa4, (byte) 0x40, (byte) 0xf2, (byte) 0x77, (byte) 0x03, (byte) 0x7d, (byte) 0x81, (byte) 0x2d, (byte) 0xeb, (byte) 0x33, (byte) 0xa0, (byte) 0xf4, (byte) 0xa1, (byte) 0x39, (byte) 0x45, (byte) 0xd8, (byte) 0x98, (byte) 0xc2, (byte) 0x96};
        byte[] Gy = {(byte) 0x4f, (byte) 0xe3, (byte) 0x42, (byte) 0xe2, (byte) 0xfe, (byte) 0x1a, (byte) 0x7f, (byte) 0x9b, (byte) 0x8e, (byte) 0xe7, (byte) 0xeb, (byte) 0x4a, (byte) 0x7c, (byte) 0x0f, (byte) 0x9e, (byte) 0x16, (byte) 0x2b, (byte) 0xce, (byte) 0x33, (byte) 0x57, (byte) 0x6b, (byte) 0x31, (byte) 0x5e, (byte) 0xce, (byte) 0xcb, (byte) 0xb6, (byte) 0x40, (byte) 0x68, (byte) 0x37, (byte) 0xbf, (byte) 0x51, (byte) 0xf5};
        G = Curve.createPoint(new BigInteger(Gx), new BigInteger(Gy));

        byte[] Mx = {(byte) 0x00, (byte) 0x88, (byte) 0x6e, (byte) 0x2f, (byte) 0x97, (byte) 0xac, (byte) 0xe4, (byte) 0x6e, (byte) 0x55, (byte) 0xba, (byte) 0x9d, (byte) 0xd7, (byte) 0x24, (byte) 0x25, (byte) 0x79, (byte) 0xf2, (byte) 0x99, (byte) 0x3b, (byte) 0x64, (byte) 0xe1, (byte) 0x6e, (byte) 0xf3, (byte) 0xdc, (byte) 0xab, (byte) 0x95, (byte) 0xaf, (byte) 0xd4, (byte) 0x97, (byte) 0x33, (byte) 0x3d, (byte) 0x8f, (byte) 0xa1, (byte) 0x2f};
        byte[] My = {(byte) 0x5f, (byte) 0xf3, (byte) 0x55, (byte) 0x16, (byte) 0x3e, (byte) 0x43, (byte) 0xce, (byte) 0x22, (byte) 0x4e, (byte) 0x0b, (byte) 0x0e, (byte) 0x65, (byte) 0xff, (byte) 0x02, (byte) 0xac, (byte) 0x8e, (byte) 0x5c, (byte) 0x7b, (byte) 0xe0, (byte) 0x94, (byte) 0x19, (byte) 0xc7, (byte) 0x85, (byte) 0xe0, (byte) 0xca, (byte) 0x54, (byte) 0x7d, (byte) 0x55, (byte) 0xa1, (byte) 0x2e, (byte) 0x2d, (byte) 0x20};
        M = Curve.createPoint(new BigInteger(Mx), new BigInteger(My));

        byte[] Nx = {(byte) 0x00, (byte) 0xd8, (byte) 0xbb, (byte) 0xd6, (byte) 0xc6, (byte) 0x39, (byte) 0xc6, (byte) 0x29, (byte) 0x37, (byte) 0xb0, (byte) 0x4d, (byte) 0x99, (byte) 0x7f, (byte) 0x38, (byte) 0xc3, (byte) 0x77, (byte) 0x07, (byte) 0x19, (byte) 0xc6, (byte) 0x29, (byte) 0xd7, (byte) 0x01, (byte) 0x4d, (byte) 0x49, (byte) 0xa2, (byte) 0x4b, (byte) 0x4f, (byte) 0x98, (byte) 0xba, (byte) 0xa1, (byte) 0x29, (byte) 0x2b, (byte) 0x49};
        byte[] Ny = {(byte) 0x07, (byte) 0xd6, (byte) 0x0a, (byte) 0xa6, (byte) 0xbf, (byte) 0xad, (byte) 0xe4, (byte) 0x50, (byte) 0x08, (byte) 0xa6, (byte) 0x36, (byte) 0x33, (byte) 0x7f, (byte) 0x51, (byte) 0x68, (byte) 0xc6, (byte) 0x4d, (byte) 0x9b, (byte) 0xd3, (byte) 0x60, (byte) 0x34, (byte) 0x80, (byte) 0x8c, (byte) 0xd5, (byte) 0x64, (byte) 0x49, (byte) 0x0b, (byte) 0x1e, (byte) 0x65, (byte) 0x6e, (byte) 0xdb, (byte) 0xe7};
        N = Curve.createPoint(new BigInteger(Nx), new BigInteger(Ny));

        byte[] ba_n = {(byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xbc, (byte) 0xe6, (byte) 0xfa, (byte) 0xad, (byte) 0xa7, (byte) 0x17, (byte) 0x9e, (byte) 0x84, (byte) 0xf3, (byte) 0xb9, (byte) 0xca, (byte) 0xc2, (byte) 0xfc, (byte) 0x63, (byte) 0x25, (byte) 0x51 - 1};
        n = new BigInteger(ba_n);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值