Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
billgraziano committed Oct 13, 2019
1 parent 328759d commit 2ed8433
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 0 deletions.
92 changes: 92 additions & 0 deletions dpapi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package dpapi

import (
"encoding/base64"
"syscall"
"unsafe"

"github.com/pkg/errors"
)

const (
cryptProtectUIForbidden = 0x1
)

var (
dllcrypt32 = syscall.NewLazyDLL("Crypt32.dll")
dllkernel32 = syscall.NewLazyDLL("Kernel32.dll")

procEncryptData = dllcrypt32.NewProc("CryptProtectData")
procDecryptData = dllcrypt32.NewProc("CryptUnprotectData")
procLocalFree = dllkernel32.NewProc("LocalFree")
)

type dataBlob struct {
cbData uint32
pbData *byte
}

func newBlob(d []byte) *dataBlob {
if len(d) == 0 {
return &dataBlob{}
}
return &dataBlob{
pbData: &d[0],
cbData: uint32(len(d)),
}
}

func (b *dataBlob) toByteArray() []byte {
d := make([]byte, b.cbData)
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
return d
}

// Encrypt a string value to a base64 string
func Encrypt(secret string) (string, error) {
var result string
var b []byte
b, err := EncryptBytes([]byte(secret))
if err != nil {
return result, errors.Wrap(err, "encryptbytes")
}
result = base64.StdEncoding.EncodeToString(b)
return result, nil
}

// EncryptBytes encrypts a byte array and returns a byte array
func EncryptBytes(data []byte) ([]byte, error) {
var outblob dataBlob
r, _, err := procEncryptData.Call(uintptr(unsafe.Pointer(newBlob(data))), 0, 0, 0, 0, cryptProtectUIForbidden, uintptr(unsafe.Pointer(&outblob)))
if r == 0 {
return nil, errors.Wrap(err, "procencryptdata")
}
defer procLocalFree.Call(uintptr(unsafe.Pointer(outblob.pbData)))
return outblob.toByteArray(), nil
}

// DecryptBytes decrypts a byte array returning a byte array
func DecryptBytes(data []byte) ([]byte, error) {
var outblob dataBlob
r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(newBlob(data))), 0, 0, 0, 0, cryptProtectUIForbidden, uintptr(unsafe.Pointer(&outblob)))
if r == 0 {
return nil, errors.Wrap(err, "procdecryptdata")
}
defer procLocalFree.Call(uintptr(unsafe.Pointer(outblob.pbData)))
return outblob.toByteArray(), nil
}

// Decrypt a string to a string
func Decrypt(data string) (string, error) {

raw, err := base64.StdEncoding.DecodeString(data)
if err != nil {
return "", errors.Wrap(err, "decodestring")
}

b, err := DecryptBytes(raw)
if err != nil {
return "", errors.Wrap(err, "decryptbytes")
}
return string(b), nil
}
40 changes: 40 additions & 0 deletions dpapi_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dpapi

import (
"bytes"
"encoding/hex"
"testing"
)

func TestString(t *testing.T) {

secret := "Hello World!;"
enc, err := Encrypt(secret)
if err != nil {
t.Error("err from Encrypt: ", err)
}
dec, err := Decrypt(enc)
if err != nil {
t.Error("err from Decrypt: ", err)
}
if dec != secret {
t.Errorf("expected: '%s' got: '%s'", secret, dec)
}
}

func TestBytes(t *testing.T) {

secret := []byte("Hello World!;")
enc, err := EncryptBytes(secret)
if err != nil {
t.Error("err from EncryptBytes: ", err)
}
dec, err := DecryptBytes(enc)
if err != nil {
t.Error("err from DecryptBytes: ", err)
}
c := bytes.Compare(dec, secret)
if c != 0 {
t.Errorf("expected: '%s' got: '%s'", hex.EncodeToString(secret), hex.EncodeToString(dec))
}
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/billgraziano/dpapi

go 1.13

require github.com/pkg/errors v0.8.1
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

0 comments on commit 2ed8433

Please sign in to comment.