Initial: fixing internal package metadata
This commit is contained in:
829
internal/actions/encrypt/encrypt.go
Executable file
829
internal/actions/encrypt/encrypt.go
Executable file
@@ -0,0 +1,829 @@
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Reference in New Issue
Block a user