crypt.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // +build !confonly
  2. package kcp
  3. import (
  4. "crypto/cipher"
  5. "encoding/binary"
  6. "hash/fnv"
  7. "github.com/v2fly/v2ray-core/v4/common"
  8. )
  9. // SimpleAuthenticator is a legacy AEAD used for KCP encryption.
  10. type SimpleAuthenticator struct{}
  11. // NewSimpleAuthenticator creates a new SimpleAuthenticator
  12. func NewSimpleAuthenticator() cipher.AEAD {
  13. return &SimpleAuthenticator{}
  14. }
  15. // NonceSize implements cipher.AEAD.NonceSize().
  16. func (*SimpleAuthenticator) NonceSize() int {
  17. return 0
  18. }
  19. // Overhead implements cipher.AEAD.NonceSize().
  20. func (*SimpleAuthenticator) Overhead() int {
  21. return 6
  22. }
  23. // Seal implements cipher.AEAD.Seal().
  24. func (a *SimpleAuthenticator) Seal(dst, nonce, plain, extra []byte) []byte {
  25. dst = append(dst, 0, 0, 0, 0, 0, 0) // 4 bytes for hash, and then 2 bytes for length
  26. binary.BigEndian.PutUint16(dst[4:], uint16(len(plain)))
  27. dst = append(dst, plain...)
  28. fnvHash := fnv.New32a()
  29. common.Must2(fnvHash.Write(dst[4:]))
  30. fnvHash.Sum(dst[:0])
  31. dstLen := len(dst)
  32. xtra := 4 - dstLen%4
  33. if xtra != 4 {
  34. dst = append(dst, make([]byte, xtra)...)
  35. }
  36. xorfwd(dst)
  37. if xtra != 4 {
  38. dst = dst[:dstLen]
  39. }
  40. return dst
  41. }
  42. // Open implements cipher.AEAD.Open().
  43. func (a *SimpleAuthenticator) Open(dst, nonce, cipherText, extra []byte) ([]byte, error) {
  44. dst = append(dst, cipherText...)
  45. dstLen := len(dst)
  46. xtra := 4 - dstLen%4
  47. if xtra != 4 {
  48. dst = append(dst, make([]byte, xtra)...)
  49. }
  50. xorbkd(dst)
  51. if xtra != 4 {
  52. dst = dst[:dstLen]
  53. }
  54. fnvHash := fnv.New32a()
  55. common.Must2(fnvHash.Write(dst[4:]))
  56. if binary.BigEndian.Uint32(dst[:4]) != fnvHash.Sum32() {
  57. return nil, newError("invalid auth")
  58. }
  59. length := binary.BigEndian.Uint16(dst[4:6])
  60. if len(dst)-6 != int(length) {
  61. return nil, newError("invalid auth")
  62. }
  63. return dst[6:], nil
  64. }