Files
syscrypt/internal/actions/encrypt/encrypt.go

830 lines
21 KiB
Go
Raw Normal View History

package encrypt
import (
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"os"
"strings"
"github.com/cloudflare/circl/kem/kyber/kyber768"
"golang.org/x/crypto/argon2"
cc20 "golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519"
"golang.org/x/crypto/hkdf"
"sources.truenas.cloud/code/syscrypt"
"sources.truenas.cloud/code/syscrypt/internal/utils"
"sources.truenas.cloud/code/syscrypt/internal/vars"
)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func Validate() {
encryptAllowedFlags := map[string]struct{}{
"-C": {},
"-L": {},
"-a": {},
"-k": {},
"-i": {},
"-c": {},
"-o": {},
"-A": {},
"-P": {},
"-PQ": {},
}
for _, arg := range os.Args {
if arg == "-L" {
encryptAllowedFlags["-A"] = struct{}{}
encryptAllowedFlags["-P"] = struct{}{}
break
}
}
utils.ValidateAllowedFlags(encryptAllowedFlags)
encryptRequiredFlags := map[string]bool{
"-k": true,
"-i": true,
"-o": true,
}
for _, arg := range os.Args {
if arg == "-L" {
encryptRequiredFlags["-A"] = true
encryptRequiredFlags["-P"] = true
break
}
}
//utils.ValidateRequiredFlags(encryptRequiredFlags, "encrypt")
isKeySet, keyHasValue := utils.IsFlagPassed("k")
keyValue, _ := utils.GetFlagValue("k")
keyIsValidPath := utils.IsValidPath(keyValue)
isInputSet, inputHasValue := utils.IsFlagPassed("i")
inputValue, _ := utils.GetFlagValue("i")
inputIsValidPath := utils.IsValidPath(inputValue)
isOutputSet, outputHasValue := utils.IsFlagPassed("o")
outputValue, _ := utils.GetFlagValue("o")
outputIsValidPath := utils.IsValidPath(outputValue)
outputFileExists := utils.FileExists(outputValue)
isArmoredSet, armoredHasValue := utils.IsFlagPassed("a")
isLockSet, lockHasValue := utils.IsFlagPassed("L")
lockValue, _ := utils.GetFlagValue("L")
_ = lockValue
isAPISet, _ := utils.IsFlagPassed("A")
apiValue, _ := utils.GetFlagValue("A")
apiIsValidPath := utils.IsValidPath(apiValue)
apiFileExists := utils.FileExists(apiValue)
//isPassSet, _ := utils.IsFlagPassed("P")
//passValue, _ := utils.GetFlagValue("P")
//passIsValidPath := utils.IsValidPath(passValue)
///////////////////////////////////////////////////////////
// -- Key
if isKeySet && !keyHasValue {
msg := fmt.Sprintf("%s: -k KEY: Requires a value.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
if isKeySet && !keyIsValidPath {
msg := fmt.Sprintf("%s: -k KEY: Requires a valid file path.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
keyExists := utils.FileExists(keyValue)
if !keyExists {
msg := fmt.Sprintf("%s: -k KEY: Key file does not exist.\n%s\n", vars.CommandFlag, keyValue)
utils.HandleFailure(msg)
os.Exit(1)
}
// -- Input
if isInputSet && !inputHasValue {
msg := fmt.Sprintf("%s: -i INPUT: Requires a value.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
if isInputSet && !inputIsValidPath {
msg := fmt.Sprintf("%s: -i INPUT: Requires a valid file path.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
inputExists := utils.FileExists(inputValue)
if !inputExists {
msg := fmt.Sprintf("%s: -i INPUT: Input file does not exist \n%s\n", vars.CommandFlag, inputValue)
utils.HandleFailure(msg)
os.Exit(1)
}
// -- Output
if isOutputSet && !outputHasValue {
msg := fmt.Sprintf("%s: -o OUTPUT: Requires a value.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
if isOutputSet && !outputIsValidPath {
msg := fmt.Sprintf("%s: -o OUTPUT: Requires a valid file path.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
// -- Armored
if isArmoredSet && armoredHasValue {
msg := fmt.Sprintf("%s: -a ARMORED: Armored does not support a value.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
// -- Lock
if isLockSet && lockHasValue {
msg := fmt.Sprintf("%s: -L LOCK: Lock does not support a value.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
if isLockSet && !isAPISet {
msg := fmt.Sprintf("%s: -L LOCK: Lock requires the -A APIKEY flag and value to be set.", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
//if isLockSet && !isPassSet {
// msg := fmt.Sprintf("%s: -L LOCK: Lock requires the -P MASTER PASSWORD flag and value to be set.", vars.CommandFlag)
// utils.HandleFailure(msg)
// os.Exit(1)
//}
// -- API
if isLockSet && apiValue == "" {
msg := fmt.Sprintf("%s: -A APIKEY: Requires a value.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
if isLockSet && !apiIsValidPath {
msg := fmt.Sprintf("%s: -A APIKEY: Requires a valid file path.\n", vars.CommandFlag)
utils.HandleFailure(msg)
os.Exit(1)
}
if isLockSet && !apiFileExists {
msg := fmt.Sprintf("%s: -A APIKEY: Key file does not exist.\n%s\n", vars.CommandFlag, apiValue)
utils.HandleFailure(msg)
os.Exit(1)
}
// -- Password
//if isLockSet && passValue == "" {
// msg := fmt.Sprintf("%s: -P MASTER PASSWORD: Requires a value.\n", vars.CommandFlag)
// utils.HandleFailure(msg)
// os.Exit(1)
//}
if isLockSet {
//masterPass := config.MasterPass
//masterPassIsValidPath := utils.IsValidPath(masterPass)
//if masterPass == "" {
// msg := fmt.Sprintf("%s: Unable to determine location of the Master Password file.\nUnable to continue.\n"+
// "Please run syscrypt -c keygen again to generate the default keys.", vars.CommandFlag)
// utils.HandleFailure(msg)
// os.Exit(1)
//}
//if !masterPassIsValidPath {
// msg := fmt.Sprintf("%s: Invalid Master Password location.\n%s"+
// "Please run syscrypt -c keygen again to generate the default keys.", vars.CommandFlag, masterPass)
// utils.HandleFailure(msg)
// os.Exit(1)
//}
}
//if isLockSet && !passIsValidPath {
// msg := fmt.Sprintf("%s: -P MASTER PASSWORD: Requires a valid file path.\n", vars.CommandFlag)
// utils.HandleFailure(msg)
// os.Exit(1)
//}
if outputFileExists {
utils.ConfirmOverwrite(outputValue)
}
///////////////////////////////////////////////////////////
fmt.Printf("\n\n")
fmt.Printf("keyset: %v\n", isKeySet)
fmt.Printf("keyvalue: %v\n", keyValue)
fmt.Printf("keyvalidpath: %v\n", keyIsValidPath)
fmt.Printf("\n")
fmt.Printf("inputset: %v\n", isInputSet)
fmt.Printf("inputvalue: %v\n", inputValue)
fmt.Printf("inputvalidpath: %v\n", inputIsValidPath)
fmt.Printf("\n")
fmt.Printf("outputset: %v\n", isOutputSet)
fmt.Printf("outputvalue: %v\n", outputValue)
fmt.Printf("outputvalidpath: %v\n", outputIsValidPath)
fmt.Printf("\n")
// Open Files
keyBytes, err := os.ReadFile(keyValue)
if err != nil {
fmt.Printf("Error: Could not read key file at %s\n", keyValue)
}
var pub syscrypt.PublicKeyWrapper
err = json.Unmarshal(keyBytes, &pub)
if err != nil {
fmt.Printf("Error: key file is not a valid syscrypt JSON: %v\n", err)
os.Exit(1)
}
EncryptFile(outputValue, inputValue, pub)
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func zeroize(data []byte) {
for i := range data {
data[i] = 0
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const PassTagSize = 28
// func EncryptFile(dst io.Writer, src io.Reader, pub syscrypt.PublicKeyWrapper) {
func EncryptFile(outputValue string, inputValue string, pub syscrypt.PublicKeyWrapper) {
// Get Values
isLockSet, _ := utils.IsFlagPassed("L")
isArmoredSet, _ := utils.IsFlagPassed("a")
keyValue, _ := utils.GetFlagValue("k")
passValue, _ := utils.GetFlagValue("P")
apiIsSet, _ := utils.IsFlagPassed("A")
apiValue, _ := utils.GetFlagValue("A")
serialKey, _ := utils.FetchFileKey(keyValue, "serial")
src, _ := os.Open(inputValue)
plaintext, _ := io.ReadAll(src)
src.Close()
// Keys
cleanPubX := strings.TrimPrefix(pub.PublicKey.Key, vars.DefaultPrefixLabel)
recipientPubX, _ := hex.DecodeString(cleanPubX)
ephPrivX := make([]byte, 32)
io.ReadFull(rand.Reader, ephPrivX)
ephPubX, _ := curve25519.X25519(ephPrivX, curve25519.Basepoint)
sharedX, _ := curve25519.X25519(ephPrivX, recipientPubX)
var kyberCT []byte
var sharedML []byte
isHybrid := pub.PublicKey.MLKEMKey != ""
if isHybrid {
scheme := kyber768.Scheme()
cleanML := strings.TrimPrefix(pub.PublicKey.MLKEMKey, vars.PQPublicKeyPrefixLabel)
pkBytes, err := hex.DecodeString(cleanML)
if err != nil {
fmt.Printf("Hex Decode Error: %v\n", err)
return
}
pkK, err := scheme.UnmarshalBinaryPublicKey(pkBytes)
if err != nil {
fmt.Printf("Error: kyber key unmarshal fail: %v\n", err)
return
}
kyberCT, sharedML, err = scheme.Encapsulate(pkK)
if err != nil {
fmt.Printf("Error: Kyber encapsulation failed: %v\n", err)
}
}
// Password Tag Generation
var passKey, passVerifyTag []byte
if isLockSet {
apiKey, _ := utils.FetchFileKey(apiValue, "key")
passKey = argon2.IDKey([]byte(passValue), []byte(apiKey), 1, 64*1024, 4, 32)
vH := hkdf.New(sha256.New, passKey, nil, []byte("syscrypt-pass-verify"))
vKey := make([]byte, 32)
io.ReadFull(vH, vKey)
vAead, _ := cc20.New(vKey)
vNonce := make([]byte, 12)
passVerifyTag = vAead.Seal(nil, vNonce, []byte("SYSC-PASS-OK"), nil)
}
// Final Symmetric Key
combined := append(sharedX, sharedML...)
if isLockSet {
combined = append(combined, passKey...)
}
h := hkdf.New(sha256.New, combined, nil, []byte("syscrypt-v1-hybrid"))
symmKey := make([]byte, 32)
io.ReadFull(h, symmKey)
aead, _ := cc20.New(symmKey)
for i := range symmKey {
symmKey[i] = 0
}
nonce := make([]byte, 12)
io.ReadFull(rand.Reader, nonce)
ciphertext := aead.Seal(nil, nonce, plaintext, nil)
// Blinded Header Assembly
serialBytes := []byte(serialKey)
serialSize := len(serialBytes)
var mode byte
if isHybrid && isLockSet {
mode = 0x04
} else if isHybrid {
mode = 0x03
} else if isLockSet {
mode = 0x02
} else {
mode = 0x01
}
var finalBlob []byte
finalBlob = append(finalBlob, mode^ephPubX[0])
finalBlob = append(finalBlob, byte(serialSize)^ephPubX[1])
finalBlob = append(finalBlob, ephPubX...)
for i := 0; i < serialSize; i++ {
finalBlob = append(finalBlob, serialBytes[i]^ephPubX[(i+2)%32])
}
if isLockSet {
finalBlob = append(finalBlob, passVerifyTag...)
}
if isHybrid {
finalBlob = append(finalBlob, kyberCT...)
}
finalBlob = append(finalBlob, nonce...)
finalBlob = append(finalBlob, ciphertext...)
dst, err := os.Create(outputValue)
if err != nil {
fmt.Printf("Error: Unable to create output file %s", outputValue)
}
defer dst.Close()
if isArmoredSet {
dst.WriteString(vars.PrivateKeyHeader + "\n")
enc := base64.StdEncoding.EncodeToString(finalBlob)
for i := 0; i < len(enc); i += 64 {
end := i + 64
if end > len(enc) {
end = len(enc)
}
dst.WriteString(enc[i:end] + "\n")
}
dst.WriteString(vars.PrivateKeyFooter + "\n")
} else {
dst.Write(finalBlob)
}
_ = apiIsSet
fmt.Printf("Success: file saved at: %s\n", outputValue)
/*
// 1. Setup Flags
isLockSet, _ := utils.IsFlagPassed("L")
isAPISet, _ := utils.IsFlagPassed("A")
isArmoredSet, _ := utils.IsFlagPassed("a")
keyValue, _ := utils.GetFlagValue("k")
apiValue, _ := utils.GetFlagValue("A")
passValue, _ := utils.GetFlagValue("P")
// 2. Read Plaintext
src, _ := os.Open(inputValue)
plaintext, _ := io.ReadAll(src)
src.Close()
// 3. Classical Key Exchange (X25519)
cleanPubX := strings.TrimPrefix(pub.PublicKey.Key, "syscrypt-")
recipientPubX, _ := hex.DecodeString(cleanPubX)
ephPrivX := make([]byte, 32)
io.ReadFull(rand.Reader, ephPrivX)
ephPubX, _ := curve25519.X25519(ephPrivX, curve25519.Basepoint)
sharedX, _ := curve25519.X25519(ephPrivX, recipientPubX)
// 4. Post-Quantum Key Exchange (Kyber768)
//var kyberCT, sharedML []byte
//isHybrid := pub.PublicKey.MLKEMKey != ""
var kyberCT []byte
var sharedML []byte
isHybrid := pub.PublicKey.MLKEMKey != ""
if isHybrid {
scheme := kyber768.Scheme()
cleanML := strings.TrimPrefix(pub.PublicKey.MLKEMKey, "syscrypt-pq-")
pkBytes, err := hex.DecodeString(cleanML)
if err != nil {
fmt.Printf("Hex Decode Error: %v\n", err)
return
}
pkK, err := scheme.UnmarshalBinaryPublicKey(pkBytes)
if err != nil {
fmt.Printf("Error: kyber key unmarshal failed: %v\n", err)
return
}
var encapErr error
kyberCT, sharedML, encapErr = scheme.Encapsulate(pkK)
if encapErr != nil {
fmt.Printf("Error: Kyber encapsulation failed: %v\n", encapErr)
return
}
}
// 5. Entropy Binding
combined := append(sharedX, sharedML...)
if isLockSet {
var apiKey string
if isAPISet {
apiKey, _ = utils.FetchFileKey(apiValue, "key")
}
passKey := argon2.IDKey([]byte(passValue), []byte(apiKey), 1, 64*1024, 4, 32)
combined = append(combined, passKey...)
}
// 6. Key Derivation & Encryption
h := hkdf.New(sha256.New, combined, nil, []byte("syscrypt-v1-hybrid"))
symmetricKey := make([]byte, 32)
io.ReadFull(h, symmetricKey)
aead, _ := cc20.New(symmetricKey)
for i := range symmetricKey {
symmetricKey[i] = 0
}
nonce := make([]byte, aead.NonceSize())
io.ReadFull(rand.Reader, nonce)
ciphertext := aead.Seal(nil, nonce, plaintext, nil)
// 7. Metadata/Serial Masking
serialKey, _ := utils.FetchFileKey(keyValue, "serial")
serialBytes := []byte(serialKey)
serialSize := len(serialBytes)
maskedSerial := make([]byte, serialSize)
for i := 0; i < serialSize; i++ {
maskedSerial[i] = serialBytes[i] ^ ephPubX[i%32]
}
// 8. Determine Mode
var mode byte
if isHybrid && isLockSet {
mode = 0x04
} else if isHybrid {
mode = 0x03
} else if isLockSet {
mode = 0x02
} else {
mode = 0x01
}
// 9. Final Assembly
var finalBlob []byte
finalBlob = append(finalBlob, mode)
finalBlob = append(finalBlob, byte(serialSize))
finalBlob = append(finalBlob, maskedSerial...)
finalBlob = append(finalBlob, ephPubX...)
if isHybrid {
if len(kyberCT) != 1088 {
fmt.Printf("CRITICAL: kyberCT is %d bytes, expected 1088\n", len(kyberCT))
return
}
finalBlob = append(finalBlob, kyberCT...)
}
finalBlob = append(finalBlob, nonce...)
finalBlob = append(finalBlob, ciphertext...)
// 10. Write output
dst, _ := os.Create(outputValue)
defer dst.Close()
if isArmoredSet {
dst.WriteString(vars.PrivateKeyHeader + "\n")
encoded := base64.StdEncoding.EncodeToString(finalBlob)
for i := 0; i < len(encoded); i += 64 {
end := i + 64
if end > len(encoded) {
end = len(encoded)
}
dst.WriteString(encoded[i:end] + "\n")
}
dst.WriteString(vars.PrivateKeyFooter + "\n")
} else {
dst.Write(finalBlob)
}
fmt.Printf("File created: %s (mode %d, %d bytes)\n", outputValue, mode, len(finalBlob))
*/
/*
isLockSet, _ := utils.IsFlagPassed("L")
isAPISet, _ := utils.IsFlagPassed("A")
isPassSet, _ := utils.IsFlagPassed("P")
isArmoredSet, _ := utils.IsFlagPassed("a")
/////////
isKeyPassed, _ := utils.IsFlagPassed("k")
keyValue, _ := utils.GetFlagValue("k")
_ = isKeyPassed
//////////
// set values
apiValue, _ := utils.GetFlagValue("A")
passValue, _ := utils.GetFlagValue("P")
_ = passValue
var apiKey string
var pass string
if isAPISet {
apiKey, _ = utils.FetchFileKey(apiValue, "key")
}
if isPassSet {
pass = ""
}
//isInputSet, inputHasValue := utils.IsFlagPassed("i")
//inputValue, _ := utils.GetFlagValue("i")
src, _ := os.Open(inputValue)
plaintext, _ := io.ReadAll(src)
cleanPub := strings.TrimPrefix(pub.PublicKey.Key, "syscrypt")
recipientPubX, _ := hex.DecodeString(cleanPub)
ephPrivX := make([]byte, 32)
io.ReadFull(rand.Reader, ephPrivX)
ephPubX, _ := curve25519.X25519(ephPrivX, curve25519.Basepoint)
sharedX, _ := curve25519.X25519(ephPrivX, recipientPubX)
var kyberCT, sharedML []byte
isHybrid := pub.PublicKey.MLKEMKey != ""
if isHybrid {
scheme := kyber768.Scheme()
pkBytes, _ := hex.DecodeString(pub.PublicKey.MLKEMKey)
pkK, _ := scheme.UnmarshalBinaryPublicKey(pkBytes)
sharedML, kyberCT, _ = scheme.Encapsulate(pkK)
}
combined := append(sharedX, sharedML...)
if isLockSet {
passKey := argon2.IDKey([]byte(pass), []byte(apiKey), 1, 64*1024, 4, 32)
combined = append(combined, passKey...)
zeroize(passKey)
}
h := hkdf.New(sha256.New, combined, nil, []byte("syscrypt-v1-hybrid"))
symmetricKey := make([]byte, 32)
io.ReadFull(h, symmetricKey)
zeroize(symmetricKey)
aead, _ := cc20.New(symmetricKey)
nonce := make([]byte, aead.NonceSize())
io.ReadFull(rand.Reader, nonce)
ciphertext := aead.Seal(nil, nonce, plaintext, nil)
var mode byte
switch {
case isHybrid && isLockSet:
mode = 0x04 // Post-Quantum + Password Protected
case isHybrid:
mode = 0x03 // Post-Quantum only
case isLockSet:
mode = 0x02 // Classical + Password Protected
default:
mode = 0x01 // Classical Only
}
serialKey, err := utils.FetchFileKey(keyValue, "serial")
if err != nil {
msg := "unable to fetch key serial. Unable to proceed."
utils.HandleFailure(msg)
os.Exit(1)
}
serialBytes := []byte(serialKey)
serialSize := len(serialBytes)
maskedSerial := make([]byte, serialSize)
for i := 0; i < serialSize; i++ {
maskedSerial[i] = serialBytes[i] ^ ephPubX[i%32]
}
var finalBlob []byte
finalBlob = append(finalBlob, mode)
finalBlob = append(finalBlob, byte(serialSize))
finalBlob = append(finalBlob, maskedSerial...)
finalBlob = append(finalBlob, ephPubX...)
if isHybrid {
finalBlob = append(finalBlob, kyberCT...)
}
finalBlob = append(finalBlob, nonce...)
finalBlob = append(finalBlob, ciphertext...)
dst, err := os.Create(outputValue)
if err != nil {
fmt.Printf("error: unable to create %s\n", outputValue)
os.Exit(1)
}
defer dst.Close()
if isArmoredSet {
dst.WriteString(vars.PrivateKeyHeader + "\n")
encoded := base64.StdEncoding.EncodeToString(finalBlob)
for i := 0; i < len(encoded); i += 64 {
end := i + 64
if end > len(encoded) {
end = len(encoded)
}
dst.WriteString(encoded[i:end] + "\n")
}
dst.WriteString(vars.PrivateKeyFooter + "\n")
} else {
dst.Write(finalBlob)
}
fmt.Printf("final blob: %v\n", finalBlob)
fmt.Printf("is hybrid: %v\n", isHybrid)
_ = ciphertext
_ = isArmoredSet
_ = ephPubX
_ = kyberCT
_ = mode
_ = serialBytes
//////////////////////////////////////////
//serialKey, err := utils.FetchFileKey(keyValue, "serial")
//if err != nil {
// msg := "Unable to fetch key serial. Unable to proceed."
// utils.HandleFailure(msg)
// os.Exit(1)
//}
//serialBytes := []byte(serialKey)
//serialSize := len(serialBytes)
//maskedSerial := make([]byte, serialSize)
//for i := 0; i < serialSize; i++ {
// maskedSerial[i] = serialBytes[i] ^ ephPubX[i%32]
//}
//fmt.Printf("serial: %s\n", serialKey)
//fmt.Printf("masked: %s\n", maskedSerial)
//os.Exit(1)
///////////////////////////////////////////
//var finalBlob []byte
//finalBlob = append(finalBlob, mode)
//finalBlob = append(finalBlob, ephPubX...)
//if isHybrid {
// finalBlob = append(finalBlob, kyberCT...)
//}
//finalBlob = append(finalBlob, nonce...)
//finalBlob = append(finalBlob, ciphertext...)
//dst, err := os.Create(outputValue)
//if err != nil {
// fmt.Printf("Error: unable to create %s\n", outputValue)
// os.Exit(1)
//}
//defer dst.Close()
//if isArmoredSet {
// dst.WriteString(vars.PrivateKeyHeader + "\n")
// encoded := base64.StdEncoding.EncodeToString(finalBlob)
// for i := 0; i < len(encoded); i += 64 {
// end := i + 64
// if end > len(encoded) {
// end = len(encoded)
// }
// dst.WriteString(encoded[i:end] + "\n")
// }
// dst.WriteString(vars.PrivateKeyFooter + "\n")
//} else {
// dst.Write(finalBlob)
//}
//fmt.Printf("Encryption Complete: %s\n", outputValue)
//dst, err := os.Create(outputValue)
//if err != nil {
// fmt.Printf("Error: unable to create %s\n", outputValue)
// os.Exit(1)
//}
//defer dst.Close()
//dst.Write([]byte{mode})
//dst.Write(ephPubX)
//switch mode {
//case 0x03, 0x04:
// dst.Write(kyberCT)
//}
//dst.Write(nonce)
//dst.Write(ciphertext)
// validate headers
*/
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////