浏览代码

Scaffold project

Neeraj Gupta 1 年之前
当前提交
b56ebf3c3d
共有 5 个文件被更改,包括 149 次插入0 次删除
  1. 8 0
      .gitignore
  2. 8 0
      go.mod
  3. 10 0
      go.sum
  4. 70 0
      internal/crypto/crypto.go
  5. 53 0
      internal/crypto/crypto_test.go

+ 8 - 0
.gitignore

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

+ 8 - 0
go.mod

@@ -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 - 0
go.sum

@@ -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 - 0
internal/crypto/crypto.go

@@ -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
+}

+ 53 - 0
internal/crypto/crypto_test.go

@@ -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)
+	}
+}