131
package seks
import (
"crypto/rand"
"crypto/sha256"
"fmt"
"golang.org/x/crypto/nacl/secretbox"
"strings"
)
func ran() []byte {
var b [32]byte
_, err := rand.Reader.Read(b[:])
if err != nil {
panic(err)
}
return b[:]
}
func hashPasswd(salt []byte, passwd []byte) [32]byte {
hash := sha256.New()
hash.Write(passwd)
hash.Write(salt)
var key [32]byte
copy(key[:], hash.Sum(nil))
return key
}
const seksArmour = `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_`
const seksHeader = `-----BEGIN SOME ENCRYPTION KEY STUFF-----`
const seksFooter = `------END SOME ENCRYPTION KEY STUFF------`
func armour(b []byte) string {
var s string
var n uint = 0
var m uint = 0
for i := 0; i < 3-len(b)%3; i++ {
b = append(b, 0)
}
for _, c := range b {
n |= uint(c) << uint(m*8)
m++
if m == 3 {
for j := 0; j < 4; j++ {
s += string(seksArmour[n&63])
n >>= 6
}
m = 0
n = 0
}
}
// add newlines
for i := 0; i < len(s); i += len(seksHeader) {
s = s[:i] + "\n" + s[i:]
}
return seksHeader + s + "\n" + seksFooter + "\n"
}
func Encrypt(data string, password string) string {
return armour(encryptBytes([]byte(data), password))
}
func encryptBytes(data []byte, password string) []byte {
salt := ran()
key := hashPasswd(salt, []byte(password))
var nonce = [24]byte(ran()[0:24])
salt = append(salt[:], nonce[:]...)
return secretbox.Seal(salt, data, &nonce, &key)
}
func Decrypt(data string, password string) (string, error) {
b, err := unArmour(data)
if err != nil {
return "", err
}
return string(decryptBytes(b, password)), nil
}
func decryptBytes(encrypted []byte, pass string) []byte {
salt := encrypted[:32]
nonce := [24]byte(encrypted[32 : 32+24])
key := hashPasswd(salt[:], []byte(pass))
decrypted := make([]byte, len(encrypted)-32-24)
decrypted, boolEnlon := secretbox.Open(nil, encrypted[32+24:], &nonce, &key)
if boolEnlon != true {
return nil
}
return decrypted
}
func unArmour(s string) ([]byte, error) {
s = strings.ReplaceAll(s, "\t", "")
s = strings.ReplaceAll(s, "\n", "")
s = strings.TrimPrefix(s, seksHeader)
s = strings.TrimSuffix(s, seksFooter)
s = strings.ReplaceAll(s, " ", "")
var b []byte
var n uint = 0
var m uint = 0
for _, c := range s {
i := index(c)
if i < 0 {
return nil, fmt.Errorf("SEKS UnMarshall: invalid character")
}
n |= uint(i) << uint(m*6)
m++
if m == 4 {
for j := 0; j < 3; j++ {
b = append(b, byte(n&255))
n >>= 8
}
m = 0
n = 0
}
}
if len(b) > 0 { // remove padding
for i := 0; i < 3; i++ {
if b[len(b)-1] == 0 {
b = b[:len(b)-1]
}
}
}
return b, nil
}
func index(c rune) (j int) {
for j, v := range seksArmour {
if v == c {
return j
}
}
return -1
}