Skip to content

Instantly share code, notes, and snippets.

@vadv
Created August 1, 2018 08:38
Show Gist options
  • Save vadv/5da9d468a51f72ba482b8c91e1f0b982 to your computer and use it in GitHub Desktop.
Save vadv/5da9d468a51f72ba482b8c91e1f0b982 to your computer and use it in GitHub Desktop.
package crypto
import (
"bytes"
"crypto/aes"
"fmt"
"io"
)
// читаем из io.Reader размером size и записываем в io.Writer дешифрованный поток ключом key
func (aesKey *CBCAesKey) DeCryptoStream(reader io.Reader, writer io.Writer, limitSize uint64) (uint64, error) {
if aes.BlockSize > limitSize {
return 0, fmt.Errorf("размер запрашиваемого сегмента для расшифровывания маленький: %d", limitSize)
}
// вычитываем полностью в память
readBuff := make([]byte, int64(limitSize))
readCount, err := reader.Read(readBuff)
if err != nil && err != io.EOF {
return 0, fmt.Errorf("при чтении возникла ошибка: %s", err.Error())
}
if readCount != int(limitSize) {
return 0, fmt.Errorf("прочитано %d из %d", readCount, limitSize)
}
// создаем буфер
readBuffBytes := bytes.NewBuffer(nil)
readBuffBytes.Write(readBuff[0:readCount])
outBlockCount := readBuffBytes.Len() / int(aes.BlockSize)
outSize := (outBlockCount - 1) * int(aes.BlockSize)
outBuff := make([]byte, (outBlockCount-1)*int(aes.BlockSize))
// обрабатываем данные
aesKey.emb.CryptBlocks(outBuff, readBuffBytes.Next(int(outSize)))
// то что обработали пишем во врайтер
writeCount, writeErr := writer.Write(outBuff)
if writeErr != nil {
// если произошла ошбка записи, то выходим
return uint64(writeCount), writeErr
}
// обрабатываем остатки
if readBuffBytes.Len() != int(aes.BlockSize) {
return uint64(writeCount), fmt.Errorf("последний блок не выровнен на 16: %d", readBuffBytes.Len())
}
outBuff = make([]byte, int(aes.BlockSize))
aesKey.emb.CryptBlocks(outBuff, readBuffBytes.Next(int(aes.BlockSize)))
err, outBuff = aesKey.testEndBlocks(outBuff)
if err != nil {
return uint64(writeCount), err
}
// записываем последние блоки
if writeCountTmp, writeErr := writer.Write(outBuff); writeErr != nil {
return uint64(writeCountTmp + writeCount), writeErr
} else {
writeCount += writeCountTmp
}
return uint64(writeCount), nil
}
// декодирование последнего блока
func (aesKey *CBCAesKey) testEndBlocks(dst []byte) (error, []byte) {
end := int(dst[15])
switch {
case end > 0 && end < 17:
tests_bytes := dst[int(aes.BlockSize)-end : 16]
for _, b := range tests_bytes {
if b != dst[15] {
return fmt.Errorf("последний блок данных не корректный, невозможно расшифровать %x", dst), nil
}
}
default:
return fmt.Errorf("последний блок данных не корректный, невозможно расшифровать %x", dst), nil
}
return nil, dst[0 : int(aes.BlockSize)-end]
}
package crypto
import (
"crypto/aes"
"crypto/cipher"
"fmt"
)
type CBCAesKey struct {
key, iv []byte
position uint64
emb cipher.BlockMode
}
func NewCBCAESKey(key []byte, ivPosition uint64) (*CBCAesKey, error) {
ivUint128 := Uint128{H: 0, L: uint64(ivPosition)}
iv := ivUint128.Bytes()
if len(key) != 16 || len(iv) != 16 {
return nil, fmt.Errorf("Некоректный формат ключа\\вектора нужно 16 байт передано key = %d, iv = %d", len(key), len(iv))
}
block, err := aes.NewCipher(key[0:16])
if err != nil {
return nil, err
}
return &CBCAesKey{emb: cipher.NewCBCDecrypter(block, iv), key: key, iv: iv, position: ivPosition}, nil
}
func (c *CBCAesKey) GetKey() []byte {
return c.key
}
func (c *CBCAesKey) GetPosition() uint64 {
return c.position
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment