gitea

Development moved to Codeberg

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
  101. 101
  102. 102
  103. 103
  104. 104
  105. 105
  106. 106
  107. 107
  108. 108
  109. 109
  110. 110
  111. 111
  112. 112
  113. 113
  114. 114
  115. 115
  116. 116
  117. 117
  118. 118
  119. 119
  120. 120
  121. 121
  122. 122
  123. 123
  124. 124
  125. 125
  126. 126
package rardecode

import (
	"crypto/aes"
	"crypto/cipher"
	"io"
)

// cipherBlockReader implements Block Mode decryption of an io.Reader object.
type cipherBlockReader struct {
	r      io.Reader
	mode   cipher.BlockMode
	inbuf  []byte // input buffer for partial data block
	outbuf []byte // output buffer used when output slice < block size
	n      int    // bytes read from outbuf
	err    error
}

// read reads and decrypts one or more input blocks into p.
// len(p) must be >= cipher block size.
func (cr *cipherBlockReader) read(p []byte) (n int, err error) {
	bs := cr.mode.BlockSize()
	// round p down to a multiple of the block size
	l := len(p) - len(p)%bs
	p = p[:l]

	l = len(cr.inbuf)
	if l > 0 {
		// copy any buffered input into p
		copy(p, cr.inbuf)
		cr.inbuf = cr.inbuf[:0]
	}
	// read data for at least one block
	n, err = io.ReadAtLeast(cr.r, p[l:], bs-l)
	n += l
	p = p[:n]

	l = n % bs
	// check if p is a multiple of the cipher block size
	if l > 0 {
		n -= l
		// save trailing partial block to process later
		cr.inbuf = append(cr.inbuf, p[n:]...)
		p = p[:n]
	}

	if err != nil {
		if err == io.ErrUnexpectedEOF || err == io.ErrShortBuffer {
			// ignore trailing bytes < block size length
			err = io.EOF
		}
		return 0, err
	}
	cr.mode.CryptBlocks(p, p) // decrypt block(s)
	return n, nil
}

// Read reads and decrypts data into p.
// If the input is not a multiple of the cipher block size,
// the trailing bytes will be ignored.
func (cr *cipherBlockReader) Read(p []byte) (n int, err error) {
	for {
		if cr.n < len(cr.outbuf) {
			// return buffered output
			n = copy(p, cr.outbuf[cr.n:])
			cr.n += n
			return n, nil
		}
		if cr.err != nil {
			err = cr.err
			cr.err = nil
			return 0, err
		}
		if len(p) >= cap(cr.outbuf) {
			break
		}
		// p is not large enough to process a block, use outbuf instead
		n, cr.err = cr.read(cr.outbuf[:cap(cr.outbuf)])
		cr.outbuf = cr.outbuf[:n]
		cr.n = 0
	}
	// read blocks into p
	return cr.read(p)
}

// ReadByte returns the next decrypted byte.
func (cr *cipherBlockReader) ReadByte() (byte, error) {
	for {
		if cr.n < len(cr.outbuf) {
			c := cr.outbuf[cr.n]
			cr.n++
			return c, nil
		}
		if cr.err != nil {
			err := cr.err
			cr.err = nil
			return 0, err
		}
		// refill outbuf
		var n int
		n, cr.err = cr.read(cr.outbuf[:cap(cr.outbuf)])
		cr.outbuf = cr.outbuf[:n]
		cr.n = 0
	}
}

// newCipherBlockReader returns a cipherBlockReader that decrypts the given io.Reader using
// the provided block mode cipher.
func newCipherBlockReader(r io.Reader, mode cipher.BlockMode) *cipherBlockReader {
	cr := &cipherBlockReader{r: r, mode: mode}
	cr.outbuf = make([]byte, 0, mode.BlockSize())
	cr.inbuf = make([]byte, 0, mode.BlockSize())
	return cr
}

// newAesDecryptReader returns a cipherBlockReader that decrypts input from a given io.Reader using AES.
// It will panic if the provided key is invalid.
func newAesDecryptReader(r io.Reader, key, iv []byte) *cipherBlockReader {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	mode := cipher.NewCBCDecrypter(block, iv)

	return newCipherBlockReader(r, mode)
}