diff --git a/internal/crypto/crypto.go b/internal/crypto/crypto.go index b757c996b..83200896b 100644 --- a/internal/crypto/crypto.go +++ b/internal/crypto/crypto.go @@ -3,6 +3,7 @@ package crypto import ( "encoding/base64" "encoding/binary" + "errors" "fmt" "github.com/minio/blake2b-simd" "golang.org/x/crypto/argon2" @@ -20,8 +21,16 @@ const ( cryptoKDFBlake2bBytesMax = 64 cryptoGenerichashBlake2bSaltBytes = 16 cryptoGenerichashBlake2bPersonalBytes = 16 + BoxSealBytes = 48 // 32 for the ephemeral public key + 16 for the MAC ) +var ( + ErrOpenBox = errors.New("failed to open box") + ErrSealedOpenBox = errors.New("failed to open sealed box") +) + +const () + // DeriveArgonKey generates a 32-bit cryptographic key using the Argon2id algorithm. // Parameters: // - password: The plaintext password to be hashed. diff --git a/internal/crypto/crypto_libsodium.go b/internal/crypto/crypto_libsodium.go index 9cc8c1f76..a65f4489a 100644 --- a/internal/crypto/crypto_libsodium.go +++ b/internal/crypto/crypto_libsodium.go @@ -1,16 +1,22 @@ package crypto import ( - "bufio" - "bytes" "cli-go/utils/encoding" - "fmt" - "github.com/jamesruan/sodium" - "io" - "log" - "os" + "golang.org/x/crypto/nacl/box" + "golang.org/x/crypto/nacl/secretbox" ) +//func EncryptChaCha20poly1305LibSodium(data []byte, key []byte) ([]byte, []byte, error) { +// var buf bytes.Buffer +// encoder := sodium.MakeSecretStreamXCPEncoder(sodium.SecretStreamXCPKey{Bytes: key}, &buf) +// _, err := encoder.WriteAndClose(data) +// if err != nil { +// log.Println("Failed to write to encoder", err) +// return nil, nil, err +// } +// return buf.Bytes(), encoder.Header().Bytes, nil +//} + // EncryptChaCha20poly1305 encrypts the given data using the ChaCha20-Poly1305 algorithm. // Parameters: // - data: The plaintext data as a byte slice. @@ -20,17 +26,6 @@ import ( // - A byte slice representing the encrypted data. // - A byte slice representing the header of the encrypted data. // - An error object, which is nil if no error occurs. -func EncryptChaCha20poly1305LibSodium(data []byte, key []byte) ([]byte, []byte, error) { - var buf bytes.Buffer - encoder := sodium.MakeSecretStreamXCPEncoder(sodium.SecretStreamXCPKey{Bytes: key}, &buf) - _, err := encoder.WriteAndClose(data) - if err != nil { - log.Println("Failed to write to encoder", err) - return nil, nil, err - } - return buf.Bytes(), encoder.Header().Bytes, nil -} - func EncryptChaCha20poly1305(data []byte, key []byte) ([]byte, []byte, error) { encryptor, header, err := NewEncryptor(key) if err != nil { @@ -52,26 +47,26 @@ func EncryptChaCha20poly1305(data []byte, key []byte) ([]byte, []byte, error) { // Returns: // - A byte slice representing the decrypted data. // - An error object, which is nil if no error occurs. -func decryptChaCha20poly1305LibSodium(data []byte, key []byte, nonce []byte) ([]byte, error) { - reader := bytes.NewReader(data) - header := sodium.SecretStreamXCPHeader{Bytes: nonce} - decoder, err := sodium.MakeSecretStreamXCPDecoder( - sodium.SecretStreamXCPKey{Bytes: key}, - reader, - header) - if err != nil { - log.Println("Failed to make secret stream decoder", err) - return nil, err - } - // Buffer to store the decrypted data - decryptedData := make([]byte, len(data)) - n, err := decoder.Read(decryptedData) - if err != nil && err != io.EOF { - log.Println("Failed to read from decoder", err) - return nil, err - } - return decryptedData[:n], nil -} +//func decryptChaCha20poly1305LibSodium(data []byte, key []byte, nonce []byte) ([]byte, error) { +// reader := bytes.NewReader(data) +// header := sodium.SecretStreamXCPHeader{Bytes: nonce} +// decoder, err := sodium.MakeSecretStreamXCPDecoder( +// sodium.SecretStreamXCPKey{Bytes: key}, +// reader, +// header) +// if err != nil { +// log.Println("Failed to make secret stream decoder", err) +// return nil, err +// } +// // Buffer to store the decrypted data +// decryptedData := make([]byte, len(data)) +// n, err := decoder.Read(decryptedData) +// if err != nil && err != io.EOF { +// log.Println("Failed to read from decoder", err) +// return nil, err +// } +// return decryptedData[:n], nil +//} func decryptChaCha20poly1305(data []byte, key []byte, nonce []byte) ([]byte, error) { decryptor, err := NewDecryptor(key, nonce) @@ -85,75 +80,121 @@ func decryptChaCha20poly1305(data []byte, key []byte, nonce []byte) ([]byte, err return decoded, nil } -func SecretBoxOpen(c []byte, n []byte, k []byte) ([]byte, error) { - var cp sodium.Bytes = c - res, err := cp.SecretBoxOpen(sodium.SecretBoxNonce{Bytes: n}, sodium.SecretBoxKey{Bytes: k}) - return res, err -} +//func SecretBoxOpenLibSodium(c []byte, n []byte, k []byte) ([]byte, error) { +// var cp sodium.Bytes = c +// res, err := cp.SecretBoxOpen(sodium.SecretBoxNonce{Bytes: n}, sodium.SecretBoxKey{Bytes: k}) +// return res, err +//} func SecretBoxOpenBase64(cipher string, nonce string, k []byte) ([]byte, error) { return SecretBoxOpen(encoding.DecodeBase64(cipher), encoding.DecodeBase64(nonce), k) } -func SealedBoxOpen(cipherText []byte, publicKey, masterSecret []byte) ([]byte, error) { - var cp sodium.Bytes = cipherText - om, err := cp.SealedBoxOpen(sodium.BoxKP{ - PublicKey: sodium.BoxPublicKey{Bytes: publicKey}, - SecretKey: sodium.BoxSecretKey{Bytes: masterSecret}, - }) - if err != nil { - return nil, fmt.Errorf("failed to open sealed box: %v", err) +func SecretBoxOpen(c []byte, n []byte, k []byte) ([]byte, error) { + // Check for valid lengths of nonce and key + if len(n) != 24 || len(k) != 32 { + return nil, ErrOpenBox } - return om, nil + + var nonce [24]byte + var key [32]byte + copy(nonce[:], n) + copy(key[:], k) + + // Decrypt the message using Go's nacl/secretbox + decrypted, ok := secretbox.Open(nil, c, &nonce, &key) + if !ok { + return nil, ErrOpenBox + } + + return decrypted, nil +} + +//func SealedBoxOpenLib(cipherText []byte, publicKey, masterSecret []byte) ([]byte, error) { +// var cp sodium.Bytes = cipherText +// om, err := cp.SealedBoxOpen(sodium.BoxKP{ +// PublicKey: sodium.BoxPublicKey{Bytes: publicKey}, +// SecretKey: sodium.BoxSecretKey{Bytes: masterSecret}, +// }) +// if err != nil { +// return nil, fmt.Errorf("failed to open sealed box: %v", err) +// } +// return om, nil +//} + +func SealedBoxOpen(cipherText, publicKey, masterSecret []byte) ([]byte, error) { + if len(cipherText) < BoxSealBytes { + return nil, ErrOpenBox + } + + // Extract ephemeral public key from the ciphertext + var ephemeralPublicKey [32]byte + copy(ephemeralPublicKey[:], publicKey[:32]) + + // Extract ephemeral public key from the ciphertext + var masterKey [32]byte + copy(masterKey[:], masterSecret[:32]) + + // Decrypt the message using nacl/box + decrypted, ok := box.OpenAnonymous(nil, cipherText, &ephemeralPublicKey, &masterKey) + if !ok { + return nil, ErrOpenBox + } + + return decrypted, nil } func DecryptFile(encryptedFilePath string, decryptedFilePath string, key, nonce []byte) error { - inputFile, err := os.Open(encryptedFilePath) - if err != nil { - return err - } - defer inputFile.Close() - - outputFile, err := os.Create(decryptedFilePath) - if err != nil { - return err - } - defer outputFile.Close() - - reader := bufio.NewReader(inputFile) - writer := bufio.NewWriter(outputFile) - - header := sodium.SecretStreamXCPHeader{Bytes: nonce} - decoder, err := sodium.MakeSecretStreamXCPDecoder( - sodium.SecretStreamXCPKey{Bytes: key}, - reader, - header) - if err != nil { - log.Println("Failed to make secret stream decoder", err) - return err - } - - buf := make([]byte, decryptionBufferSize) - for { - n, errErr := decoder.Read(buf) - if errErr != nil && errErr != io.EOF { - log.Println("Failed to read from decoder", errErr) - return errErr - } - if n == 0 { - break - } - if _, err := writer.Write(buf[:n]); err != nil { - log.Println("Failed to write to output file", err) - return err - } - if errErr == io.EOF { - break - } - } - if err := writer.Flush(); err != nil { - log.Println("Failed to flush writer", err) - return err - } - return nil + panic("not implemented decrypt file") } + +//func DecryptFileLib(encryptedFilePath string, decryptedFilePath string, key, nonce []byte) error { +// inputFile, err := os.Open(encryptedFilePath) +// if err != nil { +// return err +// } +// defer inputFile.Close() +// +// outputFile, err := os.Create(decryptedFilePath) +// if err != nil { +// return err +// } +// defer outputFile.Close() +// +// reader := bufio.NewReader(inputFile) +// writer := bufio.NewWriter(outputFile) +// +// header := sodium.SecretStreamXCPHeader{Bytes: nonce} +// decoder, err := sodium.MakeSecretStreamXCPDecoder( +// sodium.SecretStreamXCPKey{Bytes: key}, +// reader, +// header) +// if err != nil { +// log.Println("Failed to make secret stream decoder", err) +// return err +// } +// +// buf := make([]byte, decryptionBufferSize) +// for { +// n, errErr := decoder.Read(buf) +// if errErr != nil && errErr != io.EOF { +// log.Println("Failed to read from decoder", errErr) +// return errErr +// } +// if n == 0 { +// break +// } +// if _, err := writer.Write(buf[:n]); err != nil { +// log.Println("Failed to write to output file", err) +// return err +// } +// if errErr == io.EOF { +// break +// } +// } +// if err := writer.Flush(); err != nil { +// log.Println("Failed to flush writer", err) +// return err +// } +// return nil +//}