-
Notifications
You must be signed in to change notification settings - Fork 2
/
secstring.go
104 lines (84 loc) · 2.16 KB
/
secstring.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package secstring
import (
"errors"
"fmt"
"strings"
"golang.org/x/sys/unix"
)
type SecString struct {
String []byte // Protected string
Length int // Length of the target string
}
func memset(s []byte, c byte) {
for i := 0; i < len(s); i++ {
s[i] = c
}
}
// Takes a []byte and builds a SecString out of it, wiping str in the
// process.
//
// A SecString should be destroyed when it's no longer needed to prevent memory leaks.
// It is probably a good idea to defer SecString.Destroy()
func NewSecString(str []byte) (*SecString, error) {
ret := &SecString{Length: len(str)}
var err error
ret.String, err = unix.Mmap(-1, 0, ret.Length, unix.PROT_READ|unix.PROT_WRITE, unix.MAP_ANON|unix.MAP_PRIVATE)
if err != nil {
memset(str, 0)
return nil, err
}
if err := unix.Mlock(ret.String); err != nil {
memset(str, 0)
unix.Munmap(ret.String)
return nil, err
}
for i := 0; i < ret.Length; i++ {
ret.String[i] = str[i]
str[i] = 0
}
if err := unix.Mprotect(ret.String, unix.PROT_READ); err != nil {
memset(str, 0)
memset(ret.String, 0)
unix.Munmap(ret.String)
return nil, err
}
return ret, nil
}
// Makes a new SecString from a string reference. Destroys str after creating
// the secstring
func FromString(str *string) (*SecString, error) {
b := make([]byte, len(*str))
for i := 0; i < len(*str); i++ {
b[i] = (*str)[i]
}
*str = strings.Repeat("x", len(*str))
return NewSecString(b)
}
func (s *SecString) Clone() (*SecString, error) {
var ret *SecString
str := make([]byte, len(s.String), cap(s.String))
if copied := copy(str, s.String); copied != len(s.String) {
return nil, errors.New(fmt.Sprintf("Only %v copied", copied))
}
var err error
if ret, err = NewSecString(str); err != nil {
return nil, err
}
return ret, nil
}
// Destroys the s. *MUST* be called to prevent memory leaks. Probably best to
// be called in a defer
func (s *SecString) Destroy() error {
if err := unix.Mprotect(s.String, unix.PROT_READ|unix.PROT_WRITE); err != nil {
return err
}
memset(s.String, 0)
if err := unix.Munlock(s.String); err != nil {
return err
}
if err := unix.Munmap(s.String); err != nil {
return err
}
s.String = nil
return nil
}