mirror of
https://github.com/mitchell/selfpass.git
synced 2025-12-14 13:27:21 +00:00
Separate cli into its own module; rename it to sp
This commit is contained in:
parent
0e071f0f89
commit
024017338e
25 changed files with 405 additions and 392 deletions
68
sp/crypto/cbc.go
Normal file
68
sp/crypto/cbc.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/ncw/rclone/backend/crypt/pkcs7"
|
||||
)
|
||||
|
||||
func CBCEncrypt(key []byte, plaintext []byte) ([]byte, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, fmt.Errorf("key is not 32 bytes")
|
||||
}
|
||||
|
||||
plaintext = pkcs7.Pad(aes.BlockSize, plaintext)
|
||||
|
||||
if len(plaintext)%aes.BlockSize != 0 {
|
||||
return nil, fmt.Errorf("plaintext is not a multiple of the block size")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
|
||||
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func CBCDecrypt(key []byte, ciphertext []byte) ([]byte, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, fmt.Errorf("key is not 32 bytes")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(ciphertext) < aes.BlockSize {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
|
||||
ciphertext = ciphertext[aes.BlockSize:]
|
||||
|
||||
if len(ciphertext)%aes.BlockSize != 0 {
|
||||
return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(ciphertext, ciphertext)
|
||||
|
||||
return pkcs7.Unpad(aes.BlockSize, ciphertext)
|
||||
}
|
||||
60
sp/crypto/gcm.go
Normal file
60
sp/crypto/gcm.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func GCMEncrypt(key []byte, plaintext []byte) ([]byte, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, fmt.Errorf("key is not 32 bytes")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
_, err = io.ReadFull(rand.Reader, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gcm.Seal(nonce, nonce, plaintext, nil), nil
|
||||
}
|
||||
|
||||
func GCMDecrypt(key []byte, ciphertext []byte) ([]byte, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, fmt.Errorf("key is not 32 bytes")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(ciphertext) < gcm.NonceSize() {
|
||||
return nil, errors.New("malformed ciphertext")
|
||||
}
|
||||
|
||||
return gcm.Open(nil,
|
||||
ciphertext[:gcm.NonceSize()],
|
||||
ciphertext[gcm.NonceSize():],
|
||||
nil,
|
||||
)
|
||||
}
|
||||
68
sp/crypto/helpers.go
Normal file
68
sp/crypto/helpers.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GenerateKeyFromPassword(pass []byte) ([]byte, error) {
|
||||
if len(pass) < 8 {
|
||||
return nil, fmt.Errorf("master password must be at least 8 characters")
|
||||
}
|
||||
|
||||
for idx := 0; len(pass) < 32; idx++ {
|
||||
pass = append(pass, pass[idx])
|
||||
|
||||
if idx == len(pass) {
|
||||
idx = 0
|
||||
}
|
||||
}
|
||||
|
||||
return pass, nil
|
||||
}
|
||||
|
||||
func CombinePasswordAndKey(pass, key []byte) ([]byte, error) {
|
||||
if len(pass) < 8 {
|
||||
return nil, fmt.Errorf("master password must be at least 8 characters")
|
||||
}
|
||||
if len(key) != 16 {
|
||||
return nil, fmt.Errorf("key was not of length 16")
|
||||
}
|
||||
|
||||
for idx := 0; len(pass) < 16; idx++ {
|
||||
pass = append(pass, pass[idx])
|
||||
}
|
||||
|
||||
return append(pass[:16], key...), nil
|
||||
}
|
||||
|
||||
func GeneratePassword(length int, numbers, specials bool) string {
|
||||
const alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const alphanumerics = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||
const alphasAndSpecials = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()"
|
||||
const alphanumericsAndSpecials = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()"
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
pass := make([]byte, length)
|
||||
|
||||
switch {
|
||||
case numbers && specials:
|
||||
for idx := 0; idx < length; idx++ {
|
||||
pass[idx] = alphanumericsAndSpecials[rand.Int63()%int64(len(alphanumericsAndSpecials))]
|
||||
}
|
||||
case numbers:
|
||||
for idx := 0; idx < length; idx++ {
|
||||
pass[idx] = alphanumerics[rand.Int63()%int64(len(alphanumerics))]
|
||||
}
|
||||
case specials:
|
||||
for idx := 0; idx < length; idx++ {
|
||||
pass[idx] = alphasAndSpecials[rand.Int63()%int64(len(alphasAndSpecials))]
|
||||
}
|
||||
default:
|
||||
for idx := 0; idx < length; idx++ {
|
||||
pass[idx] = alphas[rand.Int63()%int64(len(alphas))]
|
||||
}
|
||||
}
|
||||
|
||||
return string(pass)
|
||||
}
|
||||
16
sp/crypto/pbkdf2.go
Normal file
16
sp/crypto/pbkdf2.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
const (
|
||||
PBKDF2Rounds = 4096
|
||||
KeyLength = 32
|
||||
)
|
||||
|
||||
func GeneratePBKDF2Key(password, salt []byte) []byte {
|
||||
return pbkdf2.Key([]byte(password), []byte(salt), PBKDF2Rounds, KeyLength, sha256.New)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue