gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/gmtls/key_schedule.go (about) 1 // Copyright (c) 2022 zhaochun 2 // core-gm 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/ks-custle/core-gm/sm2" 30 "golang.org/x/crypto/cryptobyte" 31 "golang.org/x/crypto/curve25519" 32 "golang.org/x/crypto/hkdf" 33 ) 34 35 // This file contains the functions necessary to compute the TLS 1.3 key 36 // schedule. See RFC 8446, Section 7. 37 38 const ( 39 resumptionBinderLabel = "res binder" 40 clientHandshakeTrafficLabel = "c hs traffic" 41 serverHandshakeTrafficLabel = "s hs traffic" 42 clientApplicationTrafficLabel = "c ap traffic" 43 serverApplicationTrafficLabel = "s ap traffic" 44 exporterLabel = "exp master" 45 resumptionLabel = "res master" 46 trafficUpdateLabel = "traffic upd" 47 ) 48 49 // expandLabel 密钥扩展方法,实现 HKDF-Expand-Label。 50 // - secret 基础密钥 51 // - label 标签 52 // - context 消息转录散列 53 // - length 散列长度 54 // 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 // 83 // deriveSecret implements Derive-Secret from RFC 8446, Section 7.1. 84 func (cs *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte { 85 if transcript == nil { 86 // transcript默认使用tls1.3密码套件的散列函数 87 transcript = cs.hash.New() 88 } 89 return cs.expandLabel(secret, label, transcript.Sum(nil), cs.hash.Size()) 90 } 91 92 // extract 密钥提炼方法,实现 HKDF-Extract。 93 // 94 // 该方法用于从预主密钥提取主密钥。 95 // 96 // extract implements HKDF-Extract with the cipher suite hash. 97 func (cs *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte { 98 if newSecret == nil { 99 newSecret = make([]byte, cs.hash.Size()) 100 } 101 // 使用 HKDF-Extract 提取一个新的伪随机密钥。 102 // c.hash.New 为对应HMAC函数的散列函数; 103 // newSecret 作为原始密钥; 104 // currentSecret 作为盐值。 105 return hkdf.Extract(cs.hash.New, newSecret, currentSecret) 106 } 107 108 // 根据当前的通信密钥派生一个新的通信密钥。 109 // nextTrafficSecret generates the next traffic secret, given the current one, 110 // according to RFC 8446, Section 7.2. 111 func (cs *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte { 112 return cs.expandLabel(trafficSecret, trafficUpdateLabel, nil, cs.hash.Size()) 113 } 114 115 // 根据通信密钥派生会话密钥与初始偏移量(对称加密用的key,iv) 116 // trafficKey generates traffic keys according to RFC 8446, Section 7.3. 117 func (cs *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) { 118 key = cs.expandLabel(trafficSecret, "key", nil, cs.keyLen) 119 iv = cs.expandLabel(trafficSecret, "iv", nil, aeadNonceLength) 120 return 121 } 122 123 // 生成Finished消息散列。 124 // finishedHash generates the Finished verify_data or PskBinderEntry according 125 // to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey 126 // selection. 127 func (cs *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte { 128 finishedKey := cs.expandLabel(baseKey, "finished", nil, cs.hash.Size()) 129 verifyData := hmac.New(cs.hash.New, finishedKey) 130 verifyData.Write(transcript.Sum(nil)) 131 return verifyData.Sum(nil) 132 } 133 134 // exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to 135 // RFC 8446, Section 7.5. 136 func (cs *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) { 137 expMasterSecret := cs.deriveSecret(masterSecret, exporterLabel, transcript) 138 return func(label string, context []byte, length int) ([]byte, error) { 139 secret := cs.deriveSecret(expMasterSecret, label, nil) 140 h := cs.hash.New() 141 h.Write(context) 142 return cs.expandLabel(secret, "exporter", h.Sum(nil), length), nil 143 } 144 } 145 146 // ECDHE接口 147 // 148 // Elliptic Curve Diffie-Hellman Ephemeral,基于椭圆曲线的,动态的,笛福赫尔曼算法。 149 // 150 // ecdheParameters implements Diffie-Hellman with either NIST curves or X25519, 151 // according to RFC 8446, Section 4.2.8.2. 152 type ecdheParameters interface { 153 // CurveID 曲线ID 154 CurveID() CurveID 155 // PublicKey 获取公钥 156 PublicKey() []byte 157 // SharedKey 计算共享密钥 : 己方私钥 * 对方公钥peerPublicKey 158 SharedKey(peerPublicKey []byte) []byte 159 } 160 161 // 基于给定的椭圆曲线ID,获取椭圆曲线并生成ecdhe参数,已支持SM2-P-256曲线。 162 // 163 // ecdhe : Elliptic Curve Diffie-Hellman Ephemeral, 临时的基于椭圆曲线的笛福赫尔曼密钥交换算法。 164 // ecdheParameters是一个接口,实际对象需要实现该接口的SharedKey等方法,其内部包含曲线ID与对应的公私钥。 165 func generateECDHEParameters(rand io.Reader, curveID CurveID) (ecdheParameters, error) { 166 if curveID == X25519 { 167 privateKey := make([]byte, curve25519.ScalarSize) 168 if _, err := io.ReadFull(rand, privateKey); err != nil { 169 return nil, err 170 } 171 publicKey, err := curve25519.X25519(privateKey, curve25519.Basepoint) 172 if err != nil { 173 return nil, err 174 } 175 return &x25519Parameters{privateKey: privateKey, publicKey: publicKey}, nil 176 } 177 // 椭圆曲线获取,已支持p256sm2 178 curve, ok := curveForCurveID(curveID) 179 if !ok { 180 return nil, errors.New("gmtls: internal error: unsupported curve") 181 } 182 // 生成密钥交换算法参数 183 p := &nistParameters{curveID: curveID} 184 var err error 185 // 利用曲线生成公私钥 186 p.privateKey, p.x, p.y, err = elliptic.GenerateKey(curve, rand) 187 if err != nil { 188 return nil, err 189 } 190 return p, nil 191 } 192 193 // 根据曲线ID获取对应曲线 194 func curveForCurveID(id CurveID) (elliptic.Curve, bool) { 195 switch id { 196 // 添加国密SM2曲线 197 case Curve256Sm2: 198 return sm2.P256Sm2(), true 199 case CurveP256: 200 return elliptic.P256(), true 201 case CurveP384: 202 return elliptic.P384(), true 203 case CurveP521: 204 return elliptic.P521(), true 205 default: 206 return nil, false 207 } 208 } 209 210 func CheckCurveNameById(id CurveID) (string, bool) { 211 switch id { 212 case Curve256Sm2: 213 return sm2.P256Sm2().Params().Name, true 214 case CurveP256: 215 return elliptic.P256().Params().Name, true 216 case CurveP384: 217 return elliptic.P384().Params().Name, true 218 case CurveP521: 219 return elliptic.P521().Params().Name, true 220 case X25519: 221 return "Curve25519", true 222 default: 223 return fmt.Sprintf("unknown CurveID: %d", id), false 224 } 225 } 226 227 //goland:noinspection GoUnusedExportedFunction 228 func CurveNameById(id CurveID) string { 229 switch id { 230 // 添加国密SM2曲线 231 case Curve256Sm2: 232 return sm2.P256Sm2().Params().Name 233 case CurveP256: 234 return elliptic.P256().Params().Name 235 case CurveP384: 236 return elliptic.P384().Params().Name 237 case CurveP521: 238 return elliptic.P521().Params().Name 239 case X25519: 240 return "Curve25519" 241 default: 242 return fmt.Sprintf("unknown CurveID: %d", id) 243 } 244 } 245 246 type nistParameters struct { 247 privateKey []byte 248 x, y *big.Int // public key 249 curveID CurveID 250 } 251 252 func (p *nistParameters) CurveID() CurveID { 253 return p.curveID 254 } 255 256 func (p *nistParameters) PublicKey() []byte { 257 curve, _ := curveForCurveID(p.curveID) 258 return elliptic.Marshal(curve, p.x, p.y) 259 } 260 261 func (p *nistParameters) SharedKey(peerPublicKey []byte) []byte { 262 curve, _ := curveForCurveID(p.curveID) 263 // 将 peerPublicKey 的座标位置解析出来,同时验证该座标是否在曲线上。 264 // Unmarshal also checks whether the given point is on the curve. 265 x, y := elliptic.Unmarshal(curve, peerPublicKey) 266 if x == nil { 267 return nil 268 } 269 // peerPublicKey * 私钥 获取共享密钥 270 xShared, _ := curve.ScalarMult(x, y, p.privateKey) 271 sharedKey := make([]byte, (curve.Params().BitSize+7)/8) 272 //fmt.Println("===== 使用曲线 %s 与对方公钥计算共享密钥", curve.Params().Name) 273 return xShared.FillBytes(sharedKey) 274 } 275 276 type x25519Parameters struct { 277 privateKey []byte 278 publicKey []byte 279 } 280 281 func (p *x25519Parameters) CurveID() CurveID { 282 return X25519 283 } 284 285 func (p *x25519Parameters) PublicKey() []byte { 286 return p.publicKey[:] 287 } 288 289 func (p *x25519Parameters) SharedKey(peerPublicKey []byte) []byte { 290 sharedKey, err := curve25519.X25519(p.privateKey, peerPublicKey) 291 if err != nil { 292 return nil 293 } 294 return sharedKey 295 }