153 lines
3.8 KiB
Go
153 lines
3.8 KiB
Go
|
|
|
|
// chaPolyShrink provides functions to encrypt or decrypt bytes using ChaPolyShrink
|
|
// ChaPolyShrink first compresses bytes using zlib, adds padding to obscure size of encrypted bytes, and ciphers data using chaPoly
|
|
|
|
package chaPolyShrink
|
|
|
|
import "encoding/binary"
|
|
import "golang.org/x/crypto/chacha20poly1305"
|
|
import "compress/zlib"
|
|
import "crypto/rand"
|
|
import "errors"
|
|
import "bytes"
|
|
import "io"
|
|
import "slices"
|
|
|
|
// A paddingSize is specified, which adds padding so that resulting encrypted result size is divisible by paddingSize
|
|
|
|
//Outputs:
|
|
// -[]byte: ChaPoly Encrypted bytes
|
|
// -error
|
|
func EncryptChaPolyShrink(input []byte, key [32]byte, nonce [24]byte, compressContent bool, paddingSize int, includeAdditionalData bool, additionalData [32]byte)([]byte, error){
|
|
|
|
if (paddingSize > 10000000 || paddingSize < 0) {
|
|
return nil, errors.New("EncryptChaPolyShrink called with invalid paddingSize.")
|
|
}
|
|
|
|
getCompressionStrength := func()int{
|
|
if (compressContent == false){
|
|
return 0
|
|
}
|
|
return 9
|
|
}
|
|
|
|
compressionStrength := getCompressionStrength()
|
|
|
|
var compressedBuffer bytes.Buffer
|
|
|
|
compressorWriter, err := zlib.NewWriterLevel(&compressedBuffer, compressionStrength)
|
|
if (err != nil) { return nil, err }
|
|
compressorWriter.Write(input)
|
|
compressorWriter.Close()
|
|
|
|
compressedBytes := compressedBuffer.Bytes()
|
|
|
|
compressedBytesLength := len(compressedBytes)
|
|
|
|
getNeededPaddingLength := func()int{
|
|
|
|
if (paddingSize == 0){
|
|
return 0
|
|
}
|
|
|
|
if (compressedBytesLength < paddingSize){
|
|
paddingLength := paddingSize - compressedBytesLength
|
|
return paddingLength
|
|
}
|
|
|
|
remainder := compressedBytesLength % paddingSize
|
|
|
|
if (remainder == 0){
|
|
return 0
|
|
}
|
|
|
|
paddingLengthInBytes := paddingSize - remainder
|
|
|
|
return paddingLengthInBytes
|
|
}
|
|
|
|
neededPaddingLength := getNeededPaddingLength()
|
|
|
|
paddingLengthUint32 := uint32(neededPaddingLength)
|
|
|
|
paddingLengthHeader := make([]byte, 4)
|
|
|
|
binary.LittleEndian.PutUint32(paddingLengthHeader, paddingLengthUint32)
|
|
|
|
paddingBytes := make([]byte, neededPaddingLength)
|
|
_, err = rand.Read(paddingBytes[:])
|
|
if (err != nil){ return nil, err }
|
|
|
|
compressedBytesWithPaddingAndHeader := slices.Concat(paddingLengthHeader, paddingBytes, compressedBytes)
|
|
|
|
getAdditionalDataParameter := func()[]byte{
|
|
if (includeAdditionalData == false){
|
|
return nil
|
|
}
|
|
|
|
result := additionalData[:]
|
|
|
|
return result
|
|
}
|
|
|
|
additionalDataParameter := getAdditionalDataParameter()
|
|
|
|
cipherObject, err := chacha20poly1305.NewX(key[:])
|
|
if (err != nil) { return nil, err }
|
|
|
|
encryptedMessage := cipherObject.Seal(nil, nonce[:], compressedBytesWithPaddingAndHeader, additionalDataParameter)
|
|
|
|
return encryptedMessage, nil
|
|
}
|
|
|
|
|
|
//Outputs:
|
|
// -bool: Able to decrypt
|
|
// -[]byte: Decrypted bytes
|
|
// -error (will return error if inputs are invalid)
|
|
func DecryptChaPolyShrink(inputBytes []byte, key [32]byte, nonce [24]byte, additionalDataExists bool, additionalData [32]byte)(bool, []byte, error){
|
|
|
|
getAdditionalDataParameter := func()[]byte{
|
|
if (additionalDataExists == false){
|
|
return nil
|
|
}
|
|
|
|
result := additionalData[:]
|
|
|
|
return result
|
|
}
|
|
|
|
additionalDataParameter := getAdditionalDataParameter()
|
|
|
|
cipherObject, err := chacha20poly1305.NewX(key[:])
|
|
if (err != nil) { return false, nil, err }
|
|
|
|
decryptedBytes, err := cipherObject.Open(nil, nonce[:], inputBytes, additionalDataParameter)
|
|
if (err != nil) {
|
|
return false, nil, nil
|
|
}
|
|
|
|
paddingHeader := decryptedBytes[:4]
|
|
|
|
paddingBytesUint32 := binary.LittleEndian.Uint32(paddingHeader[:])
|
|
|
|
endOfPaddingIndex := 4 + paddingBytesUint32
|
|
|
|
compressedBytes := decryptedBytes[endOfPaddingIndex:]
|
|
compressedBytesReader := bytes.NewReader(compressedBytes)
|
|
|
|
decompressedReader, err := zlib.NewReader(compressedBytesReader)
|
|
if (err != nil) {
|
|
return false, nil, nil
|
|
}
|
|
|
|
decompressedBytes, err := io.ReadAll(decompressedReader)
|
|
if (err != nil) {
|
|
return false, nil, nil
|
|
}
|
|
|
|
return true, decompressedBytes, nil
|
|
}
|
|
|
|
|