-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsigner.go
121 lines (99 loc) · 2.55 KB
/
signer.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// WebMoney Signer: a native Go implementation of the WMSigner module
package wmsigner
import (
"bytes"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"errors"
"math"
"math/big"
"os"
)
type word [2]byte
type signer struct {
power, modulus *big.Int;
}
// Create a signature for the given data
func (this *signer) Sign(data string) (string, error) {
// Make data hash (16 bytes)
hash := md4hash([]byte(data))
base := hash[:]
// Add 40 random bytes
randomBytes := make([]byte, 40)
_, err := rand.Read(randomBytes)
if err != nil {
return "", err
}
base = append(base, randomBytes...)
// Add the length of the base (56 = 16 + 40) as the first 2 bytes
baseLength := uint8(len(base))
base = append([]byte{baseLength, 0}, base...)
baseLength += 2
// Reverse byte order
baseReversed := reverseBytes(base)
// Modular exponentiation
result := new(big.Int).Exp(
new(big.Int).SetBytes(baseReversed),
this.power,
this.modulus,
)
// Reverse byte order by 2 bytes
reversedResult := reverseBytesAsWords(result.Bytes())
return hex.EncodeToString(reversedResult), nil
}
func New(wmid, keyFileName, keyPassword string) (signer, error) {
if wmid == "" {
return signer{}, errors.New("WMID not provided")
}
keyFile, err := os.Open(keyFileName)
if err != nil {
return signer{}, err
}
defer func() {
err = keyFile.Close()
}()
key, verified := initKey(keyFile, wmid, keyPassword)
if (!verified) {
// Try one more time using only the first half of the password
keyFile.Seek(0, 0)
halfPassword := keyPassword[:int(math.Floor(float64(len(keyPassword)) / 2))]
key, verified = initKey(keyFile, wmid, halfPassword)
if (!verified) {
return signer{}, errors.New("Hash check failed. Key file seems to be corrupted.")
}
}
newSigner := signer{}
newSigner.power, newSigner.modulus = key.Extract()
return newSigner, err
}
func reverseBytes(data []byte) []byte {
length := len(data)
reversed := make([]byte, length)
for i := length; i > 0; i-- {
reversed[i - 1] = data[length - i]
}
return reversed
}
func reverseWords(data []word) []word {
length := len(data)
reversed := make([]word, length)
for i := length; i > 0; i-- {
reversed[i - 1] = data[length - i]
}
return reversed
}
func reverseBytesAsWords(data []byte) []byte {
if len(data) % 2 != 0 {
data = append([]byte{0}, data...)
}
words := make([]word, len(data) / 2)
buffer := bytes.NewBuffer(data)
binary.Read(buffer, binary.LittleEndian, &words)
words = reverseWords(words)
var result []byte
for _, v := range words {
result = append(result, v[:]...)
}
return result
}