From d03fb293bce1b06d49fb9faf5c492a1e2effc24b Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko Date: Sat, 23 Dec 2017 17:46:43 +0200 Subject: [PATCH] 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 --- CHANGELOG.md | 2 + client/Makefile | 16 +- client/emv/capk.txt | 32 + client/emv/cmdemv.c | 117 +- client/emv/cmdemv.h | 1 + client/emv/crypto.c | 179 +++ client/emv/crypto.h | 48 + client/emv/crypto_backend.h | 50 + client/emv/crypto_polarssl.c | 351 +++++ client/emv/emv_pk.c | 524 +++++++ client/emv/emv_pk.h | 48 + client/emv/emv_pki.c | 511 +++++++ client/emv/emv_pki.h | 45 + client/emv/emv_pki_priv.c | 283 ++++ client/emv/emv_pki_priv.h | 35 + client/emv/emv_tags.c | 2 + client/emv/emvcore.c | 382 ++++- client/emv/emvcore.h | 18 +- client/emv/test/cda_test.c | 442 ++++++ client/emv/test/cda_test.h | 18 + client/emv/test/crypto_test.c | 327 +++++ client/emv/test/crypto_test.h | 18 + client/emv/test/cryptotest.c | 65 + client/emv/test/cryptotest.h | 13 + client/emv/test/dda_test.c | 390 ++++++ client/emv/test/dda_test.h | 18 + client/emv/test/sda_test.c | 277 ++++ client/emv/test/sda_test.h | 16 + client/obj/emv/test/.dummy | 0 client/scripting.c | 4 +- common/polarssl/aes.h | 1 - common/polarssl/bignum.c | 2143 +++++++++++++++++++++++++++++ common/polarssl/bignum.h | 685 +++++++++ common/polarssl/bn_mul.h | 864 ++++++++++++ common/polarssl/des.c | 2 +- common/polarssl/polarssl_config.h | 4 +- common/polarssl/rsa.c | 1466 ++++++++++++++++++++ common/polarssl/rsa.h | 597 ++++++++ common/{ => polarssl}/sha1.c | 119 +- common/{ => polarssl}/sha1.h | 59 +- 40 files changed, 9982 insertions(+), 190 deletions(-) create mode 100644 client/emv/capk.txt create mode 100644 client/emv/crypto.c create mode 100644 client/emv/crypto.h create mode 100644 client/emv/crypto_backend.h create mode 100644 client/emv/crypto_polarssl.c create mode 100644 client/emv/emv_pk.c create mode 100644 client/emv/emv_pk.h create mode 100644 client/emv/emv_pki.c create mode 100644 client/emv/emv_pki.h create mode 100644 client/emv/emv_pki_priv.c create mode 100644 client/emv/emv_pki_priv.h create mode 100644 client/emv/test/cda_test.c create mode 100644 client/emv/test/cda_test.h create mode 100644 client/emv/test/crypto_test.c create mode 100644 client/emv/test/crypto_test.h create mode 100644 client/emv/test/cryptotest.c create mode 100644 client/emv/test/cryptotest.h create mode 100644 client/emv/test/dda_test.c create mode 100644 client/emv/test/dda_test.h create mode 100644 client/emv/test/sda_test.c create mode 100644 client/emv/test/sda_test.h create mode 100644 client/obj/emv/test/.dummy create mode 100644 common/polarssl/bignum.c create mode 100644 common/polarssl/bignum.h create mode 100644 common/polarssl/bn_mul.h create mode 100644 common/polarssl/rsa.c create mode 100644 common/polarssl/rsa.h rename common/{ => polarssl}/sha1.c (87%) rename common/{ => polarssl}/sha1.h (81%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 644f6c0f..4162c638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 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` 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] diff --git a/client/Makefile b/client/Makefile index ec593558..52a106bd 100644 --- a/client/Makefile +++ b/client/Makefile @@ -20,7 +20,7 @@ OBJDIR = obj LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm LUALIB = ../liblua/liblua.a 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 LUAPLATFORM = generic @@ -88,6 +88,9 @@ CMDSRCS = crapto1/crapto1.c\ crapto1/crypto1.c\ polarssl/des.c \ polarssl/aes.c\ + polarssl/bignum.c\ + polarssl/rsa.c\ + polarssl/sha1.c\ mfkey.c\ loclass/cipher.c \ loclass/cipherutils.c \ @@ -107,12 +110,22 @@ CMDSRCS = crapto1/crapto1.c\ ui.c \ cmddata.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/dump.c\ emv/tlv.c\ emv/emv_tags.c\ emv/dol.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\ cmdhf.c \ cmdhf14a.c \ @@ -157,7 +170,6 @@ CMDSRCS = crapto1/crapto1.c\ pm3_binlib.c\ pm3_bitlib.c\ protocols.c\ - sha1.c\ cmdcrc.c\ reveng/reveng.c\ reveng/cli.c\ diff --git a/client/emv/capk.txt b/client/emv/capk.txt new file mode 100644 index 00000000..0925fbad --- /dev/null +++ b/client/emv/capk.txt @@ -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 diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 92ae01f9..42c8524a 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include "cmdemv.h" +#include "test/cryptotest.h" int UsageCmdHFEMVSelect(void) { PrintAndLog("HELP : Executes select applet command:\n"); @@ -277,7 +278,7 @@ int CmdHFEMVPPSE(const char *cmd) { int UsageCmdHFEMVExec(void) { 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(" -s : select card"); 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(" -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(" -g : VISA. generate AC from GPO\n"); PrintAndLog("By default : transaction type - MSD.\n"); PrintAndLog("Samples:"); - PrintAndLog(" hf emv pse -s -> select card"); - PrintAndLog(" hf emv pse -s -t -a -> select card, show responses in TLV, show APDU"); + PrintAndLog(" hf emv exec -s -a -t -> execute MSD transaction"); + PrintAndLog(" hf emv exec -s -a -t -c -> execute CDA transaction"); return 0; } #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) { bool activateField = false; @@ -301,15 +304,22 @@ int CmdHFEMVExec(const char *cmd) { bool decodeTLV = false; bool forceSearch = false; enum TransactionType TrType = TT_MSD; + bool GenACGPO = false; uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; uint8_t AID[APDU_AID_LEN] = {0}; size_t AIDlen = 0; + uint8_t ODAiList[4096]; + size_t ODAiListLen = 0; int res; + struct tlvdb *tlvSelect = NULL; + struct tlvdb *tlvRoot = NULL; + struct tlv *pdol_data_tlv = NULL; + if (strlen(cmd) < 1) { UsageCmdHFEMVExec(); return 0; @@ -352,6 +362,10 @@ int CmdHFEMVExec(const char *cmd) { case 'C': TrType = TT_CDA; break; + case 'g': + case 'G': + GenACGPO = true; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp)); return 1; @@ -361,7 +375,6 @@ int CmdHFEMVExec(const char *cmd) { // init applets list tree - struct tlvdb *tlvSelect = NULL; const char *al = "Applets list"; 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."); SetAPDULogging(false); if (EMVSearch(activateField, true, decodeTLV, tlvSelect)) { - tlvdb_free(tlvSelect); - return 2; + dreturn(2); } // check search and select application id @@ -395,14 +407,13 @@ int CmdHFEMVExec(const char *cmd) { } // Init TLV tree - struct tlvdb *tlvRoot = NULL; const char *alr = "Root terminal TLV tree"; tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); // check if we found EMV application on card if (!AIDlen) { PrintAndLog("Can't select AID. EMV AID not found"); - return 2; + dreturn(2); } // Select @@ -412,7 +423,7 @@ int CmdHFEMVExec(const char *cmd) { if (res) { PrintAndLog("Can't select AID (%d). Exit...", res); - return 3; + dreturn(3); } if (decodeTLV) @@ -422,25 +433,30 @@ int CmdHFEMVExec(const char *cmd) { PrintAndLog("\n* Init transaction parameters."); //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 + char *qVSDC = "\x26\x00\x00\x00"; + if (GenACGPO) { + qVSDC = "\x26\x80\x00\x00"; + } switch(TrType) { case TT_MSD: TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD break; - // not standart for contactless. just for test. + // not standard for contactless. just for test. case TT_VSDC: TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC break; case TT_QVSDCMCHIP: - TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC + TLV_ADD(0x9F66, qVSDC); // qVSDC break; case TT_CDA: - TLV_ADD(0x9F66, "\x86\x80\x00\x00"); // CDA + TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled) break; default: TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC break; } - //9F02:(Amount, Authorised (Numeric)) len:6 + + //9F02:(Amount, authorized (Numeric)) len:6 TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00"); //9F1A:(Terminal Country Code) len:2 TLV_ADD(0x9F1A, "ru"); @@ -459,17 +475,17 @@ int CmdHFEMVExec(const char *cmd) { TLVPrintFromTLV(tlvRoot); // TODO delete!!! 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){ PrintAndLog("ERROR: can't create PDOL TLV."); - return 4; + dreturn(4); } size_t 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) { 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)); @@ -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); free(pdol_data_tlv_data); - free(pdol_data_tlv); + //free(pdol_data_tlv); --- free on exit. if (res) { 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] @@ -567,9 +583,23 @@ int CmdHFEMVExec(const char *cmd) { PrintAndLog(""); } + // Build Input list for Offline Data Authentication + // EMV 4.3 book3 10.3, page 96 if (SFIoffline) { - // here will be offline records storing... - // dont foget: if (sfi < 11) + 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; } + // 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 const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL); uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100; @@ -585,13 +622,13 @@ int CmdHFEMVExec(const char *cmd) { // SDA if (AIP & 0x0040) { PrintAndLog("\n* SDA"); - trSDA(AID, AIDlen, tlvRoot); + trSDA(tlvRoot); } // DDA if (AIP & 0x0020) { PrintAndLog("\n* DDA"); - + trDDA(decodeTLV, tlvRoot); } // transaction check @@ -644,11 +681,11 @@ int CmdHFEMVExec(const char *cmd) { res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLog("ERROR GetChallenge. APDU error %4x", sw); - return 5; + dreturn(6); } if (len < 4) { PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len); - return 5; + dreturn(6); } // 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 if (!cdol_data_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)); @@ -671,17 +708,25 @@ int CmdHFEMVExec(const char *cmd) { // 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); - free(cdol_data_tlv); - if (res) { PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw); - return 5; + dreturn(7); } if (decodeTLV) 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) const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL); 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 if (!udol_data_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)); @@ -753,24 +798,27 @@ int CmdHFEMVExec(const char *cmd) { res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw); - return 5; + free(udol_data_tlv); + dreturn(9); } if (decodeTLV) { TLVPrintFromBuffer(buf, len); PrintAndLog(""); } + free(udol_data_tlv); } } else { PrintAndLog("ERROR MSD: Track2 data not found."); } } - + // DropField DropField(); // Destroy TLV's + free(pdol_data_tlv); tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); @@ -779,6 +827,10 @@ int CmdHFEMVExec(const char *cmd) { return 0; } +int CmdHFEMVTest(const char *cmd) { + return ExecuteCryptoTests(true); +} + int CmdHelp(const char *Cmd); static command_t CommandTable[] = { {"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."}, {"search", CmdHFEMVSearch, 0, "Try to select all applets from applets list and print installed applets."}, {"select", CmdHFEMVSelect, 0, "Select applet."}, + {"test", CmdHFEMVTest, 0, "Crypto logic test."}, {NULL, NULL, 0, NULL} }; diff --git a/client/emv/cmdemv.h b/client/emv/cmdemv.h index 78796efa..b3f76508 100644 --- a/client/emv/cmdemv.h +++ b/client/emv/cmdemv.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" diff --git a/client/emv/crypto.c b/client/emv/crypto.c new file mode 100644 index 00000000..c8ced6d4 --- /dev/null +++ b/client/emv/crypto.c @@ -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 +#endif + +#include "crypto.h" +#include "crypto_backend.h" + +#include + +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); +} diff --git a/client/emv/crypto.h b/client/emv/crypto.h new file mode 100644 index 00000000..940e8b2b --- /dev/null +++ b/client/emv/crypto.h @@ -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 +#include + +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 diff --git a/client/emv/crypto_backend.h b/client/emv/crypto_backend.h new file mode 100644 index 00000000..a815ae11 --- /dev/null +++ b/client/emv/crypto_backend.h @@ -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 +#include + +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 diff --git a/client/emv/crypto_polarssl.c b/client/emv/crypto_polarssl.c new file mode 100644 index 00000000..760395c4 --- /dev/null +++ b/client/emv/crypto_polarssl.c @@ -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 +#endif + +#include "crypto.h" +#include "crypto_backend.h" + +#include +#include +#include + +#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; +} diff --git a/client/emv/emv_pk.c b/client/emv/emv_pk.c new file mode 100644 index 00000000..b577855e --- /dev/null +++ b/client/emv/emv_pk.c @@ -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 +#endif + +/* For asprintf */ +#define _GNU_SOURCE +#include + +#include "emv_pk.h" +#include "crypto.h" +#include "proxmark3.h" + +#include +#include +#include +#include + +#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; +} diff --git a/client/emv/emv_pk.h b/client/emv/emv_pk.h new file mode 100644 index 00000000..e291a065 --- /dev/null +++ b/client/emv/emv_pk.h @@ -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 +#include + +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 diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c new file mode 100644 index 00000000..7803060e --- /dev/null +++ b/client/emv/emv_pki.c @@ -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 +#endif + +#include "emv_pki.h" +#include "crypto.h" +#include "dump.h" +#include "util.h" + +#include +#include +#include +#include + +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; +} diff --git a/client/emv/emv_pki.h b/client/emv/emv_pki.h new file mode 100644 index 00000000..e37e3c7d --- /dev/null +++ b/client/emv/emv_pki.h @@ -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 + +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 diff --git a/client/emv/emv_pki_priv.c b/client/emv/emv_pki_priv.c new file mode 100644 index 00000000..d67a8705 --- /dev/null +++ b/client/emv/emv_pki_priv.c @@ -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 +#endif + +#include "emv_pki_priv.h" +#include "crypto.h" + +#include +#include +#include + +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; +} diff --git a/client/emv/emv_pki_priv.h b/client/emv/emv_pki_priv.h new file mode 100644 index 00000000..4f1639d5 --- /dev/null +++ b/client/emv/emv_pki_priv.h @@ -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 + +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 diff --git a/client/emv/emv_tags.c b/client/emv/emv_tags.c index 25ad9658..cdd57cb5 100644 --- a/client/emv/emv_tags.c +++ b/client/emv/emv_tags.c @@ -177,6 +177,7 @@ static const struct emv_tag emv_tags[] = { { 0x01 , "", EMV_TAG_STRING }, // string for headers { 0x02 , "Raw data", }, // data { 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 { 0x41 , "Country code and national data" }, @@ -266,6 +267,7 @@ static const struct emv_tag emv_tags[] = { { 0x9f65, "PCVC3(Track2)" }, { 0x9f66, "PUNATC(Track2) / Terminal Transaction Qualifiers (TTQ)", EMV_TAG_BITMASK, &EMV_TTQ }, { 0x9f67, "NATC(Track2) / MSD Offset" }, + { 0x9f68, "Cardholder verification method list (PayPass)" }, { 0x9f69, "Card Authentication Related Data" }, { 0x9f6a, "Unpredictable Number", EMV_TAG_NUMERIC }, { 0x9f6b, "Track 2 Data" }, diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 36438413..08c6e3db 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -16,7 +16,7 @@ static const char *PSElist [] = { "325041592E5359532E4444463031", // 2PAY.SYS.DDF01 - Visa Proximity Payment System Environment - PPSE "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 { 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); } +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) { return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } // Authentication -int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) { - if (AIDlen < 5) - return 1; - - // Get public key index (0x8F) - //int PubKeyIndx = 0; - - // Get public key from key storage - // GetPublicKey(AID(0..5), PubKeyIndx) - - // Processing of Issuer Public Key Certificate (0x90) - //Certificate = - - // check issuer public key certificate +static struct emv_pk *get_ca_pk(struct tlvdb *db) { + const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL); + const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL); + + if (!df_tlv || !caidx_tlv || df_tlv->len < 6 || caidx_tlv->len != 1) + return NULL; + + PrintAndLog("CA public key index 0x%0x", caidx_tlv->value[0]); + return emv_pk_get_ca_pk(df_tlv->value, caidx_tlv->value[0]); +} + +int trSDA(struct tlvdb *tlv) { + + 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; + } + + 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] + ); + + 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; + } - // get 9F4A Static Data Authentication Tag List + 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; + } - // set Data Auth Code (9F45) from SSAD + emv_pk_free(issuer_pk); + emv_pk_free(pk); + 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; +} diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index 7df58850..94be4fcf 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -20,11 +20,13 @@ #include "common.h" #include "ui.h" #include "cmdhf14a.h" -#include "emv/apduinfo.h" -#include "emv/tlv.h" -#include "emv/dol.h" -#include "emv/dump.h" -#include "emv/emv_tags.h" +#include "apduinfo.h" +#include "tlv.h" +#include "dol.h" +#include "dump.h" +#include "emv_tags.h" +#include "emv_pk.h" +#include "emv_pki.h" #define APDU_RES_LEN 260 #define APDU_AID_LEN 50 @@ -79,10 +81,14 @@ extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t // AC 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); +// 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 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 -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 diff --git a/client/emv/test/cda_test.c b/client/emv/test/cda_test.c new file mode 100644 index 00000000..536a5862 --- /dev/null +++ b/client/emv/test/cda_test.c @@ -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 +#endif + +#include "../emv_pk.h" +#include "../crypto.h" +#include "../dump.h" +#include "../tlv.h" +#include "../emv_pki.h" + +#include +#include +#include + +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; +} diff --git a/client/emv/test/cda_test.h b/client/emv/test/cda_test.h new file mode 100644 index 00000000..1d321a26 --- /dev/null +++ b/client/emv/test/cda_test.h @@ -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 + +extern int exec_cda_test(bool verbose); diff --git a/client/emv/test/crypto_test.c b/client/emv/test/crypto_test.c new file mode 100644 index 00000000..ff18b9da --- /dev/null +++ b/client/emv/test/crypto_test.c @@ -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 +#endif + +#include "../crypto.h" +#include "../dump.h" +#include "util_posix.h" + +#include +#include +#include + +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; +} diff --git a/client/emv/test/crypto_test.h b/client/emv/test/crypto_test.h new file mode 100644 index 00000000..084bc991 --- /dev/null +++ b/client/emv/test/crypto_test.h @@ -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 + +extern int exec_crypto_test(bool verbose); diff --git a/client/emv/test/cryptotest.c b/client/emv/test/cryptotest.c new file mode 100644 index 00000000..a6d06e68 --- /dev/null +++ b/client/emv/test/cryptotest.c @@ -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; +} + diff --git a/client/emv/test/cryptotest.h b/client/emv/test/cryptotest.h new file mode 100644 index 00000000..5c6aaae2 --- /dev/null +++ b/client/emv/test/cryptotest.h @@ -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 + +extern int ExecuteCryptoTests(bool verbose); diff --git a/client/emv/test/dda_test.c b/client/emv/test/dda_test.c new file mode 100644 index 00000000..afdd4e20 --- /dev/null +++ b/client/emv/test/dda_test.c @@ -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 +#endif + +#include "dda_test.h" + +#include "../emv_pk.h" +#include "../crypto.h" +#include "../dump.h" +#include "../tlv.h" +#include "../emv_pki.h" + +#include +#include +#include + +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; +} diff --git a/client/emv/test/dda_test.h b/client/emv/test/dda_test.h new file mode 100644 index 00000000..354cd7e1 --- /dev/null +++ b/client/emv/test/dda_test.h @@ -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 + +extern int exec_dda_test(bool verbose); diff --git a/client/emv/test/sda_test.c b/client/emv/test/sda_test.c new file mode 100644 index 00000000..2aafcf19 --- /dev/null +++ b/client/emv/test/sda_test.c @@ -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 +#endif + +#include "../emv_pk.h" +#include "../crypto.h" +#include "../dump.h" +#include "../tlv.h" +#include "../emv_pki.h" + +#include +#include +#include + +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; +} diff --git a/client/emv/test/sda_test.h b/client/emv/test/sda_test.h new file mode 100644 index 00000000..43a4c948 --- /dev/null +++ b/client/emv/test/sda_test.h @@ -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); diff --git a/client/obj/emv/test/.dummy b/client/obj/emv/test/.dummy new file mode 100644 index 00000000..e69de29b diff --git a/client/scripting.c b/client/scripting.c index 13cb8cdf..3859fd48 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -23,8 +23,8 @@ #include "iso14443crc.h" #include "../common/crc16.h" #include "../common/crc64.h" -#include "../common/sha1.h" -#include "polarssl/aes.h" +#include "../common/polarssl/sha1.h" +#include "../common/polarssl/aes.h" #include "cmdcrc.h" /** * The following params expected: diff --git a/common/polarssl/aes.h b/common/polarssl/aes.h index 946bd87d..299cb4cd 100644 --- a/common/polarssl/aes.h +++ b/common/polarssl/aes.h @@ -125,7 +125,6 @@ int aes_crypt_ecb( aes_context *ctx, int mode, const unsigned char input[16], unsigned char output[16] ); - #if defined(POLARSSL_CIPHER_MODE_CBC) /** * \brief AES-CBC buffer encryption/decryption diff --git a/common/polarssl/bignum.c b/common/polarssl/bignum.c new file mode 100644 index 00000000..d22dd5c7 --- /dev/null +++ b/common/polarssl/bignum.c @@ -0,0 +1,2143 @@ +/* + * 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 + * + * 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. + */ +/* + * This MPI implementation is based on: + * + * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf + * http://www.stillhq.com/extracted/gnupg-api/mpi/ + * http://math.libtomcrypt.com/files/tommath.pdf + */ + +#include "polarssl_config.h" + +#if defined(POLARSSL_BIGNUM_C) + +#include "bignum.h" +#include "bn_mul.h" + +#include + +#define ciL (sizeof(t_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +/* + * Convert between bits/chars and number of limbs + */ +#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) +#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) + +/* + * Initialize one MPI + */ +void mpi_init( mpi *X ) +{ + if( X == NULL ) + return; + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Unallocate one MPI + */ +void mpi_free( mpi *X ) +{ + if( X == NULL ) + return; + + if( X->p != NULL ) + { + memset( X->p, 0, X->n * ciL ); + free( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Enlarge to the specified number of limbs + */ +int mpi_grow( mpi *X, size_t nblimbs ) +{ + t_uint *p; + + if( nblimbs > POLARSSL_MPI_MAX_LIMBS ) + return( POLARSSL_ERR_MPI_MALLOC_FAILED ); + + if( X->n < nblimbs ) + { + if( ( p = (t_uint *) malloc( nblimbs * ciL ) ) == NULL ) + return( POLARSSL_ERR_MPI_MALLOC_FAILED ); + + memset( p, 0, nblimbs * ciL ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + memset( X->p, 0, X->n * ciL ); + free( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mpi_copy( mpi *X, const mpi *Y ) +{ + int ret; + size_t i; + + if( X == Y ) + return( 0 ); + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + MPI_CHK( mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * ciL ); + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mpi_swap( mpi *X, mpi *Y ) +{ + mpi T; + + memcpy( &T, X, sizeof( mpi ) ); + memcpy( X, Y, sizeof( mpi ) ); + memcpy( Y, &T, sizeof( mpi ) ); +} + +/* + * Set value from integer + */ +int mpi_lset( mpi *X, t_sint z ) +{ + int ret; + + MPI_CHK( mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Get a specific bit + */ +int mpi_get_bit( const mpi *X, size_t pos ) +{ + if( X->n * biL <= pos ) + return( 0 ); + + return ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01; +} + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + + if( val != 0 && val != 1 ) + return POLARSSL_ERR_MPI_BAD_INPUT_DATA; + + if( X->n * biL <= pos ) + { + if( val == 0 ) + return ( 0 ); + + MPI_CHK( mpi_grow( X, off + 1 ) ); + } + + X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx ); + +cleanup: + + return( ret ); +} + +/* + * Return the number of least significant bits + */ +size_t mpi_lsb( const mpi *X ) +{ + size_t i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Return the number of most significant bits + */ +size_t mpi_msb( const mpi *X ) +{ + size_t i, j; + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = biL; j > 0; j-- ) + if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 ) + break; + + return( ( i * biL ) + j ); +} + +/* + * Return the total size in bytes + */ +size_t mpi_size( const mpi *X ) +{ + return( ( mpi_msb( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( t_uint *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (t_uint) radix ) + return( POLARSSL_ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mpi_read_string( mpi *X, int radix, const char *s ) +{ + int ret; + size_t i, j, slen, n; + t_uint d; + mpi T; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &T ); + + slen = strlen( s ); + + if( radix == 16 ) + { + n = BITS_TO_LIMBS( slen << 2 ); + + MPI_CHK( mpi_grow( X, n ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = slen, j = 0; i > 0; i--, j++ ) + { + if( i == 1 && s[i - 1] == '-' ) + { + X->s = -1; + break; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); + X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 ); + } + } + else + { + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = 0; i < slen; i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MPI_CHK( mpi_mul_int( &T, X, radix ) ); + + if( X->s == 1 ) + { + MPI_CHK( mpi_add_int( X, &T, d ) ); + } + else + { + MPI_CHK( mpi_sub_int( X, &T, d ) ); + } + } + } + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first + */ +static int mpi_write_hlp( mpi *X, int radix, char **p ) +{ + int ret; + t_uint r; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + MPI_CHK( mpi_mod_int( &r, X, radix ) ); + MPI_CHK( mpi_div_int( X, NULL, X, radix ) ); + + if( mpi_cmp_int( X, 0 ) != 0 ) + MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ) +{ + int ret = 0; + size_t n; + char *p; + mpi T; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + n = mpi_msb( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + n += 3; + + if( *slen < n ) + { + *slen = n; + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = s; + mpi_init( &T ); + + if( X->s == -1 ) + *p++ = '-'; + + if( radix == 16 ) + { + int c; + size_t i, j, k; + + for( i = X->n, k = 0; i > 0; i-- ) + { + for( j = ciL; j > 0; j-- ) + { + c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; + + if( c == 0 && k == 0 && ( i + j + 3 ) != 0 ) + continue; + + *(p++) = "0123456789ABCDEF" [c / 16]; + *(p++) = "0123456789ABCDEF" [c % 16]; + k = 1; + } + } + } + else + { + MPI_CHK( mpi_copy( &T, X ) ); + + if( T.s == -1 ) + T.s = 1; + + MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); + } + + *p++ = '\0'; + *slen = p - s; + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +#if defined(POLARSSL_FS_IO) +/* + * Read X from an opened file + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ) +{ + t_uint d; + size_t slen; + char *p; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ POLARSSL_MPI_RW_BUFFER_SIZE ]; + + memset( s, 0, sizeof( s ) ); + if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) + return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); + + slen = strlen( s ); + if( slen == sizeof( s ) - 2 ) + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + + if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } + if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } + + p = s + slen; + while( --p >= s ) + if( mpi_get_digit( &d, radix, *p ) != 0 ) + break; + + return( mpi_read_string( X, radix, p + 1 ) ); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ) +{ + int ret; + size_t n, slen, plen; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ POLARSSL_MPI_RW_BUFFER_SIZE ]; + + n = sizeof( s ); + memset( s, 0, n ); + n -= 2; + + MPI_CHK( mpi_write_string( X, radix, s, (size_t *) &n ) ); + + if( p == NULL ) p = ""; + + plen = strlen( p ); + slen = strlen( s ); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if( fout != NULL ) + { + if( fwrite( p, 1, plen, fout ) != plen || + fwrite( s, 1, slen, fout ) != slen ) + return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); + } + else + printf( "%s%s", p, s ); + +cleanup: + + return( ret ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * Import X from unsigned binary data, big endian + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = buflen, j = 0; i > n; i--, j++ ) + X->p[j / ciL] |= ((t_uint) buf[i - 1]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ) +{ + size_t i, j, n; + + n = mpi_size( X ); + + if( buflen < n ) + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mpi_shift_l( mpi *X, size_t count ) +{ + int ret; + size_t i, v0, t1; + t_uint r0 = 0, r1; + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mpi_msb( X ) + count; + + if( X->n * biL < i ) + MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n; i > v0; i-- ) + X->p[i - 1] = X->p[i - v0 - 1]; + + for( ; i > 0; i-- ) + X->p[i - 1] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mpi_shift_r( mpi *X, size_t count ) +{ + size_t i, v0, v1; + t_uint r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) + return mpi_lset( X, 0 ); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n; i > 0; i-- ) + { + r1 = X->p[i - 1] << (biL - v1); + X->p[i - 1] >>= v1; + X->p[i - 1] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -Y->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_int( const mpi *X, t_sint z ) +{ + mpi Y; + t_uint p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + t_uint *o, *p, c; + + if( X == B ) + { + const mpi *T = A; A = X; B = T; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned additions. + */ + X->s = 1; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, j ) ); + + o = B->p; p = X->p; c = 0; + + for( i = 0; i < j; i++, o++, p++ ) + { + *p += c; c = ( *p < c ); + *p += *o; c += ( *p < *o ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MPI_CHK( mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; p++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mpi substraction + */ +static void mpi_sub_hlp( size_t n, t_uint *s, t_uint *d ) +{ + size_t i; + t_uint c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; i++; d++; + } +} + +/* + * Unsigned substraction: X = |A| - |B| (HAC 14.9) + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ) +{ + mpi TB; + int ret; + size_t n; + + if( mpi_cmp_abs( A, B ) < 0 ) + return( POLARSSL_ERR_MPI_NEGATIVE_VALUE ); + + mpi_init( &TB ); + + if( X == B ) + { + MPI_CHK( mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned substractions. + */ + X->s = 1; + + ret = 0; + + for( n = B->n; n > 0; n-- ) + if( B->p[n - 1] != 0 ) + break; + + mpi_sub_hlp( n, B->p, X->p ); + +cleanup: + + mpi_free( &TB ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed substraction: X = A - B + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mpi_add_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed substraction: X = A - b + */ +int mpi_sub_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mpi multiplication + */ +static +#if defined(__APPLE__) && defined(__arm__) +/* + * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) + * appears to need this to prevent bad ARM code generation at -O3. + */ +__attribute__ ((noinline)) +#endif +void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b ) +{ + t_uint c = 0, t = 0; + +#if defined(MULADDC_HUIT) + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#else + for( ; i >= 16; i -= 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#endif + + t++; + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + mpi TA, TB; + + mpi_init( &TA ); mpi_init( &TB ); + + if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n; i > 0; i-- ) + if( A->p[i - 1] != 0 ) + break; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, i + j ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i++; j > 0; j-- ) + mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] ); + + X->s = A->s * B->s; + +cleanup: + + mpi_free( &TB ); mpi_free( &TA ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mpi_mul_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Division by mpi: A = Q * B + R (HAC 14.20) + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, n, t, k; + mpi X, Y, Z, T1, T2; + + if( mpi_cmp_int( B, 0 ) == 0 ) + return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); + + mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z ); + mpi_init( &T1 ); mpi_init( &T2 ); + + if( mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) ); + if( R != NULL ) MPI_CHK( mpi_copy( R, A ) ); + return( 0 ); + } + + MPI_CHK( mpi_copy( &X, A ) ); + MPI_CHK( mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MPI_CHK( mpi_grow( &Z, A->n + 2 ) ); + MPI_CHK( mpi_lset( &Z, 0 ) ); + MPI_CHK( mpi_grow( &T1, 2 ) ); + MPI_CHK( mpi_grow( &T2, 3 ) ); + + k = mpi_msb( &Y ) % biL; + if( k < biL - 1 ) + { + k = biL - 1 - k; + MPI_CHK( mpi_shift_l( &X, k ) ); + MPI_CHK( mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + MPI_CHK( mpi_shift_l( &Y, biL * (n - t) ) ); + + while( mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + mpi_sub_mpi( &X, &X, &Y ); + } + mpi_shift_r( &Y, biL * (n - t) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { +#if defined(POLARSSL_HAVE_UDBL) + t_udbl r; + + r = (t_udbl) X.p[i] << biL; + r |= (t_udbl) X.p[i - 1]; + r /= Y.p[t]; + if( r > ((t_udbl) 1 << biL) - 1) + r = ((t_udbl) 1 << biL) - 1; + + Z.p[i - t - 1] = (t_uint) r; +#else + /* + * __udiv_qrnnd_c, from gmp/longlong.h + */ + t_uint q0, q1, r0, r1; + t_uint d0, d1, d, m; + + d = Y.p[t]; + d0 = ( d << biH ) >> biH; + d1 = ( d >> biH ); + + q1 = X.p[i] / d1; + r1 = X.p[i] - d1 * q1; + r1 <<= biH; + r1 |= ( X.p[i - 1] >> biH ); + + m = q1 * d0; + if( r1 < m ) + { + q1--, r1 += d; + while( r1 >= d && r1 < m ) + q1--, r1 += d; + } + r1 -= m; + + q0 = r1 / d1; + r0 = r1 - d1 * q0; + r0 <<= biH; + r0 |= ( X.p[i - 1] << biH ) >> biH; + + m = q0 * d0; + if( r0 < m ) + { + q0--, r0 += d; + while( r0 >= d && r0 < m ) + q0--, r0 += d; + } + r0 -= m; + + Z.p[i - t - 1] = ( q1 << biH ) | q0; +#endif + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MPI_CHK( mpi_lset( &T1, 0 ) ); + T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MPI_CHK( mpi_lset( &T2, 0 ) ); + T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; + T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mpi_cmp_int( &X, 0 ) < 0 ) + { + MPI_CHK( mpi_copy( &T1, &Y ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + mpi_copy( Q, &Z ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + mpi_shift_r( &X, k ); + X.s = A->s; + mpi_copy( R, &X ); + + if( mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z ); + mpi_free( &T1 ); mpi_free( &T2 ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + + if( mpi_cmp_int( B, 0 ) < 0 ) + return POLARSSL_ERR_MPI_NEGATIVE_VALUE; + + MPI_CHK( mpi_div_mpi( NULL, R, A, B ) ); + + while( mpi_cmp_int( R, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( R, R, B ) ); + + while( mpi_cmp_mpi( R, B ) >= 0 ) + MPI_CHK( mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ) +{ + size_t i; + t_uint x, y, z; + + if( b == 0 ) + return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + return POLARSSL_ERR_MPI_NEGATIVE_VALUE; + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n, y = 0; i > 0; i-- ) + { + x = A->p[i - 1]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if( A->s < 0 && y != 0 ) + y = b - y; + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( t_uint *mm, const mpi *N ) +{ + t_uint x, m0 = N->p[0]; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + x *= ( 2 - ( m0 * x ) ); + + if( biL >= 16 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 32 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 64 ) x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_uint mm, const mpi *T ) +{ + size_t i, n, m; + t_uint u0, u1, *d; + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, (n + 1) * ciL ); + + if( mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static void mpi_montred( mpi *A, const mpi *N, t_uint mm, const mpi *T ) +{ + t_uint z = 1; + mpi U; + + U.n = U.s = (int) z; + U.p = &z; + + mpi_montmul( A, &U, N, mm, T ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ) +{ + int ret; + size_t wbits, wsize, one = 1; + size_t i, j, nblimbs; + size_t bufsize, nbits; + t_uint ei, mm, state; + mpi RR, T, W[ 2 << POLARSSL_MPI_WINDOW_SIZE ], Apos; + int neg; + + if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + if( mpi_cmp_int( E, 0 ) < 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mpi_init( &RR ); mpi_init( &T ); + memset( W, 0, sizeof( W ) ); + + i = mpi_msb( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + if( wsize > POLARSSL_MPI_WINDOW_SIZE ) + wsize = POLARSSL_MPI_WINDOW_SIZE; + + j = N->n + 1; + MPI_CHK( mpi_grow( X, j ) ); + MPI_CHK( mpi_grow( &W[1], j ) ); + MPI_CHK( mpi_grow( &T, j * 2 ) ); + + /* + * Compensate for negative A (and correct at the end) + */ + neg = ( A->s == -1 ); + + mpi_init( &Apos ); + if( neg ) + { + MPI_CHK( mpi_copy( &Apos, A ) ); + Apos.s = 1; + A = &Apos; + } + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MPI_CHK( mpi_lset( &RR, 1 ) ); + MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); + MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mpi_cmp_mpi( A, N ) >= 0 ) + mpi_mod_mpi( &W[1], A, N ); + else mpi_copy( &W[1], A ); + + mpi_montmul( &W[1], &RR, N, mm, &T ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MPI_CHK( mpi_copy( X, &RR ) ); + mpi_montred( X, N, mm, &T ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = one << (wsize - 1); + + MPI_CHK( mpi_grow( &W[j], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + mpi_montmul( &W[j], &W[j], N, mm, &T ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < (one << wsize); i++ ) + { + MPI_CHK( mpi_grow( &W[i], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) ); + + mpi_montmul( &W[i], &W[1], N, mm, &T ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs-- == 0 ) + break; + + bufsize = sizeof( t_uint ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + mpi_montmul( X, X, N, mm, &T ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= (ei << (wsize - nbits)); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + mpi_montmul( X, X, N, mm, &T ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + mpi_montmul( X, &W[wbits], N, mm, &T ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + mpi_montmul( X, X, N, mm, &T ); + + wbits <<= 1; + + if( (wbits & (one << wsize)) != 0 ) + mpi_montmul( X, &W[1], N, mm, &T ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + mpi_montred( X, N, mm, &T ); + + if( neg ) + { + X->s = -1; + mpi_add_mpi( X, N, X ); + } + +cleanup: + + for( i = (one << (wsize - 1)); i < (one << wsize); i++ ) + mpi_free( &W[i] ); + + mpi_free( &W[1] ); mpi_free( &T ); mpi_free( &Apos ); + + if( _RR == NULL ) + mpi_free( &RR ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ) +{ + int ret; + size_t lz, lzt; + mpi TG, TA, TB; + + mpi_init( &TG ); mpi_init( &TA ); mpi_init( &TB ); + + MPI_CHK( mpi_copy( &TA, A ) ); + MPI_CHK( mpi_copy( &TB, B ) ); + + lz = mpi_lsb( &TA ); + lzt = mpi_lsb( &TB ); + + if ( lzt < lz ) + lz = lzt; + + MPI_CHK( mpi_shift_r( &TA, lz ) ); + MPI_CHK( mpi_shift_r( &TB, lz ) ); + + TA.s = TB.s = 1; + + while( mpi_cmp_int( &TA, 0 ) != 0 ) + { + MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) ); + MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) ); + + if( mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) ); + MPI_CHK( mpi_shift_r( &TA, 1 ) ); + } + else + { + MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) ); + MPI_CHK( mpi_shift_r( &TB, 1 ) ); + } + } + + MPI_CHK( mpi_shift_l( &TB, lz ) ); + MPI_CHK( mpi_copy( G, &TB ) ); + +cleanup: + + mpi_free( &TG ); mpi_free( &TA ); mpi_free( &TB ); + + return( ret ); +} + +int mpi_fill_random( mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + + MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + MPI_CHK( f_rng( p_rng, (unsigned char *) X->p, size ) ); + +cleanup: + return( ret ); +} + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ) +{ + int ret; + mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + + if( mpi_cmp_int( N, 0 ) <= 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 ); + mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV ); + mpi_init( &V1 ); mpi_init( &V2 ); + + MPI_CHK( mpi_gcd( &G, A, N ) ); + + if( mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MPI_CHK( mpi_mod_mpi( &TA, A, N ) ); + MPI_CHK( mpi_copy( &TU, &TA ) ); + MPI_CHK( mpi_copy( &TB, N ) ); + MPI_CHK( mpi_copy( &TV, N ) ); + + MPI_CHK( mpi_lset( &U1, 1 ) ); + MPI_CHK( mpi_lset( &U2, 0 ) ); + MPI_CHK( mpi_lset( &V1, 0 ) ); + MPI_CHK( mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &U1, 1 ) ); + MPI_CHK( mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &V1, 1 ) ); + MPI_CHK( mpi_shift_r( &V2, 1 ) ); + } + + if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); + MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); + MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mpi_cmp_int( &V1, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( &V1, &V1, N ) ); + + while( mpi_cmp_mpi( &V1, N ) >= 0 ) + MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) ); + + MPI_CHK( mpi_copy( X, &V1 ) ); + +cleanup: + + mpi_free( &TA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 ); + mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV ); + mpi_free( &V1 ); mpi_free( &V2 ); + + return( ret ); +} + +#if defined(POLARSSL_GENPRIME) + +static const int small_prime[] = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Miller-Rabin primality test (HAC 4.24) + */ +int mpi_is_prime( mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, xs; + size_t i, j, n, s; + mpi W, R, T, A, RR; + + if( mpi_cmp_int( X, 0 ) == 0 || + mpi_cmp_int( X, 1 ) == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + + if( mpi_cmp_int( X, 2 ) == 0 ) + return( 0 ); + + mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A ); + mpi_init( &RR ); + + xs = X->s; X->s = 1; + + /* + * test trivial factors first + */ + if( ( X->p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + t_uint r; + + if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 0 ); + + MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + } + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MPI_CHK( mpi_sub_int( &W, X, 1 ) ); + s = mpi_lsb( &W ); + MPI_CHK( mpi_copy( &R, &W ) ); + MPI_CHK( mpi_shift_r( &R, s ) ); + + i = mpi_msb( X ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + MPI_CHK( mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + if( mpi_cmp_mpi( &A, &W ) >= 0 ) + { + j = mpi_msb( &A ) - mpi_msb( &W ); + MPI_CHK( mpi_shift_r( &A, j + 1 ) ); + } + A.p[0] |= 3; + + /* + * A = A^R mod |X| + */ + MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mpi_cmp_mpi( &A, &W ) == 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MPI_CHK( mpi_mul_mpi( &T, &A, &A ) ); + MPI_CHK( mpi_mod_mpi( &A, &T, X ) ); + + if( mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mpi_cmp_mpi( &A, &W ) != 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + + X->s = xs; + + mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A ); + mpi_free( &RR ); + + return( ret ); +} + +/* + * Prime number generation + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t k, n; + mpi Y; + + if( nbits < 3 || nbits > POLARSSL_MPI_MAX_BITS ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + MPI_CHK( mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + + k = mpi_msb( X ); + if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) ); + if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) ); + + X->p[0] |= 3; + + if( dh_flag == 0 ) + { + while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + { + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( X, X, 2 ) ); + } + } + else + { + MPI_CHK( mpi_sub_int( &Y, X, 1 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 ) + { + if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 ) + break; + + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + } + + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( &Y, X, 1 ) ); + MPI_CHK( mpi_add_int( X, X, 2 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + } + } + +cleanup: + + mpi_free( &Y ); + + return( ret ); +} + +#endif + +#if defined(POLARSSL_SELF_TEST) + +#define GCD_PAIR_COUNT 3 + +static const int gcd_pairs[GCD_PAIR_COUNT][3] = +{ + { 693, 609, 21 }, + { 1764, 868, 28 }, + { 768454923, 542167814, 1 } +}; + +/* + * Checkup routine + */ +int mpi_self_test( int verbose ) +{ + int ret, i; + mpi A, E, N, X, Y, U, V; + + mpi_init( &A ); mpi_init( &E ); mpi_init( &N ); mpi_init( &X ); + mpi_init( &Y ); mpi_init( &U ); mpi_init( &V ); + + MPI_CHK( mpi_read_string( &A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); + + MPI_CHK( mpi_read_string( &E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E" ) ); + + MPI_CHK( mpi_read_string( &N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5" ) ); + + MPI_CHK( mpi_mul_mpi( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E" ) ); + + if( verbose != 0 ) + printf( " MPI test #1 (mul_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "256567336059E52CAE22925474705F39A94" ) ); + + MPI_CHK( mpi_read_string( &V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642" ) ); + + if( verbose != 0 ) + printf( " MPI test #2 (div_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 || + mpi_cmp_mpi( &Y, &V ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87" ) ); + + if( verbose != 0 ) + printf( " MPI test #3 (exp_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + +#if defined(POLARSSL_GENPRIME) + MPI_CHK( mpi_inv_mod( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); + + if( verbose != 0 ) + printf( " MPI test #4 (inv_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); +#endif + + if( verbose != 0 ) + printf( " MPI test #5 (simple gcd): " ); + + for ( i = 0; i < GCD_PAIR_COUNT; i++) + { + MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) ); + MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) ); + + MPI_CHK( mpi_gcd( &A, &X, &Y ) ); + + if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) + { + if( verbose != 0 ) + printf( "failed at %d\n", i ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + +cleanup: + + if( ret != 0 && verbose != 0 ) + printf( "Unexpected error, return code = %08X\n", ret ); + + mpi_free( &A ); mpi_free( &E ); mpi_free( &N ); mpi_free( &X ); + mpi_free( &Y ); mpi_free( &U ); mpi_free( &V ); + + if( verbose != 0 ) + printf( "\n" ); + + return( ret ); +} + +#endif + +#endif diff --git a/common/polarssl/bignum.h b/common/polarssl/bignum.h new file mode 100644 index 00000000..5eaf1a57 --- /dev/null +++ b/common/polarssl/bignum.h @@ -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 + * + * 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 +#include + +#include "polarssl_config.h" + +#ifdef _MSC_VER +#include +#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 +#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 */ diff --git a/common/polarssl/bn_mul.h b/common/polarssl/bn_mul.h new file mode 100644 index 00000000..1c2da136 --- /dev/null +++ b/common/polarssl/bn_mul.h @@ -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 + * + * 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 */ diff --git a/common/polarssl/des.c b/common/polarssl/des.c index 746752d7..b33deb6c 100644 --- a/common/polarssl/des.c +++ b/common/polarssl/des.c @@ -29,7 +29,7 @@ * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf */ -//#include "polarssl/config.h" +#include "polarssl_config.h" #define POLARSSL_DES_C #if defined(POLARSSL_DES_C) diff --git a/common/polarssl/polarssl_config.h b/common/polarssl/polarssl_config.h index 5bd88fc0..3d9a2f67 100644 --- a/common/polarssl/polarssl_config.h +++ b/common/polarssl/polarssl_config.h @@ -82,7 +82,7 @@ * * Comment to disable the use of assembly code. */ -#define POLARSSL_HAVE_ASM +//#define POLARSSL_HAVE_ASM /** * \def POLARSSL_HAVE_SSE2 @@ -762,7 +762,7 @@ * * This enables support for RSAES-OAEP and RSASSA-PSS operations. */ -#define POLARSSL_PKCS1_V21 +//#define POLARSSL_PKCS1_V21 /** * \def POLARSSL_RSA_NO_CRT diff --git a/common/polarssl/rsa.c b/common/polarssl/rsa.c new file mode 100644 index 00000000..9872274b --- /dev/null +++ b/common/polarssl/rsa.c @@ -0,0 +1,1466 @@ +/* + * The RSA public-key cryptosystem + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * 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. + */ +/* + * RSA was designed by Ron Rivest, Adi Shamir and Len Adleman. + * + * http://theory.lcs.mit.edu/~rivest/rsapaper.pdf + * http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf + */ + +#include "polarssl_config.h" + +#if defined(POLARSSL_RSA_C) + +#include "rsa.h" + +#if defined(POLARSSL_PKCS1_V21) +#include "md.h" +#endif + +#include +#include + +/* + * Initialize an RSA context + */ +void rsa_init( rsa_context *ctx, + int padding, + int hash_id ) +{ + memset( ctx, 0, sizeof( rsa_context ) ); + + ctx->padding = padding; + ctx->hash_id = hash_id; +} + +#if defined(POLARSSL_GENPRIME) + +/* + * Generate an RSA keypair + */ +int rsa_gen_key( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ) +{ + int ret; + mpi P1, Q1, H, G; + + if( f_rng == NULL || nbits < 128 || exponent < 3 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + mpi_init( &P1 ); mpi_init( &Q1 ); mpi_init( &H ); mpi_init( &G ); + + /* + * find primes P and Q with Q < P so that: + * GCD( E, (P-1)*(Q-1) ) == 1 + */ + MPI_CHK( mpi_lset( &ctx->E, exponent ) ); + + do + { + MPI_CHK( mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, + f_rng, p_rng ) ); + + MPI_CHK( mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0, + f_rng, p_rng ) ); + + if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) + mpi_swap( &ctx->P, &ctx->Q ); + + if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) + continue; + + MPI_CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); + if( mpi_msb( &ctx->N ) != nbits ) + continue; + + MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); + MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); + MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) ); + } + while( mpi_cmp_int( &G, 1 ) != 0 ); + + /* + * D = E^-1 mod ((P-1)*(Q-1)) + * DP = D mod (P - 1) + * DQ = D mod (Q - 1) + * QP = Q^-1 mod P + */ + MPI_CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); + MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); + MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); + MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); + + ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3; + +cleanup: + + mpi_free( &P1 ); mpi_free( &Q1 ); mpi_free( &H ); mpi_free( &G ); + + if( ret != 0 ) + { + rsa_free( ctx ); + return( POLARSSL_ERR_RSA_KEY_GEN_FAILED + ret ); + } + + return( 0 ); +} + +#endif + +/* + * Check a public RSA key + */ +int rsa_check_pubkey( const rsa_context *ctx ) +{ + if( !ctx->N.p || !ctx->E.p ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + if( ( ctx->N.p[0] & 1 ) == 0 || + ( ctx->E.p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + if( mpi_msb( &ctx->N ) < 128 || + mpi_msb( &ctx->N ) > POLARSSL_MPI_MAX_BITS ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + if( mpi_msb( &ctx->E ) < 2 || + mpi_msb( &ctx->E ) > 64 ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + return( 0 ); +} + +/* + * Check a private RSA key + */ +int rsa_check_privkey( const rsa_context *ctx ) +{ + int ret; + mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP; + + if( ( ret = rsa_check_pubkey( ctx ) ) != 0 ) + return( ret ); + + if( !ctx->P.p || !ctx->Q.p || !ctx->D.p ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + mpi_init( &PQ ); mpi_init( &DE ); mpi_init( &P1 ); mpi_init( &Q1 ); + mpi_init( &H ); mpi_init( &I ); mpi_init( &G ); mpi_init( &G2 ); + mpi_init( &L1 ); mpi_init( &L2 ); mpi_init( &DP ); mpi_init( &DQ ); + mpi_init( &QP ); + + MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) ); + MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) ); + MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); + MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); + MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) ); + + MPI_CHK( mpi_gcd( &G2, &P1, &Q1 ) ); + MPI_CHK( mpi_div_mpi( &L1, &L2, &H, &G2 ) ); + MPI_CHK( mpi_mod_mpi( &I, &DE, &L1 ) ); + + MPI_CHK( mpi_mod_mpi( &DP, &ctx->D, &P1 ) ); + MPI_CHK( mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) ); + MPI_CHK( mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) ); + /* + * Check for a valid PKCS1v2 private key + */ + if( mpi_cmp_mpi( &PQ, &ctx->N ) != 0 || + mpi_cmp_mpi( &DP, &ctx->DP ) != 0 || + mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 || + mpi_cmp_mpi( &QP, &ctx->QP ) != 0 || + mpi_cmp_int( &L2, 0 ) != 0 || + mpi_cmp_int( &I, 1 ) != 0 || + mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = POLARSSL_ERR_RSA_KEY_CHECK_FAILED; + } + +cleanup: + mpi_free( &PQ ); mpi_free( &DE ); mpi_free( &P1 ); mpi_free( &Q1 ); + mpi_free( &H ); mpi_free( &I ); mpi_free( &G ); mpi_free( &G2 ); + mpi_free( &L1 ); mpi_free( &L2 ); mpi_free( &DP ); mpi_free( &DQ ); + mpi_free( &QP ); + + if( ret == POLARSSL_ERR_RSA_KEY_CHECK_FAILED ) + return( ret ); + + if( ret != 0 ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED + ret ); + + return( 0 ); +} + +/* + * Do an RSA public key operation + */ +int rsa_public( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mpi T; + + mpi_init( &T ); + + MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); + + if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + mpi_free( &T ); + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + olen = ctx->len; + MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); + MPI_CHK( mpi_write_binary( &T, output, olen ) ); + +cleanup: + + mpi_free( &T ); + + if( ret != 0 ) + return( POLARSSL_ERR_RSA_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Do an RSA private key operation + */ +int rsa_private( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mpi T, T1, T2; + + mpi_init( &T ); mpi_init( &T1 ); mpi_init( &T2 ); + + MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); + + if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + mpi_free( &T ); + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + +#if defined(POLARSSL_RSA_NO_CRT) + MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); +#else + /* + * faster decryption using the CRT + * + * T1 = input ^ dP mod P + * T2 = input ^ dQ mod Q + */ + MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); + MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); + + /* + * T = (T1 - T2) * (Q^-1 mod P) mod P + */ + MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) ); + MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) ); + MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) ); + + /* + * output = T2 + T * Q + */ + MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) ); + MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) ); +#endif + + olen = ctx->len; + MPI_CHK( mpi_write_binary( &T, output, olen ) ); + +cleanup: + + mpi_free( &T ); mpi_free( &T1 ); mpi_free( &T2 ); + + if( ret != 0 ) + return( POLARSSL_ERR_RSA_PRIVATE_FAILED + ret ); + + return( 0 ); +} + +#if defined(POLARSSL_PKCS1_V21) +/** + * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer. + * + * \param dst buffer to mask + * \param dlen length of destination buffer + * \param src source of the mask generation + * \param slen length of the source buffer + * \param md_ctx message digest context to use + */ +static void mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src, size_t slen, + md_context_t *md_ctx ) +{ + unsigned char mask[POLARSSL_MD_MAX_SIZE]; + unsigned char counter[4]; + unsigned char *p; + unsigned int hlen; + size_t i, use_len; + + memset( mask, 0, POLARSSL_MD_MAX_SIZE ); + memset( counter, 0, 4 ); + + hlen = md_ctx->md_info->size; + + // Generate and apply dbMask + // + p = dst; + + while( dlen > 0 ) + { + use_len = hlen; + if( dlen < hlen ) + use_len = dlen; + + md_starts( md_ctx ); + md_update( md_ctx, src, slen ); + md_update( md_ctx, counter, 4 ); + md_finish( md_ctx, mask ); + + for( i = 0; i < use_len; ++i ) + *p++ ^= mask[i]; + + counter[3]++; + + dlen -= use_len; + } +} +#endif + +#if defined(POLARSSL_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function + */ +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 ) +{ + size_t olen; + int ret; + unsigned char *p = output; + unsigned int hlen; + const md_info_t *md_info; + md_context_t md_ctx; + + if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + md_info = md_info_from_type( ctx->hash_id ); + + if( md_info == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + hlen = md_get_size( md_info ); + + if( olen < ilen + 2 * hlen + 2 || f_rng == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + memset( output, 0, olen ); + + *p++ = 0; + + // Generate a random octet string seed + // + if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 ) + return( POLARSSL_ERR_RSA_RNG_FAILED + ret ); + + p += hlen; + + // Construct DB + // + md( md_info, label, label_len, p ); + p += hlen; + p += olen - 2 * hlen - 2 - ilen; + *p++ = 1; + memcpy( p, input, ilen ); + + md_init_ctx( &md_ctx, md_info ); + + // maskedDB: Apply dbMask to DB + // + mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen, + &md_ctx ); + + // maskedSeed: Apply seedMask to seed + // + mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1, + &md_ctx ); + + md_free_ctx( &md_ctx ); + + return( ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, output, output ) + : rsa_private( ctx, output, output ) ); +} +#endif /* POLARSSL_PKCS1_V21 */ + +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function + */ +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 ) +{ + size_t nb_pad, olen; + int ret; + unsigned char *p = output; + + if( ctx->padding != RSA_PKCS_V15 || f_rng == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + if( olen < ilen + 11 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad = olen - 3 - ilen; + + *p++ = 0; + if( mode == RSA_PUBLIC ) + { + *p++ = RSA_CRYPT; + + while( nb_pad-- > 0 ) + { + int rng_dl = 100; + + do { + ret = f_rng( p_rng, p, 1 ); + } while( *p == 0 && --rng_dl && ret == 0 ); + + // Check if RNG failed to generate data + // + if( rng_dl == 0 || ret != 0) + return POLARSSL_ERR_RSA_RNG_FAILED + ret; + + p++; + } + } + else + { + *p++ = RSA_SIGN; + + while( nb_pad-- > 0 ) + *p++ = 0xFF; + } + + *p++ = 0; + memcpy( p, input, ilen ); + + return( ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, output, output ) + : rsa_private( ctx, output, output ) ); +} + +/* + * Add the message padding, then do an RSA operation + */ +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 ) +{ + switch( ctx->padding ) + { + case RSA_PKCS_V15: + return rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen, + input, output ); + +#if defined(POLARSSL_PKCS1_V21) + case RSA_PKCS_V21: + return rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0, + ilen, input, output ); +#endif + + default: + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(POLARSSL_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function + */ +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 ) +{ + int ret; + size_t ilen; + unsigned char *p; + unsigned char buf[POLARSSL_MPI_MAX_SIZE]; + unsigned char lhash[POLARSSL_MD_MAX_SIZE]; + unsigned int hlen; + const md_info_t *md_info; + md_context_t md_ctx; + + if( ctx->padding != RSA_PKCS_V21 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, input, buf ) + : rsa_private( ctx, input, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + md_info = md_info_from_type( ctx->hash_id ); + if( md_info == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + hlen = md_get_size( md_info ); + + md_init_ctx( &md_ctx, md_info ); + + // Generate lHash + // + md( md_info, label, label_len, lhash ); + + // seed: Apply seedMask to maskedSeed + // + mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1, + &md_ctx ); + + // DB: Apply dbMask to maskedDB + // + mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen, + &md_ctx ); + + p += hlen; + md_free_ctx( &md_ctx ); + + // Check validity + // + if( memcmp( lhash, p, hlen ) != 0 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + p += hlen; + + while( *p == 0 && p < buf + ilen ) + p++; + + if( p == buf + ilen ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + if( *p++ != 0x01 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + if (ilen - (p - buf) > output_max_len) + return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE ); + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + + return( 0 ); +} +#endif /* POLARSSL_PKCS1_V21 */ + +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function + */ +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) +{ + int ret, correct = 1; + size_t ilen, pad_count = 0; + unsigned char *p, *q; + unsigned char bt; + unsigned char buf[POLARSSL_MPI_MAX_SIZE]; + + if( ctx->padding != RSA_PKCS_V15 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, input, buf ) + : rsa_private( ctx, input, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 ) + correct = 0; + + bt = *p++; + if( ( bt != RSA_CRYPT && mode == RSA_PRIVATE ) || + ( bt != RSA_SIGN && mode == RSA_PUBLIC ) ) + { + correct = 0; + } + + if( bt == RSA_CRYPT ) + { + while( *p != 0 && p < buf + ilen - 1 ) + pad_count += ( *p++ != 0 ); + + correct &= ( *p == 0 && p < buf + ilen - 1 ); + + q = p; + + // Also pass over all other bytes to reduce timing differences + // + while ( q < buf + ilen - 1 ) + pad_count += ( *q++ != 0 ); + + // Prevent compiler optimization of pad_count + // + correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */ + p++; + } + else + { + while( *p == 0xFF && p < buf + ilen - 1 ) + pad_count += ( *p++ == 0xFF ); + + correct &= ( *p == 0 && p < buf + ilen - 1 ); + + q = p; + + // Also pass over all other bytes to reduce timing differences + // + while ( q < buf + ilen - 1 ) + pad_count += ( *q++ != 0 ); + + // Prevent compiler optimization of pad_count + // + correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */ + p++; + } + + if( correct == 0 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + if (ilen - (p - buf) > output_max_len) + return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE ); + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + + return( 0 ); +} + +/* + * Do an RSA operation, then remove the message padding + */ +int rsa_pkcs1_decrypt( rsa_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + switch( ctx->padding ) + { + case RSA_PKCS_V15: + return rsa_rsaes_pkcs1_v15_decrypt( ctx, mode, olen, input, output, + output_max_len ); + +#if defined(POLARSSL_PKCS1_V21) + case RSA_PKCS_V21: + return rsa_rsaes_oaep_decrypt( ctx, mode, NULL, 0, olen, input, + output, output_max_len ); +#endif + + default: + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(POLARSSL_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function + */ +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 ) +{ + size_t olen; + unsigned char *p = sig; + unsigned char salt[POLARSSL_MD_MAX_SIZE]; + unsigned int slen, hlen, offset = 0; + int ret; + size_t msb; + const md_info_t *md_info; + md_context_t md_ctx; + + if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + switch( hash_id ) + { + case SIG_RSA_MD2: + case SIG_RSA_MD4: + case SIG_RSA_MD5: + hashlen = 16; + break; + + case SIG_RSA_SHA1: + hashlen = 20; + break; + + case SIG_RSA_SHA224: + hashlen = 28; + break; + + case SIG_RSA_SHA256: + hashlen = 32; + break; + + case SIG_RSA_SHA384: + hashlen = 48; + break; + + case SIG_RSA_SHA512: + hashlen = 64; + break; + + default: + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + md_info = md_info_from_type( ctx->hash_id ); + if( md_info == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + hlen = md_get_size( md_info ); + slen = hlen; + + if( olen < hlen + slen + 2 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + memset( sig, 0, olen ); + + msb = mpi_msb( &ctx->N ) - 1; + + // Generate salt of length slen + // + if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 ) + return( POLARSSL_ERR_RSA_RNG_FAILED + ret ); + + // Note: EMSA-PSS encoding is over the length of N - 1 bits + // + msb = mpi_msb( &ctx->N ) - 1; + p += olen - hlen * 2 - 2; + *p++ = 0x01; + memcpy( p, salt, slen ); + p += slen; + + md_init_ctx( &md_ctx, md_info ); + + // Generate H = Hash( M' ) + // + md_starts( &md_ctx ); + md_update( &md_ctx, p, 8 ); + md_update( &md_ctx, hash, hashlen ); + md_update( &md_ctx, salt, slen ); + md_finish( &md_ctx, p ); + + // Compensate for boundary condition when applying mask + // + if( msb % 8 == 0 ) + offset = 1; + + // maskedDB: Apply dbMask to DB + // + mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx ); + + md_free_ctx( &md_ctx ); + + msb = mpi_msb( &ctx->N ) - 1; + sig[0] &= 0xFF >> ( olen * 8 - msb ); + + p += hlen; + *p++ = 0xBC; + + return( ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, sig, sig ) + : rsa_private( ctx, sig, sig ) ); +} +#endif /* POLARSSL_PKCS1_V21 */ + +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function + */ +/* + * Do an RSA operation to sign the message digest + */ +int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t nb_pad, olen; + unsigned char *p = sig; + + if( ctx->padding != RSA_PKCS_V15 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + switch( hash_id ) + { + case SIG_RSA_RAW: + nb_pad = olen - 3 - hashlen; + break; + + case SIG_RSA_MD2: + case SIG_RSA_MD4: + case SIG_RSA_MD5: + nb_pad = olen - 3 - 34; + break; + + case SIG_RSA_SHA1: + nb_pad = olen - 3 - 35; + break; + + case SIG_RSA_SHA224: + nb_pad = olen - 3 - 47; + break; + + case SIG_RSA_SHA256: + nb_pad = olen - 3 - 51; + break; + + case SIG_RSA_SHA384: + nb_pad = olen - 3 - 67; + break; + + case SIG_RSA_SHA512: + nb_pad = olen - 3 - 83; + break; + + + default: + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + if( ( nb_pad < 8 ) || ( nb_pad > olen ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + *p++ = 0; + *p++ = RSA_SIGN; + memset( p, 0xFF, nb_pad ); + p += nb_pad; + *p++ = 0; + + switch( hash_id ) + { + case SIG_RSA_RAW: + memcpy( p, hash, hashlen ); + break; + + case SIG_RSA_MD2: + memcpy( p, ASN1_HASH_MDX, 18 ); + memcpy( p + 18, hash, 16 ); + p[13] = 2; break; + + case SIG_RSA_MD4: + memcpy( p, ASN1_HASH_MDX, 18 ); + memcpy( p + 18, hash, 16 ); + p[13] = 4; break; + + case SIG_RSA_MD5: + memcpy( p, ASN1_HASH_MDX, 18 ); + memcpy( p + 18, hash, 16 ); + p[13] = 5; break; + + case SIG_RSA_SHA1: + memcpy( p, ASN1_HASH_SHA1, 15 ); + memcpy( p + 15, hash, 20 ); + break; + + case SIG_RSA_SHA224: + memcpy( p, ASN1_HASH_SHA2X, 19 ); + memcpy( p + 19, hash, 28 ); + p[1] += 28; p[14] = 4; p[18] += 28; break; + + case SIG_RSA_SHA256: + memcpy( p, ASN1_HASH_SHA2X, 19 ); + memcpy( p + 19, hash, 32 ); + p[1] += 32; p[14] = 1; p[18] += 32; break; + + case SIG_RSA_SHA384: + memcpy( p, ASN1_HASH_SHA2X, 19 ); + memcpy( p + 19, hash, 48 ); + p[1] += 48; p[14] = 2; p[18] += 48; break; + + case SIG_RSA_SHA512: + memcpy( p, ASN1_HASH_SHA2X, 19 ); + memcpy( p + 19, hash, 64 ); + p[1] += 64; p[14] = 3; p[18] += 64; break; + + default: + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + return( ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, sig, sig ) + : rsa_private( ctx, sig, sig ) ); +} + +/* + * Do an RSA operation to sign the message digest + */ +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 ) +{ + switch( ctx->padding ) + { + case RSA_PKCS_V15: + return rsa_rsassa_pkcs1_v15_sign( ctx, mode, hash_id, + hashlen, hash, sig ); + +#if defined(POLARSSL_PKCS1_V21) + case RSA_PKCS_V21: + return rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, hash_id, + hashlen, hash, sig ); +#endif + + default: + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(POLARSSL_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int rsa_rsassa_pss_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + int ret; + size_t siglen; + unsigned char *p; + unsigned char buf[POLARSSL_MPI_MAX_SIZE]; + unsigned char result[POLARSSL_MD_MAX_SIZE]; + unsigned char zeros[8]; + unsigned int hlen; + size_t slen, msb; + const md_info_t *md_info; + md_context_t md_ctx; + + if( ctx->padding != RSA_PKCS_V21 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, sig, buf ) + : rsa_private( ctx, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( buf[siglen - 1] != 0xBC ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + switch( hash_id ) + { + case SIG_RSA_MD2: + case SIG_RSA_MD4: + case SIG_RSA_MD5: + hashlen = 16; + break; + + case SIG_RSA_SHA1: + hashlen = 20; + break; + + case SIG_RSA_SHA224: + hashlen = 28; + break; + + case SIG_RSA_SHA256: + hashlen = 32; + break; + + case SIG_RSA_SHA384: + hashlen = 48; + break; + + case SIG_RSA_SHA512: + hashlen = 64; + break; + + default: + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + md_info = md_info_from_type( ctx->hash_id ); + if( md_info == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + hlen = md_get_size( md_info ); + slen = siglen - hlen - 1; + + memset( zeros, 0, 8 ); + + // Note: EMSA-PSS verification is over the length of N - 1 bits + // + msb = mpi_msb( &ctx->N ) - 1; + + // Compensate for boundary condition when applying mask + // + if( msb % 8 == 0 ) + { + p++; + siglen -= 1; + } + if( buf[0] >> ( 8 - siglen * 8 + msb ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + md_init_ctx( &md_ctx, md_info ); + + mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx ); + + buf[0] &= 0xFF >> ( siglen * 8 - msb ); + + while( *p == 0 && p < buf + siglen ) + p++; + + if( p == buf + siglen || + *p++ != 0x01 ) + { + md_free_ctx( &md_ctx ); + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } + + slen -= p - buf; + + // Generate H = Hash( M' ) + // + md_starts( &md_ctx ); + md_update( &md_ctx, zeros, 8 ); + md_update( &md_ctx, hash, hashlen ); + md_update( &md_ctx, p, slen ); + md_finish( &md_ctx, result ); + + md_free_ctx( &md_ctx ); + + if( memcmp( p + slen, result, hlen ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); +} +#endif /* POLARSSL_PKCS1_V21 */ + +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function + */ +int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + int ret; + size_t len, siglen; + unsigned char *p, c; + unsigned char buf[POLARSSL_MPI_MAX_SIZE]; + + if( ctx->padding != RSA_PKCS_V15 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, sig, buf ) + : rsa_private( ctx, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 || *p++ != RSA_SIGN ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + while( *p != 0 ) + { + if( p >= buf + siglen - 1 || *p != 0xFF ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + p++; + } + p++; + + len = siglen - ( p - buf ); + + if( len == 33 && hash_id == SIG_RSA_SHA1 ) + { + if( memcmp( p, ASN1_HASH_SHA1_ALT, 13 ) == 0 && + memcmp( p + 13, hash, 20 ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + if( len == 34 ) + { + c = p[13]; + p[13] = 0; + + if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 ) + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + + if( ( c == 2 && hash_id == SIG_RSA_MD2 ) || + ( c == 4 && hash_id == SIG_RSA_MD4 ) || + ( c == 5 && hash_id == SIG_RSA_MD5 ) ) + { + if( memcmp( p + 18, hash, 16 ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + } + + if( len == 35 && hash_id == SIG_RSA_SHA1 ) + { + if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 && + memcmp( p + 15, hash, 20 ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + if( ( len == 19 + 28 && p[14] == 4 && hash_id == SIG_RSA_SHA224 ) || + ( len == 19 + 32 && p[14] == 1 && hash_id == SIG_RSA_SHA256 ) || + ( len == 19 + 48 && p[14] == 2 && hash_id == SIG_RSA_SHA384 ) || + ( len == 19 + 64 && p[14] == 3 && hash_id == SIG_RSA_SHA512 ) ) + { + c = p[1] - 17; + p[1] = 17; + p[14] = 0; + + if( p[18] == c && + memcmp( p, ASN1_HASH_SHA2X, 18 ) == 0 && + memcmp( p + 19, hash, c ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + + if( len == hashlen && hash_id == SIG_RSA_RAW ) + { + if( memcmp( p, hash, hashlen ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + + return( POLARSSL_ERR_RSA_INVALID_PADDING ); +} + +/* + * Do an RSA operation and check the message digest + */ +int rsa_pkcs1_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + switch( ctx->padding ) + { + case RSA_PKCS_V15: + return rsa_rsassa_pkcs1_v15_verify( ctx, mode, hash_id, + hashlen, hash, sig ); + +#if defined(POLARSSL_PKCS1_V21) + case RSA_PKCS_V21: + return rsa_rsassa_pss_verify( ctx, mode, hash_id, + hashlen, hash, sig ); +#endif + + default: + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } +} + +/* + * Free the components of an RSA key + */ +void rsa_free( rsa_context *ctx ) +{ + mpi_free( &ctx->RQ ); mpi_free( &ctx->RP ); mpi_free( &ctx->RN ); + mpi_free( &ctx->QP ); mpi_free( &ctx->DQ ); mpi_free( &ctx->DP ); + mpi_free( &ctx->Q ); mpi_free( &ctx->P ); mpi_free( &ctx->D ); + mpi_free( &ctx->E ); mpi_free( &ctx->N ); +} + +#if defined(POLARSSL_SELF_TEST) + +#include "polarssl/sha1.h" + +/* + * Example RSA-1024 keypair, for test purposes + */ +#define KEY_LEN 128 + +#define RSA_N "9292758453063D803DD603D5E777D788" \ + "8ED1D5BF35786190FA2F23EBC0848AEA" \ + "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ + "7130B9CED7ACDF54CFC7555AC14EEBAB" \ + "93A89813FBF3C4F8066D2D800F7C38A8" \ + "1AE31942917403FF4946B0A83D3D3E05" \ + "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ + "5E94BB77B07507233A0BC7BAC8F90F79" + +#define RSA_E "10001" + +#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" + +#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" + +#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" + +#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ + "3C94D22288ACD763FD8E5600ED4A702D" \ + "F84198A5F06C2E72236AE490C93F07F8" \ + "3CC559CD27BC2D1CA488811730BB5725" + +#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ + "D8AAEA56749EA28623272E4F7D0592AF" \ + "7C1F1313CAC9471B5C523BFE592F517B" \ + "407A1BD76C164B93DA2D32A383E58357" + +#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ + "F38D18D2B2F0E2DD275AA977E2BF4411" \ + "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ + "A74206CEC169D74BF5A8C50D6F48EA08" + +#define PT_LEN 24 +#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ + "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD" + +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 ); +} + +/* + * Checkup routine + */ +int rsa_self_test( int verbose ) +{ + size_t len; + rsa_context rsa; + unsigned char rsa_plaintext[PT_LEN]; + unsigned char rsa_decrypted[PT_LEN]; + unsigned char rsa_ciphertext[KEY_LEN]; +#if defined(POLARSSL_SHA1_C) + unsigned char sha1sum[20]; +#endif + + rsa_init( &rsa, RSA_PKCS_V15, 0 ); + + rsa.len = KEY_LEN; + mpi_read_string( &rsa.N , 16, RSA_N ); + mpi_read_string( &rsa.E , 16, RSA_E ); + mpi_read_string( &rsa.D , 16, RSA_D ); + mpi_read_string( &rsa.P , 16, RSA_P ); + mpi_read_string( &rsa.Q , 16, RSA_Q ); + mpi_read_string( &rsa.DP, 16, RSA_DP ); + mpi_read_string( &rsa.DQ, 16, RSA_DQ ); + mpi_read_string( &rsa.QP, 16, RSA_QP ); + + if( verbose != 0 ) + printf( " RSA key validation: " ); + + if( rsa_check_pubkey( &rsa ) != 0 || + rsa_check_privkey( &rsa ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n PKCS#1 encryption : " ); + + memcpy( rsa_plaintext, RSA_PT, PT_LEN ); + + if( rsa_pkcs1_encrypt( &rsa, &myrand, NULL, RSA_PUBLIC, PT_LEN, + rsa_plaintext, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n PKCS#1 decryption : " ); + + if( rsa_pkcs1_decrypt( &rsa, RSA_PRIVATE, &len, + rsa_ciphertext, rsa_decrypted, + sizeof(rsa_decrypted) ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + +#if defined(POLARSSL_SHA1_C) + if( verbose != 0 ) + printf( "passed\n PKCS#1 data sign : " ); + + sha1( rsa_plaintext, PT_LEN, sha1sum ); + + if( rsa_pkcs1_sign( &rsa, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 20, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n PKCS#1 sig. verify: " ); + + if( rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1, 20, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n\n" ); +#endif /* POLARSSL_SHA1_C */ + + rsa_free( &rsa ); + + return( 0 ); +} + +#endif + +#endif diff --git a/common/polarssl/rsa.h b/common/polarssl/rsa.h new file mode 100644 index 00000000..f9a02202 --- /dev/null +++ b/common/polarssl/rsa.h @@ -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 + * + * 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 */ diff --git a/common/sha1.c b/common/polarssl/sha1.c similarity index 87% rename from common/sha1.c rename to common/polarssl/sha1.c index d20c54a4..28bcd4e3 100644 --- a/common/sha1.c +++ b/common/polarssl/sha1.c @@ -1,8 +1,12 @@ /* * FIPS-180-1 compliant SHA-1 implementation * - * Copyright (C) 2006-2014, ARM Limited, All Rights Reserved - * This file is part of mbed TLS (https://tls.mbed.org) + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * 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 @@ -24,38 +28,16 @@ * http://www.itl.nist.gov/fipspubs/fip180-1.htm */ -#if !defined(POLARSSL_CONFIG_FILE) -//#include "polarssl/config.h" -#define POLARSSL_SHA1_C - -#else -#include POLARSSL_CONFIG_FILE -#endif +#include "polarssl_config.h" #if defined(POLARSSL_SHA1_C) #include "sha1.h" -#include - -#if defined(POLARSSL_FS_IO) +#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) #include #endif -#if defined(POLARSSL_SELF_TEST) -#if defined(POLARSSL_PLATFORM_C) -#include "polarssl/platform.h" -#else -#include -#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) /* @@ -81,19 +63,6 @@ static void polarssl_zeroize( void *v, size_t n ) { } #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 */ @@ -134,8 +103,8 @@ void sha1_process( sha1_context *ctx, const unsigned char data[64] ) #define R(t) \ ( \ - temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ - W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ + temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ + W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ ( W[t & 0x0F] = S(temp,1) ) \ ) @@ -273,7 +242,7 @@ void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ) size_t fill; uint32_t left; - if( ilen == 0 ) + if( ilen <= 0 ) return; 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_init( &ctx ); sha1_starts( &ctx ); sha1_update( &ctx, input, ilen ); sha1_finish( &ctx, output ); - sha1_free( &ctx ); + + memset( &ctx, 0, sizeof( sha1_context ) ); } #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 ) return( POLARSSL_ERR_SHA1_FILE_IO_ERROR ); - sha1_init( &ctx ); sha1_starts( &ctx ); while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) sha1_update( &ctx, buf, n ); sha1_finish( &ctx, output ); - sha1_free( &ctx ); + + memset( &ctx, 0, sizeof( sha1_context ) ); if( ferror( f ) != 0 ) { @@ -395,8 +364,7 @@ int sha1_file( const char *path, unsigned char output[20] ) /* * SHA-1 HMAC context setup */ -void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, - size_t keylen ) +void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen ) { size_t i; unsigned char sum[20]; @@ -420,14 +388,13 @@ void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, sha1_starts( ctx ); sha1_update( ctx, ctx->ipad, 64 ); - polarssl_zeroize( sum, sizeof( sum ) ); + memset( sum, 0, sizeof( sum ) ); } /* * SHA-1 HMAC process buffer */ -void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, - size_t ilen ) +void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t 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_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_init( &ctx ); sha1_hmac_starts( &ctx, key, keylen ); sha1_hmac_update( &ctx, input, ilen ); sha1_hmac_finish( &ctx, output ); - sha1_free( &ctx ); + + memset( &ctx, 0, sizeof( sha1_context ) ); } #if defined(POLARSSL_SELF_TEST) /* * FIPS-180-1 test vectors */ -static const unsigned char sha1_test_buf[3][57] = +static unsigned char sha1_test_buf[3][57] = { { "abc" }, { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, @@ -502,7 +469,7 @@ static const unsigned char sha1_test_sum[3][20] = /* * 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" }, @@ -522,7 +489,7 @@ static const int sha1_hmac_test_keylen[7] = 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" }, { "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 i, j, buflen, ret = 0; + int i, j, buflen; unsigned char buf[1024]; unsigned char sha1sum[20]; sha1_context ctx; - sha1_init( &ctx ); - /* * SHA-1 */ for( i = 0; i < 3; i++ ) { if( verbose != 0 ) - polarssl_printf( " SHA-1 test #%d: ", i + 1 ); + printf( " SHA-1 test #%d: ", i + 1 ); sha1_starts( &ctx ); @@ -603,27 +568,26 @@ int sha1_self_test( int verbose ) if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 ) { if( verbose != 0 ) - polarssl_printf( "failed\n" ); + printf( "failed\n" ); - ret = 1; - goto exit; + return( 1 ); } if( verbose != 0 ) - polarssl_printf( "passed\n" ); + printf( "passed\n" ); } if( verbose != 0 ) - polarssl_printf( "\n" ); + printf( "\n" ); for( i = 0; i < 7; i++ ) { 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 ) { - memset( buf, 0xAA, buflen = 80 ); + memset( buf, '\xAA', buflen = 80 ); sha1_hmac_starts( &ctx, buf, buflen ); } else @@ -640,26 +604,21 @@ int sha1_self_test( int verbose ) if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 ) { if( verbose != 0 ) - polarssl_printf( "failed\n" ); + printf( "failed\n" ); - ret = 1; - goto exit; + return( 1 ); } if( verbose != 0 ) - polarssl_printf( "passed\n" ); + printf( "passed\n" ); } if( verbose != 0 ) - polarssl_printf( "\n" ); + printf( "\n" ); -exit: - sha1_free( &ctx ); - - return( ret ); + return( 0 ); } -#endif /* POLARSSL_SELF_TEST */ - -#endif /* POLARSSL_SHA1_C */ +#endif +#endif diff --git a/common/sha1.h b/common/polarssl/sha1.h similarity index 81% rename from common/sha1.h rename to common/polarssl/sha1.h index 056bba7e..01cb69b7 100644 --- a/common/sha1.h +++ b/common/polarssl/sha1.h @@ -3,9 +3,12 @@ * * \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 + * + * 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 @@ -24,31 +27,11 @@ #ifndef POLARSSL_SHA1_H #define POLARSSL_SHA1_H -#if !defined(POLARSSL_CONFIG_FILE) -//#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 POLARSSL_CONFIG_FILE -#endif +#include "polarssl_config.h" -#include +#include -#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32) +#ifdef _MSC_VER #include typedef UINT32 uint32_t; #else @@ -61,10 +44,6 @@ typedef UINT32 uint32_t; // Regular implementation // -#ifdef __cplusplus -extern "C" { -#endif - /** * \brief SHA-1 context structure */ @@ -79,19 +58,9 @@ typedef struct } sha1_context; -/** - * \brief Initialize SHA-1 context - * - * \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 ); +#ifdef __cplusplus +extern "C" { +#endif /** * \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 keylen length of the HMAC key */ -void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, - size_t keylen ); +void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen ); /** * \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 ilen length of the input data */ -void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, - size_t ilen ); +void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen ); /** * \brief SHA-1 HMAC final digest -- 2.39.2