github.com/PandaGoAdmin/utils@v0.0.0-20211208134815-d5461603a00f/encrypt.go (about) 1 package kgo 2 3 import ( 4 "bytes" 5 "crypto" 6 "crypto/aes" 7 "crypto/cipher" 8 "crypto/hmac" 9 "crypto/rand" 10 "crypto/rsa" 11 "crypto/sha1" 12 "crypto/sha256" 13 "crypto/sha512" 14 "crypto/x509" 15 "encoding/base64" 16 "encoding/hex" 17 "encoding/pem" 18 "errors" 19 "fmt" 20 "golang.org/x/crypto/bcrypt" 21 "hash" 22 "io" 23 "math/big" 24 "strconv" 25 "time" 26 ) 27 28 // Base64Encode 使用 MIME base64 对数据进行编码. 29 func (ke *LkkEncrypt) Base64Encode(str []byte) []byte { 30 l := len(str) 31 if l > 0 { 32 buf := make([]byte, base64.StdEncoding.EncodedLen(l)) 33 base64.StdEncoding.Encode(buf, str) 34 return buf 35 } 36 37 return nil 38 } 39 40 // Base64Decode 对使用 MIME base64 编码的数据进行解码. 41 func (ke *LkkEncrypt) Base64Decode(str []byte) ([]byte, error) { 42 l := len(str) 43 if l > 0 { 44 dbuf := make([]byte, base64.StdEncoding.DecodedLen(l)) 45 n, err := base64.StdEncoding.Decode(dbuf, str) 46 return dbuf[:n], err 47 } 48 49 return nil, nil 50 } 51 52 // Base64UrlSafeEncode url安全的Base64Encode,没有'/'和'+'及结尾的'=' . 53 func (ke *LkkEncrypt) Base64UrlEncode(str []byte) []byte { 54 l := len(str) 55 if l > 0 { 56 buf := make([]byte, base64.StdEncoding.EncodedLen(l)) 57 base64.StdEncoding.Encode(buf, str) 58 59 // Base64 Url Safe is the same as Base64 but does not contain '/' and '+' (replaced by '_' and '-') and trailing '=' are removed. 60 buf = bytes.Replace(buf, bytSlash, bytUnderscore, -1) 61 buf = bytes.Replace(buf, bytPlus, bytMinus, -1) 62 buf = bytes.Replace(buf, bytEqual, bytEmp, -1) 63 64 return buf 65 } 66 67 return nil 68 } 69 70 // Base64UrlDecode url安全的Base64Decode. 71 func (ke *LkkEncrypt) Base64UrlDecode(str []byte) ([]byte, error) { 72 l := len(str) 73 if l > 0 { 74 var missing = (4 - len(str)%4) % 4 75 str = append(str, bytes.Repeat(bytEqual, missing)...) 76 77 dbuf := make([]byte, base64.URLEncoding.DecodedLen(len(str))) 78 n, err := base64.URLEncoding.Decode(dbuf, str) 79 return dbuf[:n], err 80 } 81 82 return nil, nil 83 } 84 85 // AuthCode 授权码编码或解码;encode为true时编码,为false解码;expiry为有效期,秒;返回结果为加密/解密的字符串和有效期时间戳. 86 func (ke *LkkEncrypt) AuthCode(str, key []byte, encode bool, expiry int64) ([]byte, int64) { 87 // DYNAMIC_KEY_LEN 动态密钥长度,相同的明文会生成不同密文就是依靠动态密钥 88 // 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。 89 // 取值越大,密文变动规律越大,密文变化 = 16 的 DYNAMIC_KEY_LEN 次方 90 // 当此值为 0 时,则不产生随机密钥 91 92 strLen := len(str) 93 if str == nil || strLen == 0 { 94 return nil, 0 95 } else if !encode && strLen < DYNAMIC_KEY_LEN { 96 return nil, 0 97 } 98 99 // 密钥 100 keyByte := md5Byte(key, 32) 101 102 // 密钥a会参与加解密 103 keya := keyByte[:16] 104 105 // 密钥b会用来做数据完整性验证 106 keyb := make([]byte, 16) 107 copy(keyb, keyByte[16:]) 108 109 // 密钥c用于变化生成的密文 110 var keyc []byte 111 if encode == false { 112 keyc = str[:DYNAMIC_KEY_LEN] 113 } else { 114 now, _ := time.Now().MarshalBinary() 115 keycLen := 32 - DYNAMIC_KEY_LEN 116 timeBytes := md5Byte(now, 32) 117 keyc = timeBytes[keycLen:] 118 } 119 120 // 参与运算的密钥 121 keyd := md5Byte(append(keya, keyc...), 32) 122 cryptkey := append(keya, keyd...) 123 cryptkeyLen := len(cryptkey) 124 // 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存keyb(密钥b),解密时会通过这个密钥验证数据完整性 125 // 如果是解码的话,会从第 DYNAMIC_KEY_LEN 位开始,因为密文前 DYNAMIC_KEY_LEN 位保存 动态密钥,以保证解密正确 126 if encode == false { //解密 127 var err error 128 str, err = ke.Base64UrlDecode(str[DYNAMIC_KEY_LEN:]) 129 if err != nil { 130 return nil, 0 131 } 132 } else { 133 if expiry != 0 { 134 expiry = expiry + time.Now().Unix() 135 } 136 expMd5 := md5Byte(append(str, keyb...), 16) 137 str = []byte(fmt.Sprintf("%010d%s%s", expiry, expMd5, str)) 138 } 139 140 strLen = len(str) 141 resdata := make([]byte, 0, strLen) 142 var rndkey, box [256]int 143 // 产生密钥簿 144 h := 0 145 i := 0 146 j := 0 147 148 for i = 0; i < 256; i++ { 149 rndkey[i] = int(cryptkey[i%cryptkeyLen]) 150 box[i] = i 151 } 152 // 用固定的算法,打乱密钥簿,增加随机性,好像很复杂,实际上并不会增加密文的强度 153 for i = 0; i < 256; i++ { 154 j = (j + box[i] + rndkey[i]) % 256 155 box[i], box[j] = box[j], box[i] 156 } 157 // 核心加解密部分 158 h = 0 159 j = 0 160 for i = 0; i < strLen; i++ { 161 h = ((h + 1) % 256) 162 j = ((j + box[h]) % 256) 163 box[h], box[j] = box[j], box[h] 164 // 从密钥簿得出密钥进行异或,再转成字符 165 resdata = append(resdata, byte(int(str[i])^box[(box[h]+box[j])%256])) 166 } 167 if encode == false { //解密 168 // substr($result, 0, 10) == 0 验证数据有效性 169 // substr($result, 0, 10) - time() > 0 验证数据有效性 170 // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性 171 // 验证数据有效性,请看未加密明文的格式 172 if len(resdata) <= 26 { 173 return nil, 0 174 } 175 176 expTime, _ := strconv.ParseInt(string(resdata[:10]), 10, 0) 177 if (expTime == 0 || expTime-time.Now().Unix() > 0) && string(resdata[10:26]) == string(md5Byte(append(resdata[26:], keyb...), 16)) { 178 return resdata[26:], expTime 179 } else { 180 return nil, expTime 181 } 182 } else { //加密 183 // 把动态密钥保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因 184 resdata = append(keyc, ke.Base64UrlEncode(resdata)...) 185 return resdata, expiry 186 } 187 } 188 189 // PasswordHash 创建密码的散列值;costs为算法的cost,范围4~31,默认10;注意:值越大越耗时. 190 func (ke *LkkEncrypt) PasswordHash(password []byte, costs ...int) ([]byte, error) { 191 var cost int 192 if len(costs) == 0 { 193 cost = 10 194 } else { 195 cost = costs[0] 196 if cost < 4 { 197 cost = 4 198 } else if cost > 31 { 199 cost = 15 200 } 201 } 202 203 res, err := bcrypt.GenerateFromPassword(password, cost) 204 return res, err 205 } 206 207 // PasswordVerify 验证密码是否和散列值匹配. 208 func (ke *LkkEncrypt) PasswordVerify(password, hash []byte) bool { 209 err := bcrypt.CompareHashAndPassword(hash, password) 210 return err == nil 211 } 212 213 // EasyEncrypt 简单加密. 214 // data为要加密的原字符串,key为密钥. 215 func (ke *LkkEncrypt) EasyEncrypt(data, key []byte) []byte { 216 dataLen := len(data) 217 if dataLen == 0 { 218 return nil 219 } 220 221 keyByte := md5Byte(key, 32) 222 keyLen := len(keyByte) 223 224 var i, x, c int 225 var res []byte 226 for i = 0; i < dataLen; i++ { 227 if x == keyLen { 228 x = 0 229 } 230 231 c = (int(data[i]) + int(keyByte[x])) % 256 232 res = append(res, byte(c)) 233 234 x++ 235 } 236 237 res = append(keyByte[:DYNAMIC_KEY_LEN], ke.Base64UrlEncode(res)...) 238 return res 239 } 240 241 // EasyDecrypt 简单解密. 242 // val为待解密的字符串,key为密钥. 243 func (ke *LkkEncrypt) EasyDecrypt(val, key []byte) []byte { 244 if len(val) <= DYNAMIC_KEY_LEN { 245 return nil 246 } 247 248 data, err := ke.Base64UrlDecode(val[DYNAMIC_KEY_LEN:]) 249 if err != nil { 250 return nil 251 } 252 253 keyByte := md5Byte(key, 32) 254 if string(val[:DYNAMIC_KEY_LEN]) != string(keyByte[:DYNAMIC_KEY_LEN]) { 255 return nil 256 } 257 258 dataLen := len(data) 259 keyLen := len(keyByte) 260 261 var i, x, c int 262 var res []byte 263 for i = 0; i < dataLen; i++ { 264 if x == keyLen { 265 x = 0 266 } 267 268 if data[i] < keyByte[x] { 269 c = int(data[i]) + 256 - int(keyByte[x]) 270 } else { 271 c = int(data[i]) - int(keyByte[x]) 272 } 273 res = append(res, byte(c)) 274 275 x++ 276 } 277 278 return res 279 } 280 281 // HmacShaX HmacSHA-x加密,x为1/256/512 . 282 func (ke *LkkEncrypt) HmacShaX(data, secret []byte, x uint16) []byte { 283 // Create a new HMAC by defining the hash type and the key (as byte array) 284 var h hash.Hash 285 switch x { 286 case 1: 287 h = hmac.New(sha1.New, secret) 288 case 256: 289 h = hmac.New(sha256.New, secret) 290 case 512: 291 h = hmac.New(sha512.New, secret) 292 default: 293 panic("[HmacShaX]`x must be in [1, 256, 512]") 294 } 295 296 // Write Data to it 297 h.Write(data) 298 299 src := h.Sum(nil) 300 dst := make([]byte, hex.EncodedLen(len(src))) 301 hex.Encode(dst, src) 302 303 return dst 304 } 305 306 // aesEncrypt AES加密. 307 // clearText为明文;key为密钥,长度16/24/32; 308 // mode为模式,枚举值(CBC,CFB,CTR,OFB); 309 // paddingType为填充方式,枚举(PKCS_NONE,PKCS_ZERO,PKCS_SEVEN),默认PKCS_SEVEN. 310 // 注意:返回的是一个字节切片指针. 311 func (ke *LkkEncrypt) aesEncrypt(clearText, key []byte, mode string, paddingType ...LkkPKCSType) ([]byte, error) { 312 block, err := aes.NewCipher(key) 313 if err != nil { 314 return nil, err 315 } 316 317 pt := PKCS_SEVEN 318 blockSize := block.BlockSize() 319 if len(paddingType) > 0 { 320 pt = paddingType[0] 321 } 322 323 switch pt { 324 case PKCS_ZERO: 325 clearText = zeroPadding(clearText, blockSize) 326 case PKCS_SEVEN: 327 clearText = pkcs7Padding(clearText, blockSize, false) 328 } 329 330 //字节切片指针 331 cipherText := make([]byte, blockSize+len(clearText)) 332 //初始化向量 333 iv := cipherText[:blockSize] 334 _, _ = io.ReadFull(rand.Reader, iv) 335 336 switch mode { 337 case "CBC": 338 cipher.NewCBCEncrypter(block, iv).CryptBlocks(cipherText[blockSize:], clearText) 339 case "CFB": 340 cipher.NewCFBEncrypter(block, iv).XORKeyStream(cipherText[blockSize:], clearText) 341 case "CTR": 342 cipher.NewCTR(block, iv).XORKeyStream(cipherText[blockSize:], clearText) 343 case "OFB": 344 cipher.NewOFB(block, iv).XORKeyStream(cipherText[blockSize:], clearText) 345 } 346 347 return cipherText, nil 348 } 349 350 // aesDecrypt AES解密. 351 // cipherText为密文;key为密钥,长度16/24/32; 352 // mode为模式,枚举值(CBC,CFB,CTR,OFB); 353 // paddingType为填充方式,枚举(PKCS_NONE,PKCS_ZERO,PKCS_SEVEN),默认PKCS_SEVEN. 354 func (ke *LkkEncrypt) aesDecrypt(cipherText, key []byte, mode string, paddingType ...LkkPKCSType) ([]byte, error) { 355 block, err := aes.NewCipher(key) 356 if err != nil { 357 return nil, err 358 } 359 360 pt := PKCS_SEVEN 361 if len(paddingType) > 0 { 362 pt = paddingType[0] 363 } 364 365 blockSize := block.BlockSize() 366 clen := len(cipherText) 367 if clen == 0 || clen < blockSize { 368 return nil, errors.New("[aesDecrypt]`cipherText too short") 369 } 370 371 iv := cipherText[:blockSize] 372 cipherText = cipherText[blockSize:] 373 originData := make([]byte, clen-blockSize) 374 switch mode { 375 case "CBC": 376 cipher.NewCBCDecrypter(block, iv).CryptBlocks(originData, cipherText) 377 case "CFB": 378 cipher.NewCFBDecrypter(block, iv).XORKeyStream(originData, cipherText) 379 case "CTR": 380 cipher.NewCTR(block, iv).XORKeyStream(originData, cipherText) 381 case "OFB": 382 cipher.NewOFB(block, iv).XORKeyStream(originData, cipherText) 383 } 384 385 clen = len(originData) 386 if pt != PKCS_NONE && clen > 0 && int(originData[clen-1]) > clen { 387 return nil, errors.New(fmt.Sprintf("[aesDecrypt] [%s] decrypt failed", mode)) 388 } 389 390 var plainText []byte 391 switch pt { 392 case PKCS_ZERO: 393 plainText = zeroUnPadding(originData) 394 case PKCS_SEVEN: 395 plainText = pkcs7UnPadding(originData, blockSize) 396 default: //case PKCS_NONE 397 plainText = originData 398 } 399 400 return plainText, nil 401 } 402 403 // AesCBCEncrypt AES-CBC密码分组链接(Cipher-block chaining)模式加密.加密无法并行,不适合对流数据加密. 404 // clearText为明文;key为密钥,长16/24/32;paddingType为填充方式,枚举(PKCS_ZERO,PKCS_SEVEN),默认PKCS_SEVEN. 405 func (ke *LkkEncrypt) AesCBCEncrypt(clearText, key []byte, paddingType ...LkkPKCSType) ([]byte, error) { 406 return ke.aesEncrypt(clearText, key, "CBC", paddingType...) 407 } 408 409 // AesCBCDecrypt AES-CBC密码分组链接(Cipher-block chaining)模式解密. 410 // cipherText为密文;key为密钥,长16/24/32;paddingType为填充方式,枚举(PKCS_NONE,PKCS_ZERO,PKCS_SEVEN),默认PKCS_SEVEN. 411 func (ke *LkkEncrypt) AesCBCDecrypt(cipherText, key []byte, paddingType ...LkkPKCSType) ([]byte, error) { 412 return ke.aesDecrypt(cipherText, key, "CBC", paddingType...) 413 } 414 415 // AesCFBEncrypt AES-CFB密文反馈(Cipher feedback)模式加密.适合对流数据加密. 416 // clearText为明文;key为密钥,长16/24/32. 417 func (ke *LkkEncrypt) AesCFBEncrypt(clearText, key []byte) ([]byte, error) { 418 return ke.aesEncrypt(clearText, key, "CFB", PKCS_NONE) 419 } 420 421 // AesCFBDecrypt AES-CFB密文反馈(Cipher feedback)模式解密. 422 // cipherText为密文;key为密钥,长16/24/32. 423 func (ke *LkkEncrypt) AesCFBDecrypt(cipherText, key []byte) ([]byte, error) { 424 return ke.aesDecrypt(cipherText, key, "CFB", PKCS_NONE) 425 } 426 427 // AesCTREncrypt AES-CTR计算器(Counter)模式加密. 428 // clearText为明文;key为密钥,长16/24/32. 429 func (ke *LkkEncrypt) AesCTREncrypt(clearText, key []byte) ([]byte, error) { 430 return ke.aesEncrypt(clearText, key, "CTR", PKCS_NONE) 431 } 432 433 // AesCTRDecrypt AES-CTR计算器(Counter)模式解密. 434 // cipherText为密文;key为密钥,长16/24/32. 435 func (ke *LkkEncrypt) AesCTRDecrypt(cipherText, key []byte) ([]byte, error) { 436 return ke.aesDecrypt(cipherText, key, "CTR", PKCS_NONE) 437 } 438 439 // AesOFBEncrypt AES-OFB输出反馈(Output feedback)模式加密.适合对流数据加密. 440 // clearText为明文;key为密钥,长16/24/32. 441 func (ke *LkkEncrypt) AesOFBEncrypt(clearText, key []byte) ([]byte, error) { 442 return ke.aesEncrypt(clearText, key, "OFB", PKCS_NONE) 443 } 444 445 // AesOFBDecrypt AES-OFB输出反馈(Output feedback)模式解密. 446 // cipherText为密文;key为密钥,长16/24/32. 447 func (ke *LkkEncrypt) AesOFBDecrypt(cipherText, key []byte) ([]byte, error) { 448 return ke.aesDecrypt(cipherText, key, "OFB", PKCS_NONE) 449 } 450 451 // GenerateRsaKeys 生成RSA密钥对.bits为密钥位数,通常为1024或2048. 452 func (ke *LkkEncrypt) GenerateRsaKeys(bits int) (private []byte, public []byte, err error) { 453 // 生成私钥文件 454 var privateKey *rsa.PrivateKey 455 privateKey, err = rsa.GenerateKey(rand.Reader, bits) 456 if err != nil { 457 return 458 } 459 derStream := x509.MarshalPKCS1PrivateKey(privateKey) 460 block := &pem.Block{ 461 Type: "RSA PRIVATE KEY", 462 Bytes: derStream, 463 } 464 privateBuff := new(bytes.Buffer) 465 _ = pem.Encode(privateBuff, block) 466 467 // 生成公钥文件 468 var derPkix []byte 469 publicKey := &privateKey.PublicKey 470 derPkix, _ = x509.MarshalPKIXPublicKey(publicKey) 471 block = &pem.Block{ 472 Type: "RSA PUBLIC KEY", 473 Bytes: derPkix, 474 } 475 publicBuff := new(bytes.Buffer) 476 _ = pem.Encode(publicBuff, block) 477 478 private = privateBuff.Bytes() 479 public = publicBuff.Bytes() 480 481 return 482 } 483 484 // RsaPublicEncrypt RSA公钥加密. 485 // clearText为明文,publicKey为公钥. 486 func (ke *LkkEncrypt) RsaPublicEncrypt(clearText, publicKey []byte) ([]byte, error) { 487 // 解密pem格式的公钥 488 block, _ := pem.Decode(publicKey) 489 if block == nil { 490 return nil, errors.New("[RsaPublicEncrypt]`public key error") 491 } 492 493 // 解析公钥 494 pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) 495 if err != nil { 496 return nil, err 497 } 498 499 // 类型断言 500 pubKey := pubInterface.(*rsa.PublicKey) 501 //加密 502 return rsa.EncryptPKCS1v15(rand.Reader, pubKey, clearText) 503 } 504 505 // RsaPrivateDecrypt RSA私钥解密.比加密耗时. 506 // cipherText为密文,privateKey为私钥. 507 func (ke *LkkEncrypt) RsaPrivateDecrypt(cipherText, privateKey []byte) ([]byte, error) { 508 // 获取私钥 509 block, _ := pem.Decode(privateKey) 510 if block == nil { 511 return nil, errors.New("[RsaPrivateDecrypt]`private key error!") 512 } 513 514 // 解析PKCS1格式的私钥 515 priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) 516 if err != nil { 517 return nil, err 518 } 519 520 // 解密 521 return rsa.DecryptPKCS1v15(rand.Reader, priv, cipherText) 522 } 523 524 // RsaPrivateEncrypt RSA私钥加密.比解密耗时. 525 // clearText为明文,privateKey为私钥. 526 func (ke *LkkEncrypt) RsaPrivateEncrypt(clearText, privateKey []byte) ([]byte, error) { 527 // 获取私钥 528 block, _ := pem.Decode(privateKey) 529 if block == nil { 530 return nil, errors.New("[RsaPrivateEncrypt]`private key error!") 531 } 532 533 // 解析PKCS1格式的私钥 534 priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) 535 if err != nil { 536 return nil, err 537 } 538 539 return rsa.SignPKCS1v15(nil, priv, crypto.Hash(0), clearText) 540 } 541 542 // RsaPublicDecrypt RSA公钥解密. 543 // cipherText为密文,publicKey为公钥. 544 func (ke *LkkEncrypt) RsaPublicDecrypt(cipherText, publicKey []byte) ([]byte, error) { 545 // 解密pem格式的公钥 546 block, _ := pem.Decode(publicKey) 547 if block == nil { 548 return nil, errors.New("[RsaPublicDecrypt]`public key error") 549 } 550 551 // 解析公钥 552 pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) 553 if err != nil { 554 return nil, err 555 } 556 557 // 类型断言 558 pubKey := pubInterface.(*rsa.PublicKey) 559 560 c := new(big.Int) 561 m := new(big.Int) 562 m.SetBytes(cipherText) 563 e := big.NewInt(int64(pubKey.E)) 564 c.Exp(m, e, pubKey.N) 565 out := c.Bytes() 566 olen := len(out) 567 skip := 0 568 for i := 2; i < olen; i++ { 569 if (i+1 < olen) && out[i] == 0xff && out[i+1] == 0 { 570 skip = i + 2 571 break 572 } 573 } 574 575 return out[skip:], nil 576 }