File: key.go

package info (click to toggle)
golang-github-mitch000001-go-hbci 0.4.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 2,468 kB
  • sloc: java: 1,092; makefile: 5
file content (232 lines) | stat: -rw-r--r-- 5,949 bytes parent folder | download
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
package domain

import (
	"crypto/rand"
	"crypto/rsa"
	"math/big"
)

// Key provides an interface to an encryption/signing key
type Key interface {
	// KeyName returns the KeyName
	KeyName() KeyName
	// SetKeyNumber sets the key number in the KeyName
	SetKeyNumber(number int)
	// SetKeyVersion sets the key version in the KeyName
	SetKeyVersion(version int)
	// Sign signs message
	Sign(message []byte) (signature []byte, err error)
	// Encrypt encrypts message
	Encrypt(message []byte) (encrypted []byte, err error)
	// CanSign returns true if the key can be used for signing
	CanSign() bool
	// CanEncrypt returns true if the key can be used for encryption
	CanEncrypt() bool
}

const (
	initialKeyNumber  = 999
	initialKeyVersion = 999
	KeyTypeSigning    = KeyType("S")
	KeyTypeEncryption = KeyType("V")
)

type KeyType string

func (k KeyType) String() string { return string(k) }

// NewPinTanKeyName returns a new KeyName for the pin/tan flow
func NewPinTanKeyName(bankID BankID, userID string, keyType KeyType) *KeyName {
	return &KeyName{
		BankID:     bankID,
		UserID:     userID,
		KeyType:    keyType,
		KeyNumber:  0,
		KeyVersion: 0,
	}
}

// NewInitialKeyName represents a KeyName ready to use for initial communication
func NewInitialKeyName(countryCode int, bankID, userID string, keyType KeyType) *KeyName {
	return &KeyName{
		BankID:     BankID{CountryCode: countryCode, ID: bankID},
		UserID:     userID,
		KeyType:    keyType,
		KeyNumber:  initialKeyNumber,
		KeyVersion: initialKeyVersion,
	}
}

// KeyName provides data about a given key
type KeyName struct {
	BankID     BankID
	UserID     string
	KeyType    KeyType
	KeyNumber  int
	KeyVersion int
}

// IsInitial returns true if the KeyName represents an initial KeyName, false otherwise
func (k *KeyName) IsInitial() bool {
	return k.KeyNumber == initialKeyNumber && k.KeyVersion == initialKeyVersion
}

// SetInitial resets the KeyName to reflect an initial KeyName
func (k *KeyName) SetInitial() {
	k.KeyNumber = initialKeyNumber
	k.KeyVersion = initialKeyVersion
}

// NewPinKey returns a new PinKey
func NewPinKey(pin string, keyName *KeyName) *PinKey {
	return &PinKey{pin: pin, keyName: keyName}
}

// PinKey represents a Key used for pin/tan flow
type PinKey struct {
	pin     string
	keyName *KeyName
}

// KeyName returns the KeyName
func (p *PinKey) KeyName() KeyName {
	return *p.keyName
}

// SetKeyNumber sets the key number in the KeyName
func (p *PinKey) SetKeyNumber(number int) {
	p.keyName.KeyNumber = number
}

// SetKeyVersion sets the key version in the KeyName
func (p *PinKey) SetKeyVersion(version int) {
	p.keyName.KeyVersion = version
}

// CanSign returns true if the key can be used for signing
func (p *PinKey) CanSign() bool {
	return true
}

// CanEncrypt returns true if the key can be used for encryption
func (p *PinKey) CanEncrypt() bool {
	return true
}

// Pin returns the pin within this key
func (p *PinKey) Pin() string {
	return p.pin
}

// Sign signs message
func (p *PinKey) Sign(message []byte) ([]byte, error) {
	return []byte(p.pin), nil
}

// Encrypt encryptes the message
func (p *PinKey) Encrypt(message []byte) ([]byte, error) {
	encMessage := make([]byte, len(message))
	// Make a deep copy, just in case
	copy(encMessage, message)
	return encMessage, nil
}

// Decrypt decrypts the encryptedMessage
func (p *PinKey) Decrypt(encryptedMessage []byte) ([]byte, error) {
	decMessage := make([]byte, len(encryptedMessage))
	// Make a deep copy, just in case
	copy(decMessage, encryptedMessage)
	return decMessage, nil
}

// GenerateSigningKey generates a new signing key
func GenerateSigningKey() (*PublicKey, error) {
	rsaKey, err := rsa.GenerateKey(rand.Reader, 768)
	if err != nil {
		return nil, err
	}
	p := PublicKey{
		Type:          "S",
		Modulus:       rsaKey.N.Bytes(),
		Exponent:      big.NewInt(int64(rsaKey.E)).Bytes(),
		rsaPrivateKey: rsaKey,
	}
	return &p, nil
}

// NewRSAKey returns a new RSA key
func NewRSAKey(pubKey *PublicKey, keyName *KeyName) *RSAKey {
	return &RSAKey{PublicKey: pubKey, keyName: keyName}
}

// RSAKey represents a public RSA key which implements the Key interface
type RSAKey struct {
	*PublicKey
	keyName *KeyName
}

// KeyName returns the KeyName
func (r *RSAKey) KeyName() KeyName {
	return *r.keyName
}

// SetKeyNumber sets the key number in the KeyName
func (r *RSAKey) SetKeyNumber(number int) {
	r.keyName.KeyNumber = number
}

// SetKeyVersion sets the key version in the KeyName
func (r *RSAKey) SetKeyVersion(version int) {
	r.keyName.KeyVersion = version
}

// CanSign returns true if the key can be used for signing
func (r *RSAKey) CanSign() bool {
	return r.PublicKey.rsaPrivateKey != nil
}

// CanEncrypt returns true if the key can be used for encryption
func (r *RSAKey) CanEncrypt() bool {
	return r.PublicKey.rsaPublicKey != nil
}

// NewEncryptionKey creates a new RSA encryption key
func NewEncryptionKey(modulus, exponent []byte) *PublicKey {
	p := &PublicKey{
		Type: "V",
	}
	copy(p.Modulus, modulus)
	copy(p.Exponent, exponent)
	mod := new(big.Int).SetBytes(modulus)
	exp := new(big.Int).SetBytes(exponent)
	pubKey := rsa.PublicKey{
		N: mod,
		E: int(exp.Int64()),
	}
	p.rsaPublicKey = &pubKey
	return p
}

// PublicKey represents a key which can either embed a private or public RSA key
type PublicKey struct {
	Type          string
	Modulus       []byte
	Exponent      []byte
	rsaPrivateKey *rsa.PrivateKey
	rsaPublicKey  *rsa.PublicKey
}

// SigningKey returns the RSA private key to sign with, or nil when not set
func (p *PublicKey) SigningKey() *rsa.PrivateKey {
	return p.rsaPrivateKey
}

// Sign signs message with the private key
func (p *PublicKey) Sign(message []byte) ([]byte, error) {
	return rsa.SignPKCS1v15(rand.Reader, p.rsaPrivateKey, 0, message)
}

// Encrypt encryptes the message with the public key
func (p *PublicKey) Encrypt(message []byte) ([]byte, error) {
	return rsa.EncryptPKCS1v15(rand.Reader, p.rsaPublicKey, message)
}