-
Notifications
You must be signed in to change notification settings - Fork 2
/
ultralight.go
172 lines (143 loc) · 4.65 KB
/
ultralight.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
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
// Copyright (c) 2014, 2020 Robert Clausecker <[email protected]>
// 2020 Nikitka Karpukhin <[email protected]>
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http:https://www.gnu.org/licenses/>
package freefare
// #include <freefare.h>
import "C"
import "unsafe"
// Convert a Tag into an UltralightTag to access functionality available for
// Mifare Ultralight tags.
type UltralightTag struct {
*tag
}
// Connect to a Mifare Ultralight tag. This causes the tag to be active.
func (t UltralightTag) Connect() error {
r, err := C.mifare_ultralight_connect(t.ctag)
if r != 0 {
return t.TranslateError(err)
}
return nil
}
// Disconnect from a Mifare Ultralight tag. This causes the tag to be inactive.
func (t UltralightTag) Disconnect() error {
r, err := C.mifare_ultralight_disconnect(t.ctag)
if r != 0 {
return t.TranslateError(err)
}
return nil
}
// Read one page of data from a Mifare Ultralight tag. page denotes the page
// number you want to read. Notice that page should not be larger than 16 in
// case of an Ultralight tag and not larger than 44 in case of an Ultralight C
// tag.
//
// Please notice that this function has been renamed to avoid confusion with the
// Read() function from io.Reader.
func (t UltralightTag) ReadPage(page byte) ([4]byte, error) {
var cdata C.MifareUltralightPage
r, err := C.mifare_ultralight_read(
t.ctag,
C.MifareUltralightPageNumber(page),
&cdata,
)
if r == 0 {
var data [4]byte
for i, d := range cdata {
data[i] = byte(d)
}
return data, nil
}
return [4]byte{}, t.TranslateError(err)
}
// Write one page of data from a Mifare Ultralight tag. page denotes the page
// number you want to write. Notice that page should not be larger than 16 in
// case of an Ultralight tag and not larger than 48 in case of an Ultralight C
// tag.
//
// Please notice that this function has been renamed to avoid confusion with the
// Write() function from io.Writer.
func (t UltralightTag) WritePage(page byte, data [4]byte) error {
r, err := C.mifare_ultralight_write(
t.ctag,
C.MifareUltralightPageNumber(page),
(*C.uchar)(&data[0]),
)
if r == 0 {
return nil
}
return t.TranslateError(err)
}
// Authentificate to a Mifare Ultralight tag. Note that this only works with
// MifareUltralightC tags.
func (t UltralightTag) Authenticate(key DESFireKey) error {
r, err := C.mifare_ultralightc_authenticate(t.ctag, key.key)
if r == 0 {
return nil
}
return t.TranslateError(err)
}
// Set the provided authentication key. Note that this only works with
// MifareUltralightC tags. It _should_ work only after authentication,
// but for some reason the opposite is true: it only works without it.
func (t UltralightTag) SetKey(key DESFireKey) error {
r, err := C.mifare_ultralightc_set_key(t.ctag, key.key)
if r == 0 {
return nil
}
return t.TranslateError(err)
}
// Allocate a new key deriver object which can be used to generate
// diversified keys from masterKey in accordance with AN10922.
// The non-AN10922 compliant operation mode provided for compatibility
// with old versions of the libfreefare is not supported.
func (t UltralightTag) NewAn10922(masterKey DESFireKey, keyType MifareKeyType) (kd MifareKeyDeriver, err error) {
deriver, err := C.mifare_key_deriver_new_an10922(masterKey.key, C.MifareKeyType(keyType), 0)
if deriver == nil {
err = t.TranslateError(err)
return
}
kd.tag = t.tag
kd.deriver = deriver
kd.finalizee = newFinalizee(unsafe.Pointer(deriver))
return
}
// Helper method that takes the master key and derives a new key based on tag UID
func (t UltralightTag) Diversify(masterKey DESFireKey) (*DESFireKey, error) {
deriver, err := t.NewAn10922(masterKey, MIFARE_KEY_2K3DES)
if err != nil {
return nil, err
}
err = deriver.Begin()
if err != nil {
return nil, err
}
err = deriver.UpdateUID(nil)
if err != nil {
return nil, err
}
derivedKey, err := deriver.End()
if err != nil {
return nil, err
}
return derivedKey, nil
}
// Helper function to change the authentication keys on the tag
func (t UltralightTag) SwapKeys(oldKey, newKey DESFireKey) error {
err := t.Authenticate(oldKey)
if err != nil {
t.Disconnect()
t.Connect()
}
return t.SetKey(newKey)
}