I'm trying to encrypt a file with AES-256 using XTS mode & Golang. I just moved from CTR mode to XTS recently and I'm facing this error
A nice-to-have, my code snippet:
func Encrypt(loc string, k *kyber.Kyber) (esK string, err error) {
in, err := os.Open(loc)
if err != nil {
return "", err
}
defer in.Close()
out, err := os.Create(loc + EncryptExtension)
if err != nil {
return "", err
}
defer out.Close()
sK, esK, err := k.SecretKey()
if err != nil {
return "", err
}
cipher, err := xts.NewCipher(aes.NewCipher, sK) // sK = 32 bytes
if err != nil {
return "", err
}
pT := make([]byte, BufferSize) // BufferSize = 2 * 1024 * 1024 = 2MB
for {
len, err := in.Read(pT)
if err != nil && err != io.EOF {
return "", err
}
if len == 0 {
break
}
cT := make([]byte, len)
cipher.Encrypt(cT, pT[:len], 0) // When len % 16 != 0 the code just panic
if _, err := out.Write(cT); err != nil {
return "", err
}
}
return esK, nil
}
I know what the error means, and I know a workaround to fix it, but the main question here is, isn't XTS designed to handle arbitrary data length? Why doesn't Golang follow that?
According to NIST 800-38E
The XTS-AES mode was designed for the cryptographic protection of data on storage devices that use of fixed length “data units”.
The x/crypto/xts library explicitly states the following (link):
This package does not implement ciphertext-stealing so sectors must be a multiple of 16 bytes.
The original CL that contributed the initial code from over 10 years ago never included support for ciphertext stealing, and it did not provide the reason why. It was likely omitted due to complexity.