Scaffold project

This commit is contained in:
Neeraj Gupta 2023-09-06 10:32:32 +05:30
commit b56ebf3c3d
5 changed files with 149 additions and 0 deletions

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
data/**
.DS_Store
Photos.code-workspace
logs/**
.idea/**
.vscode/**
tmp/**
museum.yaml

8
go.mod Normal file
View file

@ -0,0 +1,8 @@
module cli-go
go 1.20
require (
github.com/jamesruan/sodium v1.0.14
golang.org/x/crypto v0.11.0
)

10
go.sum Normal file
View file

@ -0,0 +1,10 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

70
internal/crypto/crypto.go Normal file
View file

@ -0,0 +1,70 @@
package crypto
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"log"
"github.com/jamesruan/sodium"
"golang.org/x/crypto/argon2"
)
// deriveArgonKey generates a 32-bit cryptographic key using the Argon2id algorithm.
// Parameters:
// - password: The plaintext password to be hashed.
// - salt: The salt as a base64 encoded string.
// - memLimit: The memory limit in bytes.
// - opsLimit: The number of iterations.
//
// Returns:
// - A byte slice representing the derived key.
// - An error object, which is nil if no error occurs.
func deriveArgonKey(password, salt string, memLimit, opsLimit int) ([]byte, error) {
if memLimit < 1024 || opsLimit < 1 {
return nil, fmt.Errorf("invalid memory or operation limits")
}
// Decode salt from base64
saltBytes, err := base64.StdEncoding.DecodeString(salt)
if err != nil {
return nil, fmt.Errorf("invalid salt: %v", err)
}
// Generate key using Argon2id
// Note: We're assuming a fixed key length of 32 bytes and changing the threads
key := argon2.IDKey([]byte(password), saltBytes, uint32(opsLimit), uint32(memLimit/1024), 1, 32)
return key, nil
}
// decryptChaCha20poly1305 decrypts the given data using the ChaCha20-Poly1305 algorithm.
// Parameters:
// - data: The encrypted data as a byte slice.
// - key: The key for decryption as a byte slice.
// - nonce: The nonce for decryption as a byte slice.
//
// Returns:
// - A byte slice representing the decrypted data.
// - An error object, which is nil if no error occurs.
func decryptChaCha20poly1305(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
}

View file

@ -0,0 +1,53 @@
package crypto
import (
"encoding/base64"
"testing"
)
const (
password = "test_password"
kdfSalt = "vd0dcYMGNLKn/gpT6uTFTw=="
memLimit = 64 * 1024 * 1024 // 64MB
opsLimit = 2
cipherText = "kBXQ2PuX6y/aje5r22H0AehRPh6sQ0ULoeAO"
cipherNonce = "v7wsI+BFZsRMIjDm3rTxPhmi/CaUdkdJ"
expectedPlainText = "plain_text"
expectedDerivedKey = "vp8d8Nee0BbIML4ab8Cp34uYnyrN77cRwTl920flyT0="
)
func TestDeriveArgonKey(t *testing.T) {
derivedKey, err := deriveArgonKey(password, kdfSalt, memLimit, opsLimit)
if err != nil {
t.Fatalf("Failed to derive key: %v", err)
}
if base64.StdEncoding.EncodeToString(derivedKey) != expectedDerivedKey {
t.Fatalf("Derived key does not match expected key")
}
}
func TestDecryptChaCha20poly1305(t *testing.T) {
derivedKey, err := deriveArgonKey(password, kdfSalt, memLimit, opsLimit)
if err != nil {
t.Fatalf("Failed to derive key: %v", err)
}
decodedCipherText, err := base64.StdEncoding.DecodeString(cipherText)
if err != nil {
t.Fatalf("Failed to decode cipher text: %v", err)
}
decodedCipherNonce, err := base64.StdEncoding.DecodeString(cipherNonce)
if err != nil {
t.Fatalf("Failed to decode cipher nonce: %v", err)
}
decryptedText, err := decryptChaCha20poly1305(decodedCipherText, derivedKey, decodedCipherNonce)
if err != nil {
t.Fatalf("Failed to decrypt: %v", err)
}
if string(decryptedText) != expectedPlainText {
t.Fatalf("Decrypted text : %s does not match the expected text: %s", string(decryptedText), expectedPlainText)
}
}