gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/gmtls/key_schedule.go (about) 1 // Copyright (c) 2022 zhaochun 2 // gmgo is licensed under Mulan PSL v2. 3 // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 // You may obtain a copy of Mulan PSL v2 at: 5 // http://license.coscl.org.cn/MulanPSL2 6 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 7 // See the Mulan PSL v2 for more details. 8 9 /* 10 gmtls是基于`golang/go`的`tls`包实现的国密改造版本。 11 对应版权声明: thrid_licenses/github.com/golang/go/LICENSE 12 */ 13 14 package gmtls 15 16 /* 17 gmtls/key_schedule.go TLS1.3密钥调度相关函数,已补充国密SM2曲线相关处理。 18 */ 19 20 import ( 21 "crypto/elliptic" 22 "crypto/hmac" 23 "errors" 24 "fmt" 25 "hash" 26 "io" 27 "math/big" 28 29 "gitee.com/zhaochuninhefei/gmgo/sm2" 30 "gitee.com/zhaochuninhefei/zcgolog/zclog" 31 "golang.org/x/crypto/cryptobyte" 32 "golang.org/x/crypto/curve25519" 33 "golang.org/x/crypto/hkdf" 34 ) 35 36 // This file contains the functions necessary to compute the TLS 1.3 key 37 // schedule. See RFC 8446, Section 7. 38 39 const ( 40 resumptionBinderLabel = "res binder" 41 clientHandshakeTrafficLabel = "c hs traffic" 42 serverHandshakeTrafficLabel = "s hs traffic" 43 clientApplicationTrafficLabel = "c ap traffic" 44 serverApplicationTrafficLabel = "s ap traffic" 45 exporterLabel = "exp master" 46 resumptionLabel = "res master" 47 trafficUpdateLabel = "traffic upd" 48 ) 49 50 // expandLabel 密钥扩展方法,实现 HKDF-Expand-Label。 51 // - secret 基础密钥 52 // - label 标签 53 // - context 消息转录散列 54 // - length 散列长度 55 // expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1. 56 func (cs *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte { 57 var hkdfLabel cryptobyte.Builder 58 hkdfLabel.AddUint16(uint16(length)) 59 hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { 60 b.AddBytes([]byte("tls13 ")) 61 b.AddBytes([]byte(label)) 62 }) 63 hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { 64 b.AddBytes(context) 65 }) 66 out := make([]byte, length) 67 // 使用 HKDF-Expand 将 HKDF-Extract 提取的伪随机密钥(主密钥)扩展为长度为length的字节数组 68 // c.hash.New 为对应HMAC函数的散列函数; 69 // secret 为 HKDF-Extract 提取的伪随机密钥(主密钥) 70 // hkdfLabel.BytesOrPanic() 为可选上下文和应用程序特定信息 71 n, err := hkdf.Expand(cs.hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out) 72 if err != nil || n != length { 73 panic("gmtls: HKDF-Expand-Label invocation failed unexpectedly") 74 } 75 return out 76 } 77 78 // deriveSecret 密钥派生方法,实现 Derive-Secret。内部使用 HKDF-Expand。 79 // - secret 基础密钥 80 // - label 标签 81 // - transcript 转录散列函数 82 // deriveSecret implements Derive-Secret from RFC 8446, Section 7.1. 83 func (cs *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte { 84 if transcript == nil { 85 // transcript默认使用tls1.3密码套件的散列函数 86 transcript = cs.hash.New() 87 } 88 return cs.expandLabel(secret, label, transcript.Sum(nil), cs.hash.Size()) 89 } 90 91 // extract 密钥提炼方法,实现 HKDF-Extract。 92 // 该方法用于从预主密钥提取主密钥。 93 // extract implements HKDF-Extract with the cipher suite hash. 94 func (cs *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte { 95 if newSecret == nil { 96 newSecret = make([]byte, cs.hash.Size()) 97 } 98 // 使用 HKDF-Extract 提取一个新的伪随机密钥。 99 // c.hash.New 为对应HMAC函数的散列函数; 100 // newSecret 作为原始密钥; 101 // currentSecret 作为盐值。 102 return hkdf.Extract(cs.hash.New, newSecret, currentSecret) 103 } 104 105 // 根据当前的通信密钥派生一个新的通信密钥。 106 // nextTrafficSecret generates the next traffic secret, given the current one, 107 // according to RFC 8446, Section 7.2. 108 func (cs *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte { 109 return cs.expandLabel(trafficSecret, trafficUpdateLabel, nil, cs.hash.Size()) 110 } 111 112 // 根据通信密钥派生会话密钥与初始偏移量(对称加密用的key,iv) 113 // trafficKey generates traffic keys according to RFC 8446, Section 7.3. 114 func (cs *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) { 115 key = cs.expandLabel(trafficSecret, "key", nil, cs.keyLen) 116 iv = cs.expandLabel(trafficSecret, "iv", nil, aeadNonceLength) 117 return 118 } 119 120 // 生成Finished消息散列。 121 // finishedHash generates the Finished verify_data or PskBinderEntry according 122 // to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey 123 // selection. 124 func (cs *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte { 125 finishedKey := cs.expandLabel(baseKey, "finished", nil, cs.hash.Size()) 126 verifyData := hmac.New(cs.hash.New, finishedKey) 127 verifyData.Write(transcript.Sum(nil)) 128 return verifyData.Sum(nil) 129 } 130 131 // exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to 132 // RFC 8446, Section 7.5. 133 func (cs *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) { 134 expMasterSecret := cs.deriveSecret(masterSecret, exporterLabel, transcript) 135 return func(label string, context []byte, length int) ([]byte, error) { 136 secret := cs.deriveSecret(expMasterSecret, label, nil) 137 h := cs.hash.New() 138 h.Write(context) 139 return cs.expandLabel(secret, "exporter", h.Sum(nil), length), nil 140 } 141 } 142 143 // ECDHE接口 144 // Elliptic Curve Diffie-Hellman Ephemeral,基于椭圆曲线的,动态的,笛福赫尔曼算法。 145 // ecdheParameters implements Diffie-Hellman with either NIST curves or X25519, 146 // according to RFC 8446, Section 4.2.8.2. 147 type ecdheParameters interface { 148 // CurveID 曲线ID 149 CurveID() CurveID 150 // PublicKey 获取公钥 151 PublicKey() []byte 152 // SharedKey 计算共享密钥 : 己方私钥 * 对方公钥peerPublicKey 153 SharedKey(peerPublicKey []byte) []byte 154 } 155 156 // 基于给定的椭圆曲线ID,获取椭圆曲线并生成ecdhe参数,已支持SM2-P-256曲线。 157 // ecdhe : Elliptic Curve Diffie-Hellman Ephemeral, 临时的基于椭圆曲线的笛福赫尔曼密钥交换算法。 158 // ecdheParameters是一个接口,实际对象需要实现该接口的SharedKey等方法,其内部包含曲线ID与对应的公私钥。 159 func generateECDHEParameters(rand io.Reader, curveID CurveID) (ecdheParameters, error) { 160 if curveID == X25519 { 161 privateKey := make([]byte, curve25519.ScalarSize) 162 if _, err := io.ReadFull(rand, privateKey); err != nil { 163 return nil, err 164 } 165 publicKey, err := curve25519.X25519(privateKey, curve25519.Basepoint) 166 if err != nil { 167 return nil, err 168 } 169 return &x25519Parameters{privateKey: privateKey, publicKey: publicKey}, nil 170 } 171 // 椭圆曲线获取,已支持p256sm2 172 curve, ok := curveForCurveID(curveID) 173 if !ok { 174 return nil, errors.New("gmtls: internal error: unsupported curve") 175 } 176 // 生成密钥交换算法参数 177 p := &nistParameters{curveID: curveID} 178 var err error 179 // 利用曲线生成公私钥 180 p.privateKey, p.x, p.y, err = elliptic.GenerateKey(curve, rand) 181 if err != nil { 182 return nil, err 183 } 184 return p, nil 185 } 186 187 // 根据曲线ID获取对应曲线 188 func curveForCurveID(id CurveID) (elliptic.Curve, bool) { 189 switch id { 190 // 添加国密SM2曲线 191 case Curve256Sm2: 192 return sm2.P256Sm2(), true 193 case CurveP256: 194 return elliptic.P256(), true 195 case CurveP384: 196 return elliptic.P384(), true 197 case CurveP521: 198 return elliptic.P521(), true 199 default: 200 return nil, false 201 } 202 } 203 204 func CheckCurveNameById(id CurveID) (string, bool) { 205 switch id { 206 case Curve256Sm2: 207 return sm2.P256Sm2().Params().Name, true 208 case CurveP256: 209 return elliptic.P256().Params().Name, true 210 case CurveP384: 211 return elliptic.P384().Params().Name, true 212 case CurveP521: 213 return elliptic.P521().Params().Name, true 214 case X25519: 215 return "Curve25519", true 216 default: 217 return fmt.Sprintf("unknown CurveID: %d", id), false 218 } 219 } 220 221 //goland:noinspection GoUnusedExportedFunction 222 func CurveNameById(id CurveID) string { 223 switch id { 224 // 添加国密SM2曲线 225 case Curve256Sm2: 226 return sm2.P256Sm2().Params().Name 227 case CurveP256: 228 return elliptic.P256().Params().Name 229 case CurveP384: 230 return elliptic.P384().Params().Name 231 case CurveP521: 232 return elliptic.P521().Params().Name 233 case X25519: 234 return "Curve25519" 235 default: 236 return fmt.Sprintf("unknown CurveID: %d", id) 237 } 238 } 239 240 type nistParameters struct { 241 privateKey []byte 242 x, y *big.Int // public key 243 curveID CurveID 244 } 245 246 func (p *nistParameters) CurveID() CurveID { 247 return p.curveID 248 } 249 250 func (p *nistParameters) PublicKey() []byte { 251 curve, _ := curveForCurveID(p.curveID) 252 return elliptic.Marshal(curve, p.x, p.y) 253 } 254 255 func (p *nistParameters) SharedKey(peerPublicKey []byte) []byte { 256 curve, _ := curveForCurveID(p.curveID) 257 // 将 peerPublicKey 的座标位置解析出来,同时验证该座标是否在曲线上。 258 // Unmarshal also checks whether the given point is on the curve. 259 x, y := elliptic.Unmarshal(curve, peerPublicKey) 260 if x == nil { 261 return nil 262 } 263 // peerPublicKey * 私钥 获取共享密钥 264 xShared, _ := curve.ScalarMult(x, y, p.privateKey) 265 sharedKey := make([]byte, (curve.Params().BitSize+7)/8) 266 zclog.Debugf("===== 使用曲线 %s 与对方公钥计算共享密钥", curve.Params().Name) 267 return xShared.FillBytes(sharedKey) 268 } 269 270 type x25519Parameters struct { 271 privateKey []byte 272 publicKey []byte 273 } 274 275 func (p *x25519Parameters) CurveID() CurveID { 276 return X25519 277 } 278 279 func (p *x25519Parameters) PublicKey() []byte { 280 return p.publicKey[:] 281 } 282 283 func (p *x25519Parameters) SharedKey(peerPublicKey []byte) []byte { 284 sharedKey, err := curve25519.X25519(p.privateKey, peerPublicKey) 285 if err != nil { 286 return nil 287 } 288 return sharedKey 289 }