...
1
16
17 package josecipher
18
19 import (
20 "bytes"
21 "crypto"
22 "crypto/ecdsa"
23 "crypto/elliptic"
24 "encoding/binary"
25 )
26
27
28
29
30
31 func DeriveECDHES(alg string, apuData, apvData []byte, priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey, size int) []byte {
32 if size > 1<<16 {
33 panic("ECDH-ES output size too large, must be less than or equal to 1<<16")
34 }
35
36
37 algID := lengthPrefixed([]byte(alg))
38 ptyUInfo := lengthPrefixed(apuData)
39 ptyVInfo := lengthPrefixed(apvData)
40
41
42 supPubInfo := make([]byte, 4)
43 binary.BigEndian.PutUint32(supPubInfo, uint32(size)*8)
44
45 if !priv.PublicKey.Curve.IsOnCurve(pub.X, pub.Y) {
46 panic("public key not on same curve as private key")
47 }
48
49 z, _ := priv.Curve.ScalarMult(pub.X, pub.Y, priv.D.Bytes())
50 zBytes := z.Bytes()
51
52
53
54
55
56 octSize := dSize(priv.Curve)
57 if len(zBytes) != octSize {
58 zBytes = append(bytes.Repeat([]byte{0}, octSize-len(zBytes)), zBytes...)
59 }
60
61 reader := NewConcatKDF(crypto.SHA256, zBytes, algID, ptyUInfo, ptyVInfo, supPubInfo, []byte{})
62 key := make([]byte, size)
63
64
65 _, _ = reader.Read(key)
66
67 return key
68 }
69
70
71 func dSize(curve elliptic.Curve) int {
72 order := curve.Params().P
73 bitLen := order.BitLen()
74 size := bitLen / 8
75 if bitLen%8 != 0 {
76 size++
77 }
78 return size
79 }
80
81 func lengthPrefixed(data []byte) []byte {
82 out := make([]byte, len(data)+4)
83 binary.BigEndian.PutUint32(out, uint32(len(data)))
84 copy(out[4:], data)
85 return out
86 }
87
View as plain text