123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- package crypto
- import (
- "encoding/base64"
- "encoding/binary"
- "errors"
- "fmt"
- "github.com/minio/blake2b-simd"
- "golang.org/x/crypto/argon2"
- )
- const (
- loginSubKeyLen = 32
- loginSubKeyId = 1
- loginSubKeyContext = "loginctx"
- decryptionBufferSize = 4 * 1024 * 1024
- )
- const (
- cryptoKDFBlake2bBytesMin = 16
- 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.
- // - 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
- }
- // DeriveLoginKey derives a login key from the given key encryption key.
- // This loginKey act as user provided password during SRP authentication.
- // Parameters: keyEncKey: This is the keyEncryptionKey that is derived from the user's password.
- func DeriveLoginKey(keyEncKey []byte) []byte {
- subKey, _ := deriveSubKey(keyEncKey, loginSubKeyContext, loginSubKeyId, loginSubKeyLen)
- // return the first 16 bytes of the derived key
- return subKey[:16]
- }
- func deriveSubKey(masterKey []byte, context string, subKeyID uint64, subKeyLength uint32) ([]byte, error) {
- if subKeyLength < cryptoKDFBlake2bBytesMin || subKeyLength > cryptoKDFBlake2bBytesMax {
- return nil, fmt.Errorf("subKeyLength out of bounds")
- }
- // Pad the context
- ctxPadded := make([]byte, cryptoGenerichashBlake2bPersonalBytes)
- copy(ctxPadded, []byte(context))
- // Convert subKeyID to byte slice and pad
- salt := make([]byte, cryptoGenerichashBlake2bSaltBytes)
- binary.LittleEndian.PutUint64(salt, subKeyID)
- // Create a BLAKE2b configuration
- config := &blake2b.Config{
- Size: uint8(subKeyLength),
- Key: masterKey,
- Salt: salt,
- Person: ctxPadded,
- }
- hasher, err := blake2b.New(config)
- if err != nil {
- return nil, err
- }
- hasher.Write(nil) // No data, just using key, salt, and personalization
- return hasher.Sum(nil), nil
- }
- func DecryptChaChaBase64(data string, key []byte, nonce string) (string, []byte, error) {
- // Decode data from base64
- dataBytes, err := base64.StdEncoding.DecodeString(data)
- if err != nil {
- return "", nil, fmt.Errorf("invalid data: %v", err)
- }
- // Decode nonce from base64
- nonceBytes, err := base64.StdEncoding.DecodeString(nonce)
- if err != nil {
- return "", nil, fmt.Errorf("invalid nonce: %v", err)
- }
- // Decrypt data
- decryptedData, err := decryptChaCha20poly1305(dataBytes, key, nonceBytes)
- if err != nil {
- return "", nil, fmt.Errorf("failed to decrypt data: %v", err)
- }
- return base64.StdEncoding.EncodeToString(decryptedData), decryptedData, nil
- }
|