github.com/GGP1/kure@v0.8.4/commands/config/argon2/test/test.go (about)

     1  package test
     2  
     3  import (
     4  	"crypto/rand"
     5  	"errors"
     6  	"fmt"
     7  	"runtime"
     8  	"time"
     9  
    10  	cmdutil "github.com/GGP1/kure/commands"
    11  
    12  	"github.com/GGP1/atoll"
    13  
    14  	"github.com/spf13/cobra"
    15  	"golang.org/x/crypto/argon2"
    16  )
    17  
    18  const example = `
    19  kure config argon2 test -m 500000 -i 2 -t 4`
    20  
    21  type testOptions struct {
    22  	memory, iterations uint32
    23  	threads            uint8
    24  }
    25  
    26  // NewCmd returns a new command.
    27  func NewCmd() *cobra.Command {
    28  	opts := testOptions{}
    29  	cmd := &cobra.Command{
    30  		Use:   "test",
    31  		Short: "Test argon2 performance",
    32  		Long: `Test the time taken by argon2 to derive the key with the parameters passed.
    33  		
    34  The Argon2id variant with 1 iteration and maximum available memory is recommended as a default setting for all environments. This setting is secure against side-channel attacks and maximizes adversarial costs on dedicated bruteforce hardware.
    35  
    36  If one of the devices that will handle the database has lower than 1GB of memory, we recommend setting the memory according to that device's RAM availability.
    37  
    38  • Memory: amount of memory allowed for argon2 to use, the more memory the better. The value is represented in kibibytes, 1 kibibyte = 1024 bytes. Default is 1048576 kibibytes (1 GiB).
    39  
    40  • Iterations: number of passes over the memory. The running time depends linearly on this parameter. Default is 1.
    41  
    42  • Threads: number of threads number in parallel. Default is the maximum number of logical CPUs usable.`,
    43  		Example: example,
    44  		RunE:    runTest(&opts),
    45  		PostRun: func(cmd *cobra.Command, args []string) {
    46  			// Reset variables (session)
    47  			opts = testOptions{
    48  				memory:     1048576,
    49  				iterations: 1,
    50  				threads:    uint8(runtime.NumCPU()),
    51  			}
    52  		},
    53  	}
    54  
    55  	f := cmd.Flags()
    56  	f.Uint32VarP(&opts.iterations, "iterations", "i", 1, "number of passes over the memory")
    57  	f.Uint32VarP(&opts.memory, "memory", "m", 1048576, "amount of memory allowed for argon2 to use")
    58  	f.Uint8VarP(&opts.threads, "threads", "t", uint8(runtime.NumCPU()), "number of threads running in parallel")
    59  
    60  	return cmd
    61  }
    62  
    63  func runTest(opts *testOptions) cmdutil.RunEFunc {
    64  	return func(cmd *cobra.Command, args []string) error {
    65  		if opts.iterations < 1 || opts.memory < 1 {
    66  			return errors.New("iterations and memory should be higher than 0")
    67  		}
    68  		if opts.threads < 1 {
    69  			return errors.New("the number of threads must be higher than 0")
    70  		}
    71  
    72  		password, err := atoll.NewPassword(25, []atoll.Level{
    73  			atoll.Lower,
    74  			atoll.Upper,
    75  			atoll.Digit,
    76  			atoll.Space,
    77  			atoll.Special,
    78  		})
    79  		if err != nil {
    80  			return err
    81  		}
    82  
    83  		salt := make([]byte, 32)
    84  		if _, err = rand.Read(salt); err != nil {
    85  			return errors.New("failed generating salt")
    86  		}
    87  
    88  		start := time.Now()
    89  
    90  		argon2.IDKey([]byte(password), salt, opts.iterations, opts.memory, opts.threads, 32)
    91  
    92  		fmt.Println(time.Since(start))
    93  		return nil
    94  	}
    95  }