mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-08 06:00:53 -07:00
Emv4 - more additions to hf emv exec
* added rsa polarssl and changed sha1 location to polarssl dir * deleted old sha1 * added emv-tools pk files * added polarrssl wrapper sketch to emv_tols * added test command * added crypto polarssl with sda test * added crypto tests and crypto_polarssl sha logic * added SDA,DDA,fDDA,CDA
This commit is contained in:
parent
69f98ec91e
commit
d03fb293bc
40 changed files with 9983 additions and 191 deletions
|
@ -44,6 +44,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Added `hf emv select` - command for select EMV application (Merlok)
|
- Added `hf emv select` - command for select EMV application (Merlok)
|
||||||
- Added `hf emv exec` - command for execute EMV transaction (Merlok)
|
- Added `hf emv exec` - command for execute EMV transaction (Merlok)
|
||||||
- Added to `hf emv exec` MSD path for VISA and Mastercard and some other compatible EMV cards (Merlok)
|
- Added to `hf emv exec` MSD path for VISA and Mastercard and some other compatible EMV cards (Merlok)
|
||||||
|
- Added to `hf emv exec` SDA, DDA, fast DDA, CDA calculations for VISA and Mastercard and some other compatible EMV cards (Merlok)
|
||||||
|
- Added `hf emv test` - crypto tests for DES, AES, SHA, RSA, SDA, DDA, CDA and some other crypto functions (Merlok)
|
||||||
|
|
||||||
## [3.0.1][2017-06-08]
|
## [3.0.1][2017-06-08]
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ OBJDIR = obj
|
||||||
LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
|
LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
|
||||||
LUALIB = ../liblua/liblua.a
|
LUALIB = ../liblua/liblua.a
|
||||||
LDFLAGS = $(ENV_LDFLAGS)
|
LDFLAGS = $(ENV_LDFLAGS)
|
||||||
CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall -g -O3
|
CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall -g -O3
|
||||||
CXXFLAGS = -I../include -Wall -O3
|
CXXFLAGS = -I../include -Wall -O3
|
||||||
|
|
||||||
LUAPLATFORM = generic
|
LUAPLATFORM = generic
|
||||||
|
@ -88,6 +88,9 @@ CMDSRCS = crapto1/crapto1.c\
|
||||||
crapto1/crypto1.c\
|
crapto1/crypto1.c\
|
||||||
polarssl/des.c \
|
polarssl/des.c \
|
||||||
polarssl/aes.c\
|
polarssl/aes.c\
|
||||||
|
polarssl/bignum.c\
|
||||||
|
polarssl/rsa.c\
|
||||||
|
polarssl/sha1.c\
|
||||||
mfkey.c\
|
mfkey.c\
|
||||||
loclass/cipher.c \
|
loclass/cipher.c \
|
||||||
loclass/cipherutils.c \
|
loclass/cipherutils.c \
|
||||||
|
@ -107,12 +110,22 @@ CMDSRCS = crapto1/crapto1.c\
|
||||||
ui.c \
|
ui.c \
|
||||||
cmddata.c \
|
cmddata.c \
|
||||||
lfdemod.c \
|
lfdemod.c \
|
||||||
|
emv/crypto_polarssl.c\
|
||||||
|
emv/crypto.c\
|
||||||
|
emv/emv_pk.c\
|
||||||
|
emv/emv_pki.c\
|
||||||
|
emv/emv_pki_priv.c\
|
||||||
|
emv/test/cryptotest.c\
|
||||||
emv/apduinfo.c\
|
emv/apduinfo.c\
|
||||||
emv/dump.c\
|
emv/dump.c\
|
||||||
emv/tlv.c\
|
emv/tlv.c\
|
||||||
emv/emv_tags.c\
|
emv/emv_tags.c\
|
||||||
emv/dol.c\
|
emv/dol.c\
|
||||||
emv/emvcore.c\
|
emv/emvcore.c\
|
||||||
|
emv/test/crypto_test.c\
|
||||||
|
emv/test/sda_test.c\
|
||||||
|
emv/test/dda_test.c\
|
||||||
|
emv/test/cda_test.c\
|
||||||
emv/cmdemv.c\
|
emv/cmdemv.c\
|
||||||
cmdhf.c \
|
cmdhf.c \
|
||||||
cmdhf14a.c \
|
cmdhf14a.c \
|
||||||
|
@ -157,7 +170,6 @@ CMDSRCS = crapto1/crapto1.c\
|
||||||
pm3_binlib.c\
|
pm3_binlib.c\
|
||||||
pm3_bitlib.c\
|
pm3_bitlib.c\
|
||||||
protocols.c\
|
protocols.c\
|
||||||
sha1.c\
|
|
||||||
cmdcrc.c\
|
cmdcrc.c\
|
||||||
reveng/reveng.c\
|
reveng/reveng.c\
|
||||||
reveng/cli.c\
|
reveng/cli.c\
|
||||||
|
|
32
client/emv/capk.txt
Normal file
32
client/emv/capk.txt
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
a0:00:00:00:03 01 091231 rsa 03 c6:96:03:42:13:d7:d8:54:69:84:57:9d:1d:0f:0e:a5:19:cf:f8:de:ff:c4:29:35:4c:f3:a8:71:a6:f7:18:3f:12:28:da:5c:74:70:c0:55:38:71:00:cb:93:5a:71:2c:4e:28:64:df:5d:64:ba:93:fe:7e:63:e7:1f:25:b1:e5:f5:29:85:75:eb:e1:c6:3a:a6:17:70:69:17:91:1d:c2:a7:5a:c2:8b:25:1c:7e:f4:0f:23:65:91:24:90:b9:39:bc:a2:12:4a:30:a2:8f:54:40:2c:34:ae:ca:33:1a:b6:7e:1e:79:b2:85:dd:57:71:b5:d9:ff:79:ea:63:0b:75 sha1 d3:4a:6a:77:60:11:c7:e7:ce:3a:ec:5f:03:ad:2f:8c:fc:55:03:cc
|
||||||
|
a0:00:00:00:03 07 171231 rsa 03 a8:9f:25:a5:6f:a6:da:25:8c:8c:a8:b4:04:27:d9:27:b4:a1:eb:4d:7e:a3:26:bb:b1:2f:97:de:d7:0a:e5:e4:48:0f:c9:c5:e8:a9:72:17:71:10:a1:cc:31:8d:06:d2:f8:f5:c4:84:4a:c5:fa:79:a4:dc:47:0b:b1:1e:d6:35:69:9c:17:08:1b:90:f1:b9:84:f1:2e:92:c1:c5:29:27:6d:8a:f8:ec:7f:28:49:20:97:d8:cd:5b:ec:ea:16:fe:40:88:f6:cf:ab:4a:1b:42:32:8a:1b:99:6f:92:78:b0:b7:e3:31:1c:a5:ef:85:6c:2f:88:84:74:b8:36:12:a8:2e:4e:00:d0:cd:40:69:a6:78:31:40:43:3d:50:72:5f sha1 b4:bc:56:cc:4e:88:32:49:32:cb:c6:43:d6:89:8f:6f:e5:93:b1:72
|
||||||
|
a0:00:00:00:03 08 221231 rsa 03 d9:fd:6e:d7:5d:51:d0:e3:06:64:bd:15:70:23:ea:a1:ff:a8:71:e4:da:65:67:2b:86:3d:25:5e:81:e1:37:a5:1d:e4:f7:2b:cc:9e:44:ac:e1:21:27:f8:7e:26:3d:3a:f9:dd:9c:f3:5c:a4:a7:b0:1e:90:70:00:ba:85:d2:49:54:c2:fc:a3:07:48:25:dd:d4:c0:c8:f1:86:cb:02:0f:68:3e:02:f2:de:ad:39:69:13:3f:06:f7:84:51:66:ac:eb:57:ca:0f:c2:60:34:45:46:98:11:d2:93:bf:ef:ba:fa:b5:76:31:b3:dd:91:e7:96:bf:85:0a:25:01:2f:1a:e3:8f:05:aa:5c:4d:6d:03:b1:dc:2e:56:86:12:78:59:38:bb:c9:b3:cd:3a:91:0c:1d:a5:5a:5a:92:18:ac:e0:f7:a2:12:87:75:26:82:f1:58:32:a6:78:d6:e1:ed:0b sha1 20:d2:13:12:69:55:de:20:5a:dc:2f:d2:82:2b:d2:2d:e2:1c:f9:a8
|
||||||
|
a0:00:00:00:03 09 221231 rsa 03 9d:91:22:48:de:0a:4e:39:c1:a7:dd:e3:f6:d2:58:89:92:c1:a4:09:5a:fb:d1:82:4d:1b:a7:48:47:f2:bc:49:26:d2:ef:d9:04:b4:b5:49:54:cd:18:9a:54:c5:d1:17:96:54:f8:f9:b0:d2:ab:5f:03:57:eb:64:2f:ed:a9:5d:39:12:c6:57:69:45:fa:b8:97:e7:06:2c:aa:44:a4:aa:06:b8:fe:6e:3d:ba:18:af:6a:e3:73:8e:30:42:9e:e9:be:03:42:7c:9d:64:f6:95:fa:8c:ab:4b:fe:37:68:53:ea:34:ad:1d:76:bf:ca:d1:59:08:c0:77:ff:e6:dc:55:21:ec:ef:5d:27:8a:96:e2:6f:57:35:9f:fa:ed:a1:94:34:b9:37:f1:ad:99:9d:c5:c4:1e:b1:19:35:b4:4c:18:10:0e:85:7f:43:1a:4a:5a:6b:b6:51:14:f1:74:c2:d7:b5:9f:df:23:7d:6b:b1:dd:09:16:e6:44:d7:09:de:d5:64:81:47:7c:75:d9:5c:dd:68:25:46:15:f7:74:0e:c0:7f:33:0a:c5:d6:7b:cd:75:bf:23:d2:8a:14:08:26:c0:26:db:de:97:1a:37:cd:3e:f9:b8:df:64:4a:c3:85:01:05:01:ef:c6:50:9d:7a:41 sha1 1f:f8:0a:40:17:3f:52:d7:d2:7e:0f:26:a1:46:a1:c8:cc:b2:90:46
|
||||||
|
a0:00:00:00:03 95 000000 rsa 03 be:9e:1f:a5:e9:a8:03:85:29:99:c4:ab:43:2d:b2:86:00:dc:d9:da:b7:6d:fa:aa:47:35:5a:0f:e3:7b:15:08:ac:6b:f3:88:60:d3:c6:c2:e5:b1:2a:3c:aa:f2:a7:00:5a:72:41:eb:aa:77:71:11:2c:74:cf:9a:06:34:65:2f:bc:a0:e5:98:0c:54:a6:47:61:ea:10:1a:11:4e:0f:0b:55:72:ad:d5:7d:01:0b:7c:9c:88:7e:10:4c:a4:ee:12:72:da:66:d9:97:b9:a9:0b:5a:6d:62:4a:b6:c5:7e:73:c8:f9:19:00:0e:b5:f6:84:89:8e:f8:c3:db:ef:b3:30:c6:26:60:be:d8:8e:a7:8e:90:9a:ff:05:f6:da:62:7b sha1 ee:15:11:ce:c7:10:20:a9:b9:04:43:b3:7b:1d:5f:6e:70:30:30:f6
|
||||||
|
a0:00:00:00:03 92 000000 rsa 03 99:6a:f5:6f:56:91:87:d0:92:93:c1:48:10:45:0e:d8:ee:33:57:39:7b:18:a2:45:8e:fa:a9:2d:a3:b6:df:65:14:ec:06:01:95:31:8f:d4:3b:e9:b8:f0:cc:66:9e:3f:84:40:57:cb:dd:f8:bd:a1:91:bb:64:47:3b:c8:dc:9a:73:0d:b8:f6:b4:ed:e3:92:41:86:ff:d9:b8:c7:73:57:89:c2:3a:36:ba:0b:8a:f6:53:72:eb:57:ea:5d:89:e7:d1:4e:9c:7b:6b:55:74:60:f1:08:85:da:16:ac:92:3f:15:af:37:58:f0:f0:3e:bd:3c:5c:2c:94:9c:ba:30:6d:b4:4e:6a:2c:07:6c:5f:67:e2:81:d7:ef:56:78:5d:c4:d7:59:45:e4:91:f0:19:18:80:0a:9e:2d:c6:6f:60:08:05:66:ce:0d:af:8d:17:ea:d4:6a:d8:e3:0a:24:7c:9f sha1 42:9c:95:4a:38:59:ce:f9:12:95:f6:63:c9:63:e5:82:ed:6e:b2:53
|
||||||
|
a0:00:00:00:03 94 000000 rsa 03 ac:d2:b1:23:02:ee:64:4f:3f:83:5a:bd:1f:c7:a6:f6:2c:ce:48:ff:ec:62:2a:a8:ef:06:2b:ef:6f:b8:ba:8b:c6:8b:bf:6a:b5:87:0e:ed:57:9b:c3:97:3e:12:13:03:d3:48:41:a7:96:d6:dc:bc:41:db:f9:e5:2c:46:09:79:5c:0c:cf:7e:e8:6f:a1:d5:cb:04:10:71:ed:2c:51:d2:20:2f:63:f1:15:6c:58:a9:2d:38:bc:60:bd:f4:24:e1:77:6e:2b:c9:64:80:78:a0:3b:36:fb:55:43:75:fc:53:d5:7c:73:f5:16:0e:a5:9f:3a:fc:53:98:ec:7b:67:75:8d:65:c9:bf:f7:82:8b:6b:82:d4:be:12:4a:41:6a:b7:30:19:14:31:1e:a4:62:c1:9f:77:1f:31:b3:b5:73:36:00:0d:ff:73:2d:3b:83:de:07:05:2d:73:03:54:d2:97:be:c7:28:71:dc:cf:0e:19:3f:17:1a:ba:27:ee:46:4c:6a:97:69:09:43:d5:9b:da:bb:2a:27:eb:71:ce:eb:da:fa:11:76:04:64:78:fd:62:fe:c4:52:d5:ca:39:32:96:53:0a:a3:f4:19:27:ad:fe:43:4a:2d:f2:ae:30:54:f8:84:06:57:a2:6e:0f:c6:17 sha1 c4:a3:c4:3c:cf:87:32:7d:13:6b:80:41:60:e4:7d:43:b6:0e:6e:0f
|
||||||
|
a0:00:00:00:04 03 000000 rsa 03 c2:49:07:47:fe:17:eb:05:84:c8:8d:47:b1:60:27:04:15:0a:dc:88:c5:b9:98:bd:59:ce:04:3e:de:bf:0f:fe:e3:09:3a:c7:95:6a:d3:b6:ad:45:54:c6:de:19:a1:78:d6:da:29:5b:e1:5d:52:20:64:5e:3c:81:31:66:6f:a4:be:5b:84:fe:13:1e:a4:4b:03:93:07:63:8b:9e:74:a8:c4:25:64:f8:92:a6:4d:f1:cb:15:71:2b:73:6e:33:74:f1:bb:b6:81:93:71:60:2d:89:70:e9:7b:90:07:93:c7:c2:a8:9a:4a:16:49:a5:9b:e6:80:57:4d:d0:b6:01:45 sha1 5a:dd:f2:1d:09:27:86:61:14:11:79:cb:ef:f2:72:ea:38:4b:13:bb
|
||||||
|
a0:00:00:00:04 04 000000 rsa 03 a6:da:42:83:87:a5:02:d7:dd:fb:7a:74:d3:f4:12:be:76:26:27:19:7b:25:43:5b:7a:81:71:6a:70:01:57:dd:d0:6f:7c:c9:9d:6c:a2:8c:24:70:52:7e:2c:03:61:6b:9c:59:21:73:57:c2:67:4f:58:3b:3b:a5:c7:dc:f2:83:86:92:d0:23:e3:56:24:20:b4:61:5c:43:9c:a9:7c:44:dc:9a:24:9c:fc:e7:b3:bf:b2:2f:68:22:8c:3a:f1:33:29:aa:4a:61:3c:f8:dd:85:35:02:37:3d:62:e4:9a:b2:56:d2:bc:17:12:0e:54:ae:dc:ed:6d:96:a4:28:7a:cc:5c:04:67:7d:4a:5a:32:0d:b8:be:e2:f7:75:e5:fe:c5 sha1 38:1a:03:5d:a5:8b:48:2e:e2:af:75:f4:c3:f2:ca:46:9b:a4:aa:6c
|
||||||
|
a0:00:00:00:04 05 000000 rsa 03 b8:04:8a:bc:30:c9:0d:97:63:36:54:3e:3f:d7:09:1c:8f:e4:80:0d:f8:20:ed:55:e7:e9:48:13:ed:00:55:5b:57:3f:ec:a3:d8:4a:f6:13:1a:65:1d:66:cf:f4:28:4f:b1:3b:63:5e:dd:0e:e4:01:76:d8:bf:04:b7:fd:1c:7b:ac:f9:ac:73:27:df:aa:8a:a7:2d:10:db:3b:8e:70:b2:dd:d8:11:cb:41:96:52:5e:a3:86:ac:c3:3c:0d:9d:45:75:91:64:69:c4:e4:f5:3e:8e:1c:91:2c:c6:18:cb:22:dd:e7:c3:56:8e:90:02:2e:6b:ba:77:02:02:e4:52:2a:2d:d6:23:d1:80:e2:15:bd:1d:15:07:fe:3d:c9:0c:a3:10:d2:7b:3e:fc:cd:8f:83:de:30:52:ca:d1:e4:89:38:c6:8d:09:5a:ac:91:b5:f3:7e:28:bb:49:ec:7e:d5:97 sha1 eb:fa:0d:5d:06:d8:ce:70:2d:a3:ea:e8:90:70:1d:45:e2:74:c8:45
|
||||||
|
a0:00:00:00:04 06 000000 rsa 03 cb:26:fc:83:0b:43:78:5b:2b:ce:37:c8:1e:d3:34:62:2f:96:22:f4:c8:9a:ae:64:10:46:b2:35:34:33:88:3f:30:7f:b7:c9:74:16:2d:a7:2f:7a:4e:c7:5d:9d:65:73:36:86:5b:8d:30:23:d3:d6:45:66:76:25:c9:a0:7a:6b:7a:13:7c:f0:c6:41:98:ae:38:fc:23:80:06:fb:26:03:f4:1f:4f:3b:b9:da:13:47:27:0f:2f:5d:8c:60:6e:42:09:58:c5:f7:d5:0a:71:de:30:14:2f:70:de:46:88:89:b5:e3:a0:86:95:b9:38:a5:0f:c9:80:39:3a:9c:bc:e4:4a:d2:d6:4f:63:0b:b3:3a:d3:f5:f5:fd:49:5d:31:f3:78:18:c1:d9:40:71:34:2e:07:f1:be:c2:19:4f:60:35:ba:5d:ed:39:36:50:0e:b8:2d:fd:a6:e8:af:b6:55:b1:ef:3d:0d:7e:bf:86:b6:6d:d9:f2:9f:6b:1d:32:4f:e8:b2:6c:e3:8a:b2:01:3d:d1:3f:61:1e:7a:59:4d:67:5c:44:32:35:0e:a2:44:cc:34:f3:87:3c:ba:06:59:29:87:a1:d7:e8:52:ad:c2:2e:f5:a2:ee:28:13:20:31:e4:8f:74:03:7e:3b:34:ab:74:7f sha1 f9:10:a1:50:4d:5f:fb:79:3d:94:f3:b5:00:76:5e:1a:bc:ad:72:d9
|
||||||
|
a0:00:00:00:04 00 000000 rsa 03 9c:6b:e5:ad:b1:0b:4b:e3:dc:e2:09:9b:4b:21:06:72:b8:96:56:eb:a0:91:20:4f:61:3e:cc:62:3b:ed:c9:c6:d7:7b:66:0e:8b:ae:ea:7f:7c:e3:0f:1b:15:38:79:a4:e3:64:59:34:3d:1f:e4:7a:cd:bd:41:fc:d7:10:03:0c:2b:a1:d9:46:15:97:98:2c:6e:1b:dd:08:55:4b:72:6f:5e:ff:79:13:ce:59:e7:9e:35:72:95:c3:21:e2:6d:0b:8b:e2:70:a9:44:23:45:c7:53:e2:aa:2a:cf:c9:d3:08:50:60:2f:e6:ca:c0:0c:6d:df:6b:8d:9d:9b:48:79:b2:82:6b:04:2a:07:f0:e5:ae:52:6a:3d:3c:4d:22:c7:2b:9e:aa:52:ee:d8:89:38:66:f8:66:38:7a:c0:5a:13:99 sha1 ec:0a:59:d3:5d:19:f0:31:e9:e8:cb:ec:56:db:80:e2:2b:1d:e1:30
|
||||||
|
a0:00:00:00:04 02 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 33:40:8b:96:c8:14:74:2a:d7:35:36:c7:2f:09:26:e4:47:1e:8e:47
|
||||||
|
a0:00:00:00:04 05 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 53:d0:49:03:b4:96:f5:95:44:a8:43:09:af:16:92:51:f2:89:68:74
|
||||||
|
a0:00:00:00:04 ef 000000 rsa 03 a1:91:cb:87:47:3f:29:34:9b:5d:60:a8:8b:3e:ae:e0:97:3a:a6:f1:a0:82:f3:58:d8:49:fd:df:f9:c0:91:f8:99:ed:a9:79:2c:af:09:ef:28:f5:d2:24:04:b8:8a:22:93:ee:bb:c1:94:9c:43:be:a4:d6:0c:fd:87:9a:15:39:54:4e:09:e0:f0:9f:60:f0:65:b2:bf:2a:13:ec:c7:05:f3:d4:68:b9:d3:3a:e7:7a:d9:d3:f1:9c:a4:0f:23:dc:f5:eb:7c:04:dc:8f:69:eb:a5:65:b1:eb:cb:46:86:cd:27:47:85:53:0f:f6:f6:e9:ee:43:aa:43:fd:b0:2c:e0:0d:ae:c1:5c:7b:8f:d6:a9:b3:94:ba:ba:41:9d:3f:6d:c8:5e:16:56:9b:e8:e7:69:89:68:8e:fe:a2:df:22:ff:7d:35:c0:43:33:8d:ea:a9:82:a0:2b:86:6d:e5:32:85:19:eb:bc:d6:f0:3c:dd:68:66:73:84:7f:84:db:65:1a:b8:6c:28:cf:14:62:56:2c:57:7b:85:35:64:a2:90:c8:55:6d:81:85:31:26:8d:25:cc:98:a4:cc:6a:0b:df:ff:da:2d:cc:a3:a9:4c:99:85:59:e3:07:fd:df:91:50:06:d9:a9:87:b0:7d:da:eb:3b sha1 21:76:6e:bb:0e:e1:22:af:b6:5d:78:45:b7:3d:b4:6b:ab:65:42:7a
|
||||||
|
a0:00:00:00:04 f1 000000 rsa 03 a0:dc:f4:bd:e1:9c:35:46:b4:b6:f0:41:4d:17:4d:de:29:4a:ab:bb:82:8c:5a:83:4d:73:aa:e2:7c:99:b0:b0:53:a9:02:78:00:72:39:b6:45:9f:f0:bb:cd:7b:4b:9c:6c:50:ac:02:ce:91:36:8d:a1:bd:21:aa:ea:db:c6:53:47:33:7d:89:b6:8f:5c:99:a0:9d:05:be:02:dd:1f:8c:5b:a2:0e:2f:13:fb:2a:27:c4:1d:3f:85:ca:d5:cf:66:68:e7:58:51:ec:66:ed:bf:98:85:1f:d4:e4:2c:44:c1:d5:9f:59:84:70:3b:27:d5:b9:f2:1b:8f:a0:d9:32:79:fb:bf:69:e0:90:64:29:09:c9:ea:27:f8:98:95:95:41:aa:67:57:f5:f6:24:10:4f:6e:1d:3a:95:32:f2:a6:e5:15:15:ae:ad:1b:43:b3:d7:83:50:88:a2:fa:fa:7b:e7 sha1 d8:e6:8d:a1:67:ab:5a:85:d8:c3:d5:5e:cb:9b:05:17:a1:a5:b4:bb
|
||||||
|
a0:00:00:00:04 f3 000000 rsa 03 98:f0:c7:70:f2:38:64:c2:e7:66:df:02:d1:e8:33:df:f4:ff:e9:2d:69:6e:16:42:f0:a8:8c:56:94:c6:47:9d:16:db:15:37:bf:e2:9e:4f:dc:6e:6e:8a:fd:1b:0e:b7:ea:01:24:72:3c:33:31:79:bf:19:e9:3f:10:65:8b:2f:77:6e:82:9e:87:da:ed:a9:c9:4a:8b:33:82:19:9a:35:0c:07:79:77:c9:7a:ff:08:fd:11:31:0a:c9:50:a7:2c:3c:a5:00:2e:f5:13:fc:cc:28:6e:64:6e:3c:53:87:53:5d:50:95:14:b3:b3:26:e1:23:4f:9c:b4:8c:36:dd:d4:4b:41:6d:23:65:40:34:a6:6f:40:3b:a5:11:c5:ef:a3 sha1 a6:9a:c7:60:3d:af:56:6e:97:2d:ed:c2:cb:43:3e:07:e8:b0:1a:9a
|
||||||
|
a0:00:00:00:04 f5 000000 rsa 01:00:01 a6:e6:fb:72:17:95:06:f8:60:cc:ca:8c:27:f9:9c:ec:d9:4c:7d:4f:31:91:d3:03:bb:ee:37:48:1c:7a:a1:5f:23:3b:a7:55:e9:e4:37:63:45:a9:a6:7e:79:94:bd:c1:c6:80:bb:35:22:d8:c9:3e:b0:cc:c9:1a:d3:1a:d4:50:da:30:d3:37:66:2d:19:ac:03:e2:b4:ef:5f:6e:c1:82:82:d4:91:e1:97:67:d7:b2:45:42:df:de:ff:6f:62:18:55:03:53:20:69:bb:b3:69:e3:bb:9f:b1:9a:c6:f1:c3:0b:97:d2:49:ee:e7:64:e0:ba:c9:7f:25:c8:73:d9:73:95:3e:51:53:a4:20:64:bb:fa:bf:d0:6a:4b:b4:86:86:0b:f6:63:74:06:c9:fc:36:81:3a:4a:75:f7:5c:31:cc:a9:f6:9f:8d:e5:9a:de:ce:f6:bd:e7:e0:78:00:fc:be:03:5d:31:76:af:84:73:e2:3e:9a:a3:df:ee:22:11:96:d1:14:83:02:67:7c:72:0c:fe:25:44:a0:3d:b5:53:e7:f1:b8:42:7b:a1:cc:72:b0:f2:9b:12:df:ef:4c:08:1d:07:6d:35:3e:71:88:0a:ad:ff:38:63:52:af:0a:b7:b2:8e:d4:9e:1e:67:2d:11:f9 sha1 c2:23:98:04:c8:09:81:70:be:52:d6:d5:d4:15:9e:81:ce:84:66:bf
|
||||||
|
a0:00:00:00:04 f6 000000 rsa 03 a2:5a:6b:d7:83:a5:ef:6b:8f:b6:f8:30:55:c2:60:f5:f9:9e:a1:66:78:f3:b9:05:3e:0f:64:98:e8:2c:3f:5d:1e:8c:38:f1:35:88:01:7e:2b:12:b3:d8:ff:6f:50:16:7f:46:44:29:10:72:9e:9e:4d:1b:37:39:e5:06:7c:0a:c7:a1:f4:48:7e:35:f6:75:bc:16:e2:33:31:51:65:cb:14:2b:fd:b2:5e:30:1a:63:2a:54:a3:37:1e:ba:b6:57:2d:ee:ba:f3:70:f3:37:f0:57:ee:73:b4:ae:46:d1:a8:bc:4d:a8:53:ec:3c:c1:2c:8c:bc:2d:a1:83:22:d6:85:30:c7:0b:22:bd:ac:35:1d:d3:60:68:ae:32:1e:11:ab:f2:64:f4:d3:56:9b:b7:12:14:54:50:05:55:8d:e2:60:83:c7:35:db:77:63:68:17:2f:e8:c2:f5:c8:5e:8b:5b:89:0c:c6:82:91:1d:2d:e7:1f:a6:26:b8:81:7f:cc:c0:89:22:b7:03:86:9f:3b:ae:ac:14:59:d7:7c:d8:53:76:bc:36:18:2f:42:38:31:4d:6c:42:12:fb:dd:7f:23:d3 sha1 50:29:09:ed:54:5e:3c:8d:bd:00:ea:58:2d:06:17:fe:e9:f6:f6:84
|
||||||
|
a0:00:00:00:04 f7 000000 rsa 01:00:01 94:ea:62:f6:d5:83:20:e3:54:c0:22:ad:dc:f0:55:9d:8c:f2:06:cd:92:e8:69:56:49:05:ce:21:d7:20:f9:71:b7:ae:a3:74:83:0e:be:17:57:11:5a:85:e0:88:d4:1c:6b:77:cf:5e:c8:21:f3:0b:1d:89:04:17:bf:2f:a3:1e:59:08:de:d5:fa:67:7f:8c:7b:18:4a:d0:90:28:fd:de:96:b6:a6:10:98:50:aa:80:01:75:ea:bc:db:bb:68:4a:96:c2:eb:63:79:df:ea:08:d3:2f:e2:33:1f:e1:03:23:3a:d5:8d:cd:b1:e6:e0:77:cb:9f:24:ea:ec:5c:25:af sha1 ee:b0:dd:9b:24:77:be:e3:20:9a:91:4c:db:a9:4c:1c:4a:9b:de:d9
|
||||||
|
a0:00:00:00:04 f8 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 f0:6e:cc:6d:2a:ae:bf:25:9b:7e:75:5a:38:d9:a9:b2:4e:2f:f3:dd
|
||||||
|
a0:00:00:00:04 f9 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 33:67:12:dc:c2:85:54:80:9c:6a:a9:b0:23:58:de:6f:75:51:64:db
|
||||||
|
a0:00:00:00:04 fa 000000 rsa 03 a9:0f:cd:55:aa:2d:5d:99:63:e3:5e:d0:f4:40:17:76:99:83:2f:49:c6:ba:b1:5c:da:e5:79:4b:e9:3f:93:4d:44:62:d5:d1:27:62:e4:8c:38:ba:83:d8:44:5d:ea:a7:41:95:a3:01:a1:02:b2:f1:14:ea:da:0d:18:0e:e5:e7:a5:c7:3e:0c:4e:11:f6:7a:43:dd:ab:5d:55:68:3b:14:74:cc:06:27:f4:4b:8d:30:88:a4:92:ff:aa:da:d4:f4:24:22:d0:e7:01:35:36:c3:c4:9a:d3:d0:fa:e9:64:59:b0:f6:b1:b6:05:65:38:a3:d6:d4:46:40:f9:44:67:b1:08:86:7d:ec:40:fa:ae:cd:74:0c:00:e2:b7:a8:85:2d sha1 5b:ed:40:68:d9:6e:a1:6d:2d:77:e0:3d:60:36:fc:7a:16:0e:a9:9c
|
||||||
|
b0:12:34:56:78 00 000000 rsa 03 9c:6b:e5:ad:b1:0b:4b:e3:dc:e2:09:9b:4b:21:06:72:b8:96:56:eb:a0:91:20:4f:61:3e:cc:62:3b:ed:c9:c6:d7:7b:66:0e:8b:ae:ea:7f:7c:e3:0f:1b:15:38:79:a4:e3:64:59:34:3d:1f:e4:7a:cd:bd:41:fc:d7:10:03:0c:2b:a1:d9:46:15:97:98:2c:6e:1b:dd:08:55:4b:72:6f:5e:ff:79:13:ce:59:e7:9e:35:72:95:c3:21:e2:6d:0b:8b:e2:70:a9:44:23:45:c7:53:e2:aa:2a:cf:c9:d3:08:50:60:2f:e6:ca:c0:0c:6d:df:6b:8d:9d:9b:48:79:b2:82:6b:04:2a:07:f0:e5:ae:52:6a:3d:3c:4d:22:c7:2b:9e:aa:52:ee:d8:89:38:66:f8:66:38:7a:c0:5a:13:99 sha1 5d:29:70:e6:46:75:72:7e:60:46:07:65:a8:db:75:34:2a:e1:47:83
|
||||||
|
b0:12:34:56:78 02 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 29:4b:e2:02:39:ab:15:24:5a:63:be:a4:6c:c6:c1:75:a2:55:62:d1
|
||||||
|
b0:12:34:56:78 05 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 b9:a1:d6:5c:af:e0:6b:05:4e:dd:7e:a8:25:97:ab:85:f1:30:e6:63
|
||||||
|
b0:12:34:56:78 f3 000000 rsa 01:00:01 94:ea:62:f6:d5:83:20:e3:54:c0:22:ad:dc:f0:55:9d:8c:f2:06:cd:92:e8:69:56:49:05:ce:21:d7:20:f9:71:b7:ae:a3:74:83:0e:be:17:57:11:5a:85:e0:88:d4:1c:6b:77:cf:5e:c8:21:f3:0b:1d:89:04:17:bf:2f:a3:1e:59:08:de:d5:fa:67:7f:8c:7b:18:4a:d0:90:28:fd:de:96:b6:a6:10:98:50:aa:80:01:75:ea:bc:db:bb:68:4a:96:c2:eb:63:79:df:ea:08:d3:2f:e2:33:1f:e1:03:23:3a:d5:8d:cd:b1:e6:e0:77:cb:9f:24:ea:ec:5c:25:af sha1 56:94:b0:d2:78:48:18:14:a0:5e:12:b5:58:ce:c1:23:48:65:aa:5d
|
||||||
|
b0:12:34:56:78 f5 000000 rsa 03 a2:5a:6b:d7:83:a5:ef:6b:8f:b6:f8:30:55:c2:60:f5:f9:9e:a1:66:78:f3:b9:05:3e:0f:64:98:e8:2c:3f:5d:1e:8c:38:f1:35:88:01:7e:2b:12:b3:d8:ff:6f:50:16:7f:46:44:29:10:72:9e:9e:4d:1b:37:39:e5:06:7c:0a:c7:a1:f4:48:7e:35:f6:75:bc:16:e2:33:31:51:65:cb:14:2b:fd:b2:5e:30:1a:63:2a:54:a3:37:1e:ba:b6:57:2d:ee:ba:f3:70:f3:37:f0:57:ee:73:b4:ae:46:d1:a8:bc:4d:a8:53:ec:3c:c1:2c:8c:bc:2d:a1:83:22:d6:85:30:c7:0b:22:bd:ac:35:1d:d3:60:68:ae:32:1e:11:ab:f2:64:f4:d3:56:9b:b7:12:14:54:50:05:55:8d:e2:60:83:c7:35:db:77:63:68:17:2f:e8:c2:f5:c8:5e:8b:5b:89:0c:c6:82:91:1d:2d:e7:1f:a6:26:b8:81:7f:cc:c0:89:22:b7:03:86:9f:3b:ae:ac:14:59:d7:7c:d8:53:76:bc:36:18:2f:42:38:31:4d:6c:42:12:fb:dd:7f:23:d3 sha1 f7:5e:88:02:85:5c:9b:14:02:7e:51:73:45:71:7e:5c:36:35:b9:1b
|
||||||
|
b0:12:34:56:78 f6 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 e9:40:6b:65:10:c1:43:ab:1e:9b:9d:79:a3:c1:df:f8:90:9a:34:7c
|
||||||
|
b0:12:34:56:78 f7 000000 rsa 03 98:f0:c7:70:f2:38:64:c2:e7:66:df:02:d1:e8:33:df:f4:ff:e9:2d:69:6e:16:42:f0:a8:8c:56:94:c6:47:9d:16:db:15:37:bf:e2:9e:4f:dc:6e:6e:8a:fd:1b:0e:b7:ea:01:24:72:3c:33:31:79:bf:19:e9:3f:10:65:8b:2f:77:6e:82:9e:87:da:ed:a9:c9:4a:8b:33:82:19:9a:35:0c:07:79:77:c9:7a:ff:08:fd:11:31:0a:c9:50:a7:2c:3c:a5:00:2e:f5:13:fc:cc:28:6e:64:6e:3c:53:87:53:5d:50:95:14:b3:b3:26:e1:23:4f:9c:b4:8c:36:dd:d4:4b:41:6d:23:65:40:34:a6:6f:40:3b:a5:11:c5:ef:a3 sha1 f7:81:13:e8:60:f0:30:a8:72:92:3f:ce:93:e3:38:1c:77:a4:2a:30
|
||||||
|
b0:12:34:56:78 f8 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 66:46:9c:88:e7:dc:11:15:29:c7:d3:79:d7:93:8c:8d:f3:e4:c2:5e
|
||||||
|
b0:12:34:56:78 f9 000000 rsa 01:00:01 a6:e6:fb:72:17:95:06:f8:60:cc:ca:8c:27:f9:9c:ec:d9:4c:7d:4f:31:91:d3:03:bb:ee:37:48:1c:7a:a1:5f:23:3b:a7:55:e9:e4:37:63:45:a9:a6:7e:79:94:bd:c1:c6:80:bb:35:22:d8:c9:3e:b0:cc:c9:1a:d3:1a:d4:50:da:30:d3:37:66:2d:19:ac:03:e2:b4:ef:5f:6e:c1:82:82:d4:91:e1:97:67:d7:b2:45:42:df:de:ff:6f:62:18:55:03:53:20:69:bb:b3:69:e3:bb:9f:b1:9a:c6:f1:c3:0b:97:d2:49:ee:e7:64:e0:ba:c9:7f:25:c8:73:d9:73:95:3e:51:53:a4:20:64:bb:fa:bf:d0:6a:4b:b4:86:86:0b:f6:63:74:06:c9:fc:36:81:3a:4a:75:f7:5c:31:cc:a9:f6:9f:8d:e5:9a:de:ce:f6:bd:e7:e0:78:00:fc:be:03:5d:31:76:af:84:73:e2:3e:9a:a3:df:ee:22:11:96:d1:14:83:02:67:7c:72:0c:fe:25:44:a0:3d:b5:53:e7:f1:b8:42:7b:a1:cc:72:b0:f2:9b:12:df:ef:4c:08:1d:07:6d:35:3e:71:88:0a:ad:ff:38:63:52:af:0a:b7:b2:8e:d4:9e:1e:67:2d:11:f9 sha1 ae:ac:a4:54:80:c8:83:4c:b0:be:bd:cc:57:0b:7b:2b:74:bb:4b:79
|
|
@ -9,6 +9,7 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "cmdemv.h"
|
#include "cmdemv.h"
|
||||||
|
#include "test/cryptotest.h"
|
||||||
|
|
||||||
int UsageCmdHFEMVSelect(void) {
|
int UsageCmdHFEMVSelect(void) {
|
||||||
PrintAndLog("HELP : Executes select applet command:\n");
|
PrintAndLog("HELP : Executes select applet command:\n");
|
||||||
|
@ -277,7 +278,7 @@ int CmdHFEMVPPSE(const char *cmd) {
|
||||||
|
|
||||||
int UsageCmdHFEMVExec(void) {
|
int UsageCmdHFEMVExec(void) {
|
||||||
PrintAndLog("HELP : Executes EMV contactless transaction:\n");
|
PrintAndLog("HELP : Executes EMV contactless transaction:\n");
|
||||||
PrintAndLog("Usage: hf emv exec [-s][-a][-t]\n");
|
PrintAndLog("Usage: hf emv exec [-s][-a][-t][-f][-v][-c][-x][-g]\n");
|
||||||
PrintAndLog(" Options:");
|
PrintAndLog(" Options:");
|
||||||
PrintAndLog(" -s : select card");
|
PrintAndLog(" -s : select card");
|
||||||
PrintAndLog(" -a : show APDU reqests and responses\n");
|
PrintAndLog(" -a : show APDU reqests and responses\n");
|
||||||
|
@ -286,14 +287,16 @@ int UsageCmdHFEMVExec(void) {
|
||||||
PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n");
|
PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n");
|
||||||
PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
|
PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
|
||||||
PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n");
|
PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n");
|
||||||
|
PrintAndLog(" -g : VISA. generate AC from GPO\n");
|
||||||
PrintAndLog("By default : transaction type - MSD.\n");
|
PrintAndLog("By default : transaction type - MSD.\n");
|
||||||
PrintAndLog("Samples:");
|
PrintAndLog("Samples:");
|
||||||
PrintAndLog(" hf emv pse -s -> select card");
|
PrintAndLog(" hf emv exec -s -a -t -> execute MSD transaction");
|
||||||
PrintAndLog(" hf emv pse -s -t -a -> select card, show responses in TLV, show APDU");
|
PrintAndLog(" hf emv exec -s -a -t -c -> execute CDA transaction");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TLV_ADD(tag, value)( tlvdb_add(tlvRoot, tlvdb_fixed(tag, sizeof(value) - 1, (const unsigned char *)value)) )
|
#define TLV_ADD(tag, value)( tlvdb_add(tlvRoot, tlvdb_fixed(tag, sizeof(value) - 1, (const unsigned char *)value)) )
|
||||||
|
#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;}
|
||||||
|
|
||||||
int CmdHFEMVExec(const char *cmd) {
|
int CmdHFEMVExec(const char *cmd) {
|
||||||
bool activateField = false;
|
bool activateField = false;
|
||||||
|
@ -301,15 +304,22 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
bool decodeTLV = false;
|
bool decodeTLV = false;
|
||||||
bool forceSearch = false;
|
bool forceSearch = false;
|
||||||
enum TransactionType TrType = TT_MSD;
|
enum TransactionType TrType = TT_MSD;
|
||||||
|
bool GenACGPO = false;
|
||||||
|
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
uint8_t AID[APDU_AID_LEN] = {0};
|
uint8_t AID[APDU_AID_LEN] = {0};
|
||||||
size_t AIDlen = 0;
|
size_t AIDlen = 0;
|
||||||
|
uint8_t ODAiList[4096];
|
||||||
|
size_t ODAiListLen = 0;
|
||||||
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
struct tlvdb *tlvSelect = NULL;
|
||||||
|
struct tlvdb *tlvRoot = NULL;
|
||||||
|
struct tlv *pdol_data_tlv = NULL;
|
||||||
|
|
||||||
if (strlen(cmd) < 1) {
|
if (strlen(cmd) < 1) {
|
||||||
UsageCmdHFEMVExec();
|
UsageCmdHFEMVExec();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -352,6 +362,10 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
case 'C':
|
case 'C':
|
||||||
TrType = TT_CDA;
|
TrType = TT_CDA;
|
||||||
break;
|
break;
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
GenACGPO = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
|
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -361,7 +375,6 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
|
|
||||||
|
|
||||||
// init applets list tree
|
// init applets list tree
|
||||||
struct tlvdb *tlvSelect = NULL;
|
|
||||||
const char *al = "Applets list";
|
const char *al = "Applets list";
|
||||||
tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
|
tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
|
||||||
|
|
||||||
|
@ -385,8 +398,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
PrintAndLog("\n* Search AID in list.");
|
PrintAndLog("\n* Search AID in list.");
|
||||||
SetAPDULogging(false);
|
SetAPDULogging(false);
|
||||||
if (EMVSearch(activateField, true, decodeTLV, tlvSelect)) {
|
if (EMVSearch(activateField, true, decodeTLV, tlvSelect)) {
|
||||||
tlvdb_free(tlvSelect);
|
dreturn(2);
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check search and select application id
|
// check search and select application id
|
||||||
|
@ -395,14 +407,13 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init TLV tree
|
// Init TLV tree
|
||||||
struct tlvdb *tlvRoot = NULL;
|
|
||||||
const char *alr = "Root terminal TLV tree";
|
const char *alr = "Root terminal TLV tree";
|
||||||
tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
|
tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
|
||||||
|
|
||||||
// check if we found EMV application on card
|
// check if we found EMV application on card
|
||||||
if (!AIDlen) {
|
if (!AIDlen) {
|
||||||
PrintAndLog("Can't select AID. EMV AID not found");
|
PrintAndLog("Can't select AID. EMV AID not found");
|
||||||
return 2;
|
dreturn(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select
|
// Select
|
||||||
|
@ -412,7 +423,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLog("Can't select AID (%d). Exit...", res);
|
PrintAndLog("Can't select AID (%d). Exit...", res);
|
||||||
return 3;
|
dreturn(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decodeTLV)
|
if (decodeTLV)
|
||||||
|
@ -422,25 +433,30 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
PrintAndLog("\n* Init transaction parameters.");
|
PrintAndLog("\n* Init transaction parameters.");
|
||||||
|
|
||||||
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
||||||
|
char *qVSDC = "\x26\x00\x00\x00";
|
||||||
|
if (GenACGPO) {
|
||||||
|
qVSDC = "\x26\x80\x00\x00";
|
||||||
|
}
|
||||||
switch(TrType) {
|
switch(TrType) {
|
||||||
case TT_MSD:
|
case TT_MSD:
|
||||||
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
|
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
|
||||||
break;
|
break;
|
||||||
// not standart for contactless. just for test.
|
// not standard for contactless. just for test.
|
||||||
case TT_VSDC:
|
case TT_VSDC:
|
||||||
TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
|
TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
|
||||||
break;
|
break;
|
||||||
case TT_QVSDCMCHIP:
|
case TT_QVSDCMCHIP:
|
||||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
TLV_ADD(0x9F66, qVSDC); // qVSDC
|
||||||
break;
|
break;
|
||||||
case TT_CDA:
|
case TT_CDA:
|
||||||
TLV_ADD(0x9F66, "\x86\x80\x00\x00"); // CDA
|
TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//9F02:(Amount, Authorised (Numeric)) len:6
|
|
||||||
|
//9F02:(Amount, authorized (Numeric)) len:6
|
||||||
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
|
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
|
||||||
//9F1A:(Terminal Country Code) len:2
|
//9F1A:(Terminal Country Code) len:2
|
||||||
TLV_ADD(0x9F1A, "ru");
|
TLV_ADD(0x9F1A, "ru");
|
||||||
|
@ -459,17 +475,17 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
TLVPrintFromTLV(tlvRoot); // TODO delete!!!
|
TLVPrintFromTLV(tlvRoot); // TODO delete!!!
|
||||||
|
|
||||||
PrintAndLog("\n* Calc PDOL.");
|
PrintAndLog("\n* Calc PDOL.");
|
||||||
struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
|
pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
|
||||||
if (!pdol_data_tlv){
|
if (!pdol_data_tlv){
|
||||||
PrintAndLog("ERROR: can't create PDOL TLV.");
|
PrintAndLog("ERROR: can't create PDOL TLV.");
|
||||||
return 4;
|
dreturn(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t pdol_data_tlv_data_len;
|
size_t pdol_data_tlv_data_len;
|
||||||
unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
|
unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
|
||||||
if (!pdol_data_tlv_data) {
|
if (!pdol_data_tlv_data) {
|
||||||
PrintAndLog("ERROR: can't create PDOL data.");
|
PrintAndLog("ERROR: can't create PDOL data.");
|
||||||
return 4;
|
dreturn(4);
|
||||||
}
|
}
|
||||||
PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
|
PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
|
||||||
|
|
||||||
|
@ -477,11 +493,11 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||||
|
|
||||||
free(pdol_data_tlv_data);
|
free(pdol_data_tlv_data);
|
||||||
free(pdol_data_tlv);
|
//free(pdol_data_tlv); --- free on exit.
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLog("GPO error(%d): %4x. Exit...", res, sw);
|
PrintAndLog("GPO error(%d): %4x. Exit...", res, sw);
|
||||||
return 5;
|
dreturn(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// process response template format 1 [id:80 2b AIP + x4b AFL] and format 2 [id:77 TLV]
|
// process response template format 1 [id:80 2b AIP + x4b AFL] and format 2 [id:77 TLV]
|
||||||
|
@ -567,9 +583,23 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
PrintAndLog("");
|
PrintAndLog("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build Input list for Offline Data Authentication
|
||||||
|
// EMV 4.3 book3 10.3, page 96
|
||||||
if (SFIoffline) {
|
if (SFIoffline) {
|
||||||
// here will be offline records storing...
|
if (SFI < 11) {
|
||||||
// dont foget: if (sfi < 11)
|
const unsigned char *abuf = buf;
|
||||||
|
size_t elmlen = len;
|
||||||
|
struct tlv e;
|
||||||
|
if (tlv_parse_tl(&abuf, &elmlen, &e)) {
|
||||||
|
memcpy(&ODAiList[ODAiListLen], &buf[len - elmlen], elmlen);
|
||||||
|
ODAiListLen += elmlen;
|
||||||
|
} else {
|
||||||
|
PrintAndLog("ERROR SFI[%02x]. Creating input list for Offline Data Authentication error.", SFI);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(&ODAiList[ODAiListLen], buf, len);
|
||||||
|
ODAiListLen += len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -577,6 +607,13 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy Input list for Offline Data Authentication
|
||||||
|
if (ODAiListLen) {
|
||||||
|
struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag
|
||||||
|
tlvdb_add(tlvRoot, oda);
|
||||||
|
PrintAndLog("* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen);
|
||||||
|
}
|
||||||
|
|
||||||
// get AIP
|
// get AIP
|
||||||
const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);
|
const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);
|
||||||
uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
|
uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
|
||||||
|
@ -585,13 +622,13 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
// SDA
|
// SDA
|
||||||
if (AIP & 0x0040) {
|
if (AIP & 0x0040) {
|
||||||
PrintAndLog("\n* SDA");
|
PrintAndLog("\n* SDA");
|
||||||
trSDA(AID, AIDlen, tlvRoot);
|
trSDA(tlvRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DDA
|
// DDA
|
||||||
if (AIP & 0x0020) {
|
if (AIP & 0x0020) {
|
||||||
PrintAndLog("\n* DDA");
|
PrintAndLog("\n* DDA");
|
||||||
|
trDDA(decodeTLV, tlvRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transaction check
|
// transaction check
|
||||||
|
@ -644,11 +681,11 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot);
|
res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLog("ERROR GetChallenge. APDU error %4x", sw);
|
PrintAndLog("ERROR GetChallenge. APDU error %4x", sw);
|
||||||
return 5;
|
dreturn(6);
|
||||||
}
|
}
|
||||||
if (len < 4) {
|
if (len < 4) {
|
||||||
PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len);
|
PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len);
|
||||||
return 5;
|
dreturn(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ICC Dynamic Number
|
// ICC Dynamic Number
|
||||||
|
@ -663,7 +700,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||||
if (!cdol_data_tlv){
|
if (!cdol_data_tlv){
|
||||||
PrintAndLog("ERROR: can't create CDOL1 TLV.");
|
PrintAndLog("ERROR: can't create CDOL1 TLV.");
|
||||||
return 4;
|
dreturn(6);
|
||||||
}
|
}
|
||||||
PrintAndLog("CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
|
PrintAndLog("CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
|
||||||
|
|
||||||
|
@ -671,17 +708,25 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
// EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
|
// EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
|
||||||
res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||||
|
|
||||||
free(cdol_data_tlv);
|
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
|
PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
|
||||||
return 5;
|
dreturn(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decodeTLV)
|
if (decodeTLV)
|
||||||
TLVPrintFromBuffer(buf, len);
|
TLVPrintFromBuffer(buf, len);
|
||||||
|
|
||||||
PrintAndLog("* M/Chip transaction result:");
|
// CDA
|
||||||
|
PrintAndLog("\n* CDA:");
|
||||||
|
struct tlvdb *ac_tlv = tlvdb_parse_multi(buf, len);
|
||||||
|
res = trCDA(tlvRoot, ac_tlv, pdol_data_tlv, cdol_data_tlv);
|
||||||
|
if (res) {
|
||||||
|
PrintAndLog("CDA error (%d)", res);
|
||||||
|
}
|
||||||
|
free(ac_tlv);
|
||||||
|
free(cdol_data_tlv);
|
||||||
|
|
||||||
|
PrintAndLog("\n* M/Chip transaction result:");
|
||||||
// 9F27: Cryptogram Information Data (CID)
|
// 9F27: Cryptogram Information Data (CID)
|
||||||
const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL);
|
const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL);
|
||||||
if (CID) {
|
if (CID) {
|
||||||
|
@ -743,7 +788,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
|
struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
|
||||||
if (!udol_data_tlv){
|
if (!udol_data_tlv){
|
||||||
PrintAndLog("ERROR: can't create UDOL TLV.");
|
PrintAndLog("ERROR: can't create UDOL TLV.");
|
||||||
return 4;
|
dreturn(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLog("UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len));
|
PrintAndLog("UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len));
|
||||||
|
@ -753,13 +798,15 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw);
|
PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw);
|
||||||
return 5;
|
free(udol_data_tlv);
|
||||||
|
dreturn(9);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decodeTLV) {
|
if (decodeTLV) {
|
||||||
TLVPrintFromBuffer(buf, len);
|
TLVPrintFromBuffer(buf, len);
|
||||||
PrintAndLog("");
|
PrintAndLog("");
|
||||||
}
|
}
|
||||||
|
free(udol_data_tlv);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -771,6 +818,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
// Destroy TLV's
|
// Destroy TLV's
|
||||||
|
free(pdol_data_tlv);
|
||||||
tlvdb_free(tlvSelect);
|
tlvdb_free(tlvSelect);
|
||||||
tlvdb_free(tlvRoot);
|
tlvdb_free(tlvRoot);
|
||||||
|
|
||||||
|
@ -779,6 +827,10 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CmdHFEMVTest(const char *cmd) {
|
||||||
|
return ExecuteCryptoTests(true);
|
||||||
|
}
|
||||||
|
|
||||||
int CmdHelp(const char *Cmd);
|
int CmdHelp(const char *Cmd);
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, 1, "This help"},
|
{"help", CmdHelp, 1, "This help"},
|
||||||
|
@ -786,6 +838,7 @@ static command_t CommandTable[] = {
|
||||||
{"pse", CmdHFEMVPPSE, 0, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."},
|
{"pse", CmdHFEMVPPSE, 0, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."},
|
||||||
{"search", CmdHFEMVSearch, 0, "Try to select all applets from applets list and print installed applets."},
|
{"search", CmdHFEMVSearch, 0, "Try to select all applets from applets list and print installed applets."},
|
||||||
{"select", CmdHFEMVSelect, 0, "Select applet."},
|
{"select", CmdHFEMVSelect, 0, "Select applet."},
|
||||||
|
{"test", CmdHFEMVTest, 0, "Crypto logic test."},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include "proxmark3.h"
|
#include "proxmark3.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "cmdparser.h"
|
#include "cmdparser.h"
|
||||||
|
|
179
client/emv/crypto.c
Normal file
179
client/emv/crypto.c
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "crypto.h"
|
||||||
|
#include "crypto_backend.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static struct crypto_backend *crypto_backend;
|
||||||
|
|
||||||
|
static bool crypto_init(void)
|
||||||
|
{
|
||||||
|
if (crypto_backend)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
crypto_backend = crypto_polarssl_init();
|
||||||
|
|
||||||
|
if (!crypto_backend)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct crypto_hash *crypto_hash_open(enum crypto_algo_hash hash)
|
||||||
|
{
|
||||||
|
struct crypto_hash *ch;
|
||||||
|
|
||||||
|
if (!crypto_init())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ch = crypto_backend->hash_open(hash);
|
||||||
|
if (ch)
|
||||||
|
ch->algo = hash;
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_hash_close(struct crypto_hash *ch)
|
||||||
|
{
|
||||||
|
ch->close(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_hash_write(struct crypto_hash *ch, const unsigned char *buf, size_t len)
|
||||||
|
{
|
||||||
|
ch->write(ch, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *crypto_hash_read(struct crypto_hash *ch)
|
||||||
|
{
|
||||||
|
return ch->read(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t crypto_hash_get_size(const struct crypto_hash *ch)
|
||||||
|
{
|
||||||
|
return ch->get_size(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct crypto_pk *crypto_pk_open(enum crypto_algo_pk pk, ...)
|
||||||
|
{
|
||||||
|
struct crypto_pk *cp;
|
||||||
|
va_list vl;
|
||||||
|
|
||||||
|
if (!crypto_init())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
va_start(vl, pk);
|
||||||
|
cp = crypto_backend->pk_open(pk, vl);
|
||||||
|
va_end(vl);
|
||||||
|
|
||||||
|
if (cp)
|
||||||
|
cp->algo = pk;
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct crypto_pk *crypto_pk_open_priv(enum crypto_algo_pk pk, ...)
|
||||||
|
{
|
||||||
|
struct crypto_pk *cp;
|
||||||
|
va_list vl;
|
||||||
|
|
||||||
|
if (!crypto_init())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!crypto_backend->pk_open_priv)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
va_start(vl, pk);
|
||||||
|
cp = crypto_backend->pk_open_priv(pk, vl);
|
||||||
|
va_end(vl);
|
||||||
|
|
||||||
|
if (cp)
|
||||||
|
cp->algo = pk;
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct crypto_pk *crypto_pk_genkey(enum crypto_algo_pk pk, ...)
|
||||||
|
{
|
||||||
|
struct crypto_pk *cp;
|
||||||
|
va_list vl;
|
||||||
|
|
||||||
|
if (!crypto_init())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!crypto_backend->pk_genkey)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
va_start(vl, pk);
|
||||||
|
cp = crypto_backend->pk_genkey(pk, vl);
|
||||||
|
va_end(vl);
|
||||||
|
|
||||||
|
if (cp)
|
||||||
|
cp->algo = pk;
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_pk_close(struct crypto_pk *cp)
|
||||||
|
{
|
||||||
|
cp->close(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *crypto_pk_encrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen)
|
||||||
|
{
|
||||||
|
return cp->encrypt(cp, buf, len, clen);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *crypto_pk_decrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen)
|
||||||
|
{
|
||||||
|
if (!cp->decrypt) {
|
||||||
|
*clen = 0;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cp->decrypt(cp, buf, len, clen);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum crypto_algo_pk crypto_pk_get_algo(const struct crypto_pk *cp)
|
||||||
|
{
|
||||||
|
if (!cp)
|
||||||
|
return PK_INVALID;
|
||||||
|
|
||||||
|
return cp->algo;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t crypto_pk_get_nbits(const struct crypto_pk *cp)
|
||||||
|
{
|
||||||
|
if (!cp->get_nbits)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return cp->get_nbits(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *crypto_pk_get_parameter(const struct crypto_pk *cp, unsigned param, size_t *plen)
|
||||||
|
{
|
||||||
|
*plen = 0;
|
||||||
|
|
||||||
|
if (!cp->get_parameter)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return cp->get_parameter(cp, param, plen);
|
||||||
|
}
|
48
client/emv/crypto.h
Normal file
48
client/emv/crypto.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRYPTO_H
|
||||||
|
#define CRYPTO_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
enum crypto_algo_hash {
|
||||||
|
HASH_INVALID,
|
||||||
|
HASH_SHA_1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crypto_hash *crypto_hash_open(enum crypto_algo_hash hash);
|
||||||
|
void crypto_hash_close(struct crypto_hash *ch);
|
||||||
|
void crypto_hash_write(struct crypto_hash *ch, const unsigned char *buf, size_t len);
|
||||||
|
unsigned char *crypto_hash_read(struct crypto_hash *ch);
|
||||||
|
size_t crypto_hash_get_size(const struct crypto_hash *ch);
|
||||||
|
|
||||||
|
enum crypto_algo_pk {
|
||||||
|
PK_INVALID,
|
||||||
|
PK_RSA,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crypto_pk *crypto_pk_open(enum crypto_algo_pk pk, ...);
|
||||||
|
struct crypto_pk *crypto_pk_open_priv(enum crypto_algo_pk pk, ...);
|
||||||
|
struct crypto_pk *crypto_pk_genkey(enum crypto_algo_pk pk, ...);
|
||||||
|
void crypto_pk_close(struct crypto_pk *cp);
|
||||||
|
unsigned char *crypto_pk_encrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
|
||||||
|
unsigned char *crypto_pk_decrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
|
||||||
|
enum crypto_algo_pk crypto_pk_get_algo(const struct crypto_pk *cp);
|
||||||
|
size_t crypto_pk_get_nbits(const struct crypto_pk *cp);
|
||||||
|
unsigned char *crypto_pk_get_parameter(const struct crypto_pk *cp, unsigned param, size_t *plen);
|
||||||
|
|
||||||
|
#endif
|
50
client/emv/crypto_backend.h
Normal file
50
client/emv/crypto_backend.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRYPTO_BACKEND_H
|
||||||
|
#define CRYPTO_BACKEND_H
|
||||||
|
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
struct crypto_hash {
|
||||||
|
enum crypto_algo_hash algo;
|
||||||
|
void (*write)(struct crypto_hash *ch, const unsigned char *buf, size_t len);
|
||||||
|
unsigned char *(*read)(struct crypto_hash *ch);
|
||||||
|
void (*close)(struct crypto_hash *ch);
|
||||||
|
size_t (*get_size)(const struct crypto_hash *ch);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crypto_pk {
|
||||||
|
enum crypto_algo_pk algo;
|
||||||
|
unsigned char *(*encrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
|
||||||
|
unsigned char *(*decrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
|
||||||
|
unsigned char *(*get_parameter)(const struct crypto_pk *cp, unsigned param, size_t *plen);
|
||||||
|
size_t (*get_nbits)(const struct crypto_pk *cp);
|
||||||
|
void (*close)(struct crypto_pk *cp);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crypto_backend {
|
||||||
|
struct crypto_hash *(*hash_open)(enum crypto_algo_hash hash);
|
||||||
|
struct crypto_pk *(*pk_open)(enum crypto_algo_pk pk, va_list vl);
|
||||||
|
struct crypto_pk *(*pk_open_priv)(enum crypto_algo_pk pk, va_list vl);
|
||||||
|
struct crypto_pk *(*pk_genkey)(enum crypto_algo_pk pk, va_list vl);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crypto_backend *crypto_polarssl_init(void);
|
||||||
|
|
||||||
|
#endif
|
351
client/emv/crypto_polarssl.c
Normal file
351
client/emv/crypto_polarssl.c
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
* Copyright (C) 2017 Merlok
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "crypto.h"
|
||||||
|
#include "crypto_backend.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "rsa.h"
|
||||||
|
#include "sha1.h"
|
||||||
|
|
||||||
|
struct crypto_hash_polarssl {
|
||||||
|
struct crypto_hash ch;
|
||||||
|
sha1_context ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void crypto_hash_polarssl_close(struct crypto_hash *_ch)
|
||||||
|
{
|
||||||
|
struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
|
||||||
|
|
||||||
|
free(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void crypto_hash_polarssl_write(struct crypto_hash *_ch, const unsigned char *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
|
||||||
|
|
||||||
|
sha1_update(&(ch->ctx), buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *crypto_hash_polarssl_read(struct crypto_hash *_ch)
|
||||||
|
{
|
||||||
|
struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
|
||||||
|
|
||||||
|
static unsigned char sha1sum[20];
|
||||||
|
sha1_finish(&(ch->ctx), sha1sum);
|
||||||
|
return sha1sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t crypto_hash_polarssl_get_size(const struct crypto_hash *ch)
|
||||||
|
{
|
||||||
|
if (ch->algo == HASH_SHA_1)
|
||||||
|
return 20;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct crypto_hash *crypto_hash_polarssl_open(enum crypto_algo_hash hash)
|
||||||
|
{
|
||||||
|
if (hash != HASH_SHA_1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct crypto_hash_polarssl *ch = malloc(sizeof(*ch));
|
||||||
|
|
||||||
|
sha1_starts(&(ch->ctx));
|
||||||
|
|
||||||
|
ch->ch.write = crypto_hash_polarssl_write;
|
||||||
|
ch->ch.read = crypto_hash_polarssl_read;
|
||||||
|
ch->ch.close = crypto_hash_polarssl_close;
|
||||||
|
ch->ch.get_size = crypto_hash_polarssl_get_size;
|
||||||
|
|
||||||
|
return &ch->ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct crypto_pk_polarssl {
|
||||||
|
struct crypto_pk cp;
|
||||||
|
rsa_context ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct crypto_pk *crypto_pk_polarssl_open_rsa(va_list vl)
|
||||||
|
{
|
||||||
|
struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
|
||||||
|
memset(cp, 0x00, sizeof(*cp));
|
||||||
|
|
||||||
|
char *mod = va_arg(vl, char *); // N
|
||||||
|
int modlen = va_arg(vl, size_t);
|
||||||
|
char *exp = va_arg(vl, char *); // E
|
||||||
|
int explen = va_arg(vl, size_t);
|
||||||
|
|
||||||
|
rsa_init(&cp->ctx, RSA_PKCS_V15, 0);
|
||||||
|
|
||||||
|
cp->ctx.len = modlen; // size(N) in bytes
|
||||||
|
mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
|
||||||
|
mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
|
||||||
|
|
||||||
|
int res = rsa_check_pubkey(&cp->ctx);
|
||||||
|
if(res != 0) {
|
||||||
|
fprintf(stderr, "PolarSSL public key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cp->cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl)
|
||||||
|
{
|
||||||
|
struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
|
||||||
|
memset(cp, 0x00, sizeof(*cp));
|
||||||
|
char *mod = va_arg(vl, char *);
|
||||||
|
int modlen = va_arg(vl, size_t);
|
||||||
|
char *exp = va_arg(vl, char *);
|
||||||
|
int explen = va_arg(vl, size_t);
|
||||||
|
char *d = va_arg(vl, char *);
|
||||||
|
int dlen = va_arg(vl, size_t);
|
||||||
|
char *p = va_arg(vl, char *);
|
||||||
|
int plen = va_arg(vl, size_t);
|
||||||
|
char *q = va_arg(vl, char *);
|
||||||
|
int qlen = va_arg(vl, size_t);
|
||||||
|
char *dp = va_arg(vl, char *);
|
||||||
|
int dplen = va_arg(vl, size_t);
|
||||||
|
char *dq = va_arg(vl, char *);
|
||||||
|
int dqlen = va_arg(vl, size_t);
|
||||||
|
// calc QP via Q and P
|
||||||
|
// char *inv = va_arg(vl, char *);
|
||||||
|
// int invlen = va_arg(vl, size_t);
|
||||||
|
|
||||||
|
rsa_init(&cp->ctx, RSA_PKCS_V15, 0);
|
||||||
|
|
||||||
|
cp->ctx.len = modlen; // size(N) in bytes
|
||||||
|
mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
|
||||||
|
mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
|
||||||
|
|
||||||
|
mpi_read_binary(&cp->ctx.D, (const unsigned char *)d, dlen);
|
||||||
|
mpi_read_binary(&cp->ctx.P, (const unsigned char *)p, plen);
|
||||||
|
mpi_read_binary(&cp->ctx.Q, (const unsigned char *)q, qlen);
|
||||||
|
mpi_read_binary(&cp->ctx.DP, (const unsigned char *)dp, dplen);
|
||||||
|
mpi_read_binary(&cp->ctx.DQ, (const unsigned char *)dq, dqlen);
|
||||||
|
mpi_inv_mod(&cp->ctx.QP, &cp->ctx.Q, &cp->ctx.P);
|
||||||
|
|
||||||
|
int res = rsa_check_privkey(&cp->ctx);
|
||||||
|
if(res != 0) {
|
||||||
|
fprintf(stderr, "PolarSSL private key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cp->cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int myrand(void *rng_state, unsigned char *output, size_t len) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if(rng_state != NULL)
|
||||||
|
rng_state = NULL;
|
||||||
|
|
||||||
|
for( i = 0; i < len; ++i )
|
||||||
|
output[i] = rand();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct crypto_pk *crypto_pk_polarssl_genkey_rsa(va_list vl)
|
||||||
|
{
|
||||||
|
struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
|
||||||
|
memset(cp, 0x00, sizeof(*cp));
|
||||||
|
|
||||||
|
int transient = va_arg(vl, int);
|
||||||
|
unsigned int nbits = va_arg(vl, unsigned int);
|
||||||
|
unsigned int exp = va_arg(vl, unsigned int);
|
||||||
|
|
||||||
|
if (transient) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = rsa_gen_key(&cp->ctx, &myrand, NULL, nbits, exp);
|
||||||
|
if (res) {
|
||||||
|
fprintf(stderr, "PolarSSL private key generation error res=%x exp=%d nbits=%d.\n", res * -1, exp, nbits);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cp->cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void crypto_pk_polarssl_close(struct crypto_pk *_cp)
|
||||||
|
{
|
||||||
|
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||||
|
|
||||||
|
rsa_free(&cp->ctx);
|
||||||
|
free(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *crypto_pk_polarssl_encrypt(const struct crypto_pk *_cp, const unsigned char *buf, size_t len, size_t *clen)
|
||||||
|
{
|
||||||
|
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||||
|
int res;
|
||||||
|
unsigned char *result;
|
||||||
|
|
||||||
|
*clen = 0;
|
||||||
|
size_t keylen = mpi_size(&cp->ctx.N);
|
||||||
|
|
||||||
|
result = malloc(keylen);
|
||||||
|
if (!result) {
|
||||||
|
printf("RSA encrypt failed. Can't allocate result memory.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = rsa_public(&cp->ctx, buf, result);
|
||||||
|
if(res) {
|
||||||
|
printf("RSA encrypt failed. Error: %x data len: %d key len: %d\n", res * -1, len, keylen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*clen = keylen;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *crypto_pk_polarssl_decrypt(const struct crypto_pk *_cp, const unsigned char *buf, size_t len, size_t *clen)
|
||||||
|
{
|
||||||
|
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||||
|
int res;
|
||||||
|
unsigned char *result;
|
||||||
|
|
||||||
|
*clen = 0;
|
||||||
|
size_t keylen = mpi_size(&cp->ctx.N);
|
||||||
|
|
||||||
|
result = malloc(keylen);
|
||||||
|
if (!result) {
|
||||||
|
printf("RSA encrypt failed. Can't allocate result memory.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = rsa_private(&cp->ctx, buf, result); // CHECK???
|
||||||
|
if(res) {
|
||||||
|
printf("RSA decrypt failed. Error: %x data len: %d key len: %d\n", res * -1, len, keylen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*clen = keylen;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t crypto_pk_polarssl_get_nbits(const struct crypto_pk *_cp)
|
||||||
|
{
|
||||||
|
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||||
|
|
||||||
|
return cp->ctx.len * 8;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *crypto_pk_polarssl_get_parameter(const struct crypto_pk *_cp, unsigned param, size_t *plen)
|
||||||
|
{
|
||||||
|
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||||
|
unsigned char *result = NULL;
|
||||||
|
switch(param){
|
||||||
|
// mod
|
||||||
|
case 0:
|
||||||
|
*plen = mpi_size(&cp->ctx.N);
|
||||||
|
result = malloc(*plen);
|
||||||
|
memset(result, 0x00, *plen);
|
||||||
|
mpi_write_binary(&cp->ctx.N, result, *plen);
|
||||||
|
break;
|
||||||
|
// exp
|
||||||
|
case 1:
|
||||||
|
*plen = mpi_size(&cp->ctx.E);
|
||||||
|
result = malloc(*plen);
|
||||||
|
memset(result, 0x00, *plen);
|
||||||
|
mpi_write_binary(&cp->ctx.E, result, *plen);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Error get parameter. Param=%d", param);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct crypto_pk *crypto_pk_polarssl_open(enum crypto_algo_pk pk, va_list vl)
|
||||||
|
{
|
||||||
|
struct crypto_pk *cp;
|
||||||
|
|
||||||
|
if (pk == PK_RSA)
|
||||||
|
cp = crypto_pk_polarssl_open_rsa(vl);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cp->close = crypto_pk_polarssl_close;
|
||||||
|
cp->encrypt = crypto_pk_polarssl_encrypt;
|
||||||
|
cp->get_parameter = crypto_pk_polarssl_get_parameter;
|
||||||
|
cp->get_nbits = crypto_pk_polarssl_get_nbits;
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct crypto_pk *crypto_pk_polarssl_open_priv(enum crypto_algo_pk pk, va_list vl)
|
||||||
|
{
|
||||||
|
struct crypto_pk *cp;
|
||||||
|
|
||||||
|
if (pk == PK_RSA)
|
||||||
|
cp = crypto_pk_polarssl_open_priv_rsa(vl);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cp->close = crypto_pk_polarssl_close;
|
||||||
|
cp->encrypt = crypto_pk_polarssl_encrypt;
|
||||||
|
cp->decrypt = crypto_pk_polarssl_decrypt;
|
||||||
|
cp->get_parameter = crypto_pk_polarssl_get_parameter;
|
||||||
|
cp->get_nbits = crypto_pk_polarssl_get_nbits;
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct crypto_pk *crypto_pk_polarssl_genkey(enum crypto_algo_pk pk, va_list vl)
|
||||||
|
{
|
||||||
|
struct crypto_pk *cp;
|
||||||
|
|
||||||
|
if (pk == PK_RSA)
|
||||||
|
cp = crypto_pk_polarssl_genkey_rsa(vl);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cp->close = crypto_pk_polarssl_close;
|
||||||
|
cp->encrypt = crypto_pk_polarssl_encrypt;
|
||||||
|
cp->decrypt = crypto_pk_polarssl_decrypt;
|
||||||
|
cp->get_parameter = crypto_pk_polarssl_get_parameter;
|
||||||
|
cp->get_nbits = crypto_pk_polarssl_get_nbits;
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct crypto_backend crypto_polarssl_backend = {
|
||||||
|
.hash_open = crypto_hash_polarssl_open,
|
||||||
|
.pk_open = crypto_pk_polarssl_open,
|
||||||
|
.pk_open_priv = crypto_pk_polarssl_open_priv,
|
||||||
|
.pk_genkey = crypto_pk_polarssl_genkey,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crypto_backend *crypto_polarssl_init(void)
|
||||||
|
{
|
||||||
|
return &crypto_polarssl_backend;
|
||||||
|
}
|
524
client/emv/emv_pk.c
Normal file
524
client/emv/emv_pk.c
Normal file
|
@ -0,0 +1,524 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* For asprintf */
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "emv_pk.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
#include "proxmark3.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define BCD(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
|
||||||
|
-1)
|
||||||
|
|
||||||
|
#define HEX(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
|
||||||
|
((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
|
||||||
|
((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
|
||||||
|
-1)
|
||||||
|
|
||||||
|
#define TOHEX(v) ((v) < 10 ? (v) + '0' : (v) - 10 + 'a')
|
||||||
|
|
||||||
|
static ssize_t emv_pk_read_bin(char *buf, unsigned char *bin, size_t size, size_t *read)
|
||||||
|
{
|
||||||
|
size_t left = size;
|
||||||
|
char *p = buf;
|
||||||
|
while (*p && *p == ' ')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
while (left > 0) {
|
||||||
|
int c1, c2;
|
||||||
|
c1 = HEX(*p);
|
||||||
|
if (c1 == -1)
|
||||||
|
return -(p - buf);
|
||||||
|
p++;
|
||||||
|
c2 = HEX(*p);
|
||||||
|
if (c2 == -1)
|
||||||
|
return -(p - buf);
|
||||||
|
p++;
|
||||||
|
*bin = (c1 * 16 + c2);
|
||||||
|
bin ++;
|
||||||
|
left --;
|
||||||
|
if (*p == ':')
|
||||||
|
p++;
|
||||||
|
else if (read) {
|
||||||
|
*read = (size - left);
|
||||||
|
break;
|
||||||
|
} else if (left == 0)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
return -(p - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*p && *p == ' ')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
p--;
|
||||||
|
|
||||||
|
return (p - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t emv_pk_read_ymv(char *buf, unsigned *ymv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char temp[3];
|
||||||
|
char *p = buf;
|
||||||
|
|
||||||
|
*ymv = 0;
|
||||||
|
|
||||||
|
while (*p && *p == ' ')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
int c1, c2;
|
||||||
|
c1 = BCD(*p);
|
||||||
|
if (c1 == -1)
|
||||||
|
return -(p - buf);
|
||||||
|
p++;
|
||||||
|
c2 = BCD(*p);
|
||||||
|
if (c2 == -1)
|
||||||
|
return -(p - buf);
|
||||||
|
p++;
|
||||||
|
temp[i] = (c1 * 16 + c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*p && *p == ' ')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
p--;
|
||||||
|
|
||||||
|
if (temp[1] > 0x12 || temp[2] > 0x31)
|
||||||
|
return -(p - buf);
|
||||||
|
|
||||||
|
*ymv = (temp[0] * 0x10000 + temp[1] * 0x100 + temp[2]);
|
||||||
|
|
||||||
|
return (p - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t emv_pk_read_string(char *buf, char *str, size_t size)
|
||||||
|
{
|
||||||
|
char *p = buf;
|
||||||
|
while (*p && *p == ' ')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
while (size > 1) {
|
||||||
|
if (*p == ' ')
|
||||||
|
break;
|
||||||
|
else if (*p < 0x20 || *p >= 0x7f)
|
||||||
|
return -(p - buf);
|
||||||
|
*str = *p;
|
||||||
|
p++;
|
||||||
|
str ++;
|
||||||
|
size --;
|
||||||
|
}
|
||||||
|
|
||||||
|
*str = 0;
|
||||||
|
|
||||||
|
while (*p && *p == ' ')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
p--;
|
||||||
|
|
||||||
|
return (p - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct emv_pk *emv_pk_parse_pk(char *buf)
|
||||||
|
{
|
||||||
|
struct emv_pk *r = calloc(1, sizeof(*r));
|
||||||
|
ssize_t l;
|
||||||
|
char temp[10];
|
||||||
|
|
||||||
|
l = emv_pk_read_bin(buf, r->rid, 5, NULL);
|
||||||
|
if (l <= 0)
|
||||||
|
goto out;
|
||||||
|
buf += l;
|
||||||
|
|
||||||
|
l = emv_pk_read_bin(buf, &r->index, 1, NULL);
|
||||||
|
if (l <= 0)
|
||||||
|
goto out;
|
||||||
|
buf += l;
|
||||||
|
|
||||||
|
l = emv_pk_read_ymv(buf, &r->expire);
|
||||||
|
if (l <= 0)
|
||||||
|
goto out;
|
||||||
|
buf += l;
|
||||||
|
|
||||||
|
l = emv_pk_read_string(buf, temp, sizeof(temp));
|
||||||
|
if (l <= 0)
|
||||||
|
goto out;
|
||||||
|
buf += l;
|
||||||
|
|
||||||
|
if (!strcmp(temp, "rsa"))
|
||||||
|
r->pk_algo = PK_RSA;
|
||||||
|
else
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
l = emv_pk_read_bin(buf, r->exp, sizeof(r->exp), &r->elen);
|
||||||
|
if (l <= 0)
|
||||||
|
goto out;
|
||||||
|
buf += l;
|
||||||
|
|
||||||
|
r->modulus = malloc(2048/8);
|
||||||
|
l = emv_pk_read_bin(buf, r->modulus, 2048/8, &r->mlen);
|
||||||
|
if (l <= 0)
|
||||||
|
goto out2;
|
||||||
|
buf += l;
|
||||||
|
|
||||||
|
l = emv_pk_read_string(buf, temp, sizeof(temp));
|
||||||
|
if (l <= 0)
|
||||||
|
goto out2;
|
||||||
|
buf += l;
|
||||||
|
|
||||||
|
if (!strcmp(temp, "sha1"))
|
||||||
|
r->hash_algo = HASH_SHA_1;
|
||||||
|
else
|
||||||
|
goto out2;
|
||||||
|
|
||||||
|
l = emv_pk_read_bin(buf, r->hash, 20, NULL);
|
||||||
|
if (l <= 0)
|
||||||
|
goto out2;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
|
||||||
|
out2:
|
||||||
|
free(r->modulus);
|
||||||
|
out:
|
||||||
|
free(r);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t emv_pk_write_bin(char *out, size_t outlen, const unsigned char *buf, size_t len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
if (outlen < len * 3)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out[pos++] = TOHEX(buf[0] >> 4);
|
||||||
|
out[pos++] = TOHEX(buf[0] & 0xf);
|
||||||
|
for (i = 1; i < len; i++) {
|
||||||
|
out[pos++] = ':';
|
||||||
|
out[pos++] = TOHEX(buf[i] >> 4);
|
||||||
|
out[pos++] = TOHEX(buf[i] & 0xf);
|
||||||
|
}
|
||||||
|
out[pos++] = ' ';
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t emv_pk_write_str(char *out, size_t outlen, const char *str)
|
||||||
|
{
|
||||||
|
size_t len = strlen(str);
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
if (outlen < len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(out, str, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *emv_pk_dump_pk(const struct emv_pk *pk)
|
||||||
|
{
|
||||||
|
size_t outsize = 1024; /* should be enough */
|
||||||
|
char *out = malloc(outsize); /* should be enough */
|
||||||
|
size_t outpos = 0;
|
||||||
|
size_t rc;
|
||||||
|
|
||||||
|
if (!out)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->rid, 5);
|
||||||
|
if (rc == 0)
|
||||||
|
goto err;
|
||||||
|
outpos += rc;
|
||||||
|
|
||||||
|
rc = emv_pk_write_bin(out + outpos, outsize - outpos, &pk->index, 1);
|
||||||
|
if (rc == 0)
|
||||||
|
goto err;
|
||||||
|
outpos += rc;
|
||||||
|
|
||||||
|
if (outpos + 7 > outsize)
|
||||||
|
goto err;
|
||||||
|
out[outpos++] = TOHEX((pk->expire >> 20) & 0xf);
|
||||||
|
out[outpos++] = TOHEX((pk->expire >> 16) & 0xf);
|
||||||
|
out[outpos++] = TOHEX((pk->expire >> 12) & 0xf);
|
||||||
|
out[outpos++] = TOHEX((pk->expire >> 8 ) & 0xf);
|
||||||
|
out[outpos++] = TOHEX((pk->expire >> 4 ) & 0xf);
|
||||||
|
out[outpos++] = TOHEX((pk->expire >> 0 ) & 0xf);
|
||||||
|
out[outpos++] = ' ';
|
||||||
|
|
||||||
|
if (pk->pk_algo == PK_RSA) {
|
||||||
|
rc = emv_pk_write_str(out + outpos, outsize - outpos, "rsa");
|
||||||
|
if (rc == 0)
|
||||||
|
goto err;
|
||||||
|
outpos += rc;
|
||||||
|
out[outpos++] = ' ';
|
||||||
|
} else {
|
||||||
|
if (outpos + 4 > outsize)
|
||||||
|
goto err;
|
||||||
|
out[outpos++] = '?';
|
||||||
|
out[outpos++] = '?';
|
||||||
|
out[outpos++] = TOHEX(pk->pk_algo >> 4);
|
||||||
|
out[outpos++] = TOHEX(pk->pk_algo & 0xf);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->exp, pk->elen);
|
||||||
|
if (rc == 0)
|
||||||
|
goto err;
|
||||||
|
outpos += rc;
|
||||||
|
|
||||||
|
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->modulus, pk->mlen);
|
||||||
|
if (rc == 0)
|
||||||
|
goto err;
|
||||||
|
outpos += rc;
|
||||||
|
|
||||||
|
if (pk->hash_algo == HASH_SHA_1) {
|
||||||
|
rc = emv_pk_write_str(out + outpos, outsize - outpos, "sha1");
|
||||||
|
if (rc == 0)
|
||||||
|
goto err;
|
||||||
|
outpos += rc;
|
||||||
|
out[outpos++] = ' ';
|
||||||
|
} else {
|
||||||
|
if (outpos + 4 > outsize)
|
||||||
|
goto err;
|
||||||
|
out[outpos++] = '?';
|
||||||
|
out[outpos++] = '?';
|
||||||
|
out[outpos++] = TOHEX(pk->pk_algo >> 4);
|
||||||
|
out[outpos++] = TOHEX(pk->pk_algo & 0xf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->hash, 20);
|
||||||
|
if (rc == 0)
|
||||||
|
goto err;
|
||||||
|
outpos += rc;
|
||||||
|
|
||||||
|
out[outpos-1] = '\0';
|
||||||
|
|
||||||
|
return out;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(out);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emv_pk_verify(const struct emv_pk *pk)
|
||||||
|
{
|
||||||
|
struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
|
||||||
|
if (!ch)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
|
||||||
|
crypto_hash_write(ch, &pk->index, 1);
|
||||||
|
crypto_hash_write(ch, pk->modulus, pk->mlen);
|
||||||
|
crypto_hash_write(ch, pk->exp, pk->elen);
|
||||||
|
|
||||||
|
unsigned char *h = crypto_hash_read(ch);
|
||||||
|
if (!h) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hsize = crypto_hash_get_size(ch);
|
||||||
|
bool r = hsize && !memcmp(h, pk->hash, hsize) ? true : false;
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *emv_pk_new(size_t modlen, size_t explen)
|
||||||
|
{
|
||||||
|
struct emv_pk *pk;
|
||||||
|
|
||||||
|
/* Not supported ATM */
|
||||||
|
if (explen > 3)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pk = calloc(1, sizeof(*pk));
|
||||||
|
if (!pk)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pk->mlen = modlen;
|
||||||
|
pk->elen = explen;
|
||||||
|
|
||||||
|
pk->modulus = calloc(modlen, 1);
|
||||||
|
if (!pk->modulus) {
|
||||||
|
free(pk);
|
||||||
|
pk = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emv_pk_free(struct emv_pk *pk)
|
||||||
|
{
|
||||||
|
if (!pk)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free(pk->modulus);
|
||||||
|
free(pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct emv_pk *emv_pk_get_ca_pk_from_file(const char *fname,
|
||||||
|
const unsigned char *rid,
|
||||||
|
unsigned char idx)
|
||||||
|
{
|
||||||
|
if (!fname)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
FILE *f = fopen(fname, "r");
|
||||||
|
if (!f) {
|
||||||
|
perror("fopen");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof(f)) {
|
||||||
|
char buf[2048];
|
||||||
|
if (fgets(buf, sizeof(buf), f) == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
struct emv_pk *pk = emv_pk_parse_pk(buf);
|
||||||
|
if (!pk)
|
||||||
|
continue;
|
||||||
|
if (memcmp(pk->rid, rid, 5) || pk->index != idx) {
|
||||||
|
emv_pk_free(pk);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsigned char idx)
|
||||||
|
{
|
||||||
|
if (!dirname)
|
||||||
|
dirname = ".";//openemv_config_get_str("capk.dir", NULL);
|
||||||
|
|
||||||
|
if (!dirname)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char *filename;
|
||||||
|
int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0",
|
||||||
|
dirname,
|
||||||
|
rid[0],
|
||||||
|
rid[1],
|
||||||
|
rid[2],
|
||||||
|
rid[3],
|
||||||
|
rid[4],
|
||||||
|
idx);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid)
|
||||||
|
{
|
||||||
|
if (!dirname)
|
||||||
|
dirname = "."; //openemv_config_get_str("capk.dir", NULL);
|
||||||
|
|
||||||
|
if (!dirname)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char *filename;
|
||||||
|
int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks",
|
||||||
|
dirname,
|
||||||
|
rid[0],
|
||||||
|
rid[1],
|
||||||
|
rid[2],
|
||||||
|
rid[3],
|
||||||
|
rid[4]);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx)
|
||||||
|
{
|
||||||
|
struct emv_pk *pk = NULL;
|
||||||
|
|
||||||
|
/* if (!pk) {
|
||||||
|
char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
|
||||||
|
if (fname) {
|
||||||
|
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||||
|
free(fname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pk) {
|
||||||
|
char *fname = emv_pk_get_ca_pk_rid_file(NULL, rid);
|
||||||
|
if (fname) {
|
||||||
|
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||||
|
free(fname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (!pk) {
|
||||||
|
const char *relfname = "emv/capk.txt";
|
||||||
|
|
||||||
|
char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
|
||||||
|
strcpy(fname, get_my_executable_directory());
|
||||||
|
strcat(fname, relfname);
|
||||||
|
|
||||||
|
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||||
|
}
|
||||||
|
if (!pk)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
printf("Verifying CA PK for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...",
|
||||||
|
pk->rid[0],
|
||||||
|
pk->rid[1],
|
||||||
|
pk->rid[2],
|
||||||
|
pk->rid[3],
|
||||||
|
pk->rid[4],
|
||||||
|
pk->index,
|
||||||
|
pk->mlen * 8);
|
||||||
|
if (emv_pk_verify(pk)) {
|
||||||
|
printf("OK\n");
|
||||||
|
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Failed!\n");
|
||||||
|
emv_pk_free(pk);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
48
client/emv/emv_pk.h
Normal file
48
client/emv/emv_pk.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMV_PK_H
|
||||||
|
#define EMV_PK_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct emv_pk {
|
||||||
|
unsigned char rid[5];
|
||||||
|
unsigned char index;
|
||||||
|
unsigned char serial[3];
|
||||||
|
unsigned char pan[10];
|
||||||
|
unsigned char hash_algo;
|
||||||
|
unsigned char pk_algo;
|
||||||
|
unsigned char hash[20];
|
||||||
|
unsigned char exp[3];
|
||||||
|
size_t elen;
|
||||||
|
size_t mlen;
|
||||||
|
unsigned char *modulus;
|
||||||
|
unsigned int expire;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EXPIRE(yy, mm, dd) 0x ## yy ## mm ## dd
|
||||||
|
|
||||||
|
struct emv_pk *emv_pk_parse_pk(char *buf);
|
||||||
|
struct emv_pk *emv_pk_new(size_t modlen, size_t explen);
|
||||||
|
void emv_pk_free(struct emv_pk *pk);
|
||||||
|
char *emv_pk_dump_pk(const struct emv_pk *pk);
|
||||||
|
bool emv_pk_verify(const struct emv_pk *pk);
|
||||||
|
|
||||||
|
char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsigned char idx);
|
||||||
|
char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid);
|
||||||
|
struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx);
|
||||||
|
#endif
|
511
client/emv/emv_pki.c
Normal file
511
client/emv/emv_pki.c
Normal file
|
@ -0,0 +1,511 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "emv_pki.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
#include "dump.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
static const unsigned char empty_tlv_value[] = {};
|
||||||
|
static const struct tlv empty_tlv = {.tag = 0x0, .len = 0, .value = empty_tlv_value};
|
||||||
|
|
||||||
|
static size_t emv_pki_hash_psn[256] = { 0, 0, 11, 2, 17, 2, };
|
||||||
|
|
||||||
|
static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
||||||
|
uint8_t msgtype,
|
||||||
|
size_t *len,
|
||||||
|
const struct tlv *cert_tlv,
|
||||||
|
... /* A list of tlv pointers, end with NULL */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct crypto_pk *kcp;
|
||||||
|
unsigned char *data;
|
||||||
|
size_t data_len;
|
||||||
|
va_list vl;
|
||||||
|
|
||||||
|
if (!enc_pk)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!cert_tlv) {
|
||||||
|
printf("ERROR: Can't find certificate\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cert_tlv->len != enc_pk->mlen) {
|
||||||
|
printf("ERROR: Certificate length (%d) not equal key length (%d)\n", cert_tlv->len, enc_pk->mlen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
kcp = crypto_pk_open(enc_pk->pk_algo,
|
||||||
|
enc_pk->modulus, enc_pk->mlen,
|
||||||
|
enc_pk->exp, enc_pk->elen);
|
||||||
|
if (!kcp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
data = crypto_pk_encrypt(kcp, cert_tlv->value, cert_tlv->len, &data_len);
|
||||||
|
crypto_pk_close(kcp);
|
||||||
|
|
||||||
|
/* if (true){
|
||||||
|
printf("Recovered data:\n");
|
||||||
|
dump_buffer(data, data_len, stdout, 0);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (data[data_len-1] != 0xbc || data[0] != 0x6a || data[1] != msgtype) {
|
||||||
|
printf("ERROR: Certificate format\n");
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hash_pos = emv_pki_hash_psn[msgtype];
|
||||||
|
if (hash_pos == 0 || hash_pos > data_len){
|
||||||
|
printf("ERROR: Cant get hash position in the certificate\n");
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct crypto_hash *ch;
|
||||||
|
ch = crypto_hash_open(data[hash_pos]);
|
||||||
|
if (!ch) {
|
||||||
|
printf("ERROR: Cant do hash\n");
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hash_len = crypto_hash_get_size(ch);
|
||||||
|
crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
|
||||||
|
|
||||||
|
va_start(vl, cert_tlv);
|
||||||
|
while (true) {
|
||||||
|
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
||||||
|
if (!add_tlv)
|
||||||
|
break;
|
||||||
|
|
||||||
|
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
||||||
|
}
|
||||||
|
va_end(vl);
|
||||||
|
|
||||||
|
if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) {
|
||||||
|
printf("ERROR: Calculated wrong hash\n");
|
||||||
|
printf("decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
|
||||||
|
printf("calculated: %s\n",sprint_hex(crypto_hash_read(ch), hash_len));
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
|
||||||
|
*len = data_len - hash_len - 1;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned emv_cn_length(const struct tlv *tlv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < tlv->len; i++) {
|
||||||
|
unsigned char c = tlv->value[i];
|
||||||
|
|
||||||
|
if (c >> 4 == 0xf)
|
||||||
|
return 2 * i;
|
||||||
|
|
||||||
|
if ((c & 0xf) == 0xf)
|
||||||
|
return 2 * i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 2 * tlv->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char emv_cn_get(const struct tlv *tlv, unsigned pos)
|
||||||
|
{
|
||||||
|
if (pos > tlv->len * 2)
|
||||||
|
return 0xf;
|
||||||
|
|
||||||
|
unsigned char c = tlv->value[pos / 2];
|
||||||
|
|
||||||
|
if (pos % 2)
|
||||||
|
return c & 0xf;
|
||||||
|
else
|
||||||
|
return c >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
|
||||||
|
unsigned char msgtype,
|
||||||
|
const struct tlv *pan_tlv,
|
||||||
|
const struct tlv *cert_tlv,
|
||||||
|
const struct tlv *exp_tlv,
|
||||||
|
const struct tlv *rem_tlv,
|
||||||
|
const struct tlv *add_tlv,
|
||||||
|
bool showData
|
||||||
|
)
|
||||||
|
{
|
||||||
|
size_t pan_length;
|
||||||
|
unsigned char *data;
|
||||||
|
size_t data_len;
|
||||||
|
size_t pk_len;
|
||||||
|
|
||||||
|
if (!cert_tlv || !exp_tlv || !pan_tlv)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!rem_tlv)
|
||||||
|
rem_tlv = &empty_tlv;
|
||||||
|
|
||||||
|
if (msgtype == 2)
|
||||||
|
pan_length = 4;
|
||||||
|
else if (msgtype == 4)
|
||||||
|
pan_length = 10;
|
||||||
|
else {
|
||||||
|
printf("ERROR: Message type must be 2 or 4\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
|
||||||
|
cert_tlv,
|
||||||
|
rem_tlv,
|
||||||
|
exp_tlv,
|
||||||
|
add_tlv,
|
||||||
|
NULL);
|
||||||
|
if (!data || data_len < 11 + pan_length) {
|
||||||
|
printf("ERROR: Can't decode message\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showData){
|
||||||
|
printf("Recovered data:\n");
|
||||||
|
dump_buffer(data, data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the rest of checks here */
|
||||||
|
|
||||||
|
struct tlv pan2_tlv = {
|
||||||
|
.tag = 0x5a,
|
||||||
|
.len = pan_length,
|
||||||
|
.value = &data[2],
|
||||||
|
};
|
||||||
|
unsigned pan_len = emv_cn_length(pan_tlv);
|
||||||
|
unsigned pan2_len = emv_cn_length(&pan2_tlv);
|
||||||
|
|
||||||
|
if (((msgtype == 2) && (pan2_len < 4 || pan2_len > pan_len)) ||
|
||||||
|
((msgtype == 4) && (pan2_len != pan_len))) {
|
||||||
|
printf("ERROR: Invalid PAN lengths\n");
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < pan2_len; i++)
|
||||||
|
if (emv_cn_get(pan_tlv, i) != emv_cn_get(&pan2_tlv, i)) {
|
||||||
|
printf("ERROR: PAN data mismatch\n");
|
||||||
|
printf("tlv pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len));
|
||||||
|
printf("cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len));
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pk_len = data[9 + pan_length];
|
||||||
|
if (pk_len > data_len - 11 - pan_length + rem_tlv->len) {
|
||||||
|
printf("ERROR: Invalid pk length\n");
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_tlv->len != data[10 + pan_length]) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *pk = emv_pk_new(pk_len, exp_tlv->len);
|
||||||
|
|
||||||
|
memcpy(pk->rid, enc_pk->rid, 5);
|
||||||
|
pk->index = enc_pk->index;
|
||||||
|
|
||||||
|
pk->hash_algo = data[7 + pan_length];
|
||||||
|
pk->pk_algo = data[8 + pan_length];
|
||||||
|
pk->expire = (data[3 + pan_length] << 16) | (data[2 + pan_length] << 8) | 0x31;
|
||||||
|
memcpy(pk->serial, data + 4 + pan_length, 3);
|
||||||
|
memcpy(pk->pan, data + 2, pan_length);
|
||||||
|
memset(pk->pan + pan_length, 0xff, 10 - pan_length);
|
||||||
|
|
||||||
|
memcpy(pk->modulus, data + 11 + pan_length,
|
||||||
|
pk_len < data_len - (11 + pan_length) ?
|
||||||
|
pk_len :
|
||||||
|
data_len - (11 + pan_length));
|
||||||
|
memcpy(pk->modulus + data_len - (11 + pan_length), rem_tlv->value, rem_tlv->len);
|
||||||
|
memcpy(pk->exp, exp_tlv->value, exp_tlv->len);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk,
|
||||||
|
unsigned char msgtype,
|
||||||
|
const struct tlv *pan_tlv,
|
||||||
|
const struct tlv *cert_tlv,
|
||||||
|
const struct tlv *exp_tlv,
|
||||||
|
const struct tlv *rem_tlv,
|
||||||
|
const struct tlv *add_tlv
|
||||||
|
) {
|
||||||
|
return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db)
|
||||||
|
{
|
||||||
|
return emv_pki_decode_key(pk, 2,
|
||||||
|
tlvdb_get(db, 0x5a, NULL),
|
||||||
|
tlvdb_get(db, 0x90, NULL),
|
||||||
|
tlvdb_get(db, 0x9f32, NULL),
|
||||||
|
tlvdb_get(db, 0x92, NULL),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv)
|
||||||
|
{
|
||||||
|
return emv_pki_decode_key(pk, 4,
|
||||||
|
tlvdb_get(db, 0x5a, NULL),
|
||||||
|
tlvdb_get(db, 0x9f46, NULL),
|
||||||
|
tlvdb_get(db, 0x9f47, NULL),
|
||||||
|
tlvdb_get(db, 0x9f48, NULL),
|
||||||
|
sda_tlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db)
|
||||||
|
{
|
||||||
|
return emv_pki_decode_key(pk, 4,
|
||||||
|
tlvdb_get(db, 0x5a, NULL),
|
||||||
|
tlvdb_get(db, 0x9f2d, NULL),
|
||||||
|
tlvdb_get(db, 0x9f2e, NULL),
|
||||||
|
tlvdb_get(db, 0x9f2f, NULL),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData)
|
||||||
|
{
|
||||||
|
size_t data_len;
|
||||||
|
unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
|
||||||
|
tlvdb_get(db, 0x93, NULL),
|
||||||
|
sda_tlv,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!data || data_len < 5)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (showData){
|
||||||
|
printf("Recovered data:\n");
|
||||||
|
dump_buffer(data, data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *dac_db = tlvdb_fixed(0x9f45, 2, data+3);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return dac_db;
|
||||||
|
}
|
||||||
|
struct tlvdb *emv_pki_recover_dac(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv) {
|
||||||
|
return emv_pki_recover_dac_ex(enc_pk, db, sda_tlv, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv) {
|
||||||
|
return emv_pki_recover_idn_ex(enc_pk, db, dyn_tlv, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData)
|
||||||
|
{
|
||||||
|
size_t data_len;
|
||||||
|
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||||
|
tlvdb_get(db, 0x9f4b, NULL),
|
||||||
|
dyn_tlv,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!data || data_len < 3)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showData){
|
||||||
|
printf("Recovered data:\n");
|
||||||
|
dump_buffer(data, data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idn_len = data[4];
|
||||||
|
if (idn_len > data[3] - 1) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9f4c ICC Dynamic Number
|
||||||
|
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return idn_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData)
|
||||||
|
{
|
||||||
|
size_t data_len;
|
||||||
|
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||||
|
tlvdb_get(db, 0x9f4b, NULL),
|
||||||
|
tlvdb_get(db, 0x9f37, NULL),
|
||||||
|
tlvdb_get(db, 0x9f02, NULL),
|
||||||
|
tlvdb_get(db, 0x5f2a, NULL),
|
||||||
|
tlvdb_get(db, 0x9f69, NULL),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!data || data_len < 3)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showData){
|
||||||
|
printf("Recovered data:\n");
|
||||||
|
dump_buffer(data, data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idn_len = data[4];
|
||||||
|
if (idn_len > data[3] - 1) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9f36 Application Transaction Counter (ATC)
|
||||||
|
struct tlvdb *atc_db = tlvdb_fixed(0x9f36, idn_len, data + 5);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return atc_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tlv_hash(void *data, const struct tlv *tlv, int level, bool is_leaf)
|
||||||
|
{
|
||||||
|
struct crypto_hash *ch = data;
|
||||||
|
size_t tag_len;
|
||||||
|
unsigned char *tag;
|
||||||
|
|
||||||
|
if (tlv_is_constructed(tlv))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (tlv->tag == 0x9f4b)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
tag = tlv_encode(tlv, &tag_len);
|
||||||
|
crypto_hash_write(ch, tag, tag_len);
|
||||||
|
free(tag);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||||
|
const struct tlvdb *this_db,
|
||||||
|
const struct tlv *pdol_data_tlv,
|
||||||
|
const struct tlv *crm1_tlv,
|
||||||
|
const struct tlv *crm2_tlv)
|
||||||
|
{
|
||||||
|
return emv_pki_perform_cda_ex(enc_pk, db, this_db, pdol_data_tlv, crm1_tlv, crm2_tlv, false);
|
||||||
|
}
|
||||||
|
struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||||
|
const struct tlvdb *this_db, // AC TLV result
|
||||||
|
const struct tlv *pdol_data_tlv, // PDOL
|
||||||
|
const struct tlv *crm1_tlv, // CDOL1
|
||||||
|
const struct tlv *crm2_tlv, // CDOL2
|
||||||
|
bool showData)
|
||||||
|
{
|
||||||
|
const struct tlv *un_tlv = tlvdb_get(db, 0x9f37, NULL);
|
||||||
|
const struct tlv *cid_tlv = tlvdb_get(this_db, 0x9f27, NULL);
|
||||||
|
|
||||||
|
if (!un_tlv || !cid_tlv)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t data_len = 0;
|
||||||
|
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||||
|
tlvdb_get(this_db, 0x9f4b, NULL),
|
||||||
|
un_tlv,
|
||||||
|
NULL);
|
||||||
|
if (!data || data_len < 3) {
|
||||||
|
printf("ERROR: can't decode message. len %d\n", data_len);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showData){
|
||||||
|
printf("Recovered data:\n");
|
||||||
|
dump_buffer(data, data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[3] < 30 || data[3] > data_len - 4) {
|
||||||
|
printf("ERROR: Invalid data length\n");
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cid_tlv || cid_tlv->len != 1 || cid_tlv->value[0] != data[5 + data[4]]) {
|
||||||
|
printf("ERROR: CID mismatch\n");
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct crypto_hash *ch;
|
||||||
|
ch = crypto_hash_open(enc_pk->hash_algo);
|
||||||
|
if (!ch) {
|
||||||
|
printf("ERROR: can't create hash\n");
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdol_data_tlv)
|
||||||
|
crypto_hash_write(ch, pdol_data_tlv->value, pdol_data_tlv->len);
|
||||||
|
if (crm1_tlv)
|
||||||
|
crypto_hash_write(ch, crm1_tlv->value, crm1_tlv->len);
|
||||||
|
if (crm2_tlv)
|
||||||
|
crypto_hash_write(ch, crm2_tlv->value, crm2_tlv->len);
|
||||||
|
|
||||||
|
tlvdb_visit(this_db, tlv_hash, ch, 0);
|
||||||
|
|
||||||
|
if (memcmp(data + 5 + data[4] + 1 + 8, crypto_hash_read(ch), 20)) {
|
||||||
|
printf("ERROR: calculated hash error\n");
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
|
||||||
|
size_t idn_len = data[4];
|
||||||
|
if (idn_len > data[3] - 1) {
|
||||||
|
printf("ERROR: Invalid IDN length\n");
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return idn_db;
|
||||||
|
}
|
45
client/emv/emv_pki.h
Normal file
45
client/emv/emv_pki.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMV_PKI_H
|
||||||
|
#define EMV_PKI_H
|
||||||
|
|
||||||
|
#include "emv_pk.h"
|
||||||
|
#include "tlv.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db);
|
||||||
|
struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv);
|
||||||
|
struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db);
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_recover_dac(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv);
|
||||||
|
struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData);
|
||||||
|
struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv);
|
||||||
|
struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData);
|
||||||
|
struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData);
|
||||||
|
struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||||
|
const struct tlvdb *this_db,
|
||||||
|
const struct tlv *pdol_data_tlv,
|
||||||
|
const struct tlv *crm1_tlv,
|
||||||
|
const struct tlv *crm2_tlv);
|
||||||
|
struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||||
|
const struct tlvdb *this_db,
|
||||||
|
const struct tlv *pdol_data_tlv,
|
||||||
|
const struct tlv *crm1_tlv,
|
||||||
|
const struct tlv *crm2_tlv,
|
||||||
|
bool showData);
|
||||||
|
|
||||||
|
#endif
|
283
client/emv/emv_pki_priv.c
Normal file
283
client/emv/emv_pki_priv.c
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "emv_pki_priv.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
|
||||||
|
const unsigned char *rid, unsigned char index,
|
||||||
|
unsigned int expire, enum crypto_algo_hash hash_algo)
|
||||||
|
{
|
||||||
|
size_t modlen, explen;
|
||||||
|
unsigned char *mod, *exp;
|
||||||
|
|
||||||
|
if (!rid)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mod = crypto_pk_get_parameter(cp, 0, &modlen);
|
||||||
|
exp = crypto_pk_get_parameter(cp, 1, &explen);
|
||||||
|
|
||||||
|
if (!mod || !modlen || !exp || !explen) {
|
||||||
|
free(mod);
|
||||||
|
free(exp);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *pk = emv_pk_new(modlen, explen);
|
||||||
|
memcpy(pk->rid, rid, 5);
|
||||||
|
pk->index = index;
|
||||||
|
pk->expire = expire;
|
||||||
|
pk->pk_algo = crypto_pk_get_algo(cp);
|
||||||
|
pk->hash_algo = hash_algo;
|
||||||
|
memcpy(pk->modulus, mod, modlen);
|
||||||
|
memcpy(pk->exp, exp, explen);
|
||||||
|
|
||||||
|
free(mod);
|
||||||
|
free(exp);
|
||||||
|
|
||||||
|
struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
|
||||||
|
if (!ch) {
|
||||||
|
emv_pk_free(pk);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
|
||||||
|
crypto_hash_write(ch, &pk->index, 1);
|
||||||
|
crypto_hash_write(ch, pk->modulus, pk->mlen);
|
||||||
|
crypto_hash_write(ch, pk->exp, pk->elen);
|
||||||
|
|
||||||
|
unsigned char *h = crypto_hash_read(ch);
|
||||||
|
if (!h) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
emv_pk_free(pk);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pk->hash, h, crypto_hash_get_size(ch));
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tlvdb *emv_pki_sign_message(const struct crypto_pk *cp,
|
||||||
|
tlv_tag_t cert_tag, tlv_tag_t rem_tag,
|
||||||
|
const unsigned char *msg, size_t msg_len,
|
||||||
|
... /* A list of tlv pointers, end with NULL */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
size_t tmp_len = (crypto_pk_get_nbits(cp) + 7) / 8;
|
||||||
|
unsigned char *tmp = malloc(tmp_len);
|
||||||
|
if (!tmp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
struct crypto_hash *ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp[0] = 0x6a;
|
||||||
|
tmp[tmp_len - 1] = 0xbc;
|
||||||
|
|
||||||
|
const unsigned char *rem;
|
||||||
|
size_t rem_len;
|
||||||
|
size_t hash_len = crypto_hash_get_size(ch);
|
||||||
|
size_t part_len = tmp_len - 2 - hash_len;
|
||||||
|
if (part_len < msg_len) {
|
||||||
|
memcpy(tmp + 1, msg, part_len);
|
||||||
|
rem = msg + part_len;
|
||||||
|
rem_len = msg_len - part_len;
|
||||||
|
} else {
|
||||||
|
memcpy(tmp + 1, msg, msg_len);
|
||||||
|
memset(tmp + 1 + msg_len, 0xbb, part_len - msg_len);
|
||||||
|
rem = NULL;
|
||||||
|
rem_len = 0;
|
||||||
|
}
|
||||||
|
crypto_hash_write(ch, tmp + 1, part_len);
|
||||||
|
crypto_hash_write(ch, rem, rem_len);
|
||||||
|
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, msg_len);
|
||||||
|
while (true) {
|
||||||
|
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
||||||
|
if (!add_tlv)
|
||||||
|
break;
|
||||||
|
|
||||||
|
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
||||||
|
}
|
||||||
|
va_end(vl);
|
||||||
|
|
||||||
|
unsigned char *h = crypto_hash_read(ch);
|
||||||
|
if (!h) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(tmp + 1 + part_len, h, hash_len);
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
|
||||||
|
size_t cert_len;
|
||||||
|
unsigned char *cert = crypto_pk_decrypt(cp, tmp, tmp_len, &cert_len);
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
if (!cert)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct tlvdb *db = tlvdb_fixed(cert_tag, cert_len, cert);
|
||||||
|
free(cert);
|
||||||
|
if (!db)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (rem) {
|
||||||
|
struct tlvdb *rdb = tlvdb_fixed(rem_tag, rem_len, rem);
|
||||||
|
if (!rdb) {
|
||||||
|
tlvdb_free(db);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
tlvdb_add(db, rdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tlvdb *emv_pki_sign_key(const struct crypto_pk *cp,
|
||||||
|
struct emv_pk *ipk,
|
||||||
|
unsigned char msgtype,
|
||||||
|
size_t pan_len,
|
||||||
|
tlv_tag_t cert_tag,
|
||||||
|
tlv_tag_t exp_tag,
|
||||||
|
tlv_tag_t rem_tag,
|
||||||
|
const struct tlv *add_tlv
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unsigned pos = 0;
|
||||||
|
unsigned char *msg = malloc(1 + pan_len + 2 + 3 + 1 + 1 + 1 + 1 + ipk->mlen);
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
msg[pos++] = msgtype;
|
||||||
|
memcpy(msg + pos, ipk->pan, pan_len); pos += pan_len;
|
||||||
|
msg[pos++] = (ipk->expire >> 8) & 0xff;
|
||||||
|
msg[pos++] = (ipk->expire >> 16) & 0xff;
|
||||||
|
memcpy(msg + pos, ipk->serial, 3); pos += 3;
|
||||||
|
msg[pos++] = ipk->hash_algo;
|
||||||
|
msg[pos++] = ipk->pk_algo;
|
||||||
|
msg[pos++] = ipk->mlen;
|
||||||
|
msg[pos++] = ipk->elen;
|
||||||
|
memcpy(msg + pos, ipk->modulus, ipk->mlen);
|
||||||
|
pos += ipk->mlen;
|
||||||
|
|
||||||
|
struct tlvdb *exp_db = tlvdb_fixed(exp_tag, ipk->elen, ipk->exp);
|
||||||
|
if (!exp_db) {
|
||||||
|
free(msg);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||||
|
cert_tag, rem_tag,
|
||||||
|
msg, pos,
|
||||||
|
tlvdb_get(exp_db, exp_tag, NULL),
|
||||||
|
add_tlv,
|
||||||
|
NULL);
|
||||||
|
free(msg);
|
||||||
|
if (!db)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
tlvdb_add(db, exp_db);
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_sign_issuer_cert(const struct crypto_pk *cp, struct emv_pk *issuer_pk)
|
||||||
|
{
|
||||||
|
return emv_pki_sign_key(cp, issuer_pk, 2, 4, 0x90, 0x9f32, 0x92, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_sign_icc_cert(const struct crypto_pk *cp, struct emv_pk *icc_pk, const struct tlv *sda_tlv)
|
||||||
|
{
|
||||||
|
return emv_pki_sign_key(cp, icc_pk, 4, 10, 0x9f46, 0x9f47, 0x9f48, sda_tlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk *icc_pe_pk)
|
||||||
|
{
|
||||||
|
return emv_pki_sign_key(cp, icc_pe_pk, 4, 10, 0x9f2d, 0x9f2e, 0x9f2f, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_sign_dac(const struct crypto_pk *cp, const struct tlv *dac_tlv, const struct tlv *sda_tlv)
|
||||||
|
{
|
||||||
|
unsigned pos = 0;
|
||||||
|
unsigned char *msg = malloc(1+1+dac_tlv->len);
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
msg[pos++] = 3;
|
||||||
|
msg[pos++] = HASH_SHA_1;
|
||||||
|
memcpy(msg+pos, dac_tlv->value, dac_tlv->len);
|
||||||
|
pos += dac_tlv->len;
|
||||||
|
|
||||||
|
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||||
|
0x93, 0,
|
||||||
|
msg, pos,
|
||||||
|
sda_tlv,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
free(msg);
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_sign_idn(const struct crypto_pk *cp, const struct tlv *idn_tlv, const struct tlv *dyn_tlv)
|
||||||
|
{
|
||||||
|
unsigned pos = 0;
|
||||||
|
unsigned char *msg = malloc(1+1+1+1+idn_tlv->len);
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
msg[pos++] = 5;
|
||||||
|
msg[pos++] = HASH_SHA_1;
|
||||||
|
msg[pos++] = idn_tlv->len + 1;
|
||||||
|
msg[pos++] = idn_tlv->len;
|
||||||
|
memcpy(msg+pos, idn_tlv->value, idn_tlv->len);
|
||||||
|
pos += idn_tlv->len;
|
||||||
|
|
||||||
|
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||||
|
0x9f4b, 0,
|
||||||
|
msg, pos,
|
||||||
|
dyn_tlv,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
free(msg);
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
35
client/emv/emv_pki_priv.h
Normal file
35
client/emv/emv_pki_priv.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* libopenemv - a library to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMV_PKI_PRIV_H
|
||||||
|
#define EMV_PKI_PRIV_H
|
||||||
|
|
||||||
|
#include "crypto.h"
|
||||||
|
#include "emv_pk.h"
|
||||||
|
#include "tlv.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
|
||||||
|
const unsigned char *rid, unsigned char index,
|
||||||
|
unsigned int expire, enum crypto_algo_hash hash_algo);
|
||||||
|
struct tlvdb *emv_pki_sign_issuer_cert(const struct crypto_pk *cp, struct emv_pk *issuer_pk);
|
||||||
|
struct tlvdb *emv_pki_sign_icc_cert(const struct crypto_pk *cp, struct emv_pk *icc_pk, const struct tlv *sda_tlv);
|
||||||
|
struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk *icc_pe_pk);
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_sign_dac(const struct crypto_pk *cp, const struct tlv *dac_tlv, const struct tlv *sda_tlv);
|
||||||
|
struct tlvdb *emv_pki_sign_idn(const struct crypto_pk *cp, const struct tlv *idn_tlv, const struct tlv *dyn_tlv);
|
||||||
|
|
||||||
|
#endif
|
|
@ -177,6 +177,7 @@ static const struct emv_tag emv_tags[] = {
|
||||||
{ 0x01 , "", EMV_TAG_STRING }, // string for headers
|
{ 0x01 , "", EMV_TAG_STRING }, // string for headers
|
||||||
{ 0x02 , "Raw data", }, // data
|
{ 0x02 , "Raw data", }, // data
|
||||||
{ 0x20 , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard!
|
{ 0x20 , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard!
|
||||||
|
{ 0x21 , "Input list for Offline Data Authentication" }, // not standard! data for "Offline Data Authentication" come from "read records" command. (EMV book3 10.3)
|
||||||
|
|
||||||
// EMV
|
// EMV
|
||||||
{ 0x41 , "Country code and national data" },
|
{ 0x41 , "Country code and national data" },
|
||||||
|
@ -266,6 +267,7 @@ static const struct emv_tag emv_tags[] = {
|
||||||
{ 0x9f65, "PCVC3(Track2)" },
|
{ 0x9f65, "PCVC3(Track2)" },
|
||||||
{ 0x9f66, "PUNATC(Track2) / Terminal Transaction Qualifiers (TTQ)", EMV_TAG_BITMASK, &EMV_TTQ },
|
{ 0x9f66, "PUNATC(Track2) / Terminal Transaction Qualifiers (TTQ)", EMV_TAG_BITMASK, &EMV_TTQ },
|
||||||
{ 0x9f67, "NATC(Track2) / MSD Offset" },
|
{ 0x9f67, "NATC(Track2) / MSD Offset" },
|
||||||
|
{ 0x9f68, "Cardholder verification method list (PayPass)" },
|
||||||
{ 0x9f69, "Card Authentication Related Data" },
|
{ 0x9f69, "Card Authentication Related Data" },
|
||||||
{ 0x9f6a, "Unpredictable Number", EMV_TAG_NUMERIC },
|
{ 0x9f6a, "Unpredictable Number", EMV_TAG_NUMERIC },
|
||||||
{ 0x9f6b, "Track 2 Data" },
|
{ 0x9f6b, "Track 2 Data" },
|
||||||
|
|
|
@ -16,7 +16,7 @@ static const char *PSElist [] = {
|
||||||
"325041592E5359532E4444463031", // 2PAY.SYS.DDF01 - Visa Proximity Payment System Environment - PPSE
|
"325041592E5359532E4444463031", // 2PAY.SYS.DDF01 - Visa Proximity Payment System Environment - PPSE
|
||||||
"315041592E5359532E4444463031" // 1PAY.SYS.DDF01 - Visa Payment System Environment - PSE
|
"315041592E5359532E4444463031" // 1PAY.SYS.DDF01 - Visa Payment System Environment - PSE
|
||||||
};
|
};
|
||||||
static const size_t PSElistLen = sizeof(PSElist)/sizeof(char*);
|
//static const size_t PSElistLen = sizeof(PSElist)/sizeof(char*);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
enum CardPSVendor vendor;
|
enum CardPSVendor vendor;
|
||||||
|
@ -464,32 +464,378 @@ int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen
|
||||||
return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||||
|
return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||||
|
}
|
||||||
|
|
||||||
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||||
return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authentication
|
// Authentication
|
||||||
int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) {
|
static struct emv_pk *get_ca_pk(struct tlvdb *db) {
|
||||||
if (AIDlen < 5)
|
const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL);
|
||||||
return 1;
|
const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL);
|
||||||
|
|
||||||
// Get public key index (0x8F)
|
if (!df_tlv || !caidx_tlv || df_tlv->len < 6 || caidx_tlv->len != 1)
|
||||||
//int PubKeyIndx = 0;
|
return NULL;
|
||||||
|
|
||||||
// Get public key from key storage
|
PrintAndLog("CA public key index 0x%0x", caidx_tlv->value[0]);
|
||||||
// GetPublicKey(AID(0..5), PubKeyIndx)
|
return emv_pk_get_ca_pk(df_tlv->value, caidx_tlv->value[0]);
|
||||||
|
}
|
||||||
|
|
||||||
// Processing of Issuer Public Key Certificate (0x90)
|
int trSDA(struct tlvdb *tlv) {
|
||||||
//Certificate =
|
|
||||||
|
|
||||||
// check issuer public key certificate
|
struct emv_pk *pk = get_ca_pk(tlv);
|
||||||
|
if (!pk) {
|
||||||
|
PrintAndLog("ERROR: Key not found. Exit.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
// Verification of Signed Static Application Data (SSAD) (0x93)
|
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
|
||||||
|
if (!issuer_pk) {
|
||||||
|
emv_pk_free(pk);
|
||||||
|
PrintAndLog("ERROR: Issuer certificate not found. Exit.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
// get 9F4A Static Data Authentication Tag List
|
PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx",
|
||||||
|
issuer_pk->rid[0],
|
||||||
|
issuer_pk->rid[1],
|
||||||
|
issuer_pk->rid[2],
|
||||||
|
issuer_pk->rid[3],
|
||||||
|
issuer_pk->rid[4],
|
||||||
|
issuer_pk->index,
|
||||||
|
issuer_pk->serial[0],
|
||||||
|
issuer_pk->serial[1],
|
||||||
|
issuer_pk->serial[2]
|
||||||
|
);
|
||||||
|
|
||||||
// set Data Auth Code (9F45) from SSAD
|
const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
|
||||||
|
if (!sda_tlv || sda_tlv->len < 1) {
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(pk);
|
||||||
|
PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit.");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||||
|
if (dac_db) {
|
||||||
|
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||||
|
PrintAndLog("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
|
||||||
|
tlvdb_add(tlv, dac_db);
|
||||||
|
} else {
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(pk);
|
||||||
|
PrintAndLog("ERROR: SSAD verify error");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(pk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
|
||||||
|
static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
|
||||||
|
|
||||||
|
int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
|
size_t len = 0;
|
||||||
|
uint16_t sw = 0;
|
||||||
|
|
||||||
|
struct emv_pk *pk = get_ca_pk(tlv);
|
||||||
|
if (!pk) {
|
||||||
|
PrintAndLog("ERROR: Key not found. Exit.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
|
||||||
|
if (!sda_tlv || sda_tlv->len < 1) {
|
||||||
|
emv_pk_free(pk);
|
||||||
|
PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit.");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
|
||||||
|
if (!issuer_pk) {
|
||||||
|
emv_pk_free(pk);
|
||||||
|
PrintAndLog("ERROR: Issuer certificate not found. Exit.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
printf("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||||
|
issuer_pk->rid[0],
|
||||||
|
issuer_pk->rid[1],
|
||||||
|
issuer_pk->rid[2],
|
||||||
|
issuer_pk->rid[3],
|
||||||
|
issuer_pk->rid[4],
|
||||||
|
issuer_pk->index,
|
||||||
|
issuer_pk->serial[0],
|
||||||
|
issuer_pk->serial[1],
|
||||||
|
issuer_pk->serial[2]
|
||||||
|
);
|
||||||
|
|
||||||
|
struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
|
||||||
|
if (!icc_pk) {
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
PrintAndLog("ERROR: ICC setrificate not found. Exit.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||||
|
icc_pk->rid[0],
|
||||||
|
icc_pk->rid[1],
|
||||||
|
icc_pk->rid[2],
|
||||||
|
icc_pk->rid[3],
|
||||||
|
icc_pk->rid[4],
|
||||||
|
icc_pk->index,
|
||||||
|
icc_pk->serial[0],
|
||||||
|
icc_pk->serial[1],
|
||||||
|
icc_pk->serial[2]
|
||||||
|
);
|
||||||
|
|
||||||
|
struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv);
|
||||||
|
if (!icc_pe_pk) {
|
||||||
|
PrintAndLog("WARNING: ICC PE PK recover error. ");
|
||||||
|
} else {
|
||||||
|
printf("ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||||
|
icc_pe_pk->rid[0],
|
||||||
|
icc_pe_pk->rid[1],
|
||||||
|
icc_pe_pk->rid[2],
|
||||||
|
icc_pe_pk->rid[3],
|
||||||
|
icc_pe_pk->rid[4],
|
||||||
|
icc_pe_pk->index,
|
||||||
|
icc_pe_pk->serial[0],
|
||||||
|
icc_pe_pk->serial[1],
|
||||||
|
icc_pe_pk->serial[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9F4B: Signed Dynamic Application Data
|
||||||
|
const struct tlv *sdad_tlv = tlvdb_get(tlv, 0x9f4b, NULL);
|
||||||
|
// DDA with internal authenticate OR fDDA with filled 0x9F4B tag (GPO result)
|
||||||
|
// EMV kernel3 v2.4, contactless book C-3, C.1., page 147
|
||||||
|
if (sdad_tlv) {
|
||||||
|
PrintAndLog("\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
|
||||||
|
|
||||||
|
const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true);
|
||||||
|
if (!atc_db) {
|
||||||
|
PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)");
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9f36 Application Transaction Counter (ATC)
|
||||||
|
const struct tlv *atc_tlv = tlvdb_get(atc_db, 0x9f36, NULL);
|
||||||
|
if(atc_tlv) {
|
||||||
|
PrintAndLog("\nATC (Application Transaction Counter) [%zu] %s", atc_tlv->len, sprint_hex_inrow(atc_tlv->value, atc_tlv->len));
|
||||||
|
|
||||||
|
const struct tlv *core_atc_tlv = tlvdb_get(tlv, 0x9f36, NULL);
|
||||||
|
if(tlv_equal(core_atc_tlv, atc_tlv)) {
|
||||||
|
PrintAndLog("ATC check OK.");
|
||||||
|
PrintAndLog("fDDA (fast DDA) verified OK.");
|
||||||
|
} else {
|
||||||
|
PrintAndLog("ERROR: fDDA verified, but ATC in the certificate and ATC in the record not the same.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PrintAndLog("\nERROR: fDDA (fast DDA) verify error");
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||||
|
if (dac_db) {
|
||||||
|
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||||
|
printf("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
|
||||||
|
tlvdb_add(tlv, dac_db);
|
||||||
|
} else {
|
||||||
|
PrintAndLog("ERROR: SSAD verify error");
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("\n* Calc DDOL");
|
||||||
|
const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL);
|
||||||
|
if (!ddol_tlv) {
|
||||||
|
ddol_tlv = &default_ddol_tlv;
|
||||||
|
PrintAndLog("DDOL [9f49] not found. Using default DDOL");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlv *ddol_data_tlv = dol_process(ddol_tlv, tlv, 0);
|
||||||
|
if (!ddol_data_tlv) {
|
||||||
|
PrintAndLog("ERROR: Can't create DDOL TLV");
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
|
||||||
|
|
||||||
|
PrintAndLog("\n* Internal Authenticate");
|
||||||
|
int res = EMVInternalAuthenticate(true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL);
|
||||||
|
if (res) {
|
||||||
|
PrintAndLog("Internal Authenticate error(%d): %4x. Exit...", res, sw);
|
||||||
|
free(ddol_data_tlv);
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *dda_db = NULL;
|
||||||
|
if (buf[0] == 0x80) {
|
||||||
|
if (len < 3 ) {
|
||||||
|
PrintAndLog("ERROR: Internal Authenticate format1 parsing error. length=%d", len);
|
||||||
|
} else {
|
||||||
|
// 9f4b Signed Dynamic Application Data
|
||||||
|
dda_db = tlvdb_fixed(0x9f4b, len - 2, buf + 2);
|
||||||
|
tlvdb_add(tlv, dda_db);
|
||||||
|
if (decodeTLV){
|
||||||
|
PrintAndLog("* * Decode response format 1:");
|
||||||
|
TLVPrintFromTLV(dda_db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dda_db = tlvdb_parse_multi(buf, len);
|
||||||
|
if(!dda_db) {
|
||||||
|
PrintAndLog("ERROR: Can't parse Internal Authenticate result as TLV");
|
||||||
|
free(ddol_data_tlv);
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
tlvdb_add(tlv, dda_db);
|
||||||
|
|
||||||
|
if (decodeTLV)
|
||||||
|
TLVPrintFromTLV(dda_db);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *idn_db = emv_pki_recover_idn_ex(icc_pk, dda_db, ddol_data_tlv, true);
|
||||||
|
free(ddol_data_tlv);
|
||||||
|
if (!idn_db) {
|
||||||
|
PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)");
|
||||||
|
tlvdb_free(dda_db);
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
tlvdb_free(dda_db);
|
||||||
|
|
||||||
|
// 9f4c ICC Dynamic Number
|
||||||
|
const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
|
||||||
|
if(idn_tlv) {
|
||||||
|
PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
|
||||||
|
PrintAndLog("DDA verified OK.");
|
||||||
|
tlvdb_add(tlv, idn_db);
|
||||||
|
tlvdb_free(idn_db);
|
||||||
|
} else {
|
||||||
|
PrintAndLog("\nERROR: DDA verify error");
|
||||||
|
tlvdb_free(idn_db);
|
||||||
|
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv) {
|
||||||
|
|
||||||
|
struct emv_pk *pk = get_ca_pk(tlv);
|
||||||
|
if (!pk) {
|
||||||
|
PrintAndLog("ERROR: Key not found. Exit.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
|
||||||
|
if (!sda_tlv || sda_tlv->len < 1) {
|
||||||
|
PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit.");
|
||||||
|
emv_pk_free(pk);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
|
||||||
|
if (!issuer_pk) {
|
||||||
|
PrintAndLog("ERROR: Issuer certificate not found. Exit.");
|
||||||
|
emv_pk_free(pk);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
printf("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||||
|
issuer_pk->rid[0],
|
||||||
|
issuer_pk->rid[1],
|
||||||
|
issuer_pk->rid[2],
|
||||||
|
issuer_pk->rid[3],
|
||||||
|
issuer_pk->rid[4],
|
||||||
|
issuer_pk->index,
|
||||||
|
issuer_pk->serial[0],
|
||||||
|
issuer_pk->serial[1],
|
||||||
|
issuer_pk->serial[2]
|
||||||
|
);
|
||||||
|
|
||||||
|
struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
|
||||||
|
if (!icc_pk) {
|
||||||
|
PrintAndLog("ERROR: ICC setrificate not found. Exit.");
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||||
|
icc_pk->rid[0],
|
||||||
|
icc_pk->rid[1],
|
||||||
|
icc_pk->rid[2],
|
||||||
|
icc_pk->rid[3],
|
||||||
|
icc_pk->rid[4],
|
||||||
|
icc_pk->index,
|
||||||
|
icc_pk->serial[0],
|
||||||
|
icc_pk->serial[1],
|
||||||
|
icc_pk->serial[2]
|
||||||
|
);
|
||||||
|
|
||||||
|
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||||
|
if (dac_db) {
|
||||||
|
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||||
|
PrintAndLog("SSAD verified OK. (%02hhx:%02hhx)", dac_tlv->value[0], dac_tlv->value[1]);
|
||||||
|
tlvdb_add(tlv, dac_db);
|
||||||
|
} else {
|
||||||
|
PrintAndLog("ERROR: SSAD verify error");
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("\n* * Check Signed Dynamic Application Data (SDAD)");
|
||||||
|
struct tlvdb *idn_db = emv_pki_perform_cda_ex(icc_pk, tlv, ac_tlv,
|
||||||
|
pdol_data_tlv, // pdol
|
||||||
|
ac_data_tlv, // cdol1
|
||||||
|
NULL, // cdol2
|
||||||
|
true);
|
||||||
|
if (idn_db) {
|
||||||
|
const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
|
||||||
|
PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
|
||||||
|
PrintAndLog("CDA verified OK.");
|
||||||
|
tlvdb_add(tlv, idn_db);
|
||||||
|
} else {
|
||||||
|
PrintAndLog("\nERROR: CDA verify error");
|
||||||
|
}
|
||||||
|
|
||||||
|
emv_pk_free(pk);
|
||||||
|
emv_pk_free(issuer_pk);
|
||||||
|
emv_pk_free(icc_pk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -20,11 +20,13 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "cmdhf14a.h"
|
#include "cmdhf14a.h"
|
||||||
#include "emv/apduinfo.h"
|
#include "apduinfo.h"
|
||||||
#include "emv/tlv.h"
|
#include "tlv.h"
|
||||||
#include "emv/dol.h"
|
#include "dol.h"
|
||||||
#include "emv/dump.h"
|
#include "dump.h"
|
||||||
#include "emv/emv_tags.h"
|
#include "emv_tags.h"
|
||||||
|
#include "emv_pk.h"
|
||||||
|
#include "emv_pki.h"
|
||||||
|
|
||||||
#define APDU_RES_LEN 260
|
#define APDU_RES_LEN 260
|
||||||
#define APDU_AID_LEN 50
|
#define APDU_AID_LEN 50
|
||||||
|
@ -79,10 +81,14 @@ extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t
|
||||||
// AC
|
// AC
|
||||||
extern int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
extern int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||||
extern int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
extern int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||||
|
// DDA
|
||||||
|
extern int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||||
// Mastercard
|
// Mastercard
|
||||||
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||||
// Auth
|
// Auth
|
||||||
extern int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv);
|
extern int trSDA(struct tlvdb *tlv);
|
||||||
|
extern int trDDA(bool decodeTLV, struct tlvdb *tlv);
|
||||||
|
extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
442
client/emv/test/cda_test.c
Normal file
442
client/emv/test/cda_test.c
Normal file
|
@ -0,0 +1,442 @@
|
||||||
|
/*
|
||||||
|
* emv-tools - a set of tools to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../emv_pk.h"
|
||||||
|
#include "../crypto.h"
|
||||||
|
#include "../dump.h"
|
||||||
|
#include "../tlv.h"
|
||||||
|
#include "../emv_pki.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct emv_pk c_mchip_05 = {
|
||||||
|
.rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
|
||||||
|
.index = 5,
|
||||||
|
.hash_algo = HASH_SHA_1,
|
||||||
|
.pk_algo = PK_RSA,
|
||||||
|
.hash = {
|
||||||
|
0xeb, 0xfa, 0x0d, 0x5d,
|
||||||
|
0x06, 0xd8, 0xce, 0x70,
|
||||||
|
0x2d, 0xa3, 0xea, 0xe8,
|
||||||
|
0x90, 0x70, 0x1d, 0x45,
|
||||||
|
0xe2, 0x74, 0xc8, 0x45, },
|
||||||
|
.exp = { 0x03, },
|
||||||
|
.elen = 1,
|
||||||
|
.mlen = 1408 / 8,
|
||||||
|
.modulus = (unsigned char[]){
|
||||||
|
0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
|
||||||
|
0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
|
||||||
|
0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
|
||||||
|
0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
|
||||||
|
0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
|
||||||
|
0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
|
||||||
|
0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
|
||||||
|
0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
|
||||||
|
0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
|
||||||
|
0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
|
||||||
|
0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_issuer_cert[] = {
|
||||||
|
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||||
|
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||||
|
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||||
|
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||||
|
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||||
|
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||||
|
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||||
|
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||||
|
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||||
|
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||||
|
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_issuer_rem[] = {
|
||||||
|
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||||
|
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||||
|
0x6d, 0xbd, 0x64, 0x15,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_issuer_exp[] = {
|
||||||
|
0x03,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_icc_cert[] = {
|
||||||
|
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||||
|
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||||
|
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||||
|
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||||
|
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||||
|
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||||
|
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||||
|
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||||
|
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||||
|
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||||
|
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_icc_exp[] = {
|
||||||
|
0x03,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_sdad_cr[] = {
|
||||||
|
0x1c, 0x00, 0x9f, 0xc4, 0x86, 0x79, 0x15, 0x7d, 0xbf, 0xf4, 0x5f, 0x65, 0xd3, 0x3f, 0xf7, 0x8d,
|
||||||
|
0x4f, 0xcb, 0xf0, 0xcf, 0x5e, 0xa4, 0x20, 0x8d, 0x10, 0x7a, 0xe9, 0x5a, 0xa3, 0x8c, 0x54, 0x6d,
|
||||||
|
0x0e, 0x5a, 0x18, 0xb8, 0x74, 0x03, 0xa1, 0x2b, 0xd4, 0x47, 0xa8, 0xbb, 0xfc, 0x1e, 0x49, 0xce,
|
||||||
|
0x0b, 0x2e, 0x25, 0x13, 0x89, 0x20, 0x57, 0x03, 0xc9, 0xbb, 0x1a, 0x88, 0xcc, 0x79, 0xf1, 0xdd,
|
||||||
|
0xc2, 0xf9, 0x84, 0x1e, 0xad, 0xf0, 0x7c, 0xe0, 0x7b, 0x62, 0x51, 0x1d, 0xdc, 0x93, 0xdf, 0x59,
|
||||||
|
0xf2, 0x8f, 0x0e, 0x91, 0xf9, 0x23, 0x32, 0xd2, 0x9c, 0xde, 0xf2, 0xbc, 0xcb, 0x10, 0x08, 0x85,
|
||||||
|
0x05, 0x00, 0xef, 0x3e, 0x47, 0x0a, 0x4c, 0xb1, 0x8c, 0xd9, 0x1a, 0xa5, 0xc1, 0xa1, 0x08, 0xf3,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_ssd1[] = {
|
||||||
|
0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
|
||||||
|
0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
|
||||||
|
0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
|
||||||
|
0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
|
||||||
|
0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
|
||||||
|
0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
|
||||||
|
0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
|
||||||
|
0x39, 0x00,
|
||||||
|
};
|
||||||
|
static const struct tlv ssd1_tlv = {
|
||||||
|
.len = sizeof(c_ssd1),
|
||||||
|
.value = c_ssd1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_pan[] = {
|
||||||
|
0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_dd1[] = {
|
||||||
|
0x12, 0x34, 0x57, 0x79,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_dd2[] = {
|
||||||
|
0x9f, 0x27, 0x01, 0x40, 0x9f, 0x36, 0x02, 0x00, 0x10, 0x9f, 0x10, 0x12, 0x00, 0x10, 0x90, 0x40,
|
||||||
|
0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char c_crm1[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x06, 0x43, 0x14, 0x09, 0x25, 0x50, 0x12, 0x34, 0x57, 0x79, 0x23, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x00,
|
||||||
|
};
|
||||||
|
static const struct tlv crm1_tlv = {
|
||||||
|
.len = sizeof(c_crm1),
|
||||||
|
.value = c_crm1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int cda_test_raw(bool verbose)
|
||||||
|
{
|
||||||
|
const struct emv_pk *pk = &c_mchip_05;
|
||||||
|
|
||||||
|
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||||
|
pk->modulus, pk->mlen,
|
||||||
|
pk->exp, pk->elen);
|
||||||
|
if (!kcp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unsigned char *ipk_data;
|
||||||
|
size_t ipk_data_len;
|
||||||
|
ipk_data = crypto_pk_encrypt(kcp, c_issuer_cert, sizeof(c_issuer_cert), &ipk_data_len);
|
||||||
|
crypto_pk_close(kcp);
|
||||||
|
|
||||||
|
if (!ipk_data)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("issuer cert:\n");
|
||||||
|
dump_buffer(ipk_data, ipk_data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ipk_pk_len = ipk_data[13];
|
||||||
|
unsigned char *ipk_pk = malloc(ipk_pk_len);
|
||||||
|
memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
|
||||||
|
memcpy(ipk_pk + ipk_data_len - 36, c_issuer_rem, sizeof(c_issuer_rem));
|
||||||
|
|
||||||
|
struct crypto_hash *ch;
|
||||||
|
ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(ipk_pk);
|
||||||
|
free(ipk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, ipk_data + 1, 14);
|
||||||
|
crypto_hash_write(ch, ipk_pk, ipk_pk_len);
|
||||||
|
crypto_hash_write(ch, c_issuer_exp, sizeof(c_issuer_exp));
|
||||||
|
|
||||||
|
unsigned char *h = crypto_hash_read(ch);
|
||||||
|
if (!h) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ipk_pk);
|
||||||
|
free(ipk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("crypto hash:\n");
|
||||||
|
dump_buffer(h, 20, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ipk_pk);
|
||||||
|
free(ipk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ipk_data);
|
||||||
|
|
||||||
|
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||||
|
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||||
|
free(ipk_pk);
|
||||||
|
if (!ikcp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unsigned char *iccpk_data;
|
||||||
|
size_t iccpk_data_len;
|
||||||
|
iccpk_data = crypto_pk_encrypt(ikcp, c_icc_cert, sizeof(c_icc_cert), &iccpk_data_len);
|
||||||
|
crypto_pk_close(ikcp);
|
||||||
|
|
||||||
|
if (!iccpk_data)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("icc cert:\n");
|
||||||
|
dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t iccpk_pk_len = iccpk_data[19];
|
||||||
|
unsigned char *iccpk_pk = malloc(iccpk_pk_len);
|
||||||
|
memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
|
||||||
|
/*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
|
||||||
|
|
||||||
|
ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(iccpk_pk);
|
||||||
|
free(iccpk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
|
||||||
|
crypto_hash_write(ch, c_icc_exp, sizeof(c_icc_exp));
|
||||||
|
crypto_hash_write(ch, c_ssd1, sizeof(c_ssd1));
|
||||||
|
|
||||||
|
h = crypto_hash_read(ch);
|
||||||
|
if (!h) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(iccpk_pk);
|
||||||
|
free(iccpk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("crypto hash1.1:\n");
|
||||||
|
dump_buffer(h, 20, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(iccpk_pk);
|
||||||
|
free(iccpk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(iccpk_data);
|
||||||
|
|
||||||
|
struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
|
||||||
|
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||||
|
free(iccpk_pk);
|
||||||
|
if (!icckcp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
size_t sdad_len;
|
||||||
|
unsigned char *sdad = crypto_pk_encrypt(icckcp, c_sdad_cr, sizeof(c_sdad_cr), &sdad_len);
|
||||||
|
crypto_pk_close(icckcp);
|
||||||
|
if (!sdad)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("SDAD:\n");
|
||||||
|
dump_buffer(sdad, sdad_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(sdad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, sdad + 1, sdad_len - 22);
|
||||||
|
crypto_hash_write(ch, c_dd1, sizeof(c_dd1));
|
||||||
|
|
||||||
|
unsigned char *h2 = crypto_hash_read(ch);
|
||||||
|
if (!h2) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(sdad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("crypto hash2:\n");
|
||||||
|
dump_buffer(h2, 20, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
|
||||||
|
ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(sdad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, c_crm1, sizeof(c_crm1));
|
||||||
|
crypto_hash_write(ch, c_dd2, sizeof(c_dd2));
|
||||||
|
|
||||||
|
h = crypto_hash_read(ch);
|
||||||
|
if (!h) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(sdad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("crypto hash2.1:\n");
|
||||||
|
dump_buffer(h, 20, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(sdad + 5 + 8 + 1 + 8, h, 20)) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(sdad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
|
||||||
|
free(sdad);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cda_test_pk(bool verbose)
|
||||||
|
{
|
||||||
|
const struct emv_pk *pk = &c_mchip_05;
|
||||||
|
struct tlvdb *db;
|
||||||
|
|
||||||
|
db = tlvdb_external(0x90, sizeof(c_issuer_cert), c_issuer_cert);
|
||||||
|
tlvdb_add(db, tlvdb_external(0x9f32, sizeof(c_issuer_exp), c_issuer_exp));
|
||||||
|
tlvdb_add(db, tlvdb_external(0x92, sizeof(c_issuer_rem), c_issuer_rem));
|
||||||
|
tlvdb_add(db, tlvdb_external(0x5a, sizeof(c_pan), c_pan));
|
||||||
|
|
||||||
|
struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
|
||||||
|
if (!ipk) {
|
||||||
|
fprintf(stderr, "Could not recover Issuer certificate!\n");
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvdb_add(db, tlvdb_external(0x9f46, sizeof(c_icc_cert), c_icc_cert));
|
||||||
|
tlvdb_add(db, tlvdb_external(0x9f47, sizeof(c_icc_exp), c_icc_exp));
|
||||||
|
/*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(issuer_rem), issuer_rem));*/
|
||||||
|
|
||||||
|
struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
|
||||||
|
if (!iccpk) {
|
||||||
|
fprintf(stderr, "Could not recover ICC certificate!\n");
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvdb_add(db, tlvdb_fixed(0x9f37, sizeof(c_dd1), c_dd1));
|
||||||
|
|
||||||
|
struct tlvdb *cda_db;
|
||||||
|
cda_db = tlvdb_fixed(0x9f27, 1, (unsigned char[]){ 0x40 });
|
||||||
|
tlvdb_add(cda_db, tlvdb_fixed(0x9f36, 2, (unsigned char[]) { 0x00, 0x10 }));
|
||||||
|
tlvdb_add(cda_db, tlvdb_external(0x9f4b, sizeof(c_sdad_cr), c_sdad_cr));
|
||||||
|
tlvdb_add(cda_db, tlvdb_fixed(0x9f10, 0x12,
|
||||||
|
(unsigned char[]) { 0x00, 0x10, 0x90, 0x40, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}));
|
||||||
|
|
||||||
|
struct tlvdb *idndb = emv_pki_perform_cda(iccpk, db, cda_db,
|
||||||
|
NULL,
|
||||||
|
&crm1_tlv,
|
||||||
|
NULL);
|
||||||
|
if (!idndb) {
|
||||||
|
fprintf(stderr, "Could not recover IDN!\n");
|
||||||
|
tlvdb_free(cda_db);
|
||||||
|
emv_pk_free(iccpk);
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
|
||||||
|
if (!idn) {
|
||||||
|
fprintf(stderr, "IDN not found!\n");
|
||||||
|
tlvdb_free(idndb);
|
||||||
|
tlvdb_free(cda_db);
|
||||||
|
emv_pk_free(iccpk);
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("IDN:\n");
|
||||||
|
dump_buffer(idn->value, idn->len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvdb_free(idndb);
|
||||||
|
tlvdb_free(cda_db);
|
||||||
|
emv_pk_free(iccpk);
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec_cda_test(bool verbose)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
|
ret = cda_test_raw(verbose);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "CDA raw test: failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "CDA raw test: passed\n");
|
||||||
|
|
||||||
|
ret = cda_test_pk(verbose);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "CDA test pk: failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "CDA test pk: passed\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
18
client/emv/test/cda_test.h
Normal file
18
client/emv/test/cda_test.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* emv-tools - a set of tools to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
extern int exec_cda_test(bool verbose);
|
327
client/emv/test/crypto_test.c
Normal file
327
client/emv/test/crypto_test.c
Normal file
|
@ -0,0 +1,327 @@
|
||||||
|
/*
|
||||||
|
* emv-tools - a set of tools to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../crypto.h"
|
||||||
|
#include "../dump.h"
|
||||||
|
#include "util_posix.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
static int test_genkey(unsigned int keylength, unsigned char *msg, size_t msg_len, bool verbose)
|
||||||
|
{
|
||||||
|
int ret = 1;
|
||||||
|
size_t tmp_len, tmp2_len;
|
||||||
|
unsigned char *tmp, *tmp2;
|
||||||
|
struct crypto_pk *pk;
|
||||||
|
|
||||||
|
printf("Testing key length %u ", keylength);
|
||||||
|
uint64_t ms = msclock();
|
||||||
|
|
||||||
|
pk = crypto_pk_genkey(PK_RSA, 1, keylength, 3);
|
||||||
|
if (!pk) {
|
||||||
|
fprintf(stderr, "ERROR: key generation error.\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_len = crypto_pk_get_nbits(pk);
|
||||||
|
if (tmp_len != keylength) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_get_nbits.\n");
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = crypto_pk_decrypt(pk, msg, msg_len, &tmp_len);
|
||||||
|
if (!tmp) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp2 = crypto_pk_encrypt(pk, tmp, tmp_len, &tmp2_len);
|
||||||
|
if (!tmp2) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
|
||||||
|
goto free_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tmp2);
|
||||||
|
printf("passed. (%"PRIu64" ms) \n", msclock() - ms);
|
||||||
|
free_tmp:
|
||||||
|
free(tmp);
|
||||||
|
close:
|
||||||
|
crypto_pk_close(pk);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char message[4096 / 8] =
|
||||||
|
"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
|
||||||
|
"ccccccccccccccccdddddddddddddddd"
|
||||||
|
"eeeeeeeeeeeeeeeeffffffffffffffff"
|
||||||
|
"gggggggggggggggghhhhhhhhhhhhhhhh"
|
||||||
|
"iiiiiiiiiiiiiiiijjjjjjjjjjjjjjjj"
|
||||||
|
"kkkkkkkkkkkkkkkkllllllllllllllll"
|
||||||
|
"mmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnn"
|
||||||
|
"oooooooooooooooopppppppppppppppp"
|
||||||
|
"qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr"
|
||||||
|
"sssssssssssssssstttttttttttttttt"
|
||||||
|
"uuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvv"
|
||||||
|
"wwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxx"
|
||||||
|
"yyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzz"
|
||||||
|
"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
|
||||||
|
"ccccccccccccccccdddddddddddddddd"
|
||||||
|
"eeeeeeeeeeeeeeeeffffffffffffffff"
|
||||||
|
;
|
||||||
|
|
||||||
|
static unsigned char pk_N[] = {
|
||||||
|
0xdb, 0x12, 0xe4, 0xf1, 0x8d, 0x43, 0x74, 0xf0, 0xec, 0x38, 0xdc, 0xfb, 0xf9, 0x20, 0x75, 0x6d,
|
||||||
|
0x05, 0xf4, 0x36, 0xc2, 0x21, 0xac, 0x34, 0x0d, 0x16, 0xc5, 0x23, 0xcb, 0xfc, 0x9a, 0x8a, 0xd1,
|
||||||
|
0xe0, 0xbd, 0xda, 0xe5, 0x77, 0xd5, 0xaf, 0x65, 0x8d, 0x6b, 0x62, 0x5c, 0xcd, 0x89, 0x06, 0x8d,
|
||||||
|
0x11, 0x19, 0x6b, 0x0e, 0x3e, 0xe2, 0x80, 0x45, 0xf6, 0x44, 0x55, 0x21, 0x9c, 0x86, 0x90, 0x00,
|
||||||
|
0xa8, 0xaf, 0x8c, 0x94, 0xde, 0x3f, 0xe8, 0x56, 0x52, 0xfe, 0xee, 0xa5, 0x36, 0x72, 0x07, 0xf2,
|
||||||
|
0xcf, 0x8e, 0xf0, 0xbd, 0xff, 0x36, 0xd5, 0xf2, 0xad, 0x74, 0x1d, 0x17, 0xd0, 0xb7, 0x93, 0xe2,
|
||||||
|
0x2c, 0x8d, 0x3f, 0xb6, 0x7c, 0x65, 0x19, 0x9f, 0xa7, 0x80, 0x1f, 0x9f, 0xe5, 0x2f, 0x2d, 0x75,
|
||||||
|
0xc9, 0xc2, 0xe9, 0x70, 0xfa, 0x1e, 0x5a, 0xc6, 0xa3, 0x82, 0xd1, 0x29, 0x5a, 0x60, 0xce, 0x1f,
|
||||||
|
0x40, 0x2e, 0xfc, 0x2a, 0x5e, 0xde, 0xc9, 0x67, 0xfc, 0x45, 0x18, 0xce, 0xf2, 0x83, 0x94, 0x53,
|
||||||
|
0xd6, 0x4f, 0x2e, 0xc5, 0x2d, 0xa1, 0xa5, 0x7a, 0x63, 0x26, 0x70, 0xcb, 0x76, 0xfc, 0xb5, 0x8d,
|
||||||
|
0x0f, 0x88, 0x4c, 0x07, 0xba, 0xfa, 0x8b, 0xbc, 0xa0, 0xea, 0xea, 0x0a, 0xe6, 0xa5, 0x44, 0xa5,
|
||||||
|
0x0d, 0x12, 0x66, 0x2b, 0xf7, 0xc4, 0x76, 0xa3, 0x82, 0xa6, 0x2b, 0xb2, 0x5a, 0x27, 0xcd, 0x11,
|
||||||
|
0xd2, 0x9d, 0x42, 0x86, 0x8c, 0x82, 0xc8, 0xe1, 0xff, 0x7d, 0xf1, 0xd9, 0xd9, 0xa1, 0xf3, 0x3d,
|
||||||
|
0xc3, 0x12, 0x4e, 0x47, 0xc8, 0xa2, 0xcd, 0x72, 0x5a, 0x18, 0xea, 0x89, 0x5c, 0x73, 0x28, 0x52,
|
||||||
|
0xf8, 0xdb, 0x70, 0xdc, 0x92, 0xc9, 0xb7, 0x98, 0x10, 0x94, 0x79, 0xdc, 0x9e, 0x12, 0x6c, 0x14,
|
||||||
|
0x78, 0xf9, 0x5a, 0xad, 0x00, 0x98, 0xc8, 0x17, 0x79, 0x8a, 0xed, 0xe7, 0xc3, 0xd3, 0xa7, 0x8b,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char pk_E[] = {
|
||||||
|
0x01, 0x00, 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char pk_D[] = {
|
||||||
|
0x01, 0x17, 0xd4, 0x0a, 0x9c, 0x80, 0xd4, 0xa9, 0x8b, 0x14, 0x31, 0x8e, 0x14, 0x4d, 0x24, 0x28,
|
||||||
|
0xda, 0x19, 0xc0, 0xd8, 0x31, 0x20, 0xd1, 0xd5, 0xaa, 0xe2, 0x6a, 0xee, 0x4e, 0xa1, 0x5a, 0xc5,
|
||||||
|
0xf7, 0x50, 0x1b, 0x32, 0x7f, 0xe9, 0x92, 0x09, 0x78, 0xae, 0x2b, 0x7c, 0x79, 0x0e, 0x10, 0xf9,
|
||||||
|
0x4d, 0x37, 0x8a, 0x40, 0x34, 0xf2, 0x1e, 0x5f, 0xba, 0xfd, 0xd6, 0x4a, 0xe7, 0xa4, 0x08, 0x3d,
|
||||||
|
0xe8, 0x99, 0x8f, 0xa3, 0x02, 0x84, 0xe1, 0x1c, 0xe5, 0x27, 0x1e, 0x7b, 0xb6, 0x8c, 0xd5, 0x1b,
|
||||||
|
0x52, 0x0b, 0xcd, 0x89, 0xb5, 0x27, 0x49, 0xe3, 0xff, 0x17, 0x90, 0x39, 0x99, 0x32, 0x01, 0x4b,
|
||||||
|
0xe4, 0x9b, 0x03, 0xd1, 0x5e, 0x47, 0x86, 0xdc, 0x34, 0x12, 0xc0, 0x95, 0xa4, 0xa8, 0x1a, 0x9a,
|
||||||
|
0xf6, 0xd9, 0xc1, 0x1e, 0x6e, 0x31, 0x0e, 0x94, 0xe5, 0x25, 0xf6, 0xf3, 0x34, 0xdf, 0x3c, 0xc8,
|
||||||
|
0x0a, 0xc5, 0x8c, 0x00, 0x5c, 0x59, 0x55, 0x06, 0xd1, 0x39, 0x84, 0x35, 0x96, 0x40, 0xe8, 0xb2,
|
||||||
|
0xf7, 0x13, 0x83, 0x37, 0xe1, 0xe2, 0x79, 0x41, 0x90, 0x2a, 0xc3, 0x71, 0xc5, 0xcf, 0xf0, 0xaa,
|
||||||
|
0x01, 0x2f, 0x48, 0x9c, 0x3f, 0x29, 0x7b, 0xb7, 0x5c, 0xef, 0x25, 0xde, 0x34, 0x23, 0x81, 0x7a,
|
||||||
|
0x4c, 0x3a, 0x9b, 0xe4, 0xa7, 0x44, 0x73, 0xbf, 0xf7, 0x39, 0x43, 0xa4, 0x39, 0xa0, 0x1b, 0xf7,
|
||||||
|
0x4f, 0x5f, 0x14, 0x49, 0x32, 0x0e, 0x66, 0xd0, 0x29, 0xb5, 0x80, 0xe0, 0xba, 0x3b, 0x88, 0x2b,
|
||||||
|
0x14, 0xa4, 0x26, 0x00, 0x2f, 0x50, 0x20, 0x4e, 0xfa, 0xc2, 0x44, 0x72, 0x72, 0x6c, 0x2a, 0x77,
|
||||||
|
0x85, 0x20, 0xe0, 0x1d, 0x95, 0x6a, 0x66, 0xe7, 0xb8, 0xca, 0x5b, 0xc9, 0xc3, 0xf3, 0x39, 0xef,
|
||||||
|
0xd7, 0xd5, 0x45, 0xb6, 0x3e, 0x19, 0xea, 0x7c, 0x56, 0x20, 0x1b, 0x95, 0x86, 0x2e, 0xc7, 0x51,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char pk_P[] = {
|
||||||
|
0xf5, 0x93, 0x0f, 0x76, 0x00, 0xab, 0x37, 0x01, 0xb9, 0x52, 0xb6, 0x82, 0xf9, 0xf5, 0xae, 0x29,
|
||||||
|
0x8f, 0xd5, 0x08, 0xbc, 0xf7, 0x9f, 0x84, 0xb6, 0x4c, 0x94, 0xb5, 0xfc, 0xfe, 0xe1, 0xcd, 0x6a,
|
||||||
|
0xf4, 0x9c, 0xa7, 0x33, 0xdb, 0xd8, 0xc8, 0xc1, 0xc0, 0x8d, 0x65, 0xed, 0x29, 0x99, 0x6c, 0x5c,
|
||||||
|
0xbe, 0x08, 0xac, 0x04, 0xe4, 0x3a, 0x18, 0xe2, 0x0f, 0x70, 0x26, 0x70, 0x9b, 0x71, 0xfc, 0x9f,
|
||||||
|
0x22, 0xea, 0x90, 0x3b, 0xc2, 0xa5, 0x16, 0x7a, 0xcd, 0x04, 0x3e, 0xa6, 0x37, 0x49, 0xa7, 0xee,
|
||||||
|
0xaa, 0xe4, 0x9d, 0xaa, 0x9b, 0xb0, 0xe2, 0x6a, 0x9d, 0x1e, 0xcd, 0x83, 0x4e, 0xd8, 0x59, 0x6d,
|
||||||
|
0x03, 0xd5, 0x4c, 0x5e, 0xc5, 0x22, 0x10, 0xb7, 0xcc, 0x0c, 0x90, 0x76, 0x05, 0x21, 0xe7, 0x77,
|
||||||
|
0x5c, 0x88, 0x5f, 0xd0, 0x5f, 0x9e, 0x2e, 0x49, 0x56, 0xf4, 0x2b, 0xa9, 0x99, 0x57, 0x74, 0x19,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char pk_Q[] = {
|
||||||
|
0xe4, 0x5f, 0xd2, 0x28, 0xbd, 0xf3, 0xdd, 0x70, 0x3d, 0xfd, 0x01, 0x23, 0xae, 0x93, 0x6a, 0x91,
|
||||||
|
0xca, 0x68, 0xb1, 0xdb, 0x81, 0xab, 0x1e, 0x63, 0x76, 0x9b, 0x6d, 0xaa, 0x41, 0x87, 0x5a, 0x79,
|
||||||
|
0xe7, 0xce, 0xd6, 0x84, 0x32, 0x53, 0xf5, 0xfc, 0xb7, 0x41, 0x7c, 0xcb, 0x88, 0x09, 0xcb, 0xe9,
|
||||||
|
0x07, 0x16, 0x28, 0x55, 0x23, 0xe5, 0xf2, 0xf5, 0x23, 0xf5, 0xee, 0x2b, 0x9d, 0x91, 0x56, 0xc6,
|
||||||
|
0x30, 0x91, 0x4d, 0x16, 0x11, 0x6c, 0x48, 0x45, 0xe8, 0x5d, 0x0e, 0x9e, 0x04, 0xc8, 0xb6, 0xdd,
|
||||||
|
0xba, 0x0d, 0xdf, 0x53, 0x56, 0xfa, 0x0b, 0x0b, 0x99, 0x8d, 0xea, 0x5c, 0x45, 0x7d, 0xed, 0xad,
|
||||||
|
0x1f, 0xc5, 0xc1, 0x7d, 0x63, 0x31, 0xf8, 0x32, 0xb5, 0x33, 0xb0, 0xef, 0xce, 0x2e, 0x74, 0x1e,
|
||||||
|
0x77, 0x2a, 0x18, 0x35, 0x3d, 0x6e, 0x01, 0xba, 0xde, 0x21, 0x8e, 0x14, 0x12, 0xc3, 0x0d, 0x43,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char pk_dP[] = {
|
||||||
|
0x5a, 0xc8, 0xf7, 0x1a, 0x44, 0xbd, 0x07, 0x24, 0xd8, 0x02, 0x3f, 0xfe, 0xc3, 0xb1, 0x93, 0xa5,
|
||||||
|
0x41, 0xcb, 0x1b, 0xe3, 0xe0, 0x17, 0x54, 0xd4, 0xa0, 0x13, 0x0a, 0x04, 0x71, 0xa5, 0xc0, 0x6f,
|
||||||
|
0x1d, 0xe7, 0x1b, 0xd9, 0x0c, 0x19, 0x64, 0x7e, 0x5c, 0x54, 0xe9, 0xad, 0x77, 0x87, 0x84, 0x8b,
|
||||||
|
0xf4, 0xa4, 0xf8, 0x13, 0x06, 0xdc, 0x83, 0x7e, 0x6e, 0xfe, 0xa2, 0xf7, 0x56, 0x40, 0x19, 0x88,
|
||||||
|
0x2b, 0x3c, 0x53, 0xfe, 0x03, 0xc3, 0x4c, 0x40, 0x31, 0xb2, 0xb4, 0x06, 0x76, 0xc2, 0x00, 0x17,
|
||||||
|
0x37, 0x8e, 0x34, 0xcb, 0x71, 0xab, 0x3e, 0xc8, 0xf3, 0x35, 0x03, 0xfc, 0xdb, 0x15, 0x18, 0x5a,
|
||||||
|
0x38, 0xe4, 0x8d, 0xcb, 0x2b, 0x4d, 0xa0, 0xa8, 0x92, 0x02, 0xc3, 0x15, 0x1e, 0x68, 0x9e, 0x4d,
|
||||||
|
0x7e, 0x23, 0xdc, 0x68, 0x08, 0x31, 0x4e, 0x23, 0x46, 0xc6, 0x15, 0xae, 0x29, 0x46, 0x2f, 0x61,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char pk_dQ[] = {
|
||||||
|
0x33, 0x61, 0x9f, 0xae, 0x0c, 0xf6, 0xc6, 0x16, 0x8f, 0xcb, 0xd1, 0xaa, 0xce, 0x87, 0x5a, 0x4d,
|
||||||
|
0xcc, 0xe5, 0x7b, 0x46, 0xb0, 0xc8, 0xe8, 0x40, 0x66, 0x9a, 0x17, 0xb5, 0x5b, 0xa2, 0xf1, 0x67,
|
||||||
|
0x46, 0x11, 0x52, 0x50, 0x51, 0xe6, 0x74, 0x0c, 0xd4, 0xca, 0x46, 0x22, 0xa0, 0xcb, 0xdb, 0x75,
|
||||||
|
0xe5, 0x63, 0x45, 0xd5, 0xca, 0x0a, 0xdd, 0x7b, 0xec, 0x08, 0x53, 0xfa, 0xba, 0x2b, 0xce, 0x03,
|
||||||
|
0x2f, 0x40, 0x31, 0xc0, 0xca, 0x50, 0xbb, 0x7e, 0x07, 0x06, 0x90, 0xd8, 0x5a, 0xa9, 0x32, 0x03,
|
||||||
|
0x76, 0xed, 0xd2, 0x16, 0x35, 0x16, 0x72, 0xcf, 0xbc, 0x4f, 0xa2, 0xaf, 0xf9, 0xee, 0x98, 0x40,
|
||||||
|
0x00, 0x4b, 0x04, 0xfa, 0x8a, 0x0b, 0xdf, 0x14, 0xc1, 0x92, 0x0c, 0xb8, 0x17, 0x82, 0x7a, 0x1b,
|
||||||
|
0xb4, 0xa1, 0xe2, 0xea, 0x6f, 0x94, 0xc5, 0x8c, 0xde, 0x97, 0x5c, 0x19, 0x06, 0x13, 0x9e, 0x73,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char pk_I[] = {
|
||||||
|
0x75, 0x40, 0xc6, 0x02, 0x7e, 0x4f, 0xad, 0xdb, 0x95, 0xac, 0x07, 0x8d, 0x80, 0xb6, 0x80, 0x02,
|
||||||
|
0x06, 0xdd, 0xb8, 0x5d, 0x92, 0x65, 0x69, 0x26, 0x86, 0x61, 0x6c, 0x87, 0x4e, 0xe5, 0x03, 0x68,
|
||||||
|
0xc6, 0x10, 0x15, 0x8c, 0x43, 0x3a, 0x45, 0x63, 0x48, 0xb7, 0x8a, 0x8c, 0xa2, 0x2b, 0x34, 0xb6,
|
||||||
|
0x83, 0xfe, 0xa8, 0x10, 0xa5, 0x74, 0xa5, 0xa9, 0x52, 0x42, 0x1f, 0xa0, 0x80, 0x6a, 0xc5, 0x35,
|
||||||
|
0xe8, 0xb8, 0xc2, 0xa0, 0x3f, 0x49, 0x18, 0xcf, 0x0e, 0x54, 0x3c, 0x70, 0x11, 0x11, 0xd3, 0x85,
|
||||||
|
0x8c, 0xb2, 0xe5, 0x74, 0xdf, 0x98, 0xea, 0x6c, 0xc0, 0x5f, 0x7f, 0xff, 0x69, 0xbf, 0x08, 0x8d,
|
||||||
|
0x1b, 0xc4, 0x90, 0xcc, 0xa4, 0xcd, 0xcc, 0x34, 0x58, 0xe5, 0x91, 0x53, 0x3a, 0xd5, 0x39, 0xf4,
|
||||||
|
0xd4, 0x42, 0xc9, 0x17, 0xb2, 0x2c, 0x92, 0x12, 0x37, 0x1b, 0xd3, 0xc5, 0x79, 0xd2, 0x65, 0x61,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int test_pk(bool verbose)
|
||||||
|
{
|
||||||
|
int ret = 1;
|
||||||
|
size_t tmp_len, tmp2_len;
|
||||||
|
unsigned char *tmp, *tmp2;
|
||||||
|
struct crypto_pk *pubk, *privk;
|
||||||
|
unsigned char *msg = message;
|
||||||
|
size_t msg_len = sizeof(pk_N);
|
||||||
|
|
||||||
|
printf("Testing public keys interfaces\n");
|
||||||
|
|
||||||
|
pubk = crypto_pk_open(PK_RSA,
|
||||||
|
pk_N, sizeof(pk_N),
|
||||||
|
pk_E, sizeof(pk_E));
|
||||||
|
if (!pubk) {
|
||||||
|
fprintf(stderr, "ERROR: open public key.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_len = crypto_pk_get_nbits(pubk);
|
||||||
|
if (tmp_len != sizeof(pk_N) * 8) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
|
||||||
|
goto close_pub;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = crypto_pk_get_parameter(pubk, 0, &tmp_len);
|
||||||
|
if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %d len %d\n", tmp_len, sizeof(pk_N));
|
||||||
|
free(tmp);
|
||||||
|
goto close_pub;
|
||||||
|
}
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
tmp = crypto_pk_get_parameter(pubk, 1, &tmp_len);
|
||||||
|
if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
|
||||||
|
free(tmp);
|
||||||
|
goto close_pub;
|
||||||
|
}
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
privk = crypto_pk_open_priv(PK_RSA,
|
||||||
|
pk_N, sizeof(pk_N),
|
||||||
|
pk_E, sizeof(pk_E),
|
||||||
|
pk_D, sizeof(pk_D),
|
||||||
|
pk_P, sizeof(pk_P),
|
||||||
|
pk_Q, sizeof(pk_Q),
|
||||||
|
pk_dP, sizeof(pk_dP),
|
||||||
|
pk_dQ, sizeof(pk_dQ),
|
||||||
|
pk_I, sizeof(pk_I));
|
||||||
|
if (!privk) {
|
||||||
|
fprintf(stderr, "ERROR: open private key.\n");
|
||||||
|
goto close_pub;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tmp_len = crypto_pk_get_nbits(privk);
|
||||||
|
if (tmp_len != sizeof(pk_N) * 8) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
|
||||||
|
goto close_pub;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = crypto_pk_get_parameter(privk, 0, &tmp_len);
|
||||||
|
if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %d len %d\n", tmp_len, sizeof(pk_N));
|
||||||
|
free(tmp);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
tmp = crypto_pk_get_parameter(privk, 1, &tmp_len);
|
||||||
|
if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
|
||||||
|
free(tmp);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
tmp = crypto_pk_decrypt(privk, msg, msg_len, &tmp_len);
|
||||||
|
if (!tmp) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp2 = crypto_pk_encrypt(pubk, tmp, tmp_len, &tmp2_len);
|
||||||
|
if (!tmp2) {
|
||||||
|
fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
|
||||||
|
goto free_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tmp2);
|
||||||
|
free_tmp:
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
close:
|
||||||
|
crypto_pk_close(privk);
|
||||||
|
close_pub:
|
||||||
|
crypto_pk_close(pubk);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec_crypto_test(bool verbose)
|
||||||
|
{
|
||||||
|
unsigned int keylengths[] = {1024, 1152, 1408, 1984, 2048, 3072, 4096};
|
||||||
|
int i;
|
||||||
|
int ret;
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
|
ret = test_pk(verbose);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "Crypto raw test: failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "Crypto raw test: passed\n\n");
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(keylengths) / sizeof(keylengths[0]); i++) {
|
||||||
|
unsigned int kl = keylengths[i];
|
||||||
|
ret = test_genkey(kl, message, kl / 8, verbose);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "Crypto generate key[%d] test: failed\n", kl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
18
client/emv/test/crypto_test.h
Normal file
18
client/emv/test/crypto_test.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* emv-tools - a set of tools to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
extern int exec_crypto_test(bool verbose);
|
65
client/emv/test/cryptotest.c
Normal file
65
client/emv/test/cryptotest.c
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2017 Merlok
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Crypto algorithms testing
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "cryptotest.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
|
#include "bignum.h"
|
||||||
|
#include "aes.h"
|
||||||
|
#include "des.h"
|
||||||
|
#include "rsa.h"
|
||||||
|
#include "sha1.h"
|
||||||
|
|
||||||
|
#include "crypto_test.h"
|
||||||
|
#include "sda_test.h"
|
||||||
|
#include "dda_test.h"
|
||||||
|
#include "cda_test.h"
|
||||||
|
|
||||||
|
int ExecuteCryptoTests(bool verbose) {
|
||||||
|
int res;
|
||||||
|
bool TestFail = false;
|
||||||
|
|
||||||
|
res = mpi_self_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
res = aes_self_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
res = des_self_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
res = sha1_self_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
res = rsa_self_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
res = exec_sda_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
res = exec_dda_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
res = exec_cda_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
res = exec_crypto_test(verbose);
|
||||||
|
if (res) TestFail = true;
|
||||||
|
|
||||||
|
PrintAndLog("\n--------------------------");
|
||||||
|
if (TestFail)
|
||||||
|
PrintAndLog("Test(s) [ERROR].");
|
||||||
|
else
|
||||||
|
PrintAndLog("Tests [OK].");
|
||||||
|
|
||||||
|
return TestFail;
|
||||||
|
}
|
||||||
|
|
13
client/emv/test/cryptotest.h
Normal file
13
client/emv/test/cryptotest.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2017 Merlok
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Crypto algorithms testing
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
extern int ExecuteCryptoTests(bool verbose);
|
390
client/emv/test/dda_test.c
Normal file
390
client/emv/test/dda_test.c
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
/*
|
||||||
|
* emv-tools - a set of tools to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dda_test.h"
|
||||||
|
|
||||||
|
#include "../emv_pk.h"
|
||||||
|
#include "../crypto.h"
|
||||||
|
#include "../dump.h"
|
||||||
|
#include "../tlv.h"
|
||||||
|
#include "../emv_pki.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct emv_pk mchip_05 = {
|
||||||
|
.rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
|
||||||
|
.index = 5,
|
||||||
|
.hash_algo = HASH_SHA_1,
|
||||||
|
.pk_algo = PK_RSA,
|
||||||
|
.hash = {
|
||||||
|
0xeb, 0xfa, 0x0d, 0x5d,
|
||||||
|
0x06, 0xd8, 0xce, 0x70,
|
||||||
|
0x2d, 0xa3, 0xea, 0xe8,
|
||||||
|
0x90, 0x70, 0x1d, 0x45,
|
||||||
|
0xe2, 0x74, 0xc8, 0x45, },
|
||||||
|
.exp = { 0x03, },
|
||||||
|
.elen = 1,
|
||||||
|
.mlen = 1408 / 8,
|
||||||
|
.modulus = (unsigned char[]){
|
||||||
|
0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
|
||||||
|
0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
|
||||||
|
0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
|
||||||
|
0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
|
||||||
|
0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
|
||||||
|
0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
|
||||||
|
0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
|
||||||
|
0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
|
||||||
|
0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
|
||||||
|
0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
|
||||||
|
0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char d_issuer_cert[] = {
|
||||||
|
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||||
|
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||||
|
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||||
|
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||||
|
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||||
|
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||||
|
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||||
|
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||||
|
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||||
|
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||||
|
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char d_issuer_rem[] = {
|
||||||
|
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||||
|
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||||
|
0x6d, 0xbd, 0x64, 0x15,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char d_issuer_exp[] = {
|
||||||
|
0x03,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char d_icc_cert[] = {
|
||||||
|
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||||
|
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||||
|
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||||
|
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||||
|
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||||
|
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||||
|
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||||
|
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||||
|
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||||
|
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||||
|
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char d_icc_exp[] = {
|
||||||
|
0x03,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char d_sdad_cr[] = {
|
||||||
|
0x3d, 0x87, 0xf3, 0x10, 0x56, 0x10, 0x2d, 0x25, 0x12, 0xcf, 0xde, 0x30, 0x90, 0x06, 0x27, 0xc1,
|
||||||
|
0x26, 0x3a, 0x76, 0xd1, 0xda, 0xa8, 0x21, 0xf5, 0x08, 0x31, 0xe6, 0x06, 0xc5, 0x45, 0x44, 0xc2,
|
||||||
|
0x58, 0x13, 0x1e, 0xae, 0xbe, 0x87, 0x4d, 0xcb, 0x1a, 0x28, 0xcf, 0x82, 0xd3, 0xff, 0x91, 0x11,
|
||||||
|
0x82, 0x60, 0xbc, 0x91, 0x11, 0x37, 0x11, 0xd3, 0xb2, 0x89, 0xfa, 0x41, 0xbe, 0x69, 0xc7, 0xa7,
|
||||||
|
0xb5, 0xc7, 0x83, 0xe6, 0xf8, 0xf9, 0x7f, 0xce, 0x13, 0xf0, 0x8b, 0x13, 0xfa, 0x44, 0x18, 0x3e,
|
||||||
|
0x37, 0x18, 0xce, 0xbf, 0x0c, 0x41, 0x47, 0x3d, 0x2b, 0x0f, 0xf4, 0xde, 0x44, 0xb6, 0xa0, 0x2d,
|
||||||
|
0x75, 0xad, 0xb6, 0xd4, 0x96, 0x23, 0x93, 0xff, 0xdf, 0x4e, 0x69, 0x02, 0x6c, 0xdf, 0x38, 0xff,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char d_ssd1[] = {
|
||||||
|
0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
|
||||||
|
0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
|
||||||
|
0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
|
||||||
|
0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
|
||||||
|
0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
|
||||||
|
0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
|
||||||
|
0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
|
||||||
|
0x39, 0x00,
|
||||||
|
};
|
||||||
|
static const struct tlv ssd1_tlv = {
|
||||||
|
.len = sizeof(d_ssd1),
|
||||||
|
.value = d_ssd1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char d_pan[] = {
|
||||||
|
0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char d_dd1[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
static const struct tlv dd1_tlv = {
|
||||||
|
.len = sizeof(d_dd1),
|
||||||
|
.value = d_dd1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dda_test_raw(bool verbose)
|
||||||
|
{
|
||||||
|
const struct emv_pk *pk = &mchip_05;
|
||||||
|
|
||||||
|
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||||
|
pk->modulus, pk->mlen,
|
||||||
|
pk->exp, pk->elen);
|
||||||
|
if (!kcp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unsigned char *ipk_data;
|
||||||
|
size_t ipk_data_len;
|
||||||
|
ipk_data = crypto_pk_encrypt(kcp, d_issuer_cert, sizeof(d_issuer_cert), &ipk_data_len);
|
||||||
|
crypto_pk_close(kcp);
|
||||||
|
|
||||||
|
if (!ipk_data)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("issuer cert:\n");
|
||||||
|
dump_buffer(ipk_data, ipk_data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ipk_pk_len = ipk_data[13];
|
||||||
|
unsigned char *ipk_pk = malloc(ipk_pk_len);
|
||||||
|
memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
|
||||||
|
memcpy(ipk_pk + ipk_data_len - 36, d_issuer_rem, sizeof(d_issuer_rem));
|
||||||
|
|
||||||
|
struct crypto_hash *ch;
|
||||||
|
ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(ipk_pk);
|
||||||
|
free(ipk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, ipk_data + 1, 14);
|
||||||
|
crypto_hash_write(ch, ipk_pk, ipk_pk_len);
|
||||||
|
crypto_hash_write(ch, d_issuer_exp, sizeof(d_issuer_exp));
|
||||||
|
|
||||||
|
unsigned char *h = crypto_hash_read(ch);
|
||||||
|
if (!h) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ipk_pk);
|
||||||
|
free(ipk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("crypto hash:\n");
|
||||||
|
dump_buffer(h, 20, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ipk_pk);
|
||||||
|
free(ipk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ipk_data);
|
||||||
|
|
||||||
|
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||||
|
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||||
|
free(ipk_pk);
|
||||||
|
if (!ikcp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unsigned char *iccpk_data;
|
||||||
|
size_t iccpk_data_len;
|
||||||
|
iccpk_data = crypto_pk_encrypt(ikcp, d_icc_cert, sizeof(d_icc_cert), &iccpk_data_len);
|
||||||
|
crypto_pk_close(ikcp);
|
||||||
|
|
||||||
|
if (!iccpk_data)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("icc cert:\n");
|
||||||
|
dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t iccpk_pk_len = iccpk_data[19];
|
||||||
|
unsigned char *iccpk_pk = malloc(iccpk_pk_len);
|
||||||
|
memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
|
||||||
|
/*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
|
||||||
|
|
||||||
|
ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(iccpk_pk);
|
||||||
|
free(iccpk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
|
||||||
|
crypto_hash_write(ch, d_icc_exp, sizeof(d_icc_exp));
|
||||||
|
crypto_hash_write(ch, d_ssd1, sizeof(d_ssd1));
|
||||||
|
|
||||||
|
h = crypto_hash_read(ch);
|
||||||
|
if (!h) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(iccpk_pk);
|
||||||
|
free(iccpk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("crypto hash1.1:\n");
|
||||||
|
dump_buffer(h, 20, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(iccpk_pk);
|
||||||
|
free(iccpk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(iccpk_data);
|
||||||
|
|
||||||
|
struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
|
||||||
|
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||||
|
free(iccpk_pk);
|
||||||
|
if (!icckcp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
size_t sdad_len;
|
||||||
|
unsigned char *sdad = crypto_pk_encrypt(icckcp, d_sdad_cr, sizeof(d_sdad_cr), &sdad_len);
|
||||||
|
crypto_pk_close(icckcp);
|
||||||
|
if (!sdad)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("sdad:\n");
|
||||||
|
dump_buffer(sdad, sdad_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(sdad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, sdad + 1, sdad_len - 22);
|
||||||
|
crypto_hash_write(ch, d_dd1, sizeof(d_dd1));
|
||||||
|
|
||||||
|
unsigned char *h2 = crypto_hash_read(ch);
|
||||||
|
if (!h2) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(sdad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("crypto hash2:\n");
|
||||||
|
dump_buffer(h2, 20, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
|
||||||
|
free(sdad);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dda_test_pk(bool verbose)
|
||||||
|
{
|
||||||
|
const struct emv_pk *pk = &mchip_05;
|
||||||
|
struct tlvdb *db;
|
||||||
|
|
||||||
|
db = tlvdb_external(0x90, sizeof(d_issuer_cert), d_issuer_cert);
|
||||||
|
tlvdb_add(db, tlvdb_external(0x9f32, sizeof(d_issuer_exp), d_issuer_exp));
|
||||||
|
tlvdb_add(db, tlvdb_external(0x92, sizeof(d_issuer_rem), d_issuer_rem));
|
||||||
|
tlvdb_add(db, tlvdb_external(0x5a, sizeof(d_pan), d_pan));
|
||||||
|
|
||||||
|
struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
|
||||||
|
if (!ipk) {
|
||||||
|
fprintf(stderr, "Could not recover Issuer certificate!\n");
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvdb_add(db, tlvdb_external(0x9f46, sizeof(d_icc_cert), d_icc_cert));
|
||||||
|
tlvdb_add(db, tlvdb_external(0x9f47, sizeof(d_icc_exp), d_icc_exp));
|
||||||
|
/*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(d_issuer_rem), d_issuer_rem));*/
|
||||||
|
|
||||||
|
struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
|
||||||
|
if (!iccpk) {
|
||||||
|
fprintf(stderr, "Could not recover ICC certificate!\n");
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvdb_add(db, tlvdb_external(0x9f4b, sizeof(d_sdad_cr), d_sdad_cr));
|
||||||
|
|
||||||
|
struct tlvdb *idndb = emv_pki_recover_idn(iccpk, db, &dd1_tlv);
|
||||||
|
if (!idndb) {
|
||||||
|
fprintf(stderr, "Could not recover IDN!\n");
|
||||||
|
emv_pk_free(iccpk);
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
|
||||||
|
if (!idn) {
|
||||||
|
fprintf(stderr, "IDN not found!\n");
|
||||||
|
tlvdb_free(idndb);
|
||||||
|
emv_pk_free(iccpk);
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("IDN:\n");
|
||||||
|
dump_buffer(idn->value, idn->len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvdb_free(idndb);
|
||||||
|
emv_pk_free(iccpk);
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec_dda_test(bool verbose)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
|
ret = dda_test_raw(verbose);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "DDA raw test: failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "DDA raw test: passed\n");
|
||||||
|
|
||||||
|
ret = dda_test_pk(verbose);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "DDA test pk: failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "DDA test pk: passed\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
18
client/emv/test/dda_test.h
Normal file
18
client/emv/test/dda_test.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* emv-tools - a set of tools to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
extern int exec_dda_test(bool verbose);
|
277
client/emv/test/sda_test.c
Normal file
277
client/emv/test/sda_test.c
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
/*
|
||||||
|
* emv-tools - a set of tools to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../emv_pk.h"
|
||||||
|
#include "../crypto.h"
|
||||||
|
#include "../dump.h"
|
||||||
|
#include "../tlv.h"
|
||||||
|
#include "../emv_pki.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct emv_pk vsdc_01 = {
|
||||||
|
.rid = { 0xa0, 0x00, 0x00, 0x00, 0x03, },
|
||||||
|
.index = 1,
|
||||||
|
.hash_algo = HASH_SHA_1,
|
||||||
|
.pk_algo = PK_RSA,
|
||||||
|
.hash = {
|
||||||
|
0xd3, 0x4a, 0x6a, 0x77,
|
||||||
|
0x60, 0x11, 0xc7, 0xe7,
|
||||||
|
0xce, 0x3a, 0xec, 0x5f,
|
||||||
|
0x03, 0xad, 0x2f, 0x8c,
|
||||||
|
0xfc, 0x55, 0x03, 0xcc, },
|
||||||
|
.exp = { 0x03, },
|
||||||
|
.elen = 1,
|
||||||
|
.mlen = 1024 / 8,
|
||||||
|
.modulus = (unsigned char[]){
|
||||||
|
0xc6, 0x96, 0x03, 0x42, 0x13, 0xd7, 0xd8, 0x54, 0x69, 0x84, 0x57, 0x9d, 0x1d, 0x0f, 0x0e, 0xa5,
|
||||||
|
0x19, 0xcf, 0xf8, 0xde, 0xff, 0xc4, 0x29, 0x35, 0x4c, 0xf3, 0xa8, 0x71, 0xa6, 0xf7, 0x18, 0x3f,
|
||||||
|
0x12, 0x28, 0xda, 0x5c, 0x74, 0x70, 0xc0, 0x55, 0x38, 0x71, 0x00, 0xcb, 0x93, 0x5a, 0x71, 0x2c,
|
||||||
|
0x4e, 0x28, 0x64, 0xdf, 0x5d, 0x64, 0xba, 0x93, 0xfe, 0x7e, 0x63, 0xe7, 0x1f, 0x25, 0xb1, 0xe5,
|
||||||
|
0xf5, 0x29, 0x85, 0x75, 0xeb, 0xe1, 0xc6, 0x3a, 0xa6, 0x17, 0x70, 0x69, 0x17, 0x91, 0x1d, 0xc2,
|
||||||
|
0xa7, 0x5a, 0xc2, 0x8b, 0x25, 0x1c, 0x7e, 0xf4, 0x0f, 0x23, 0x65, 0x91, 0x24, 0x90, 0xb9, 0x39,
|
||||||
|
0xbc, 0xa2, 0x12, 0x4a, 0x30, 0xa2, 0x8f, 0x54, 0x40, 0x2c, 0x34, 0xae, 0xca, 0x33, 0x1a, 0xb6,
|
||||||
|
0x7e, 0x1e, 0x79, 0xb2, 0x85, 0xdd, 0x57, 0x71, 0xb5, 0xd9, 0xff, 0x79, 0xea, 0x63, 0x0b, 0x75,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char issuer_cert[] = {
|
||||||
|
0x3c, 0x5f, 0xea, 0xd4, 0xdd, 0x7b, 0xca, 0x44, 0xf9, 0x3e, 0x90, 0xc4, 0x4f, 0x76, 0xed, 0xe5,
|
||||||
|
0x4a, 0x32, 0x88, 0xec, 0xdc, 0x78, 0x46, 0x9f, 0xcb, 0x12, 0x25, 0xc0, 0x3b, 0x2c, 0x04, 0xf2,
|
||||||
|
0xc2, 0xf4, 0x12, 0x28, 0x1a, 0x08, 0x22, 0xdf, 0x14, 0x64, 0x92, 0x30, 0x98, 0x9f, 0xb1, 0x49,
|
||||||
|
0x40, 0x70, 0xda, 0xf8, 0xc9, 0x53, 0x4a, 0x78, 0x81, 0x96, 0x01, 0x48, 0x61, 0x6a, 0xce, 0x58,
|
||||||
|
0x17, 0x88, 0x12, 0x0d, 0x35, 0x06, 0xac, 0xe4, 0xce, 0xe5, 0x64, 0xfb, 0x27, 0xee, 0x53, 0x34,
|
||||||
|
0x1c, 0x22, 0xf0, 0xb4, 0x5b, 0x31, 0x87, 0x3d, 0x05, 0xde, 0x54, 0x5e, 0xfe, 0x33, 0xbc, 0xd2,
|
||||||
|
0x9b, 0x21, 0x85, 0xd0, 0x35, 0xa8, 0x06, 0xad, 0x08, 0xc6, 0x97, 0x6f, 0x35, 0x05, 0xa1, 0x99,
|
||||||
|
0x99, 0x93, 0x0c, 0xa8, 0xa0, 0x3e, 0xfa, 0x32, 0x1c, 0x48, 0x60, 0x61, 0xf7, 0xdc, 0xec, 0x9f,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char issuer_rem[] = {
|
||||||
|
0x1e, 0xbc, 0xa3, 0x0f, 0x00, 0xce, 0x59, 0x62, 0xa8, 0xc6, 0xe1, 0x30, 0x54, 0x4b, 0x82, 0x89,
|
||||||
|
0x1b, 0x23, 0x6c, 0x65, 0xde, 0x29, 0x31, 0x7f, 0x36, 0x47, 0x35, 0xde, 0xe6, 0x3f, 0x65, 0x98,
|
||||||
|
0x97, 0x58, 0x35, 0xd5
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char issuer_exp[] = {
|
||||||
|
0x03,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char ssad_cr[] = {
|
||||||
|
0x99, 0xa5, 0x58, 0xb6, 0x2b, 0x67, 0x4a, 0xa5, 0xe7, 0xd2, 0xa5, 0x7e, 0x5e, 0xf6, 0xa6, 0xf2,
|
||||||
|
0x25, 0x8e, 0x5d, 0xa0, 0x52, 0xd0, 0x5b, 0x54, 0xe5, 0xc1, 0x15, 0xff, 0x1c, 0xec, 0xf9, 0x4a,
|
||||||
|
0xa2, 0xdf, 0x8f, 0x39, 0xa0, 0x1d, 0x71, 0xc6, 0x19, 0xeb, 0x81, 0x9d, 0xa5, 0x2e, 0xf3, 0x81,
|
||||||
|
0xe8, 0x49, 0x79, 0x58, 0x6a, 0xea, 0x78, 0x55, 0xff, 0xbe, 0xf4, 0x0a, 0xa3, 0xa7, 0x1c, 0xd3,
|
||||||
|
0xb0, 0x4c, 0xfd, 0xf2, 0x70, 0xae, 0xc8, 0x15, 0x8a, 0x27, 0x97, 0xf2, 0x4f, 0xd6, 0x13, 0xb7,
|
||||||
|
0x48, 0x13, 0x46, 0x61, 0x13, 0x5c, 0xd2, 0x90, 0xe4, 0x5b, 0x04, 0xa8, 0xe0, 0xcc, 0xc7, 0x11,
|
||||||
|
0xae, 0x04, 0x2f, 0x15, 0x9e, 0x73, 0xc8, 0x9c, 0x2a, 0x7e, 0x65, 0xa4, 0xc2, 0xfd, 0x1d, 0x61,
|
||||||
|
0x06, 0x02, 0x4a, 0xa2, 0x71, 0x30, 0xb0, 0xec, 0xec, 0x02, 0x38, 0xf9, 0x16, 0x59, 0xde, 0x96,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char ssd1[] = {
|
||||||
|
0x5f, 0x24, 0x03, 0x08, 0x12, 0x31, 0x5a, 0x08, 0x42, 0x76, 0x55, 0x00, 0x13, 0x23, 0x45, 0x99, 0x5f, 0x34, 0x01, 0x01, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05, 0xd0, 0x40, 0xac, 0xa8, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05, 0xd0, 0x68, 0xbc, 0xf8, 0x00,
|
||||||
|
0x5c, 0x00,
|
||||||
|
};
|
||||||
|
static const struct tlv ssd1_tlv = {
|
||||||
|
.len = sizeof(ssd1),
|
||||||
|
.value = ssd1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char pan[] = {
|
||||||
|
0x42, 0x76, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sda_test_raw(bool verbose)
|
||||||
|
{
|
||||||
|
const struct emv_pk *pk = &vsdc_01;
|
||||||
|
|
||||||
|
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||||
|
pk->modulus, pk->mlen,
|
||||||
|
pk->exp, pk->elen);
|
||||||
|
if (!kcp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unsigned char *ipk_data;
|
||||||
|
size_t ipk_data_len;
|
||||||
|
ipk_data = crypto_pk_encrypt(kcp, issuer_cert, sizeof(issuer_cert), &ipk_data_len);
|
||||||
|
crypto_pk_close(kcp);
|
||||||
|
|
||||||
|
if (!ipk_data)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("issuer cert:\n");
|
||||||
|
dump_buffer(ipk_data, ipk_data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ipk_pk_len = ipk_data[13];
|
||||||
|
unsigned char *ipk_pk = malloc(ipk_pk_len);
|
||||||
|
memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
|
||||||
|
memcpy(ipk_pk + ipk_data_len - 36, issuer_rem, sizeof(issuer_rem));
|
||||||
|
|
||||||
|
struct crypto_hash *ch;
|
||||||
|
ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(ipk_pk);
|
||||||
|
free(ipk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, ipk_data + 1, 14);
|
||||||
|
crypto_hash_write(ch, ipk_pk, ipk_pk_len);
|
||||||
|
crypto_hash_write(ch, issuer_exp, sizeof(issuer_exp));
|
||||||
|
|
||||||
|
unsigned char *h = crypto_hash_read(ch);
|
||||||
|
if (!h) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ipk_pk);
|
||||||
|
free(ipk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("crypto hash:\n");
|
||||||
|
dump_buffer(h, 20, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ipk_pk);
|
||||||
|
free(ipk_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ipk_data);
|
||||||
|
|
||||||
|
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||||
|
issuer_exp, (int) sizeof(issuer_exp));
|
||||||
|
free(ipk_pk);
|
||||||
|
if (!ikcp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
size_t ssad_len;
|
||||||
|
unsigned char *ssad = crypto_pk_encrypt(ikcp, ssad_cr, sizeof(ssad_cr), &ssad_len);
|
||||||
|
crypto_pk_close(ikcp);
|
||||||
|
if (!ssad)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("ssad:\n");
|
||||||
|
dump_buffer(ssad, ssad_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = crypto_hash_open(HASH_SHA_1);
|
||||||
|
if (!ch) {
|
||||||
|
free(ssad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_write(ch, ssad + 1, ssad_len - 22);
|
||||||
|
crypto_hash_write(ch, ssd1, sizeof(ssd1));
|
||||||
|
|
||||||
|
unsigned char *h2 = crypto_hash_read(ch);
|
||||||
|
if (!h2) {
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
free(ssad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("crypto hash2:\n");
|
||||||
|
dump_buffer(h2, 20, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_hash_close(ch);
|
||||||
|
|
||||||
|
free(ssad);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sda_test_pk(bool verbose)
|
||||||
|
{
|
||||||
|
const struct emv_pk *pk = &vsdc_01;
|
||||||
|
struct tlvdb *db;
|
||||||
|
|
||||||
|
db = tlvdb_external(0x90, sizeof(issuer_cert), issuer_cert);
|
||||||
|
tlvdb_add(db, tlvdb_external(0x9f32, sizeof(issuer_exp), issuer_exp));
|
||||||
|
tlvdb_add(db, tlvdb_external(0x92, sizeof(issuer_rem), issuer_rem));
|
||||||
|
tlvdb_add(db, tlvdb_external(0x5a, sizeof(pan), pan));
|
||||||
|
|
||||||
|
struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
|
||||||
|
if (!ipk) {
|
||||||
|
fprintf(stderr, "Could not recover Issuer certificate!\n");
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvdb_add(db, tlvdb_external(0x93, sizeof(ssad_cr), ssad_cr));
|
||||||
|
|
||||||
|
struct tlvdb *dacdb = emv_pki_recover_dac(ipk, db, &ssd1_tlv);
|
||||||
|
if (!dacdb) {
|
||||||
|
fprintf(stderr, "Could not recover DAC!\n");
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tlv *dac = tlvdb_get(dacdb, 0x9f45, NULL);
|
||||||
|
if (!dac) {
|
||||||
|
fprintf(stderr, "DAC not found!\n");
|
||||||
|
tlvdb_free(dacdb);
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("dac:\n");
|
||||||
|
dump_buffer(dac->value, dac->len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvdb_free(dacdb);
|
||||||
|
emv_pk_free(ipk);
|
||||||
|
tlvdb_free(db);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec_sda_test(bool verbose)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
|
ret = sda_test_raw(verbose);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "SDA raw test: failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "SDA raw test: passed\n");
|
||||||
|
|
||||||
|
ret = sda_test_pk(verbose);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "SDA test pk: failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "SDA test pk: passed\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
16
client/emv/test/sda_test.h
Normal file
16
client/emv/test/sda_test.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* emv-tools - a set of tools to work with EMV family of smart cards
|
||||||
|
* Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
|
||||||
|
*
|
||||||
|
* This library 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; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int exec_sda_test(bool verbose);
|
0
client/obj/emv/test/.dummy
Normal file
0
client/obj/emv/test/.dummy
Normal file
|
@ -23,8 +23,8 @@
|
||||||
#include "iso14443crc.h"
|
#include "iso14443crc.h"
|
||||||
#include "../common/crc16.h"
|
#include "../common/crc16.h"
|
||||||
#include "../common/crc64.h"
|
#include "../common/crc64.h"
|
||||||
#include "../common/sha1.h"
|
#include "../common/polarssl/sha1.h"
|
||||||
#include "polarssl/aes.h"
|
#include "../common/polarssl/aes.h"
|
||||||
#include "cmdcrc.h"
|
#include "cmdcrc.h"
|
||||||
/**
|
/**
|
||||||
* The following params expected:
|
* The following params expected:
|
||||||
|
|
|
@ -125,7 +125,6 @@ int aes_crypt_ecb( aes_context *ctx,
|
||||||
int mode,
|
int mode,
|
||||||
const unsigned char input[16],
|
const unsigned char input[16],
|
||||||
unsigned char output[16] );
|
unsigned char output[16] );
|
||||||
|
|
||||||
#if defined(POLARSSL_CIPHER_MODE_CBC)
|
#if defined(POLARSSL_CIPHER_MODE_CBC)
|
||||||
/**
|
/**
|
||||||
* \brief AES-CBC buffer encryption/decryption
|
* \brief AES-CBC buffer encryption/decryption
|
||||||
|
|
2143
common/polarssl/bignum.c
Normal file
2143
common/polarssl/bignum.c
Normal file
File diff suppressed because it is too large
Load diff
685
common/polarssl/bignum.h
Normal file
685
common/polarssl/bignum.h
Normal file
|
@ -0,0 +1,685 @@
|
||||||
|
/**
|
||||||
|
* \file bignum.h
|
||||||
|
*
|
||||||
|
* \brief Multi-precision integer library
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2013, Brainspark B.V.
|
||||||
|
*
|
||||||
|
* This file is part of PolarSSL (http://www.polarssl.org)
|
||||||
|
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
#ifndef POLARSSL_BIGNUM_H
|
||||||
|
#define POLARSSL_BIGNUM_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "polarssl_config.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <basetsd.h>
|
||||||
|
#if (_MSC_VER <= 1200)
|
||||||
|
typedef signed short int16_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
#else
|
||||||
|
typedef INT16 int16_t;
|
||||||
|
typedef UINT16 uint16_t;
|
||||||
|
#endif
|
||||||
|
typedef INT32 int32_t;
|
||||||
|
typedef INT64 int64_t;
|
||||||
|
typedef UINT32 uint32_t;
|
||||||
|
typedef UINT64 uint64_t;
|
||||||
|
#else
|
||||||
|
#include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define POLARSSL_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */
|
||||||
|
#define POLARSSL_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */
|
||||||
|
#define POLARSSL_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */
|
||||||
|
#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */
|
||||||
|
#define POLARSSL_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */
|
||||||
|
#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */
|
||||||
|
#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */
|
||||||
|
#define POLARSSL_ERR_MPI_MALLOC_FAILED -0x0010 /**< Memory allocation failed. */
|
||||||
|
|
||||||
|
#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum size MPIs are allowed to grow to in number of limbs.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_MPI_MAX_LIMBS 10000
|
||||||
|
|
||||||
|
#if !defined(POLARSSL_CONFIG_OPTIONS)
|
||||||
|
/*
|
||||||
|
* Maximum window size used for modular exponentiation. Default: 6
|
||||||
|
* Minimum value: 1. Maximum value: 6.
|
||||||
|
*
|
||||||
|
* Result is an array of ( 2 << POLARSSL_MPI_WINDOW_SIZE ) MPIs used
|
||||||
|
* for the sliding window calculation. (So 64 by default)
|
||||||
|
*
|
||||||
|
* Reduction in size, reduces speed.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum size of MPIs allowed in bits and bytes for user-MPIs.
|
||||||
|
* ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits )
|
||||||
|
*
|
||||||
|
* Note: Calculations can results temporarily in larger MPIs. So the number
|
||||||
|
* of limbs required (POLARSSL_MPI_MAX_LIMBS) is higher.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */
|
||||||
|
|
||||||
|
#endif /* !POLARSSL_CONFIG_OPTIONS */
|
||||||
|
|
||||||
|
#define POLARSSL_MPI_MAX_BITS ( 8 * POLARSSL_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When reading from files with mpi_read_file() and writing to files with
|
||||||
|
* mpi_write_file() the buffer should have space
|
||||||
|
* for a (short) label, the MPI (in the provided radix), the newline
|
||||||
|
* characters and the '\0'.
|
||||||
|
*
|
||||||
|
* By default we assume at least a 10 char label, a minimum radix of 10
|
||||||
|
* (decimal) and a maximum of 4096 bit numbers (1234 decimal chars).
|
||||||
|
* Autosized at compile time for at least a 10 char label, a minimum radix
|
||||||
|
* of 10 (decimal) for a number of POLARSSL_MPI_MAX_BITS size.
|
||||||
|
*
|
||||||
|
* This used to be statically sized to 1250 for a maximum of 4096 bit
|
||||||
|
* numbers (1234 decimal chars).
|
||||||
|
*
|
||||||
|
* Calculate using the formula:
|
||||||
|
* POLARSSL_MPI_RW_BUFFER_SIZE = ceil(POLARSSL_MPI_MAX_BITS / ln(10) * ln(2)) +
|
||||||
|
* LabelSize + 6
|
||||||
|
*/
|
||||||
|
#define POLARSSL_MPI_MAX_BITS_SCALE100 ( 100 * POLARSSL_MPI_MAX_BITS )
|
||||||
|
#define LN_2_DIV_LN_10_SCALE100 332
|
||||||
|
#define POLARSSL_MPI_RW_BUFFER_SIZE ( ((POLARSSL_MPI_MAX_BITS_SCALE100 + LN_2_DIV_LN_10_SCALE100 - 1) / LN_2_DIV_LN_10_SCALE100) + 10 + 6 )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define the base integer type, architecture-wise
|
||||||
|
*/
|
||||||
|
#if defined(POLARSSL_HAVE_INT8)
|
||||||
|
typedef signed char t_sint;
|
||||||
|
typedef unsigned char t_uint;
|
||||||
|
typedef uint16_t t_udbl;
|
||||||
|
#define POLARSSL_HAVE_UDBL
|
||||||
|
#else
|
||||||
|
#if defined(POLARSSL_HAVE_INT16)
|
||||||
|
typedef int16_t t_sint;
|
||||||
|
typedef uint16_t t_uint;
|
||||||
|
typedef uint32_t t_udbl;
|
||||||
|
#define POLARSSL_HAVE_UDBL
|
||||||
|
#else
|
||||||
|
#if ( defined(_MSC_VER) && defined(_M_AMD64) )
|
||||||
|
typedef int64_t t_sint;
|
||||||
|
typedef uint64_t t_uint;
|
||||||
|
#else
|
||||||
|
#if ( defined(__GNUC__) && ( \
|
||||||
|
defined(__amd64__) || defined(__x86_64__) || \
|
||||||
|
defined(__ppc64__) || defined(__powerpc64__) || \
|
||||||
|
defined(__ia64__) || defined(__alpha__) || \
|
||||||
|
(defined(__sparc__) && defined(__arch64__)) || \
|
||||||
|
defined(__s390x__) ) )
|
||||||
|
typedef int64_t t_sint;
|
||||||
|
typedef uint64_t t_uint;
|
||||||
|
typedef unsigned int t_udbl __attribute__((mode(TI)));
|
||||||
|
#define POLARSSL_HAVE_UDBL
|
||||||
|
#else
|
||||||
|
typedef int32_t t_sint;
|
||||||
|
typedef uint32_t t_uint;
|
||||||
|
#if ( defined(_MSC_VER) && defined(_M_IX86) )
|
||||||
|
typedef uint64_t t_udbl;
|
||||||
|
#define POLARSSL_HAVE_UDBL
|
||||||
|
#else
|
||||||
|
#if defined( POLARSSL_HAVE_LONGLONG )
|
||||||
|
typedef unsigned long long t_udbl;
|
||||||
|
#define POLARSSL_HAVE_UDBL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif /* POLARSSL_HAVE_INT16 */
|
||||||
|
#endif /* POLARSSL_HAVE_INT8 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief MPI structure
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int s; /*!< integer sign */
|
||||||
|
size_t n; /*!< total # of limbs */
|
||||||
|
t_uint *p; /*!< pointer to limbs */
|
||||||
|
}
|
||||||
|
mpi;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize one MPI
|
||||||
|
*
|
||||||
|
* \param X One MPI to initialize.
|
||||||
|
*/
|
||||||
|
void mpi_init( mpi *X );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Unallocate one MPI
|
||||||
|
*
|
||||||
|
* \param X One MPI to unallocate.
|
||||||
|
*/
|
||||||
|
void mpi_free( mpi *X );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Enlarge to the specified number of limbs
|
||||||
|
*
|
||||||
|
* \param X MPI to grow
|
||||||
|
* \param nblimbs The target number of limbs
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_grow( mpi *X, size_t nblimbs );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Copy the contents of Y into X
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param Y Source MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_copy( mpi *X, const mpi *Y );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Swap the contents of X and Y
|
||||||
|
*
|
||||||
|
* \param X First MPI value
|
||||||
|
* \param Y Second MPI value
|
||||||
|
*/
|
||||||
|
void mpi_swap( mpi *X, mpi *Y );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set value from integer
|
||||||
|
*
|
||||||
|
* \param X MPI to set
|
||||||
|
* \param z Value to use
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_lset( mpi *X, t_sint z );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get a specific bit from X
|
||||||
|
*
|
||||||
|
* \param X MPI to use
|
||||||
|
* \param pos Zero-based index of the bit in X
|
||||||
|
*
|
||||||
|
* \return Either a 0 or a 1
|
||||||
|
*/
|
||||||
|
int mpi_get_bit( const mpi *X, size_t pos );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set a bit of X to a specific value of 0 or 1
|
||||||
|
*
|
||||||
|
* \note Will grow X if necessary to set a bit to 1 in a not yet
|
||||||
|
* existing limb. Will not grow if bit should be set to 0
|
||||||
|
*
|
||||||
|
* \param X MPI to use
|
||||||
|
* \param pos Zero-based index of the bit in X
|
||||||
|
* \param val The value to set the bit to (0 or 1)
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
|
||||||
|
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1
|
||||||
|
*/
|
||||||
|
int mpi_set_bit( mpi *X, size_t pos, unsigned char val );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return the number of zero-bits before the least significant
|
||||||
|
* '1' bit
|
||||||
|
*
|
||||||
|
* Note: Thus also the zero-based index of the least significant '1' bit
|
||||||
|
*
|
||||||
|
* \param X MPI to use
|
||||||
|
*/
|
||||||
|
size_t mpi_lsb( const mpi *X );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return the number of bits up to and including the most
|
||||||
|
* significant '1' bit'
|
||||||
|
*
|
||||||
|
* Note: Thus also the one-based index of the most significant '1' bit
|
||||||
|
*
|
||||||
|
* \param X MPI to use
|
||||||
|
*/
|
||||||
|
size_t mpi_msb( const mpi *X );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return the total size in bytes
|
||||||
|
*
|
||||||
|
* \param X MPI to use
|
||||||
|
*/
|
||||||
|
size_t mpi_size( const mpi *X );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Import from an ASCII string
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param radix Input numeric base
|
||||||
|
* \param s Null-terminated string buffer
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code
|
||||||
|
*/
|
||||||
|
int mpi_read_string( mpi *X, int radix, const char *s );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Export into an ASCII string
|
||||||
|
*
|
||||||
|
* \param X Source MPI
|
||||||
|
* \param radix Output numeric base
|
||||||
|
* \param s String buffer
|
||||||
|
* \param slen String buffer size
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code.
|
||||||
|
* *slen is always updated to reflect the amount
|
||||||
|
* of data that has (or would have) been written.
|
||||||
|
*
|
||||||
|
* \note Call this function with *slen = 0 to obtain the
|
||||||
|
* minimum required buffer size in *slen.
|
||||||
|
*/
|
||||||
|
int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen );
|
||||||
|
|
||||||
|
#if defined(POLARSSL_FS_IO)
|
||||||
|
/**
|
||||||
|
* \brief Read X from an opened file
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param radix Input numeric base
|
||||||
|
* \param fin Input file handle
|
||||||
|
*
|
||||||
|
* \return 0 if successful, POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if
|
||||||
|
* the file read buffer is too small or a
|
||||||
|
* POLARSSL_ERR_MPI_XXX error code
|
||||||
|
*/
|
||||||
|
int mpi_read_file( mpi *X, int radix, FILE *fin );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Write X into an opened file, or stdout if fout is NULL
|
||||||
|
*
|
||||||
|
* \param p Prefix, can be NULL
|
||||||
|
* \param X Source MPI
|
||||||
|
* \param radix Output numeric base
|
||||||
|
* \param fout Output file handle (can be NULL)
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code
|
||||||
|
*
|
||||||
|
* \note Set fout == NULL to print X on the console.
|
||||||
|
*/
|
||||||
|
int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout );
|
||||||
|
#endif /* POLARSSL_FS_IO */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Import X from unsigned binary data, big endian
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param buf Input buffer
|
||||||
|
* \param buflen Input buffer size
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Export X into unsigned binary data, big endian
|
||||||
|
*
|
||||||
|
* \param X Source MPI
|
||||||
|
* \param buf Output buffer
|
||||||
|
* \param buflen Output buffer size
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
|
||||||
|
*/
|
||||||
|
int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Left-shift: X <<= count
|
||||||
|
*
|
||||||
|
* \param X MPI to shift
|
||||||
|
* \param count Amount to shift
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_shift_l( mpi *X, size_t count );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Right-shift: X >>= count
|
||||||
|
*
|
||||||
|
* \param X MPI to shift
|
||||||
|
* \param count Amount to shift
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_shift_r( mpi *X, size_t count );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compare unsigned values
|
||||||
|
*
|
||||||
|
* \param X Left-hand MPI
|
||||||
|
* \param Y Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 1 if |X| is greater than |Y|,
|
||||||
|
* -1 if |X| is lesser than |Y| or
|
||||||
|
* 0 if |X| is equal to |Y|
|
||||||
|
*/
|
||||||
|
int mpi_cmp_abs( const mpi *X, const mpi *Y );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compare signed values
|
||||||
|
*
|
||||||
|
* \param X Left-hand MPI
|
||||||
|
* \param Y Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 1 if X is greater than Y,
|
||||||
|
* -1 if X is lesser than Y or
|
||||||
|
* 0 if X is equal to Y
|
||||||
|
*/
|
||||||
|
int mpi_cmp_mpi( const mpi *X, const mpi *Y );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compare signed values
|
||||||
|
*
|
||||||
|
* \param X Left-hand MPI
|
||||||
|
* \param z The integer value to compare to
|
||||||
|
*
|
||||||
|
* \return 1 if X is greater than z,
|
||||||
|
* -1 if X is lesser than z or
|
||||||
|
* 0 if X is equal to z
|
||||||
|
*/
|
||||||
|
int mpi_cmp_int( const mpi *X, t_sint z );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Unsigned addition: X = |A| + |B|
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param B Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_add_abs( mpi *X, const mpi *A, const mpi *B );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Unsigned substraction: X = |A| - |B|
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param B Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A
|
||||||
|
*/
|
||||||
|
int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Signed addition: X = A + B
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param B Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Signed substraction: X = A - B
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param B Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Signed addition: X = A + b
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param b The integer value to add
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_add_int( mpi *X, const mpi *A, t_sint b );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Signed substraction: X = A - b
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param b The integer value to subtract
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_sub_int( mpi *X, const mpi *A, t_sint b );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Baseline multiplication: X = A * B
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param B Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Baseline multiplication: X = A * b
|
||||||
|
* Note: b is an unsigned integer type, thus
|
||||||
|
* Negative values of b are ignored.
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param b The integer value to multiply with
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_mul_int( mpi *X, const mpi *A, t_sint b );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Division by mpi: A = Q * B + R
|
||||||
|
*
|
||||||
|
* \param Q Destination MPI for the quotient
|
||||||
|
* \param R Destination MPI for the rest value
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param B Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
|
||||||
|
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0
|
||||||
|
*
|
||||||
|
* \note Either Q or R can be NULL.
|
||||||
|
*/
|
||||||
|
int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Division by int: A = Q * b + R
|
||||||
|
*
|
||||||
|
* \param Q Destination MPI for the quotient
|
||||||
|
* \param R Destination MPI for the rest value
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param b Integer to divide by
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
|
||||||
|
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
|
||||||
|
*
|
||||||
|
* \note Either Q or R can be NULL.
|
||||||
|
*/
|
||||||
|
int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Modulo: R = A mod B
|
||||||
|
*
|
||||||
|
* \param R Destination MPI for the rest value
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param B Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
|
||||||
|
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0,
|
||||||
|
* POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0
|
||||||
|
*/
|
||||||
|
int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Modulo: r = A mod b
|
||||||
|
*
|
||||||
|
* \param r Destination t_uint
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param b Integer to divide by
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
|
||||||
|
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0,
|
||||||
|
* POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0
|
||||||
|
*/
|
||||||
|
int mpi_mod_int( t_uint *r, const mpi *A, t_sint b );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sliding-window exponentiation: X = A^E mod N
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param E Exponent MPI
|
||||||
|
* \param N Modular MPI
|
||||||
|
* \param _RR Speed-up MPI used for recalculations
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
|
||||||
|
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even or if
|
||||||
|
* E is negative
|
||||||
|
*
|
||||||
|
* \note _RR is used to avoid re-computing R*R mod N across
|
||||||
|
* multiple calls, which speeds up things a bit. It can
|
||||||
|
* be set to NULL if the extra performance is unneeded.
|
||||||
|
*/
|
||||||
|
int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Fill an MPI X with size bytes of random
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param size Size in bytes
|
||||||
|
* \param f_rng RNG function
|
||||||
|
* \param p_rng RNG parameter
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_fill_random( mpi *X, size_t size,
|
||||||
|
int (*f_rng)(void *, unsigned char *, size_t),
|
||||||
|
void *p_rng );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Greatest common divisor: G = gcd(A, B)
|
||||||
|
*
|
||||||
|
* \param G Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param B Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
|
||||||
|
*/
|
||||||
|
int mpi_gcd( mpi *G, const mpi *A, const mpi *B );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Modular inverse: X = A^-1 mod N
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param A Left-hand MPI
|
||||||
|
* \param N Right-hand MPI
|
||||||
|
*
|
||||||
|
* \return 0 if successful,
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
|
||||||
|
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil
|
||||||
|
POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N
|
||||||
|
*/
|
||||||
|
int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Miller-Rabin primality test
|
||||||
|
*
|
||||||
|
* \param X MPI to check
|
||||||
|
* \param f_rng RNG function
|
||||||
|
* \param p_rng RNG parameter
|
||||||
|
*
|
||||||
|
* \return 0 if successful (probably prime),
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
|
||||||
|
* POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
|
||||||
|
*/
|
||||||
|
int mpi_is_prime( mpi *X,
|
||||||
|
int (*f_rng)(void *, unsigned char *, size_t),
|
||||||
|
void *p_rng );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Prime number generation
|
||||||
|
*
|
||||||
|
* \param X Destination MPI
|
||||||
|
* \param nbits Required size of X in bits ( 3 <= nbits <= POLARSSL_MPI_MAX_BITS )
|
||||||
|
* \param dh_flag If 1, then (X-1)/2 will be prime too
|
||||||
|
* \param f_rng RNG function
|
||||||
|
* \param p_rng RNG parameter
|
||||||
|
*
|
||||||
|
* \return 0 if successful (probably prime),
|
||||||
|
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
|
||||||
|
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
|
||||||
|
*/
|
||||||
|
int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag,
|
||||||
|
int (*f_rng)(void *, unsigned char *, size_t),
|
||||||
|
void *p_rng );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checkup routine
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or 1 if the test failed
|
||||||
|
*/
|
||||||
|
int mpi_self_test( int verbose );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* bignum.h */
|
864
common/polarssl/bn_mul.h
Normal file
864
common/polarssl/bn_mul.h
Normal file
|
@ -0,0 +1,864 @@
|
||||||
|
/**
|
||||||
|
* \file bn_mul.h
|
||||||
|
*
|
||||||
|
* \brief Multi-precision integer library
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2010, Brainspark B.V.
|
||||||
|
*
|
||||||
|
* This file is part of PolarSSL (http://www.polarssl.org)
|
||||||
|
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Multiply source vector [s] with b, add result
|
||||||
|
* to destination vector [d] and set carry c.
|
||||||
|
*
|
||||||
|
* Currently supports:
|
||||||
|
*
|
||||||
|
* . IA-32 (386+) . AMD64 / EM64T
|
||||||
|
* . IA-32 (SSE2) . Motorola 68000
|
||||||
|
* . PowerPC, 32-bit . MicroBlaze
|
||||||
|
* . PowerPC, 64-bit . TriCore
|
||||||
|
* . SPARC v8 . ARM v3+
|
||||||
|
* . Alpha . MIPS32
|
||||||
|
* . C, longlong . C, generic
|
||||||
|
*/
|
||||||
|
#ifndef POLARSSL_BN_MUL_H
|
||||||
|
#define POLARSSL_BN_MUL_H
|
||||||
|
|
||||||
|
#include "bignum.h"
|
||||||
|
|
||||||
|
#if defined(POLARSSL_HAVE_ASM)
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#if defined(__i386__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( " \
|
||||||
|
movl %%ebx, %0; \
|
||||||
|
movl %5, %%esi; \
|
||||||
|
movl %6, %%edi; \
|
||||||
|
movl %7, %%ecx; \
|
||||||
|
movl %8, %%ebx; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
" \
|
||||||
|
lodsl; \
|
||||||
|
mull %%ebx; \
|
||||||
|
addl %%ecx, %%eax; \
|
||||||
|
adcl $0, %%edx; \
|
||||||
|
addl (%%edi), %%eax; \
|
||||||
|
adcl $0, %%edx; \
|
||||||
|
movl %%edx, %%ecx; \
|
||||||
|
stosl; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#if defined(POLARSSL_HAVE_SSE2)
|
||||||
|
|
||||||
|
#define MULADDC_HUIT \
|
||||||
|
" \
|
||||||
|
movd %%ecx, %%mm1; \
|
||||||
|
movd %%ebx, %%mm0; \
|
||||||
|
movd (%%edi), %%mm3; \
|
||||||
|
paddq %%mm3, %%mm1; \
|
||||||
|
movd (%%esi), %%mm2; \
|
||||||
|
pmuludq %%mm0, %%mm2; \
|
||||||
|
movd 4(%%esi), %%mm4; \
|
||||||
|
pmuludq %%mm0, %%mm4; \
|
||||||
|
movd 8(%%esi), %%mm6; \
|
||||||
|
pmuludq %%mm0, %%mm6; \
|
||||||
|
movd 12(%%esi), %%mm7; \
|
||||||
|
pmuludq %%mm0, %%mm7; \
|
||||||
|
paddq %%mm2, %%mm1; \
|
||||||
|
movd 4(%%edi), %%mm3; \
|
||||||
|
paddq %%mm4, %%mm3; \
|
||||||
|
movd 8(%%edi), %%mm5; \
|
||||||
|
paddq %%mm6, %%mm5; \
|
||||||
|
movd 12(%%edi), %%mm4; \
|
||||||
|
paddq %%mm4, %%mm7; \
|
||||||
|
movd %%mm1, (%%edi); \
|
||||||
|
movd 16(%%esi), %%mm2; \
|
||||||
|
pmuludq %%mm0, %%mm2; \
|
||||||
|
psrlq $32, %%mm1; \
|
||||||
|
movd 20(%%esi), %%mm4; \
|
||||||
|
pmuludq %%mm0, %%mm4; \
|
||||||
|
paddq %%mm3, %%mm1; \
|
||||||
|
movd 24(%%esi), %%mm6; \
|
||||||
|
pmuludq %%mm0, %%mm6; \
|
||||||
|
movd %%mm1, 4(%%edi); \
|
||||||
|
psrlq $32, %%mm1; \
|
||||||
|
movd 28(%%esi), %%mm3; \
|
||||||
|
pmuludq %%mm0, %%mm3; \
|
||||||
|
paddq %%mm5, %%mm1; \
|
||||||
|
movd 16(%%edi), %%mm5; \
|
||||||
|
paddq %%mm5, %%mm2; \
|
||||||
|
movd %%mm1, 8(%%edi); \
|
||||||
|
psrlq $32, %%mm1; \
|
||||||
|
paddq %%mm7, %%mm1; \
|
||||||
|
movd 20(%%edi), %%mm5; \
|
||||||
|
paddq %%mm5, %%mm4; \
|
||||||
|
movd %%mm1, 12(%%edi); \
|
||||||
|
psrlq $32, %%mm1; \
|
||||||
|
paddq %%mm2, %%mm1; \
|
||||||
|
movd 24(%%edi), %%mm5; \
|
||||||
|
paddq %%mm5, %%mm6; \
|
||||||
|
movd %%mm1, 16(%%edi); \
|
||||||
|
psrlq $32, %%mm1; \
|
||||||
|
paddq %%mm4, %%mm1; \
|
||||||
|
movd 28(%%edi), %%mm5; \
|
||||||
|
paddq %%mm5, %%mm3; \
|
||||||
|
movd %%mm1, 20(%%edi); \
|
||||||
|
psrlq $32, %%mm1; \
|
||||||
|
paddq %%mm6, %%mm1; \
|
||||||
|
movd %%mm1, 24(%%edi); \
|
||||||
|
psrlq $32, %%mm1; \
|
||||||
|
paddq %%mm3, %%mm1; \
|
||||||
|
movd %%mm1, 28(%%edi); \
|
||||||
|
addl $32, %%edi; \
|
||||||
|
addl $32, %%esi; \
|
||||||
|
psrlq $32, %%mm1; \
|
||||||
|
movd %%mm1, %%ecx; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
" \
|
||||||
|
emms; \
|
||||||
|
movl %4, %%ebx; \
|
||||||
|
movl %%ecx, %1; \
|
||||||
|
movl %%edi, %2; \
|
||||||
|
movl %%esi, %3; \
|
||||||
|
" \
|
||||||
|
: "=m" (t), "=m" (c), "=m" (d), "=m" (s) \
|
||||||
|
: "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \
|
||||||
|
: "eax", "ecx", "edx", "esi", "edi" \
|
||||||
|
);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
" \
|
||||||
|
movl %4, %%ebx; \
|
||||||
|
movl %%ecx, %1; \
|
||||||
|
movl %%edi, %2; \
|
||||||
|
movl %%esi, %3; \
|
||||||
|
" \
|
||||||
|
: "=m" (t), "=m" (c), "=m" (d), "=m" (s) \
|
||||||
|
: "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \
|
||||||
|
: "eax", "ecx", "edx", "esi", "edi" \
|
||||||
|
);
|
||||||
|
#endif /* SSE2 */
|
||||||
|
#endif /* i386 */
|
||||||
|
|
||||||
|
#if defined(__amd64__) || defined (__x86_64__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "movq %0, %%rsi " :: "m" (s)); \
|
||||||
|
asm( "movq %0, %%rdi " :: "m" (d)); \
|
||||||
|
asm( "movq %0, %%rcx " :: "m" (c)); \
|
||||||
|
asm( "movq %0, %%rbx " :: "m" (b)); \
|
||||||
|
asm( "xorq %r8, %r8 " );
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "movq (%rsi),%rax " ); \
|
||||||
|
asm( "mulq %rbx " ); \
|
||||||
|
asm( "addq $8, %rsi " ); \
|
||||||
|
asm( "addq %rcx, %rax " ); \
|
||||||
|
asm( "movq %r8, %rcx " ); \
|
||||||
|
asm( "adcq $0, %rdx " ); \
|
||||||
|
asm( "nop " ); \
|
||||||
|
asm( "addq %rax, (%rdi) " ); \
|
||||||
|
asm( "adcq %rdx, %rcx " ); \
|
||||||
|
asm( "addq $8, %rdi " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "movq %%rcx, %0 " : "=m" (c)); \
|
||||||
|
asm( "movq %%rdi, %0 " : "=m" (d)); \
|
||||||
|
asm( "movq %%rsi, %0 " : "=m" (s) :: \
|
||||||
|
"rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
|
||||||
|
|
||||||
|
#endif /* AMD64 */
|
||||||
|
|
||||||
|
#if defined(__mc68020__) || defined(__mcpu32__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "movl %0, %%a2 " :: "m" (s)); \
|
||||||
|
asm( "movl %0, %%a3 " :: "m" (d)); \
|
||||||
|
asm( "movl %0, %%d3 " :: "m" (c)); \
|
||||||
|
asm( "movl %0, %%d2 " :: "m" (b)); \
|
||||||
|
asm( "moveq #0, %d0 " );
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "movel %a2@+, %d1 " ); \
|
||||||
|
asm( "mulul %d2, %d4:%d1 " ); \
|
||||||
|
asm( "addl %d3, %d1 " ); \
|
||||||
|
asm( "addxl %d0, %d4 " ); \
|
||||||
|
asm( "moveq #0, %d3 " ); \
|
||||||
|
asm( "addl %d1, %a3@+ " ); \
|
||||||
|
asm( "addxl %d4, %d3 " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "movl %%d3, %0 " : "=m" (c)); \
|
||||||
|
asm( "movl %%a3, %0 " : "=m" (d)); \
|
||||||
|
asm( "movl %%a2, %0 " : "=m" (s) :: \
|
||||||
|
"d0", "d1", "d2", "d3", "d4", "a2", "a3" );
|
||||||
|
|
||||||
|
#define MULADDC_HUIT \
|
||||||
|
asm( "movel %a2@+, %d1 " ); \
|
||||||
|
asm( "mulul %d2, %d4:%d1 " ); \
|
||||||
|
asm( "addxl %d3, %d1 " ); \
|
||||||
|
asm( "addxl %d0, %d4 " ); \
|
||||||
|
asm( "addl %d1, %a3@+ " ); \
|
||||||
|
asm( "movel %a2@+, %d1 " ); \
|
||||||
|
asm( "mulul %d2, %d3:%d1 " ); \
|
||||||
|
asm( "addxl %d4, %d1 " ); \
|
||||||
|
asm( "addxl %d0, %d3 " ); \
|
||||||
|
asm( "addl %d1, %a3@+ " ); \
|
||||||
|
asm( "movel %a2@+, %d1 " ); \
|
||||||
|
asm( "mulul %d2, %d4:%d1 " ); \
|
||||||
|
asm( "addxl %d3, %d1 " ); \
|
||||||
|
asm( "addxl %d0, %d4 " ); \
|
||||||
|
asm( "addl %d1, %a3@+ " ); \
|
||||||
|
asm( "movel %a2@+, %d1 " ); \
|
||||||
|
asm( "mulul %d2, %d3:%d1 " ); \
|
||||||
|
asm( "addxl %d4, %d1 " ); \
|
||||||
|
asm( "addxl %d0, %d3 " ); \
|
||||||
|
asm( "addl %d1, %a3@+ " ); \
|
||||||
|
asm( "movel %a2@+, %d1 " ); \
|
||||||
|
asm( "mulul %d2, %d4:%d1 " ); \
|
||||||
|
asm( "addxl %d3, %d1 " ); \
|
||||||
|
asm( "addxl %d0, %d4 " ); \
|
||||||
|
asm( "addl %d1, %a3@+ " ); \
|
||||||
|
asm( "movel %a2@+, %d1 " ); \
|
||||||
|
asm( "mulul %d2, %d3:%d1 " ); \
|
||||||
|
asm( "addxl %d4, %d1 " ); \
|
||||||
|
asm( "addxl %d0, %d3 " ); \
|
||||||
|
asm( "addl %d1, %a3@+ " ); \
|
||||||
|
asm( "movel %a2@+, %d1 " ); \
|
||||||
|
asm( "mulul %d2, %d4:%d1 " ); \
|
||||||
|
asm( "addxl %d3, %d1 " ); \
|
||||||
|
asm( "addxl %d0, %d4 " ); \
|
||||||
|
asm( "addl %d1, %a3@+ " ); \
|
||||||
|
asm( "movel %a2@+, %d1 " ); \
|
||||||
|
asm( "mulul %d2, %d3:%d1 " ); \
|
||||||
|
asm( "addxl %d4, %d1 " ); \
|
||||||
|
asm( "addxl %d0, %d3 " ); \
|
||||||
|
asm( "addl %d1, %a3@+ " ); \
|
||||||
|
asm( "addxl %d0, %d3 " );
|
||||||
|
|
||||||
|
#endif /* MC68000 */
|
||||||
|
|
||||||
|
#if defined(__powerpc__) || defined(__ppc__)
|
||||||
|
#if defined(__powerpc64__) || defined(__ppc64__)
|
||||||
|
|
||||||
|
#if defined(__MACH__) && defined(__APPLE__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "ld r3, %0 " :: "m" (s)); \
|
||||||
|
asm( "ld r4, %0 " :: "m" (d)); \
|
||||||
|
asm( "ld r5, %0 " :: "m" (c)); \
|
||||||
|
asm( "ld r6, %0 " :: "m" (b)); \
|
||||||
|
asm( "addi r3, r3, -8 " ); \
|
||||||
|
asm( "addi r4, r4, -8 " ); \
|
||||||
|
asm( "addic r5, r5, 0 " );
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "ldu r7, 8(r3) " ); \
|
||||||
|
asm( "mulld r8, r7, r6 " ); \
|
||||||
|
asm( "mulhdu r9, r7, r6 " ); \
|
||||||
|
asm( "adde r8, r8, r5 " ); \
|
||||||
|
asm( "ld r7, 8(r4) " ); \
|
||||||
|
asm( "addze r5, r9 " ); \
|
||||||
|
asm( "addc r8, r8, r7 " ); \
|
||||||
|
asm( "stdu r8, 8(r4) " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "addze r5, r5 " ); \
|
||||||
|
asm( "addi r4, r4, 8 " ); \
|
||||||
|
asm( "addi r3, r3, 8 " ); \
|
||||||
|
asm( "std r5, %0 " : "=m" (c)); \
|
||||||
|
asm( "std r4, %0 " : "=m" (d)); \
|
||||||
|
asm( "std r3, %0 " : "=m" (s) :: \
|
||||||
|
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "ld %%r3, %0 " :: "m" (s)); \
|
||||||
|
asm( "ld %%r4, %0 " :: "m" (d)); \
|
||||||
|
asm( "ld %%r5, %0 " :: "m" (c)); \
|
||||||
|
asm( "ld %%r6, %0 " :: "m" (b)); \
|
||||||
|
asm( "addi %r3, %r3, -8 " ); \
|
||||||
|
asm( "addi %r4, %r4, -8 " ); \
|
||||||
|
asm( "addic %r5, %r5, 0 " );
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "ldu %r7, 8(%r3) " ); \
|
||||||
|
asm( "mulld %r8, %r7, %r6 " ); \
|
||||||
|
asm( "mulhdu %r9, %r7, %r6 " ); \
|
||||||
|
asm( "adde %r8, %r8, %r5 " ); \
|
||||||
|
asm( "ld %r7, 8(%r4) " ); \
|
||||||
|
asm( "addze %r5, %r9 " ); \
|
||||||
|
asm( "addc %r8, %r8, %r7 " ); \
|
||||||
|
asm( "stdu %r8, 8(%r4) " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "addze %r5, %r5 " ); \
|
||||||
|
asm( "addi %r4, %r4, 8 " ); \
|
||||||
|
asm( "addi %r3, %r3, 8 " ); \
|
||||||
|
asm( "std %%r5, %0 " : "=m" (c)); \
|
||||||
|
asm( "std %%r4, %0 " : "=m" (d)); \
|
||||||
|
asm( "std %%r3, %0 " : "=m" (s) :: \
|
||||||
|
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* PPC32 */
|
||||||
|
|
||||||
|
#if defined(__MACH__) && defined(__APPLE__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "lwz r3, %0 " :: "m" (s)); \
|
||||||
|
asm( "lwz r4, %0 " :: "m" (d)); \
|
||||||
|
asm( "lwz r5, %0 " :: "m" (c)); \
|
||||||
|
asm( "lwz r6, %0 " :: "m" (b)); \
|
||||||
|
asm( "addi r3, r3, -4 " ); \
|
||||||
|
asm( "addi r4, r4, -4 " ); \
|
||||||
|
asm( "addic r5, r5, 0 " );
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "lwzu r7, 4(r3) " ); \
|
||||||
|
asm( "mullw r8, r7, r6 " ); \
|
||||||
|
asm( "mulhwu r9, r7, r6 " ); \
|
||||||
|
asm( "adde r8, r8, r5 " ); \
|
||||||
|
asm( "lwz r7, 4(r4) " ); \
|
||||||
|
asm( "addze r5, r9 " ); \
|
||||||
|
asm( "addc r8, r8, r7 " ); \
|
||||||
|
asm( "stwu r8, 4(r4) " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "addze r5, r5 " ); \
|
||||||
|
asm( "addi r4, r4, 4 " ); \
|
||||||
|
asm( "addi r3, r3, 4 " ); \
|
||||||
|
asm( "stw r5, %0 " : "=m" (c)); \
|
||||||
|
asm( "stw r4, %0 " : "=m" (d)); \
|
||||||
|
asm( "stw r3, %0 " : "=m" (s) :: \
|
||||||
|
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "lwz %%r3, %0 " :: "m" (s)); \
|
||||||
|
asm( "lwz %%r4, %0 " :: "m" (d)); \
|
||||||
|
asm( "lwz %%r5, %0 " :: "m" (c)); \
|
||||||
|
asm( "lwz %%r6, %0 " :: "m" (b)); \
|
||||||
|
asm( "addi %r3, %r3, -4 " ); \
|
||||||
|
asm( "addi %r4, %r4, -4 " ); \
|
||||||
|
asm( "addic %r5, %r5, 0 " );
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "lwzu %r7, 4(%r3) " ); \
|
||||||
|
asm( "mullw %r8, %r7, %r6 " ); \
|
||||||
|
asm( "mulhwu %r9, %r7, %r6 " ); \
|
||||||
|
asm( "adde %r8, %r8, %r5 " ); \
|
||||||
|
asm( "lwz %r7, 4(%r4) " ); \
|
||||||
|
asm( "addze %r5, %r9 " ); \
|
||||||
|
asm( "addc %r8, %r8, %r7 " ); \
|
||||||
|
asm( "stwu %r8, 4(%r4) " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "addze %r5, %r5 " ); \
|
||||||
|
asm( "addi %r4, %r4, 4 " ); \
|
||||||
|
asm( "addi %r3, %r3, 4 " ); \
|
||||||
|
asm( "stw %%r5, %0 " : "=m" (c)); \
|
||||||
|
asm( "stw %%r4, %0 " : "=m" (d)); \
|
||||||
|
asm( "stw %%r3, %0 " : "=m" (s) :: \
|
||||||
|
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* PPC32 */
|
||||||
|
#endif /* PPC64 */
|
||||||
|
|
||||||
|
#if defined(__sparc__) && defined(__sparc64__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( \
|
||||||
|
" \
|
||||||
|
ldx %3, %%o0; \
|
||||||
|
ldx %4, %%o1; \
|
||||||
|
ld %5, %%o2; \
|
||||||
|
ld %6, %%o3; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
" \
|
||||||
|
ld [%%o0], %%o4; \
|
||||||
|
inc 4, %%o0; \
|
||||||
|
ld [%%o1], %%o5; \
|
||||||
|
umul %%o3, %%o4, %%o4; \
|
||||||
|
addcc %%o4, %%o2, %%o4; \
|
||||||
|
rd %%y, %%g1; \
|
||||||
|
addx %%g1, 0, %%g1; \
|
||||||
|
addcc %%o4, %%o5, %%o4; \
|
||||||
|
st %%o4, [%%o1]; \
|
||||||
|
addx %%g1, 0, %%o2; \
|
||||||
|
inc 4, %%o1; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
" \
|
||||||
|
st %%o2, %0; \
|
||||||
|
stx %%o1, %1; \
|
||||||
|
stx %%o0, %2; \
|
||||||
|
" \
|
||||||
|
: "=m" (c), "=m" (d), "=m" (s) \
|
||||||
|
: "m" (s), "m" (d), "m" (c), "m" (b) \
|
||||||
|
: "g1", "o0", "o1", "o2", "o3", "o4", \
|
||||||
|
"o5" \
|
||||||
|
);
|
||||||
|
#endif /* SPARCv9 */
|
||||||
|
|
||||||
|
#if defined(__sparc__) && !defined(__sparc64__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( \
|
||||||
|
" \
|
||||||
|
ld %3, %%o0; \
|
||||||
|
ld %4, %%o1; \
|
||||||
|
ld %5, %%o2; \
|
||||||
|
ld %6, %%o3; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
" \
|
||||||
|
ld [%%o0], %%o4; \
|
||||||
|
inc 4, %%o0; \
|
||||||
|
ld [%%o1], %%o5; \
|
||||||
|
umul %%o3, %%o4, %%o4; \
|
||||||
|
addcc %%o4, %%o2, %%o4; \
|
||||||
|
rd %%y, %%g1; \
|
||||||
|
addx %%g1, 0, %%g1; \
|
||||||
|
addcc %%o4, %%o5, %%o4; \
|
||||||
|
st %%o4, [%%o1]; \
|
||||||
|
addx %%g1, 0, %%o2; \
|
||||||
|
inc 4, %%o1; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
" \
|
||||||
|
st %%o2, %0; \
|
||||||
|
st %%o1, %1; \
|
||||||
|
st %%o0, %2; \
|
||||||
|
" \
|
||||||
|
: "=m" (c), "=m" (d), "=m" (s) \
|
||||||
|
: "m" (s), "m" (d), "m" (c), "m" (b) \
|
||||||
|
: "g1", "o0", "o1", "o2", "o3", "o4", \
|
||||||
|
"o5" \
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* SPARCv8 */
|
||||||
|
|
||||||
|
#if defined(__microblaze__) || defined(microblaze)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "lwi r3, %0 " :: "m" (s)); \
|
||||||
|
asm( "lwi r4, %0 " :: "m" (d)); \
|
||||||
|
asm( "lwi r5, %0 " :: "m" (c)); \
|
||||||
|
asm( "lwi r6, %0 " :: "m" (b)); \
|
||||||
|
asm( "andi r7, r6, 0xffff" ); \
|
||||||
|
asm( "bsrli r6, r6, 16 " );
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "lhui r8, r3, 0 " ); \
|
||||||
|
asm( "addi r3, r3, 2 " ); \
|
||||||
|
asm( "lhui r9, r3, 0 " ); \
|
||||||
|
asm( "addi r3, r3, 2 " ); \
|
||||||
|
asm( "mul r10, r9, r6 " ); \
|
||||||
|
asm( "mul r11, r8, r7 " ); \
|
||||||
|
asm( "mul r12, r9, r7 " ); \
|
||||||
|
asm( "mul r13, r8, r6 " ); \
|
||||||
|
asm( "bsrli r8, r10, 16 " ); \
|
||||||
|
asm( "bsrli r9, r11, 16 " ); \
|
||||||
|
asm( "add r13, r13, r8 " ); \
|
||||||
|
asm( "add r13, r13, r9 " ); \
|
||||||
|
asm( "bslli r10, r10, 16 " ); \
|
||||||
|
asm( "bslli r11, r11, 16 " ); \
|
||||||
|
asm( "add r12, r12, r10 " ); \
|
||||||
|
asm( "addc r13, r13, r0 " ); \
|
||||||
|
asm( "add r12, r12, r11 " ); \
|
||||||
|
asm( "addc r13, r13, r0 " ); \
|
||||||
|
asm( "lwi r10, r4, 0 " ); \
|
||||||
|
asm( "add r12, r12, r10 " ); \
|
||||||
|
asm( "addc r13, r13, r0 " ); \
|
||||||
|
asm( "add r12, r12, r5 " ); \
|
||||||
|
asm( "addc r5, r13, r0 " ); \
|
||||||
|
asm( "swi r12, r4, 0 " ); \
|
||||||
|
asm( "addi r4, r4, 4 " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "swi r5, %0 " : "=m" (c)); \
|
||||||
|
asm( "swi r4, %0 " : "=m" (d)); \
|
||||||
|
asm( "swi r3, %0 " : "=m" (s) :: \
|
||||||
|
"r3", "r4" , "r5" , "r6" , "r7" , "r8" , \
|
||||||
|
"r9", "r10", "r11", "r12", "r13" );
|
||||||
|
|
||||||
|
#endif /* MicroBlaze */
|
||||||
|
|
||||||
|
#if defined(__tricore__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "ld.a %%a2, %0 " :: "m" (s)); \
|
||||||
|
asm( "ld.a %%a3, %0 " :: "m" (d)); \
|
||||||
|
asm( "ld.w %%d4, %0 " :: "m" (c)); \
|
||||||
|
asm( "ld.w %%d1, %0 " :: "m" (b)); \
|
||||||
|
asm( "xor %d5, %d5 " );
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "ld.w %d0, [%a2+] " ); \
|
||||||
|
asm( "madd.u %e2, %e4, %d0, %d1 " ); \
|
||||||
|
asm( "ld.w %d0, [%a3] " ); \
|
||||||
|
asm( "addx %d2, %d2, %d0 " ); \
|
||||||
|
asm( "addc %d3, %d3, 0 " ); \
|
||||||
|
asm( "mov %d4, %d3 " ); \
|
||||||
|
asm( "st.w [%a3+], %d2 " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "st.w %0, %%d4 " : "=m" (c)); \
|
||||||
|
asm( "st.a %0, %%a3 " : "=m" (d)); \
|
||||||
|
asm( "st.a %0, %%a2 " : "=m" (s) :: \
|
||||||
|
"d0", "d1", "e2", "d4", "a2", "a3" );
|
||||||
|
|
||||||
|
#endif /* TriCore */
|
||||||
|
|
||||||
|
#if defined(__arm__)
|
||||||
|
|
||||||
|
#if defined(__thumb__) && !defined(__thumb2__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( \
|
||||||
|
" \
|
||||||
|
ldr r0, %3; \
|
||||||
|
ldr r1, %4; \
|
||||||
|
ldr r2, %5; \
|
||||||
|
ldr r3, %6; \
|
||||||
|
lsr r7, r3, #16; \
|
||||||
|
mov r9, r7; \
|
||||||
|
lsl r7, r3, #16; \
|
||||||
|
lsr r7, r7, #16; \
|
||||||
|
mov r8, r7; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
" \
|
||||||
|
ldmia r0!, {r6}; \
|
||||||
|
lsr r7, r6, #16; \
|
||||||
|
lsl r6, r6, #16; \
|
||||||
|
lsr r6, r6, #16; \
|
||||||
|
mov r4, r8; \
|
||||||
|
mul r4, r6; \
|
||||||
|
mov r3, r9; \
|
||||||
|
mul r6, r3; \
|
||||||
|
mov r5, r9; \
|
||||||
|
mul r5, r7; \
|
||||||
|
mov r3, r8; \
|
||||||
|
mul r7, r3; \
|
||||||
|
lsr r3, r6, #16; \
|
||||||
|
add r5, r5, r3; \
|
||||||
|
lsr r3, r7, #16; \
|
||||||
|
add r5, r5, r3; \
|
||||||
|
add r4, r4, r2; \
|
||||||
|
mov r2, #0; \
|
||||||
|
adc r5, r2; \
|
||||||
|
lsl r3, r6, #16; \
|
||||||
|
add r4, r4, r3; \
|
||||||
|
adc r5, r2; \
|
||||||
|
lsl r3, r7, #16; \
|
||||||
|
add r4, r4, r3; \
|
||||||
|
adc r5, r2; \
|
||||||
|
ldr r3, [r1]; \
|
||||||
|
add r4, r4, r3; \
|
||||||
|
adc r2, r5; \
|
||||||
|
stmia r1!, {r4}; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
" \
|
||||||
|
str r2, %0; \
|
||||||
|
str r1, %1; \
|
||||||
|
str r0, %2; \
|
||||||
|
" \
|
||||||
|
: "=m" (c), "=m" (d), "=m" (s) \
|
||||||
|
: "m" (s), "m" (d), "m" (c), "m" (b) \
|
||||||
|
: "r0", "r1", "r2", "r3", "r4", "r5", \
|
||||||
|
"r6", "r7", "r8", "r9", "cc" \
|
||||||
|
);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( \
|
||||||
|
" \
|
||||||
|
ldr r0, %3; \
|
||||||
|
ldr r1, %4; \
|
||||||
|
ldr r2, %5; \
|
||||||
|
ldr r3, %6; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
" \
|
||||||
|
ldr r4, [r0], #4; \
|
||||||
|
mov r5, #0; \
|
||||||
|
ldr r6, [r1]; \
|
||||||
|
umlal r2, r5, r3, r4; \
|
||||||
|
adds r7, r6, r2; \
|
||||||
|
adc r2, r5, #0; \
|
||||||
|
str r7, [r1], #4; \
|
||||||
|
"
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
" \
|
||||||
|
str r2, %0; \
|
||||||
|
str r1, %1; \
|
||||||
|
str r0, %2; \
|
||||||
|
" \
|
||||||
|
: "=m" (c), "=m" (d), "=m" (s) \
|
||||||
|
: "m" (s), "m" (d), "m" (c), "m" (b) \
|
||||||
|
: "r0", "r1", "r2", "r3", "r4", "r5", \
|
||||||
|
"r6", "r7", "cc" \
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* Thumb */
|
||||||
|
|
||||||
|
#endif /* ARMv3 */
|
||||||
|
|
||||||
|
#if defined(__alpha__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "ldq $1, %0 " :: "m" (s)); \
|
||||||
|
asm( "ldq $2, %0 " :: "m" (d)); \
|
||||||
|
asm( "ldq $3, %0 " :: "m" (c)); \
|
||||||
|
asm( "ldq $4, %0 " :: "m" (b));
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "ldq $6, 0($1) " ); \
|
||||||
|
asm( "addq $1, 8, $1 " ); \
|
||||||
|
asm( "mulq $6, $4, $7 " ); \
|
||||||
|
asm( "umulh $6, $4, $6 " ); \
|
||||||
|
asm( "addq $7, $3, $7 " ); \
|
||||||
|
asm( "cmpult $7, $3, $3 " ); \
|
||||||
|
asm( "ldq $5, 0($2) " ); \
|
||||||
|
asm( "addq $7, $5, $7 " ); \
|
||||||
|
asm( "cmpult $7, $5, $5 " ); \
|
||||||
|
asm( "stq $7, 0($2) " ); \
|
||||||
|
asm( "addq $2, 8, $2 " ); \
|
||||||
|
asm( "addq $6, $3, $3 " ); \
|
||||||
|
asm( "addq $5, $3, $3 " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "stq $3, %0 " : "=m" (c)); \
|
||||||
|
asm( "stq $2, %0 " : "=m" (d)); \
|
||||||
|
asm( "stq $1, %0 " : "=m" (s) :: \
|
||||||
|
"$1", "$2", "$3", "$4", "$5", "$6", "$7" );
|
||||||
|
|
||||||
|
#endif /* Alpha */
|
||||||
|
|
||||||
|
#if defined(__mips__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( "lw $10, %0 " :: "m" (s)); \
|
||||||
|
asm( "lw $11, %0 " :: "m" (d)); \
|
||||||
|
asm( "lw $12, %0 " :: "m" (c)); \
|
||||||
|
asm( "lw $13, %0 " :: "m" (b));
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
asm( "lw $14, 0($10) " ); \
|
||||||
|
asm( "multu $13, $14 " ); \
|
||||||
|
asm( "addi $10, $10, 4 " ); \
|
||||||
|
asm( "mflo $14 " ); \
|
||||||
|
asm( "mfhi $9 " ); \
|
||||||
|
asm( "addu $14, $12, $14 " ); \
|
||||||
|
asm( "lw $15, 0($11) " ); \
|
||||||
|
asm( "sltu $12, $14, $12 " ); \
|
||||||
|
asm( "addu $15, $14, $15 " ); \
|
||||||
|
asm( "sltu $14, $15, $14 " ); \
|
||||||
|
asm( "addu $12, $12, $9 " ); \
|
||||||
|
asm( "sw $15, 0($11) " ); \
|
||||||
|
asm( "addu $12, $12, $14 " ); \
|
||||||
|
asm( "addi $11, $11, 4 " );
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
asm( "sw $12, %0 " : "=m" (c)); \
|
||||||
|
asm( "sw $11, %0 " : "=m" (d)); \
|
||||||
|
asm( "sw $10, %0 " : "=m" (s) :: \
|
||||||
|
"$9", "$10", "$11", "$12", "$13", "$14", "$15" );
|
||||||
|
|
||||||
|
#endif /* MIPS */
|
||||||
|
#endif /* GNUC */
|
||||||
|
|
||||||
|
#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
__asm mov esi, s \
|
||||||
|
__asm mov edi, d \
|
||||||
|
__asm mov ecx, c \
|
||||||
|
__asm mov ebx, b
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
__asm lodsd \
|
||||||
|
__asm mul ebx \
|
||||||
|
__asm add eax, ecx \
|
||||||
|
__asm adc edx, 0 \
|
||||||
|
__asm add eax, [edi] \
|
||||||
|
__asm adc edx, 0 \
|
||||||
|
__asm mov ecx, edx \
|
||||||
|
__asm stosd
|
||||||
|
|
||||||
|
#if defined(POLARSSL_HAVE_SSE2)
|
||||||
|
|
||||||
|
#define EMIT __asm _emit
|
||||||
|
|
||||||
|
#define MULADDC_HUIT \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0xC9 \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0xC3 \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x1F \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x16 \
|
||||||
|
EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \
|
||||||
|
EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \
|
||||||
|
EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \
|
||||||
|
EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xCA \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xDC \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xEE \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xFC \
|
||||||
|
EMIT 0x0F EMIT 0x7E EMIT 0x0F \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \
|
||||||
|
EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \
|
||||||
|
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \
|
||||||
|
EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \
|
||||||
|
EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \
|
||||||
|
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \
|
||||||
|
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \
|
||||||
|
EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xCD \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \
|
||||||
|
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \
|
||||||
|
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xCF \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \
|
||||||
|
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \
|
||||||
|
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xCA \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \
|
||||||
|
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \
|
||||||
|
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xCC \
|
||||||
|
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xDD \
|
||||||
|
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \
|
||||||
|
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xCE \
|
||||||
|
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \
|
||||||
|
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
|
||||||
|
EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
|
||||||
|
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \
|
||||||
|
EMIT 0x83 EMIT 0xC7 EMIT 0x20 \
|
||||||
|
EMIT 0x83 EMIT 0xC6 EMIT 0x20 \
|
||||||
|
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
|
||||||
|
EMIT 0x0F EMIT 0x7E EMIT 0xC9
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
EMIT 0x0F EMIT 0x77 \
|
||||||
|
__asm mov c, ecx \
|
||||||
|
__asm mov d, edi \
|
||||||
|
__asm mov s, esi \
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
__asm mov c, ecx \
|
||||||
|
__asm mov d, edi \
|
||||||
|
__asm mov s, esi \
|
||||||
|
|
||||||
|
#endif /* SSE2 */
|
||||||
|
#endif /* MSVC */
|
||||||
|
|
||||||
|
#endif /* POLARSSL_HAVE_ASM */
|
||||||
|
|
||||||
|
#if !defined(MULADDC_CORE)
|
||||||
|
#if defined(POLARSSL_HAVE_UDBL)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
{ \
|
||||||
|
t_udbl r; \
|
||||||
|
t_uint r0, r1;
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
r = *(s++) * (t_udbl) b; \
|
||||||
|
r0 = r; \
|
||||||
|
r1 = r >> biL; \
|
||||||
|
r0 += c; r1 += (r0 < c); \
|
||||||
|
r0 += *d; r1 += (r0 < *d); \
|
||||||
|
c = r1; *(d++) = r0;
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
{ \
|
||||||
|
t_uint s0, s1, b0, b1; \
|
||||||
|
t_uint r0, r1, rx, ry; \
|
||||||
|
b0 = ( b << biH ) >> biH; \
|
||||||
|
b1 = ( b >> biH );
|
||||||
|
|
||||||
|
#define MULADDC_CORE \
|
||||||
|
s0 = ( *s << biH ) >> biH; \
|
||||||
|
s1 = ( *s >> biH ); s++; \
|
||||||
|
rx = s0 * b1; r0 = s0 * b0; \
|
||||||
|
ry = s1 * b0; r1 = s1 * b1; \
|
||||||
|
r1 += ( rx >> biH ); \
|
||||||
|
r1 += ( ry >> biH ); \
|
||||||
|
rx <<= biH; ry <<= biH; \
|
||||||
|
r0 += rx; r1 += (r0 < rx); \
|
||||||
|
r0 += ry; r1 += (r0 < ry); \
|
||||||
|
r0 += c; r1 += (r0 < c); \
|
||||||
|
r0 += *d; r1 += (r0 < *d); \
|
||||||
|
c = r1; *(d++) = r0;
|
||||||
|
|
||||||
|
#define MULADDC_STOP \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* C (generic) */
|
||||||
|
#endif /* C (longlong) */
|
||||||
|
|
||||||
|
#endif /* bn_mul.h */
|
|
@ -29,7 +29,7 @@
|
||||||
* http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
|
* http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//#include "polarssl/config.h"
|
#include "polarssl_config.h"
|
||||||
#define POLARSSL_DES_C
|
#define POLARSSL_DES_C
|
||||||
|
|
||||||
#if defined(POLARSSL_DES_C)
|
#if defined(POLARSSL_DES_C)
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
*
|
*
|
||||||
* Comment to disable the use of assembly code.
|
* Comment to disable the use of assembly code.
|
||||||
*/
|
*/
|
||||||
#define POLARSSL_HAVE_ASM
|
//#define POLARSSL_HAVE_ASM
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \def POLARSSL_HAVE_SSE2
|
* \def POLARSSL_HAVE_SSE2
|
||||||
|
@ -762,7 +762,7 @@
|
||||||
*
|
*
|
||||||
* This enables support for RSAES-OAEP and RSASSA-PSS operations.
|
* This enables support for RSAES-OAEP and RSASSA-PSS operations.
|
||||||
*/
|
*/
|
||||||
#define POLARSSL_PKCS1_V21
|
//#define POLARSSL_PKCS1_V21
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \def POLARSSL_RSA_NO_CRT
|
* \def POLARSSL_RSA_NO_CRT
|
||||||
|
|
1466
common/polarssl/rsa.c
Normal file
1466
common/polarssl/rsa.c
Normal file
File diff suppressed because it is too large
Load diff
597
common/polarssl/rsa.h
Normal file
597
common/polarssl/rsa.h
Normal file
|
@ -0,0 +1,597 @@
|
||||||
|
/**
|
||||||
|
* \file rsa.h
|
||||||
|
*
|
||||||
|
* \brief The RSA public-key cryptosystem
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2010, Brainspark B.V.
|
||||||
|
*
|
||||||
|
* This file is part of PolarSSL (http://www.polarssl.org)
|
||||||
|
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
#ifndef POLARSSL_RSA_H
|
||||||
|
#define POLARSSL_RSA_H
|
||||||
|
|
||||||
|
#include "bignum.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RSA Error codes
|
||||||
|
*/
|
||||||
|
#define POLARSSL_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */
|
||||||
|
#define POLARSSL_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */
|
||||||
|
#define POLARSSL_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */
|
||||||
|
#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the libraries validity check. */
|
||||||
|
#define POLARSSL_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */
|
||||||
|
#define POLARSSL_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */
|
||||||
|
#define POLARSSL_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */
|
||||||
|
#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */
|
||||||
|
#define POLARSSL_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PKCS#1 constants
|
||||||
|
*/
|
||||||
|
#define SIG_RSA_RAW 0
|
||||||
|
#define SIG_RSA_MD2 2
|
||||||
|
#define SIG_RSA_MD4 3
|
||||||
|
#define SIG_RSA_MD5 4
|
||||||
|
#define SIG_RSA_SHA1 5
|
||||||
|
#define SIG_RSA_SHA224 14
|
||||||
|
#define SIG_RSA_SHA256 11
|
||||||
|
#define SIG_RSA_SHA384 12
|
||||||
|
#define SIG_RSA_SHA512 13
|
||||||
|
|
||||||
|
#define RSA_PUBLIC 0
|
||||||
|
#define RSA_PRIVATE 1
|
||||||
|
|
||||||
|
#define RSA_PKCS_V15 0
|
||||||
|
#define RSA_PKCS_V21 1
|
||||||
|
|
||||||
|
#define RSA_SIGN 1
|
||||||
|
#define RSA_CRYPT 2
|
||||||
|
|
||||||
|
#define ASN1_STR_CONSTRUCTED_SEQUENCE "\x30"
|
||||||
|
#define ASN1_STR_NULL "\x05"
|
||||||
|
#define ASN1_STR_OID "\x06"
|
||||||
|
#define ASN1_STR_OCTET_STRING "\x04"
|
||||||
|
|
||||||
|
#define OID_DIGEST_ALG_MDX "\x2A\x86\x48\x86\xF7\x0D\x02\x00"
|
||||||
|
#define OID_HASH_ALG_SHA1 "\x2b\x0e\x03\x02\x1a"
|
||||||
|
#define OID_HASH_ALG_SHA2X "\x60\x86\x48\x01\x65\x03\x04\x02\x00"
|
||||||
|
|
||||||
|
#define OID_ISO_MEMBER_BODIES "\x2a"
|
||||||
|
#define OID_ISO_IDENTIFIED_ORG "\x2b"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ISO Member bodies OID parts
|
||||||
|
*/
|
||||||
|
#define OID_COUNTRY_US "\x86\x48"
|
||||||
|
#define OID_RSA_DATA_SECURITY "\x86\xf7\x0d"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ISO Identified organization OID parts
|
||||||
|
*/
|
||||||
|
#define OID_OIW_SECSIG_SHA1 "\x0e\x03\x02\x1a"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DigestInfo ::= SEQUENCE {
|
||||||
|
* digestAlgorithm DigestAlgorithmIdentifier,
|
||||||
|
* digest Digest }
|
||||||
|
*
|
||||||
|
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
|
||||||
|
*
|
||||||
|
* Digest ::= OCTET STRING
|
||||||
|
*/
|
||||||
|
#define ASN1_HASH_MDX \
|
||||||
|
( \
|
||||||
|
ASN1_STR_CONSTRUCTED_SEQUENCE "\x20" \
|
||||||
|
ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C" \
|
||||||
|
ASN1_STR_OID "\x08" \
|
||||||
|
OID_DIGEST_ALG_MDX \
|
||||||
|
ASN1_STR_NULL "\x00" \
|
||||||
|
ASN1_STR_OCTET_STRING "\x10" \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define ASN1_HASH_SHA1 \
|
||||||
|
ASN1_STR_CONSTRUCTED_SEQUENCE "\x21" \
|
||||||
|
ASN1_STR_CONSTRUCTED_SEQUENCE "\x09" \
|
||||||
|
ASN1_STR_OID "\x05" \
|
||||||
|
OID_HASH_ALG_SHA1 \
|
||||||
|
ASN1_STR_NULL "\x00" \
|
||||||
|
ASN1_STR_OCTET_STRING "\x14"
|
||||||
|
|
||||||
|
#define ASN1_HASH_SHA1_ALT \
|
||||||
|
ASN1_STR_CONSTRUCTED_SEQUENCE "\x1F" \
|
||||||
|
ASN1_STR_CONSTRUCTED_SEQUENCE "\x07" \
|
||||||
|
ASN1_STR_OID "\x05" \
|
||||||
|
OID_HASH_ALG_SHA1 \
|
||||||
|
ASN1_STR_OCTET_STRING "\x14"
|
||||||
|
|
||||||
|
#define ASN1_HASH_SHA2X \
|
||||||
|
ASN1_STR_CONSTRUCTED_SEQUENCE "\x11" \
|
||||||
|
ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d" \
|
||||||
|
ASN1_STR_OID "\x09" \
|
||||||
|
OID_HASH_ALG_SHA2X \
|
||||||
|
ASN1_STR_NULL "\x00" \
|
||||||
|
ASN1_STR_OCTET_STRING "\x00"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief RSA context structure
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int ver; /*!< always 0 */
|
||||||
|
size_t len; /*!< size(N) in chars */
|
||||||
|
|
||||||
|
mpi N; /*!< public modulus */
|
||||||
|
mpi E; /*!< public exponent */
|
||||||
|
|
||||||
|
mpi D; /*!< private exponent */
|
||||||
|
mpi P; /*!< 1st prime factor */
|
||||||
|
mpi Q; /*!< 2nd prime factor */
|
||||||
|
mpi DP; /*!< D % (P - 1) */
|
||||||
|
mpi DQ; /*!< D % (Q - 1) */
|
||||||
|
mpi QP; /*!< 1 / (Q % P) */
|
||||||
|
|
||||||
|
mpi RN; /*!< cached R^2 mod N */
|
||||||
|
mpi RP; /*!< cached R^2 mod P */
|
||||||
|
mpi RQ; /*!< cached R^2 mod Q */
|
||||||
|
|
||||||
|
int padding; /*!< RSA_PKCS_V15 for 1.5 padding and
|
||||||
|
RSA_PKCS_v21 for OAEP/PSS */
|
||||||
|
int hash_id; /*!< Hash identifier of md_type_t as
|
||||||
|
specified in the md.h header file
|
||||||
|
for the EME-OAEP and EMSA-PSS
|
||||||
|
encoding */
|
||||||
|
}
|
||||||
|
rsa_context;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize an RSA context
|
||||||
|
*
|
||||||
|
* Note: Set padding to RSA_PKCS_V21 for the RSAES-OAEP
|
||||||
|
* encryption scheme and the RSASSA-PSS signature scheme.
|
||||||
|
*
|
||||||
|
* \param ctx RSA context to be initialized
|
||||||
|
* \param padding RSA_PKCS_V15 or RSA_PKCS_V21
|
||||||
|
* \param hash_id RSA_PKCS_V21 hash identifier
|
||||||
|
*
|
||||||
|
* \note The hash_id parameter is actually ignored
|
||||||
|
* when using RSA_PKCS_V15 padding.
|
||||||
|
*/
|
||||||
|
void rsa_init( rsa_context *ctx,
|
||||||
|
int padding,
|
||||||
|
int hash_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Generate an RSA keypair
|
||||||
|
*
|
||||||
|
* \param ctx RSA context that will hold the key
|
||||||
|
* \param f_rng RNG function
|
||||||
|
* \param p_rng RNG parameter
|
||||||
|
* \param nbits size of the public key in bits
|
||||||
|
* \param exponent public exponent (e.g., 65537)
|
||||||
|
*
|
||||||
|
* \note rsa_init() must be called beforehand to setup
|
||||||
|
* the RSA context.
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*/
|
||||||
|
int rsa_gen_key( rsa_context *ctx,
|
||||||
|
int (*f_rng)(void *, unsigned char *, size_t),
|
||||||
|
void *p_rng,
|
||||||
|
unsigned int nbits, int exponent );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check a public RSA key
|
||||||
|
*
|
||||||
|
* \param ctx RSA context to be checked
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*/
|
||||||
|
int rsa_check_pubkey( const rsa_context *ctx );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check a private RSA key
|
||||||
|
*
|
||||||
|
* \param ctx RSA context to be checked
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*/
|
||||||
|
int rsa_check_privkey( const rsa_context *ctx );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Do an RSA public key operation
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param input input buffer
|
||||||
|
* \param output output buffer
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note This function does NOT take care of message
|
||||||
|
* padding. Also, be sure to set input[0] = 0 or assure that
|
||||||
|
* input is smaller than N.
|
||||||
|
*
|
||||||
|
* \note The input and output buffers must be large
|
||||||
|
* enough (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*/
|
||||||
|
int rsa_public( rsa_context *ctx,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned char *output );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Do an RSA private key operation
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param input input buffer
|
||||||
|
* \param output output buffer
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The input and output buffers must be large
|
||||||
|
* enough (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*/
|
||||||
|
int rsa_private( rsa_context *ctx,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned char *output );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Generic wrapper to perform a PKCS#1 encryption using the
|
||||||
|
* mode from the context. Add the message padding, then do an
|
||||||
|
* RSA operation.
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding)
|
||||||
|
* \param p_rng RNG parameter
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param ilen contains the plaintext length
|
||||||
|
* \param input buffer holding the data to be encrypted
|
||||||
|
* \param output buffer that will hold the ciphertext
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The output buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*/
|
||||||
|
int rsa_pkcs1_encrypt( rsa_context *ctx,
|
||||||
|
int (*f_rng)(void *, unsigned char *, size_t),
|
||||||
|
void *p_rng,
|
||||||
|
int mode, size_t ilen,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned char *output );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT)
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param f_rng RNG function (Needed for padding)
|
||||||
|
* \param p_rng RNG parameter
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param ilen contains the plaintext length
|
||||||
|
* \param input buffer holding the data to be encrypted
|
||||||
|
* \param output buffer that will hold the ciphertext
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The output buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*/
|
||||||
|
int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx,
|
||||||
|
int (*f_rng)(void *, unsigned char *, size_t),
|
||||||
|
void *p_rng,
|
||||||
|
int mode, size_t ilen,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned char *output );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT)
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding)
|
||||||
|
* \param p_rng RNG parameter
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param label buffer holding the custom label to use
|
||||||
|
* \param label_len contains the label length
|
||||||
|
* \param ilen contains the plaintext length
|
||||||
|
* \param input buffer holding the data to be encrypted
|
||||||
|
* \param output buffer that will hold the ciphertext
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The output buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*/
|
||||||
|
int rsa_rsaes_oaep_encrypt( rsa_context *ctx,
|
||||||
|
int (*f_rng)(void *, unsigned char *, size_t),
|
||||||
|
void *p_rng,
|
||||||
|
int mode,
|
||||||
|
const unsigned char *label, size_t label_len,
|
||||||
|
size_t ilen,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned char *output );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Generic wrapper to perform a PKCS#1 decryption using the
|
||||||
|
* mode from the context. Do an RSA operation, then remove
|
||||||
|
* the message padding
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param olen will contain the plaintext length
|
||||||
|
* \param input buffer holding the encrypted data
|
||||||
|
* \param output buffer that will hold the plaintext
|
||||||
|
* \param output_max_len maximum length of the output buffer
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The output buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
|
||||||
|
* an error is thrown.
|
||||||
|
*/
|
||||||
|
int rsa_pkcs1_decrypt( rsa_context *ctx,
|
||||||
|
int mode, size_t *olen,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned char *output,
|
||||||
|
size_t output_max_len );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT)
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param olen will contain the plaintext length
|
||||||
|
* \param input buffer holding the encrypted data
|
||||||
|
* \param output buffer that will hold the plaintext
|
||||||
|
* \param output_max_len maximum length of the output buffer
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The output buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
|
||||||
|
* an error is thrown.
|
||||||
|
*/
|
||||||
|
int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx,
|
||||||
|
int mode, size_t *olen,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned char *output,
|
||||||
|
size_t output_max_len );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT)
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param label buffer holding the custom label to use
|
||||||
|
* \param label_len contains the label length
|
||||||
|
* \param olen will contain the plaintext length
|
||||||
|
* \param input buffer holding the encrypted data
|
||||||
|
* \param output buffer that will hold the plaintext
|
||||||
|
* \param output_max_len maximum length of the output buffer
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The output buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
|
||||||
|
* an error is thrown.
|
||||||
|
*/
|
||||||
|
int rsa_rsaes_oaep_decrypt( rsa_context *ctx,
|
||||||
|
int mode,
|
||||||
|
const unsigned char *label, size_t label_len,
|
||||||
|
size_t *olen,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned char *output,
|
||||||
|
size_t output_max_len );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Generic wrapper to perform a PKCS#1 signature using the
|
||||||
|
* mode from the context. Do a private RSA operation to sign
|
||||||
|
* a message digest
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding)
|
||||||
|
* \param p_rng RNG parameter
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
|
||||||
|
* \param hashlen message digest length (for SIG_RSA_RAW only)
|
||||||
|
* \param hash buffer holding the message digest
|
||||||
|
* \param sig buffer that will hold the ciphertext
|
||||||
|
*
|
||||||
|
* \return 0 if the signing operation was successful,
|
||||||
|
* or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The "sig" buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*
|
||||||
|
* \note In case of PKCS#1 v2.1 encoding keep in mind that
|
||||||
|
* the hash_id in the RSA context is the one used for the
|
||||||
|
* encoding. hash_id in the function call is the type of hash
|
||||||
|
* that is encoded. According to RFC 3447 it is advised to
|
||||||
|
* keep both hashes the same.
|
||||||
|
*/
|
||||||
|
int rsa_pkcs1_sign( rsa_context *ctx,
|
||||||
|
int (*f_rng)(void *, unsigned char *, size_t),
|
||||||
|
void *p_rng,
|
||||||
|
int mode,
|
||||||
|
int hash_id,
|
||||||
|
unsigned int hashlen,
|
||||||
|
const unsigned char *hash,
|
||||||
|
unsigned char *sig );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN)
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
|
||||||
|
* \param hashlen message digest length (for SIG_RSA_RAW only)
|
||||||
|
* \param hash buffer holding the message digest
|
||||||
|
* \param sig buffer that will hold the ciphertext
|
||||||
|
*
|
||||||
|
* \return 0 if the signing operation was successful,
|
||||||
|
* or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The "sig" buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*/
|
||||||
|
int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx,
|
||||||
|
int mode,
|
||||||
|
int hash_id,
|
||||||
|
unsigned int hashlen,
|
||||||
|
const unsigned char *hash,
|
||||||
|
unsigned char *sig );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN)
|
||||||
|
*
|
||||||
|
* \param ctx RSA context
|
||||||
|
* \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding)
|
||||||
|
* \param p_rng RNG parameter
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
|
||||||
|
* \param hashlen message digest length (for SIG_RSA_RAW only)
|
||||||
|
* \param hash buffer holding the message digest
|
||||||
|
* \param sig buffer that will hold the ciphertext
|
||||||
|
*
|
||||||
|
* \return 0 if the signing operation was successful,
|
||||||
|
* or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The "sig" buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*
|
||||||
|
* \note In case of PKCS#1 v2.1 encoding keep in mind that
|
||||||
|
* the hash_id in the RSA context is the one used for the
|
||||||
|
* encoding. hash_id in the function call is the type of hash
|
||||||
|
* that is encoded. According to RFC 3447 it is advised to
|
||||||
|
* keep both hashes the same.
|
||||||
|
*/
|
||||||
|
int rsa_rsassa_pss_sign( rsa_context *ctx,
|
||||||
|
int (*f_rng)(void *, unsigned char *, size_t),
|
||||||
|
void *p_rng,
|
||||||
|
int mode,
|
||||||
|
int hash_id,
|
||||||
|
unsigned int hashlen,
|
||||||
|
const unsigned char *hash,
|
||||||
|
unsigned char *sig );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Generic wrapper to perform a PKCS#1 verification using the
|
||||||
|
* mode from the context. Do a public RSA operation and check
|
||||||
|
* the message digest
|
||||||
|
*
|
||||||
|
* \param ctx points to an RSA public key
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
|
||||||
|
* \param hashlen message digest length (for SIG_RSA_RAW only)
|
||||||
|
* \param hash buffer holding the message digest
|
||||||
|
* \param sig buffer holding the ciphertext
|
||||||
|
*
|
||||||
|
* \return 0 if the verify operation was successful,
|
||||||
|
* or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The "sig" buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*
|
||||||
|
* \note In case of PKCS#1 v2.1 encoding keep in mind that
|
||||||
|
* the hash_id in the RSA context is the one used for the
|
||||||
|
* verification. hash_id in the function call is the type of hash
|
||||||
|
* that is verified. According to RFC 3447 it is advised to
|
||||||
|
* keep both hashes the same.
|
||||||
|
*/
|
||||||
|
int rsa_pkcs1_verify( rsa_context *ctx,
|
||||||
|
int mode,
|
||||||
|
int hash_id,
|
||||||
|
unsigned int hashlen,
|
||||||
|
const unsigned char *hash,
|
||||||
|
unsigned char *sig );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY)
|
||||||
|
*
|
||||||
|
* \param ctx points to an RSA public key
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
|
||||||
|
* \param hashlen message digest length (for SIG_RSA_RAW only)
|
||||||
|
* \param hash buffer holding the message digest
|
||||||
|
* \param sig buffer holding the ciphertext
|
||||||
|
*
|
||||||
|
* \return 0 if the verify operation was successful,
|
||||||
|
* or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The "sig" buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*/
|
||||||
|
int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx,
|
||||||
|
int mode,
|
||||||
|
int hash_id,
|
||||||
|
unsigned int hashlen,
|
||||||
|
const unsigned char *hash,
|
||||||
|
unsigned char *sig );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY)
|
||||||
|
* \brief Do a public RSA and check the message digest
|
||||||
|
*
|
||||||
|
* \param ctx points to an RSA public key
|
||||||
|
* \param mode RSA_PUBLIC or RSA_PRIVATE
|
||||||
|
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
|
||||||
|
* \param hashlen message digest length (for SIG_RSA_RAW only)
|
||||||
|
* \param hash buffer holding the message digest
|
||||||
|
* \param sig buffer holding the ciphertext
|
||||||
|
*
|
||||||
|
* \return 0 if the verify operation was successful,
|
||||||
|
* or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
*
|
||||||
|
* \note The "sig" buffer must be as large as the size
|
||||||
|
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
*
|
||||||
|
* \note In case of PKCS#1 v2.1 encoding keep in mind that
|
||||||
|
* the hash_id in the RSA context is the one used for the
|
||||||
|
* verification. hash_id in the function call is the type of hash
|
||||||
|
* that is verified. According to RFC 3447 it is advised to
|
||||||
|
* keep both hashes the same.
|
||||||
|
*/
|
||||||
|
int rsa_rsassa_pss_verify( rsa_context *ctx,
|
||||||
|
int mode,
|
||||||
|
int hash_id,
|
||||||
|
unsigned int hashlen,
|
||||||
|
const unsigned char *hash,
|
||||||
|
unsigned char *sig );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Free the components of an RSA key
|
||||||
|
*
|
||||||
|
* \param ctx RSA Context to free
|
||||||
|
*/
|
||||||
|
void rsa_free( rsa_context *ctx );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checkup routine
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or 1 if the test failed
|
||||||
|
*/
|
||||||
|
int rsa_self_test( int verbose );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* rsa.h */
|
|
@ -1,8 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* FIPS-180-1 compliant SHA-1 implementation
|
* FIPS-180-1 compliant SHA-1 implementation
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
|
* Copyright (C) 2006-2013, Brainspark B.V.
|
||||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
*
|
||||||
|
* This file is part of PolarSSL (http://www.polarssl.org)
|
||||||
|
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -24,38 +28,16 @@
|
||||||
* http://www.itl.nist.gov/fipspubs/fip180-1.htm
|
* http://www.itl.nist.gov/fipspubs/fip180-1.htm
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(POLARSSL_CONFIG_FILE)
|
#include "polarssl_config.h"
|
||||||
//#include "polarssl/config.h"
|
|
||||||
#define POLARSSL_SHA1_C
|
|
||||||
|
|
||||||
#else
|
|
||||||
#include POLARSSL_CONFIG_FILE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(POLARSSL_SHA1_C)
|
#if defined(POLARSSL_SHA1_C)
|
||||||
|
|
||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
|
|
||||||
#include <string.h>
|
#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST)
|
||||||
|
|
||||||
#if defined(POLARSSL_FS_IO)
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(POLARSSL_SELF_TEST)
|
|
||||||
#if defined(POLARSSL_PLATFORM_C)
|
|
||||||
#include "polarssl/platform.h"
|
|
||||||
#else
|
|
||||||
#include <stdio.h>
|
|
||||||
#define polarssl_printf printf
|
|
||||||
#endif /* POLARSSL_PLATFORM_C */
|
|
||||||
#endif /* POLARSSL_SELF_TEST */
|
|
||||||
|
|
||||||
/* Implementation that should never be optimized out by the compiler */
|
|
||||||
static void polarssl_zeroize( void *v, size_t n ) {
|
|
||||||
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(POLARSSL_SHA1_ALT)
|
#if !defined(POLARSSL_SHA1_ALT)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -81,19 +63,6 @@ static void polarssl_zeroize( void *v, size_t n ) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void sha1_init( sha1_context *ctx )
|
|
||||||
{
|
|
||||||
memset( ctx, 0, sizeof( sha1_context ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void sha1_free( sha1_context *ctx )
|
|
||||||
{
|
|
||||||
if( ctx == NULL )
|
|
||||||
return;
|
|
||||||
|
|
||||||
polarssl_zeroize( ctx, sizeof( sha1_context ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SHA-1 context setup
|
* SHA-1 context setup
|
||||||
*/
|
*/
|
||||||
|
@ -273,7 +242,7 @@ void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen )
|
||||||
size_t fill;
|
size_t fill;
|
||||||
uint32_t left;
|
uint32_t left;
|
||||||
|
|
||||||
if( ilen == 0 )
|
if( ilen <= 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
left = ctx->total[0] & 0x3F;
|
left = ctx->total[0] & 0x3F;
|
||||||
|
@ -351,11 +320,11 @@ void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] )
|
||||||
{
|
{
|
||||||
sha1_context ctx;
|
sha1_context ctx;
|
||||||
|
|
||||||
sha1_init( &ctx );
|
|
||||||
sha1_starts( &ctx );
|
sha1_starts( &ctx );
|
||||||
sha1_update( &ctx, input, ilen );
|
sha1_update( &ctx, input, ilen );
|
||||||
sha1_finish( &ctx, output );
|
sha1_finish( &ctx, output );
|
||||||
sha1_free( &ctx );
|
|
||||||
|
memset( &ctx, 0, sizeof( sha1_context ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(POLARSSL_FS_IO)
|
#if defined(POLARSSL_FS_IO)
|
||||||
|
@ -372,14 +341,14 @@ int sha1_file( const char *path, unsigned char output[20] )
|
||||||
if( ( f = fopen( path, "rb" ) ) == NULL )
|
if( ( f = fopen( path, "rb" ) ) == NULL )
|
||||||
return( POLARSSL_ERR_SHA1_FILE_IO_ERROR );
|
return( POLARSSL_ERR_SHA1_FILE_IO_ERROR );
|
||||||
|
|
||||||
sha1_init( &ctx );
|
|
||||||
sha1_starts( &ctx );
|
sha1_starts( &ctx );
|
||||||
|
|
||||||
while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
|
while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
|
||||||
sha1_update( &ctx, buf, n );
|
sha1_update( &ctx, buf, n );
|
||||||
|
|
||||||
sha1_finish( &ctx, output );
|
sha1_finish( &ctx, output );
|
||||||
sha1_free( &ctx );
|
|
||||||
|
memset( &ctx, 0, sizeof( sha1_context ) );
|
||||||
|
|
||||||
if( ferror( f ) != 0 )
|
if( ferror( f ) != 0 )
|
||||||
{
|
{
|
||||||
|
@ -395,8 +364,7 @@ int sha1_file( const char *path, unsigned char output[20] )
|
||||||
/*
|
/*
|
||||||
* SHA-1 HMAC context setup
|
* SHA-1 HMAC context setup
|
||||||
*/
|
*/
|
||||||
void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key,
|
void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen )
|
||||||
size_t keylen )
|
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
unsigned char sum[20];
|
unsigned char sum[20];
|
||||||
|
@ -420,14 +388,13 @@ void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key,
|
||||||
sha1_starts( ctx );
|
sha1_starts( ctx );
|
||||||
sha1_update( ctx, ctx->ipad, 64 );
|
sha1_update( ctx, ctx->ipad, 64 );
|
||||||
|
|
||||||
polarssl_zeroize( sum, sizeof( sum ) );
|
memset( sum, 0, sizeof( sum ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SHA-1 HMAC process buffer
|
* SHA-1 HMAC process buffer
|
||||||
*/
|
*/
|
||||||
void sha1_hmac_update( sha1_context *ctx, const unsigned char *input,
|
void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen )
|
||||||
size_t ilen )
|
|
||||||
{
|
{
|
||||||
sha1_update( ctx, input, ilen );
|
sha1_update( ctx, input, ilen );
|
||||||
}
|
}
|
||||||
|
@ -445,7 +412,7 @@ void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] )
|
||||||
sha1_update( ctx, tmpbuf, 20 );
|
sha1_update( ctx, tmpbuf, 20 );
|
||||||
sha1_finish( ctx, output );
|
sha1_finish( ctx, output );
|
||||||
|
|
||||||
polarssl_zeroize( tmpbuf, sizeof( tmpbuf ) );
|
memset( tmpbuf, 0, sizeof( tmpbuf ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -466,18 +433,18 @@ void sha1_hmac( const unsigned char *key, size_t keylen,
|
||||||
{
|
{
|
||||||
sha1_context ctx;
|
sha1_context ctx;
|
||||||
|
|
||||||
sha1_init( &ctx );
|
|
||||||
sha1_hmac_starts( &ctx, key, keylen );
|
sha1_hmac_starts( &ctx, key, keylen );
|
||||||
sha1_hmac_update( &ctx, input, ilen );
|
sha1_hmac_update( &ctx, input, ilen );
|
||||||
sha1_hmac_finish( &ctx, output );
|
sha1_hmac_finish( &ctx, output );
|
||||||
sha1_free( &ctx );
|
|
||||||
|
memset( &ctx, 0, sizeof( sha1_context ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(POLARSSL_SELF_TEST)
|
#if defined(POLARSSL_SELF_TEST)
|
||||||
/*
|
/*
|
||||||
* FIPS-180-1 test vectors
|
* FIPS-180-1 test vectors
|
||||||
*/
|
*/
|
||||||
static const unsigned char sha1_test_buf[3][57] =
|
static unsigned char sha1_test_buf[3][57] =
|
||||||
{
|
{
|
||||||
{ "abc" },
|
{ "abc" },
|
||||||
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
|
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
|
||||||
|
@ -502,7 +469,7 @@ static const unsigned char sha1_test_sum[3][20] =
|
||||||
/*
|
/*
|
||||||
* RFC 2202 test vectors
|
* RFC 2202 test vectors
|
||||||
*/
|
*/
|
||||||
static const unsigned char sha1_hmac_test_key[7][26] =
|
static unsigned char sha1_hmac_test_key[7][26] =
|
||||||
{
|
{
|
||||||
{ "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
|
{ "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
|
||||||
"\x0B\x0B\x0B\x0B" },
|
"\x0B\x0B\x0B\x0B" },
|
||||||
|
@ -522,7 +489,7 @@ static const int sha1_hmac_test_keylen[7] =
|
||||||
20, 4, 20, 25, 20, 80, 80
|
20, 4, 20, 25, 20, 80, 80
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char sha1_hmac_test_buf[7][74] =
|
static unsigned char sha1_hmac_test_buf[7][74] =
|
||||||
{
|
{
|
||||||
{ "Hi There" },
|
{ "Hi There" },
|
||||||
{ "what do ya want for nothing?" },
|
{ "what do ya want for nothing?" },
|
||||||
|
@ -570,20 +537,18 @@ static const unsigned char sha1_hmac_test_sum[7][20] =
|
||||||
*/
|
*/
|
||||||
int sha1_self_test( int verbose )
|
int sha1_self_test( int verbose )
|
||||||
{
|
{
|
||||||
int i, j, buflen, ret = 0;
|
int i, j, buflen;
|
||||||
unsigned char buf[1024];
|
unsigned char buf[1024];
|
||||||
unsigned char sha1sum[20];
|
unsigned char sha1sum[20];
|
||||||
sha1_context ctx;
|
sha1_context ctx;
|
||||||
|
|
||||||
sha1_init( &ctx );
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SHA-1
|
* SHA-1
|
||||||
*/
|
*/
|
||||||
for( i = 0; i < 3; i++ )
|
for( i = 0; i < 3; i++ )
|
||||||
{
|
{
|
||||||
if( verbose != 0 )
|
if( verbose != 0 )
|
||||||
polarssl_printf( " SHA-1 test #%d: ", i + 1 );
|
printf( " SHA-1 test #%d: ", i + 1 );
|
||||||
|
|
||||||
sha1_starts( &ctx );
|
sha1_starts( &ctx );
|
||||||
|
|
||||||
|
@ -603,27 +568,26 @@ int sha1_self_test( int verbose )
|
||||||
if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
|
if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
|
||||||
{
|
{
|
||||||
if( verbose != 0 )
|
if( verbose != 0 )
|
||||||
polarssl_printf( "failed\n" );
|
printf( "failed\n" );
|
||||||
|
|
||||||
ret = 1;
|
return( 1 );
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( verbose != 0 )
|
if( verbose != 0 )
|
||||||
polarssl_printf( "passed\n" );
|
printf( "passed\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( verbose != 0 )
|
if( verbose != 0 )
|
||||||
polarssl_printf( "\n" );
|
printf( "\n" );
|
||||||
|
|
||||||
for( i = 0; i < 7; i++ )
|
for( i = 0; i < 7; i++ )
|
||||||
{
|
{
|
||||||
if( verbose != 0 )
|
if( verbose != 0 )
|
||||||
polarssl_printf( " HMAC-SHA-1 test #%d: ", i + 1 );
|
printf( " HMAC-SHA-1 test #%d: ", i + 1 );
|
||||||
|
|
||||||
if( i == 5 || i == 6 )
|
if( i == 5 || i == 6 )
|
||||||
{
|
{
|
||||||
memset( buf, 0xAA, buflen = 80 );
|
memset( buf, '\xAA', buflen = 80 );
|
||||||
sha1_hmac_starts( &ctx, buf, buflen );
|
sha1_hmac_starts( &ctx, buf, buflen );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -640,26 +604,21 @@ int sha1_self_test( int verbose )
|
||||||
if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 )
|
if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 )
|
||||||
{
|
{
|
||||||
if( verbose != 0 )
|
if( verbose != 0 )
|
||||||
polarssl_printf( "failed\n" );
|
printf( "failed\n" );
|
||||||
|
|
||||||
ret = 1;
|
return( 1 );
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( verbose != 0 )
|
if( verbose != 0 )
|
||||||
polarssl_printf( "passed\n" );
|
printf( "passed\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( verbose != 0 )
|
if( verbose != 0 )
|
||||||
polarssl_printf( "\n" );
|
printf( "\n" );
|
||||||
|
|
||||||
exit:
|
return( 0 );
|
||||||
sha1_free( &ctx );
|
|
||||||
|
|
||||||
return( ret );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* POLARSSL_SELF_TEST */
|
#endif
|
||||||
|
|
||||||
#endif /* POLARSSL_SHA1_C */
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,9 +3,12 @@
|
||||||
*
|
*
|
||||||
* \brief SHA-1 cryptographic hash function
|
* \brief SHA-1 cryptographic hash function
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
|
* Copyright (C) 2006-2013, Brainspark B.V.
|
||||||
*
|
*
|
||||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
* This file is part of PolarSSL (http://www.polarssl.org)
|
||||||
|
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -24,31 +27,11 @@
|
||||||
#ifndef POLARSSL_SHA1_H
|
#ifndef POLARSSL_SHA1_H
|
||||||
#define POLARSSL_SHA1_H
|
#define POLARSSL_SHA1_H
|
||||||
|
|
||||||
#if !defined(POLARSSL_CONFIG_FILE)
|
#include "polarssl_config.h"
|
||||||
//#include "config.h"
|
|
||||||
/**
|
|
||||||
* \def POLARSSL_SHA1_C
|
|
||||||
*
|
|
||||||
* Enable the SHA1 cryptographic hash algorithm.
|
|
||||||
*
|
|
||||||
* Module: library/sha1.c
|
|
||||||
* Caller: library/md.c
|
|
||||||
* library/ssl_cli.c
|
|
||||||
* library/ssl_srv.c
|
|
||||||
* library/ssl_tls.c
|
|
||||||
* library/x509write_crt.c
|
|
||||||
*
|
|
||||||
* This module is required for SSL/TLS and SHA1-signed certificates.
|
|
||||||
*/
|
|
||||||
#define POLARSSL_SHA1_C
|
|
||||||
|
|
||||||
#else
|
#include <string.h>
|
||||||
#include POLARSSL_CONFIG_FILE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
|
|
||||||
#include <basetsd.h>
|
#include <basetsd.h>
|
||||||
typedef UINT32 uint32_t;
|
typedef UINT32 uint32_t;
|
||||||
#else
|
#else
|
||||||
|
@ -61,10 +44,6 @@ typedef UINT32 uint32_t;
|
||||||
// Regular implementation
|
// Regular implementation
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief SHA-1 context structure
|
* \brief SHA-1 context structure
|
||||||
*/
|
*/
|
||||||
|
@ -79,19 +58,9 @@ typedef struct
|
||||||
}
|
}
|
||||||
sha1_context;
|
sha1_context;
|
||||||
|
|
||||||
/**
|
#ifdef __cplusplus
|
||||||
* \brief Initialize SHA-1 context
|
extern "C" {
|
||||||
*
|
#endif
|
||||||
* \param ctx SHA-1 context to be initialized
|
|
||||||
*/
|
|
||||||
void sha1_init( sha1_context *ctx );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Clear SHA-1 context
|
|
||||||
*
|
|
||||||
* \param ctx SHA-1 context to be cleared
|
|
||||||
*/
|
|
||||||
void sha1_free( sha1_context *ctx );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief SHA-1 context setup
|
* \brief SHA-1 context setup
|
||||||
|
@ -158,8 +127,7 @@ int sha1_file( const char *path, unsigned char output[20] );
|
||||||
* \param key HMAC secret key
|
* \param key HMAC secret key
|
||||||
* \param keylen length of the HMAC key
|
* \param keylen length of the HMAC key
|
||||||
*/
|
*/
|
||||||
void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key,
|
void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen );
|
||||||
size_t keylen );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief SHA-1 HMAC process buffer
|
* \brief SHA-1 HMAC process buffer
|
||||||
|
@ -168,8 +136,7 @@ void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key,
|
||||||
* \param input buffer holding the data
|
* \param input buffer holding the data
|
||||||
* \param ilen length of the input data
|
* \param ilen length of the input data
|
||||||
*/
|
*/
|
||||||
void sha1_hmac_update( sha1_context *ctx, const unsigned char *input,
|
void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen );
|
||||||
size_t ilen );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief SHA-1 HMAC final digest
|
* \brief SHA-1 HMAC final digest
|
Loading…
Add table
Add a link
Reference in a new issue