Compare commits

..

112 Commits

Author SHA1 Message Date
NIIBE Yutaka
e7e8b9f5ca version 1.1.4 2014-12-15 14:05:46 +09:00
NIIBE Yutaka
d6e70ab0f4 fix key page release 2014-12-15 12:12:54 +09:00
NIIBE Yutaka
3cca2798b0 RSA can be a bit faster with -O3 (no -Os) 2014-12-12 17:20:06 +09:00
NIIBE Yutaka
a695ad03ab configure default change 2014-12-12 15:39:15 +09:00
NIIBE Yutaka
41f5145fe1 remove support of STBee Mini for ChibiOS/RT 2014-12-12 15:39:02 +09:00
NIIBE Yutaka
b6db3b449e Modify test suite 2014-12-12 15:06:22 +09:00
NIIBE Yutaka
c54bb0c559 fix USB 2014-12-12 15:00:51 +09:00
NIIBE Yutaka
91222b5e22 Upgrade Chopstx 2014-12-12 14:26:58 +09:00
NIIBE Yutaka
f89b9ef8b7 Remove useless files 2014-12-12 14:23:57 +09:00
NIIBE Yutaka
4e984276e3 ECC change finished 2014-12-12 14:22:13 +09:00
NIIBE Yutaka
abde30b943 fixes for ECC 2014-12-12 14:17:35 +09:00
NIIBE Yutaka
8d56a4bff5 Change required by RSA-4096 support 2014-12-12 14:06:16 +09:00
NIIBE Yutaka
fd8543f092 proc_key_import supports key algo attrs 2014-12-12 13:57:00 +09:00
NIIBE Yutaka
9cba1e2a8e Support modifiable key algo attrs and divert on runtime 2014-12-12 13:53:29 +09:00
NIIBE Yutaka
8f33df9819 Implement writable key algorithm attributes 2014-12-12 13:12:06 +09:00
NIIBE Yutaka
ff3df302e4 Extended capabilities change 2014-12-12 13:10:33 +09:00
NIIBE Yutaka
75e8de2df1 Add new records in flash for writable key attributes 2014-12-12 13:09:37 +09:00
NIIBE Yutaka
8e6fa1a627 Variable length keysize supported in flash.c 2014-12-12 11:53:51 +09:00
NIIBE Yutaka
14e2633c52 Remove non-needed 'extern' in gnuk.h 2014-12-12 11:23:15 +09:00
NIIBE Yutaka
0d59d31230 Don't use fixed len for RSA computation 2014-12-12 11:19:24 +09:00
NIIBE Yutaka
f82206e7d5 Fix/add comment to clarify. 2014-06-19 12:48:13 +09:00
NIIBE Yutaka
9ea262ffde Add new tool/add_openpgp_authkey_from_gpgssh.py 2014-06-05 13:02:05 +09:00
NIIBE Yutaka
1309527c3c fix submodule for both of gniibe and gitorious 2014-05-22 13:48:59 +09:00
NIIBE Yutaka
df08bb473c relative path is required for submodule 2014-05-22 13:23:12 +09:00
NIIBE Yutaka
d7c3441dd4 Fixed .gitmodules again. 2014-05-22 11:46:50 +09:00
NIIBE Yutaka
cd06bada05 Fixed .gitmodules to relative for anonymous user of git.gniibe.org 2014-05-22 11:42:29 +09:00
NIIBE Yutaka
e25f50eabc more. 2014-04-17 17:28:08 +09:00
NIIBE Yutaka
62a59b56fe more minor improvement around 2^256-38. 2014-04-17 12:21:00 +09:00
NIIBE Yutaka
4f1343e154 minor improvement. 2014-04-16 21:07:11 +09:00
NIIBE Yutaka
272875ee76 version 1.1.3 2014-04-16 13:26:47 +09:00
NIIBE Yutaka
85b2698bb3 Add curve25519 computation. 2014-04-15 10:28:17 +09:00
NIIBE Yutaka
4d6f59079a minor fixes. 2014-04-14 18:37:25 +09:00
NIIBE Yutaka
53aa3de9b4 cleanup mod_inv. 2014-04-08 10:57:46 +09:00
NIIBE Yutaka
afa0683495 EdDSA-sha512 means SHA512 implicitly. 2014-04-07 14:42:59 +09:00
NIIBE Yutaka
a7f3a3e260 now EdDSA works. 2014-04-03 16:06:42 +09:00
NIIBE Yutaka
9cd4a1a47f fix EdDSA 2014-04-03 16:02:56 +09:00
NIIBE Yutaka
f9ed79f644 gpg_do_write_prvkey for ed25519 2014-04-01 11:09:17 +09:00
NIIBE Yutaka
c7a6370b74 proc_key_import for ed25519 2014-03-31 17:12:07 +09:00
NIIBE Yutaka
dc4584a8a5 gpg_do_public_key for ed25519 2014-03-31 16:58:48 +09:00
NIIBE Yutaka
89f0af1496 Add attribute for ed25519 2014-03-31 16:54:29 +09:00
NIIBE Yutaka
28a5799cf7 eddsa_sign_25519 2014-03-31 16:46:40 +09:00
NIIBE Yutaka
07b960009a flash private key handling. 2014-03-31 15:23:37 +09:00
NIIBE Yutaka
b37a1e728e clean up. 2014-03-29 07:59:31 +09:00
NIIBE Yutaka
c5bdc370dd Change API of eddsa_25519 2014-03-28 16:04:00 +09:00
NIIBE Yutaka
9c5eb9ea4b Add implementation note 2014-03-27 15:12:21 +09:00
NIIBE Yutaka
356a9cc615 eddsa_25519: API change 2014-03-27 12:04:03 +09:00
NIIBE Yutaka
5882b37b58 simplify compute_kG_25519 2014-03-27 11:52:30 +09:00
NIIBE Yutaka
1920c5fc69 improve a bit 2014-03-26 18:37:38 +09:00
NIIBE Yutaka
fc53d507ce fix wrong comment 2014-03-25 16:24:31 +09:00
NIIBE Yutaka
da027eb67f add test code 2014-03-25 14:30:51 +09:00
NIIBE Yutaka
fcf6c60336 cleanup 2014-03-25 11:23:33 +09:00
NIIBE Yutaka
cbf896a61b Implemented EdDSA 2014-03-25 11:05:26 +09:00
NIIBE Yutaka
adbb67deb8 compute_kG_25519 2014-03-20 19:53:38 +09:00
NIIBE Yutaka
129d1b0d30 add precomputed tables. 2014-03-20 17:15:53 +09:00
NIIBE Yutaka
25e71cb29b use 64-bit for mul 2014-03-20 15:51:55 +09:00
NIIBE Yutaka
7d8696946a more bn fix 2014-03-20 15:42:32 +09:00
NIIBE Yutaka
2bb12e55c2 fix 2014-03-19 23:47:59 +09:00
NIIBE Yutaka
fa10e78344 fix bn.c 2014-03-19 23:47:19 +09:00
NIIBE Yutaka
116486affa Add ecc-edwards.c 2014-03-19 17:07:49 +09:00
NIIBE Yutaka
53bf87acf5 fix 2014-03-19 17:07:04 +09:00
NIIBE Yutaka
22bc67959e add comments 2014-03-19 11:12:36 +09:00
NIIBE Yutaka
971ee94d8f affine.h 2014-03-18 15:13:56 +09:00
NIIBE Yutaka
a3504e8510 mod25638 2014-03-18 14:18:39 +09:00
NIIBE Yutaka
bfe0466bd2 move fe25519 2014-03-14 13:07:51 +09:00
NIIBE Yutaka
fb8cb58c5c version 1.1.2 2014-03-07 15:43:05 +09:00
NIIBE Yutaka
db2187835c don't put OID for public key info. 2014-02-25 11:06:11 +09:00
NIIBE Yutaka
653868c00b fix configure for certdo 2014-02-25 09:25:49 +09:00
NIIBE Yutaka
ede98fbe7e bug fixes for secp256k1 2014-02-21 17:24:19 +09:00
NIIBE Yutaka
2accc339e2 fix modp256k1_shift 2014-02-21 11:36:15 +09:00
NIIBE Yutaka
9feeeb308b Add RSA_SIG (disable to use p256k1) 2014-02-20 12:02:44 +09:00
NIIBE Yutaka
01806c2e5e authentication with ecdsa p256r1 2014-02-20 10:58:51 +09:00
NIIBE Yutaka
a32f577dfa add call-ec_p256k1 2014-02-20 10:55:20 +09:00
NIIBE Yutaka
deaf340687 add ec_p256k1 2014-02-19 14:51:09 +09:00
NIIBE Yutaka
f5e8e94bf7 fix ec_p256r1 2014-02-19 11:36:27 +09:00
NIIBE Yutaka
df4e8c5481 Use CPP for jpc_p256[kr]1 2014-02-18 15:54:28 +09:00
NIIBE Yutaka
888eb2aa31 minor fix 2014-02-18 14:07:25 +09:00
NIIBE Yutaka
1436223320 sha256 bug fix 2014-02-18 14:01:57 +09:00
NIIBE Yutaka
13a52a0862 minor fixes 2014-02-18 14:01:34 +09:00
NIIBE Yutaka
ea73e1ee7e bugfic for modp256k1 2014-02-18 14:01:04 +09:00
NIIBE Yutaka
8ca0416be8 Add modp256k1.[ch] 2014-02-18 12:07:33 +09:00
NIIBE Yutaka
d42eba5cb0 Use P256R1 2014-02-18 11:00:28 +09:00
NIIBE Yutaka
60820f5a5f name change p256 -> p256r1 2014-02-17 13:49:35 +09:00
NIIBE Yutaka
2c8f1cb0ce sha improvement 2014-02-05 16:33:21 +09:00
NIIBE Yutaka
2e80472f1c Add sha512 2014-02-05 16:20:26 +09:00
NIIBE Yutaka
8f60b1568f fix sha256 2014-02-05 13:33:58 +09:00
NIIBE Yutaka
91ca2d9827 Assembler MUL/SQR 2014-01-28 11:31:52 +09:00
NIIBE Yutaka
6d2f9f8df1 bug fix for compute_kP 2014-01-28 09:59:26 +09:00
NIIBE Yutaka
42251eea8e Fix for constant time: compute_kP (for ECDH in future) 2014-01-27 16:27:51 +09:00
NIIBE Yutaka
fc5df5019f clean up 2014-01-27 11:26:58 +09:00
NIIBE Yutaka
e18df3af6b clean up 2014-01-27 11:17:10 +09:00
NIIBE Yutaka
4b65ed1a5b simplify compute_kP 2014-01-24 16:16:41 +09:00
NIIBE Yutaka
f4e10311c7 Fix for constant time (step 10): ECDSA done 2014-01-24 14:49:38 +09:00
NIIBE Yutaka
78ffb4179e Fix for constant time (step 9) 2014-01-24 11:05:49 +09:00
NIIBE Yutaka
36541838f9 bug fix 2014-01-23 14:59:55 +09:00
NIIBE Yutaka
29e76d0ba7 cosmetic change 2014-01-22 16:57:19 +09:00
NIIBE Yutaka
c29bd10555 bug fix 2014-01-22 15:53:13 +09:00
NIIBE Yutaka
5c01e92c20 bug fix for ecdsa 2014-01-22 14:34:46 +09:00
NIIBE Yutaka
94508ae5d9 Fix for constant time (step 8) 2014-01-22 14:33:40 +09:00
NIIBE Yutaka
251760d5da Fix for constant time (step 7) 2014-01-22 14:26:41 +09:00
NIIBE Yutaka
6a69c31c3b Fix for constant time (step 6) 2014-01-22 14:09:55 +09:00
NIIBE Yutaka
486f20bfd4 more fix on ecc 2014-01-22 10:02:08 +09:00
NIIBE Yutaka
8d05addc87 bug fix for inf check 2014-01-22 09:58:59 +09:00
NIIBE Yutaka
9f0e2eabd1 bug fix for mod.c change 2014-01-21 21:02:03 +09:00
NIIBE Yutaka
f21a89588c Fix for constant time (step 5) 2014-01-21 14:40:58 +09:00
NIIBE Yutaka
af66c5fa08 format 2014-01-21 14:26:31 +09:00
NIIBE Yutaka
0e7078bacb Fix for constant time (step 4) 2014-01-21 14:14:39 +09:00
NIIBE Yutaka
df8434db59 Fix for constant time (step 3) 2014-01-21 13:58:01 +09:00
NIIBE Yutaka
80d935d913 Fix for constant time (step 2) 2014-01-21 13:31:23 +09:00
NIIBE Yutaka
007eada502 Fix for constant time (step 1) 2014-01-21 13:25:30 +09:00
NIIBE Yutaka
3bb3c6e9d8 member name change 2014-01-21 13:07:20 +09:00
NIIBE Yutaka
4f154cc61d add fe25519 2014-01-20 16:14:10 +09:00
NIIBE Yutaka
38f8b91335 bn.c: constant time 2014-01-15 22:05:18 +09:00
67 changed files with 6012 additions and 2179 deletions

2
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "chopstx"]
path = chopstx
url = git@gitorious.org:chopstx/chopstx.git
url = ../../chopstx/chopstx.git

465
ChangeLog
View File

@@ -1,3 +1,468 @@
2014-12-15 Niibe Yutaka <gniibe@fsij.org>
* VERSION: 1.1.4.
2014-12-13 Niibe Yutaka <gniibe@fsij.org>
* src/flash.c (flash_key_getpage, flash_key_release_page): New.
* src/openpgp-do.c (gpg_do_delete_prvkey): New arg.
(rw_algorithm_attr): Call gpg_do_delete_prvkey with CLEAN_PAGE_FULL.
2014-12-12 Niibe Yutaka <gniibe@fsij.org>
* src/Makefile.in (build/bignum.o): Specific OPT for this target.
* src/configure (target): Default is FST-01.
(--with-dfu): FST-01 doesn't have DFU. If set, it must be
mistake.
* boards/STBEE_MINI: Remove, since it is now supported by Chopstx.
* test/features/802_get_data_static.feature: Reflect the change
of extended capabilities.
* test/features/402_get_data_static.feature: Ditto.
* test/features/002_get_data_static.feature: Ditto.
* test/features/003_keyattr_change.feature: New test.
* src/usb_lld.h: Don't use 'extern' for function declarations.
* src/usb-icc.c (end_cmd_apdu_data): Fix Le handling.
2014-12-11 Niibe Yutaka <gniibe@fsij.org>
* chopstx: Upgrade to 0.04.
* src/syc.c: Update from 0.04.
2014-12-10 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-cdh.c: Remove as smartcard only does
a part of ECDH computation as gpg-agent does.
* src/chconf.h, src/halconf.h: Remove files needed for ChibiOS/RT.
2014-12-09 Niibe Yutaka <gniibe@fsij.org>
* src/call-ec.c (ecc_compute_public): Rename, as we share
same routine among ECDSA and ECDH.
(ecdh_decrypt): New.
2014-12-09 Niibe Yutaka <gniibe@fsij.org>
* src/ecc.c (compute_kP): Bug fix. It's P, not G.
(point_is_on_the_curve): Bug fix.
2014-12-03 Niibe Yutaka <gniibe@fsij.org>
Changes for RSA-4096.
* src/gnuk.h (MAX_CMD_APDU_DATA_SIZE, MAX_RES_APDU_DATA_SIZE):
Send/Recv buffer should be bigger.
* polarssl/library/bignum.c (mpi_exp_mod): Don't consume much.
* polarssl/library/rsa.c (rsa_rsaes_pkcs1_v15_decrypt): buffer
allocation size should be variable.
2014-12-01 Niibe Yutaka <gniibe@fsij.org>
* src/Makefile.in (DEFS): Don't define compile time preference of
key algo attributes.
* src/openpgp-do.c (proc_key_import): Support modifiable key algo
attributes.
2014-11-21 Niibe Yutaka <gniibe@fsij.org>
* src/gnuk.h (ALGO_RSA4K, ALGO_NISTP256R1, ALGO_SECP256K1)
(ALGO_ED25519, ALGO_RSA2K): New.
(struct key_data_internal): Move to ...
* src/openpgp-do.c (struct key_data_internal): ... here.
(CHECKSUM_ADDR, kdi_len): New.
(CKDC_CALC, CKDC_CHECK): New.
(compute_key_data_checksum): Add arg PRVKEY_LEN.
(gpg_do_load_prvkey, gpg_do_delete_prvkey): Support modifiable key
algo attributes.
(gpg_do_write_prvkey, gpg_do_public_key, gpg_do_keygen): Likewise.
(gpg_do_clear_prvkey): Use MAX_PRVKEY_LEN.
* src/openpgp.c (gpg_init): Call flash_init_keys after
gpg_data_scan.
(cmd_pso): Support modifiable key algo attributes.
(cmd_internal_authenticate): Likewise.
2014-11-21 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (algorithm_attr_rsa2k): Rename from *_rsa.
(algorithm_attr_rsa4k): New.
(get_algo_attr_pointer, kk_to_nr, gpg_get_algo_attr)
(get_algo_attr_data_object, gpg_get_algo_attr_key_size): New.
(rw_algorithm_attr): New.
(gpg_do_table): Register rw_algorithm_attr for GPG_DO_ALG_*.
(gpg_data_scan, gpg_data_copy): Handle algo attributes.
(rw_pw_status): Fix checking against redundant write.
2014-11-20 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (extended_capabilities): Key attributes can be
modifid now.
2014-11-20 Niibe Yutaka <gniibe@fsij.org>
* src/gnuk.h (NR_NONE, NR_DO__FIRST__): Remove.
(NR_DO_*): Redefine.
(NR_KEY_ALGO_ATTR_SIG, NR_KEY_ALGO_ATTR_DEC)
(NR_KEY_ALGO_ATTR_AUT): New.
* src/openpgp-do.c (gpg_do_load_prvkey, gpg_do_delete_prvkey)
(gpg_do_write_prvkey, gpg_do_chks_prvkey, gpg_data_scan)
(gpg_data_copy, gpg_do_read_simple)
(gpg_do_write_simple): Don't use NR_DO__FIRST__.
(gpg_do_put_data): Don't use NR_NONE any more.
(do_tag_to_nr): Use -1 to specify NONE.
* src/flash.c (flash_enum_clear, flash_enum_write_internal)
(flash_enum_write): New.
2014-11-19 Niibe Yutaka <gniibe@fsij.org>
* src/gnuk.h (FIRMWARE_UPDATE_KEY_CONTENT_LEN): New.
(size_of_key): New enum.
* src/openpgp.c (gpg_get_firmware_update_key)
(cmd_read_binary, cmd_external_authenticate): Use
FIRMWARE_UPDATE_KEY_CONTENT_LEN.
* src/flash.c (KEY_SIZE): Remove.
(key_available_at): Add new arg as KEY_SIZE.
(flash_check_all_other_keys_released): Likewise.
(flash_key_fill_zero_as_released, flash_key_release): Likewise.
(flash_init): Move initializing keys into another function.
(flash_init_keys): New function.
(flash_key_alloc): Use gpg_get_algo_attr_key_size.
(flash_key_write): Add new arg as KEY_DATA_LEN.
(flash_write_binary): Use FIRMWARE_UPDATE_KEY_CONTENT_LEN.
2014-09-16 Niibe Yutaka <gniibe@fsij.org>
* src/gnuk.h (MAX_PRVKEY_LEN): New.
(KEY_CONTENT_LEN): Remove.
* src/call-rsa.c (RSA_SIGNATURE_LENGTH): Remove.
(rsa_sign, rsa_verify, rsa_genkey): Add new arg: PUBKEY_LEN.
(rsa_decrypt): Don't use KEY_CONTENT_LEN.
2014-06-19 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-mont.c (compute_nQ): Add comment.
* src/mod.c (mod_inv): Fix comment. X^-1 = 0 when X=0
is important for Montgomery curve computation.
2014-06-05 Niibe Yutaka <gniibe@fsij.org>
* tool/add_openpgp_authkey_from_gpgssh.py: New.
2014-04-17 Niibe Yutaka <gniibe@fsij.org>
* src/muladd_256.h (MULADD_256_ASM): New.
(MULADD_256): Use MULADD_256_ASM.
* src/ecc-mont.c (mod25638_mul_121665): Add asm implementation.
* src/bn.c (bn256_add_uint, bn256_sub_uint): Simplify.
* src/mod25638.c (mod25638_add, mod25638_sub): Simplify.
(n25638, add19): Remove.
(ADDWORD_256): Add s_ as source pointer.
(mod25519_reduce): Remove a call to memcpy. Use bn256_add_uint.
* src/ecc-edwards.c (point_double): Simplify.
2014-04-16 Niibe Yutaka <gniibe@fsij.org>
* VERSION: 1.1.3.
2014-04-15 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-mont.c: New.
* src/mod25638.c (p25519): Move from ecc-edwards.c.
(mod25519_reduce, add19): Likewise.
(mod25638_reduce) [!ASM_IMPLEMENTATION]: Use bn256_add_uint.
2014-04-14 Niibe Yutaka <gniibe@fsij.org>
* src/jpc.c (jpc_to_ac): Error check before mod_inv.
* src/mod.c (mod_inv): No return value (if N==0 returns ZERO).
* src/bn.c [BN256_NO_RANDOM]: Only include "random.h" if needed.
2014-04-08 Niibe Yutaka <gniibe@fsij.org>
* src/mod.c (mod_inv): Use MAX_GCD_STEPS_BN256.
Return failure or success.
* src/jpc.c (jpc_to_ac): Use mod_inv.
* src/modp256k1.c (modp256k1_inv): Remove.
* src/modp256r1.c (modp256r1_inv): Remove.
2014-04-07 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (algorithm_attr_ed25519): It's OID only.
2014-04-03 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (eddsa_sign_25519): Change type of OUT.
* src/openpgp.c (cmd_internal_authenticate): Have a buffer.
* src/flash.c (flash_init): Fix key address finder.
2014-04-02 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (proc_key_import): Handle EdDSA.
(algorithm_attr_ed25519): Fix OID and add ID for SHA512.
2014-04-01 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (eddsa_compute_public_25519): New.
* src/openpgp-do.c (algorithm_attr_ed25519): New.
(gpg_do_write_prvkey, proc_key_import, gpg_do_public_key): Add
EdDSA handling.
2014-03-31 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (eddsa_sign_25519): Rename and API change.
* src/openpgp-do.c (gpg_do_load_prvkey, gpg_do_delete_prvkey)
(gpg_do_write_prvkey, gpg_do_public_key, gpg_do_keygen): Follow
the change of PRVKEY_DATA and KEY_DATA.
* src/flash.c (key_available_at): New.
(flash_init): Initilize KD.
* src/gnuk.h (struct prvkey_data): Remove member KEY_ADDR.
(struct key_data): Addd member KEY_ADDR.
* src/openpgp-do.c (gpg_do_keygen): Bug fix. Reset the signature
counter when new key is generated.
* src/flash.c (flash_key_alloc): Change API, supply KK.
2014-03-29 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (point_double, point_add): Rename.
(mod25519_reduce): New.
2014-03-28 Niibe Yutaka <gniibe@fsij.org>
* misc/t-eddsa.c (main): Update for new API of eddsa_25519.
* src/ecc-edwards.c (compute_kG_25519): Tune for 252-bit.
(eddsa_25519): Public key should be provided by caller.
(eddsa_public_key_25519): New.
2014-03-27 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (ed_add_25638): Remove the third argument.
(compute_kG_25519): The curve is complete, we don't need to avoid
identity element as NIST curve or secp256k1 curve.
(eddsa_25519): Change the API, with A and the seed.
2014-03-26 Niibe Yutaka <gniibe@fsij.org>
* src/mod25638.c (mod25638_reduce): New.
(mod25638_mul, mod25638_sqr): Use mod25638_reduce.
* src/ecc-edwards.c (ptc_to_ac_25519): No need to subtract p25519.
2014-03-25 Niibe Yutaka <gniibe@fsij.org>
* misc/t-eddsa.c: New.
* src/ecc-edwards.c (bnX_mul_C, mod_reduce_M): New.
(eddsa_25519): New.
2014-03-20 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (ed_add_25638): Fix for X == A.
(main): Compute pre-computed tables.
(precomputed_KG, precomputed_2E_KG): Add.
(compute_kG_25519): New.
2014-03-19 Niibe Yutaka <gniibe@fsij.org>
* src/bn.c (bn256_add): Fix for X == B.
(bn256_sub): Likewise.
* src/ecc-edwards.c: New.
2014-03-18 Niibe Yutaka <gniibe@fsij.org>
* src/mod25638.c (mod25638_add, mod25638_sub, mod25638_sqr)
(mod25638_shift): New.
2014-03-13 Niibe Yutaka <gniibe@fsij.org>
* src/mod25638.c: Rename from fe25519.c.
* src/mod25638.h: Likewise.
2014-03-07 Niibe Yutaka <gniibe@fsij.org>
* VERSION: 1.1.2.
2014-02-25 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (gpg_do_public_key): Don't put OID.
* src/configure [certdo] (gnuk.ld): Add TIM_SIZE and EXT_SIZE.
Thanks to Vasily Evseenko for the bug report.
2014-02-21 Niibe Yutaka <gniibe@fsij.org>
* src/ecc.c (compute_kG): Compute higer index at first.
(point_is_on_the_curve): Don't use coefficient_a if it's zero.
* src/jpc.c (jpc_double): Care coefficient A.
* src/ec_p256r1.c (COEFFICIENT_A_IS_MINUS_3): New.
* src/ec_p256k1.c (COEFFICIENT_A_IS_ZERO): New.
* src/jpc_p256r1.c (COEFFICIENT_A_IS_MINUS_3): Likewise.
* src/jpc_p256k1.c (COEFFICIENT_A_IS_MINUS_3): Likewise.
* src/modp256k1.c (modp256k1_shift): Bug fix.
2014-02-20 Niibe Yutaka <gniibe@fsij.org>
* src/Makefile.in (CSRC): Add files of p256k1.
* src/openpgp.c (cmd_pso): Support p256k1 for signature.
* src/openpgp-do.c (algorithm_attr_p256k1): New.
(gpg_do_write_prvkey): Support p256k1 for signature.
(proc_key_import, gpg_do_table, gpg_do_public_key): Likewise.
* src/Makefile.in (DEFS): Add -DRSA_SIG.
* src/openpgp-do.c (gpg_do_write_prvkey): Use _p256r1.
* src/openpgp.c (cmd_internal_authenticate): Likewise.
* src/call-ec_p256k1.c: New. Use call-ec.c.
* src/call-ec_p256r1.c: Use call-ec.c.
* src/call-ec.c: New.
(ecdsa_sign): Change the signature.
2014-02-19 Niibe Yutaka <gniibe@fsij.org>
* tool/calc_precompute_table_ecc.py: New.
* src/ec_p256k1.c: New. Use ecc.c.
* src/ec_p256k1.h: New.
* src/ec_p256r1.c: Use ecc.c.
* src/ecc.c: New.
2014-02-18 Niibe Yutaka <gniibe@fsij.org>
* src/jpc_p256k1.c: New. Use jpc.c.
* src/jpc_p256r1.c: Use jpc.c.
* src/jpc.c: New.
* src/sha256.c (memcpy_output_bswap32): Bug fix.
* src/modp256k1.h, src/modp256k1.c: New.
2014-02-17 Niibe Yutaka <gniibe@fsij.org>
* src/Makefile.in (CSRC): Follow the changes of filenames.
* src/modp256r1.c (modp256r1_add, modp256r1_sub, S3)
(modp256r1_mul, modp256r1_sqr, modp256r1_inv, modp256r1_shift):
Use new function names.
* src/jpc_p256r1.c (jpc_double_p256r1, jpc_add_ac_signed_p256r1)
(jpc_to_ac_p256r1): Likewise.
* src/ec_p256r1.c (point_is_on_the_curve)
(compute_kG_p256r1, compute_kP_p256r1): Likewise.
* src/call-ec_p256r1.c (ecdsa_sign): Likewise.
* src/modp256r1.h: Rename from modp256.h.
* src/jpc-ac_p256r1.h: Rename from jpc-ac.h.
* src/ec_p256r1.h: Rename from ec_p256.h.
* src/modp256r1.c: Rename from modp256.c.
* src/jpc_p256r1.c: Rename from jpc.c.
* src/ec_p256r1.c: Rename from ec_p256.c.
* src/call-ec_p256r1.c: Rename from call-ec_p256.c.
2014-02-05 NIIBE Yutaka <gniibe@fsij.org>
* src/sha512.h, src/sha512.c: New.
* src/sha256.c (initial_state): Don't export, it's internal.
(memcpy_output_bswap32): Rename and remove last argument.
2014-01-28 Niibe Yutaka <gniibe@fsij.org>
* src/muladd_256.h: New.
* src/bn.c (bn256_mul, bn256_sqr): Assembler implementation.
* src/ec_p256.c (get_vk_kP): Bug fix.
(compute_kP): Bug fix for index table.
2014-01-27 Niibe Yutaka <gniibe@fsij.org>
* src/ec_p256.c (get_vk_kP): New.
(naf4_257_set, naf4_257_get, compute_naf4_257): Remove.
(compute_kP): Change the argument, fixing for constant time.
2014-01-24 Niibe Yutaka <gniibe@fsij.org>
* src/ec_p256.c (get_vk): New.
(compute_kG): Fix for constant time.
(compute_kP): Simplify.
2014-01-23 Niibe Yutaka <gniibe@fsij.org>
* src/jpc.c (jpc_add_ac_signed): Fix for constant time.
* src/ec_p256.c (ecdsa): Bug fix for k selection.
2014-01-22 Niibe Yutaka <gniibe@fsij.org>
* src/modp256.c (modp256_inv): Fix for constant time.
* src/bn.c (bn256_sqr): Fix for constant time.
* src/mod.c (mod_inv): Fix for constant time.
* src/ec_p256.c (compute_kG): Simplify.
* src/jpc.c (jpc_double): Support calling with A = infinity.
2014-01-21 Niibe Yutaka <gniibe@fsij.org>
* src/jpc.c (jpc_add_ac_signed): Bug fix for A check.
* src/ec_p256.c (ecdsa): Fix for constant time.
* src/modp256.c (modp256_add, modp256_sub, modp256_reduce)
(modp256_shift): Fix for constant time.
(modp256_inv): Likewise (not fully constant time, yet).
* src/mod.c (mod_reduce): Fix for constant time.
(mod_inv): Likewise (not fully constant time, yet).
* src/bn.h (bn256, bn512): words -> word.
* src/ec_p256.h (naf4_257): Likewise.
2014-01-20 Niibe Yutaka <gniibe@fsij.org>
* src/fe25519.h, src/fe25519.c: New.
2014-01-15 Niibe Yutaka <gniibe@fsij.org>
* src/bn.c (bn256_is_zero, bn256_is_ge, bn256_cmp): Computation
should be constant time.
2013-12-25 Niibe Yutaka <gniibe@fsij.org>
* VERSION: 1.1.1.

48
NEWS
View File

@@ -1,5 +1,53 @@
Gnuk NEWS - User visible changes
* Major changes in Gnuk 1.1.4
Released 2014-12-15, by NIIBE Yutaka
** Experimental RSA-4096 support.
Although it takes too long (more than 8.7 second), RSA-4096
is now implemented.
** ECDH support.
ECDH is now supported. You need development branch (master)
of GnuPG to use this feature.
** ECDSA and EdDSA is not that experimental.
You don't need to edit DEFS variable in src/Makefile.
** STM8S_DISCOVERY is not supported any more.
It's flash ROM size (64KiB) is a bit small to have all features of
Gnuk now. If you manually edit code to limit the size of executable,
it still could run Gnuk, though.
** configure's default target is now FST-01.
Receiving reports from those who complain default target, I
reconsidered. Those who has Olimex STM32 H103 usually has JTAG
debugger, while FST-01 users don't. So, to be safe, the default
target is now FST-01, instead of Olimex STM32 H103.
* Major changes in Gnuk 1.1.3
Released 2014-04-16, by NIIBE Yutaka
** Experimental EdDSA support.
After configure, you can edit the DEFS variable in src/Makefile, so
that Gnuk can support EdDSA with Ed25519 (for authentication). Note
that this is pretty much experimental, and subjects to change.
* Major changes in Gnuk 1.1.2
Released 2014-03-07, by NIIBE Yutaka
** Experimental ECC support for secp256k1.
After configure, you can edit the DEFS variable in src/Makefile, so
that Gnuk can support ECDSA with NIST P256 (for authentication), and
ECDSA with secp256k1 (for signature). Note that this is pretty much
experimental, and subjects to change.
* Major changes in Gnuk 1.1.1
Released 2013-12-25, by NIIBE Yutaka

119
README
View File

@@ -1,18 +1,24 @@
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
Version 1.1.1
2013-12-25
Version 1.1.4
2014-12-15
Niibe Yutaka
Free Software Initiative of Japan
Warning
=======
This is another experimental release of Gnuk 1.1.1, which has
This is another experimental release of Gnuk, version 1.1.4, which has
incompatible changes to Gnuk 1.0.x. Specifically, it now supports
overriding key import, but importing keys (or generating keys) results
password reset. Please update your documentation for Gnuk Token, so
that the instruction of importing keys won't cause any confusion.
that the instruction of importing keys won't cause any confusion. It
has supports of ECDSA (with NIST P256 and secp256k1) and EdDSA with
EdDSA, but this feature is pretty much experimental, and it requires
development version of GnuPG with newest version of libgcrypt. You
will not able to keep using EdDSA keys, as the key format is subject
to change. It also support RSA-4096 experimentally, but users should
know that it takes more than 8 second to sign/decrypt.
What's Gnuk?
@@ -52,15 +58,15 @@ A0: Good points of Gnuk are:
"for Free Software"; Gnuk supports GnuPG.
Q1: What kind of key algorithm is supported?
A1: Gnuk version 1 only supports 2048-bit RSA.
A1: Gnuk version 1.0 only supports RSA 2048.
Development version of Gnuk (1.1.x) supports 256-bit ECDSA and EdDSA,
as well as RSA 4096-bit. But it takes long time to sign with RSA 4096.
Q2: How long does it take for digital signing?
A2: It takes a second and a half or so.
Q3: What's your recommendation for target board?
A3: Orthodox choice is Olimex STM32-H103.
If you have skill of electronics and like DIY, STM32 part of STM8S
Discovery Kit might be the best choice.
FST-01 (Flying Stone Tiny 01) is available for sale, and it is a
kind of the best choice, hopefully.
@@ -83,13 +89,7 @@ A6: You need a target board plus a JTAG/SWD debugger. If you just
Q7: How much does it cost?
A7: Olimex STM32-H103 plus ARM-USB-TINY-H cost 70 Euro or so.
Q8: How much does it cost for DIY version?
A8: STM8S Discovery Kit costs 750 JPY (< $10 USD) only. You can build
your own JTAG debugger using FTDI2232 module (1450 JPY), see:
http://www.fsij.org/gnuk/jtag_dongle_ftdi2232
Q9: I got an error like "gpg: selecting openpgp failed: ec=6.108", what's up?
A9: GnuPG's SCDaemon has problems for handling insertion/removal of
card/reader. When your newly inserted token is not found by
GnuPG, try killing scdaemon and let it to be invoked again. I do:
@@ -106,7 +106,7 @@ Aa: You need to deactivate seahorse-agent and gnome-keyring, but use
$ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false
Qb: With GNOME 3, I can't use Gnuk Token at all. Why?
Qb: With GNOME 3.0, I can't use Gnuk Token at all. Why?
Ab: That's because gnome-keyring-daemon interferes GnuPG. Type:
$ gnome-session-properties
@@ -118,15 +118,27 @@ Qc: Do you know a good SWD debugger to connect FST-01 or something?
Ac: ST-Link/V2 is cheap one. We have a tool/stlinkv2.py as flash ROM
writer program.
Qd: With GNOME 3.x (x >= 8?), I can't use Gnuk Token at all. Why?
Ad: Please set the configration variable OnlyShowIn as none. Like:
OnlyShowIn=
In the files of /etc/xdg/autostart/gnome-keyring-gpg.desktop and
/etc/xdg/autostart/gnome-keyring-ssh.desktop
Release notes
=============
This is another experimental release in version 1.1 series of Gnuk.
This is third experimental release in version 1.1 series of Gnuk.
While it is daily use for more than two years, some newly introduced
features (including key generation and firmware upgrade) should be
considered experimental.
While it is daily use by its developer, some newly introduced features
(including ECDSA/EdDSA, key generation and firmware upgrade) should be
considered experimental. ECDSA/EdDSA is really experimental.
Further, EdDSA is much experimental. You won't be able to keep using
the EdDSA key, as the key format of GnuPG is subject to change.
Tested features are:
@@ -167,20 +179,19 @@ It is known not-working well:
Targets
=======
We use Olimex STM32-H103 board and Flying Stone Tiny 01 (FST-01). We
also use STM32 part of STM8S Discovery Kit.
We use Olimex STM32-H103 board and Flying Stone Tiny 01 (FST-01).
With DfuSe support, STBee is also our targets. But this target with
DfuSe is for experiment only, because it is impossible for DfuSe to
disable read from flash. For real use, please consider killing DfuSe
and enabling read protection using JTAG debugger.
For PIN-pad support, I connect a consumer IR receive module to FST-01
and STM8S Discovery Kit, and use controller for TV. PIN verification
is supported by this configuration. Yes, it is not secure at all,
since it is very easy to monitor IR output of the controllers. It is
just an experiment. Note that hardware needed for this experiment is
only a consumer IR receive module which is as cheap as 50 JPY.
For PIN-pad support, I connect a consumer IR receive module to FST-01,
and use controller for TV. PIN verification is supported by this
configuration. Yes, it is not secure at all, since it is very easy to
monitor IR output of the controllers. It is just an experiment. Note
that hardware needed for this experiment is only a consumer IR receive
module which is as cheap as 50 JPY.
Note that you need pinpad support for GnuPG to use PIN-pad enabled
Gnuk. The pinpad support for GnuPG is only available in version 2.
@@ -218,7 +229,7 @@ External source code
Gnuk is distributed with external source code.
* chopstx/ -- Chopstx 0.03 (+ STBee support)
* chopstx/ -- Chopstx 0.04
We use Chopstx as the kernel for Gnuk.
@@ -360,7 +371,7 @@ Olimex STM32-H103 board
If you are using Olimex JTAG-Tiny, type following to invoke OpenOCD:
$ openocd -f interface/olimex-jtag-tiny.cfg -f board/olimex_stm32_h103.cfg
$ openocd -f interface/ftdi/olimex-jtag-tiny.cfg -f board/olimex_stm32_h103.cfg
Then, with another terminal, type following to write "gnuk.elf" to Flash ROM:
@@ -375,30 +386,7 @@ Then, with another terminal, type following to write "gnuk.elf" to Flash ROM:
Flying Stone Tiny 01
--------------------
If you are using Flying Stone Tiny 01, you need a SWD writer. I am
using revision 946 of Simon Qian's Versaloon.
svn checkout -r 946 http://vsprog.googlecode.com/svn/trunk/
For OpenOCD, we need unofficial patch.
See the article of Versaloon Forum:
http://www.versaloon.com/bbs/viewtopic.php?p=16179
Type following to invoke OpenOCD:
$ openocd -f interface/vsllink.cfg -c "transport select swd" -c "swd_mode 2" -f target/stm32f1x.cfg
Then, with another terminal, type following to write "gnuk.elf" to Flash ROM:
$ telnet localhost 4444
> reset halt
> flash write_image erase gnuk.elf
> reset
> exit
$
If you are using Flying Stone Tiny 01, you need a SWD writer.
OpenOCD 0.6.1 now supports ST-Link/V2. We can use it:
@@ -407,29 +395,6 @@ OpenOCD 0.6.1 now supports ST-Link/V2. We can use it:
But it doesn't support option bytes handling (protection) yet.
STM8S Discovery Kit
-------------------
If you are using FTDI-2232D module and the connection is standard, type:
$ openocd -f interface/openocd-usb.cfg -f target/stm32f1x.cfg
Initially, the flash ROM of the chip is protected. you need to do:
$ telnet localhost 4444
> reset halt
> stm32f1x unlock 0
> reset
> shutdown
$
and re-connect the board. Note that power-off / power-on sequence is
required to reset flash ROM.
Then, invoke OpenOCD again and telnet to connect OpenCD and write
image as above example of Olimex STM32-H103.
STBee
-----
@@ -465,7 +430,7 @@ How to configure
================
You need python and pyscard (python-pyscard package in Debian) or
PyUSB (python-usb package in Debian).
PyUSB 0.4.3 (python-usb package in Debian).
(1) [pyscard] Stop scdaemon
[PyUSB] Stop the pcsc daemon.
@@ -586,7 +551,7 @@ You can get it by:
$ git clone git://gitorious.org/gnuk/gnuk.git
It's also available at: www.gniibe.org
You can browse at: http://www.gniibe.org/gitweb?p=gnuk.git;a=summary
You can browse at: http://git.gniibe.org/gitweb?p=gnuk/gnuk.git;a=summary
I put Chopstx as a submodule of Git. Please do this:

1
THANKS
View File

@@ -19,4 +19,5 @@ NAGAMI Takeshi nagami-takeshi@aist.go.jp
Nguyễn Hồng Quân quannguyen@mbm.vn
Paul Bakker polarssl_maintainer@polarssl.org
Shane Coughlan scoughlan@openinventionnetwork.com
Vasily Evseenko
Werner Koch wk@gnupg.org

View File

@@ -1 +1 @@
release/1.1.1
release/1.1.4

View File

@@ -1,151 +0,0 @@
#include "config.h"
#include "ch.h"
#include "hal.h"
/*
* Board-specific initialization code.
*/
void boardInit(void)
{
#if !defined(DFU_SUPPORT)
if (palReadPad (IOPORT3, GPIOC_BUTTON) == 0)
/*
* Since LEDs are connected to JTMS/SWDIO and JTDI pin,
* we can't use LED to let know users in this state.
*/
for (;;); /* Wait for JTAG debugger connection */
#endif
#if defined(PINPAD_SUPPORT) && !defined(DFU_SUPPORT)
palWritePort(IOPORT2, 0x7fff); /* Only clear GPIOB_7SEG_DP */
while (palReadPad (IOPORT2, GPIOB_BUTTON) != 0)
; /* Wait for JTAG debugger connection */
palWritePort(IOPORT2, 0xffff); /* All set */
#endif
#if defined(PINPAD_CIR_SUPPORT)
/* EXTI0 <= PB0 */
AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI0_PB;
EXTI->IMR = 0;
EXTI->FTSR = EXTI_FTSR_TR0;
NVICEnableVector(EXTI0_IRQn,
CORTEX_PRIORITY_MASK(CORTEX_MINIMUM_PRIORITY));
/* TIM3 */
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
RCC->APB1RSTR = RCC_APB1RSTR_TIM3RST;
RCC->APB1RSTR = 0;
NVICEnableVector(TIM3_IRQn,
CORTEX_PRIORITY_MASK(CORTEX_MINIMUM_PRIORITY));
TIM3->CR1 = TIM_CR1_URS | TIM_CR1_ARPE; /* Don't enable TIM3 for now */
TIM3->CR2 = TIM_CR2_TI1S;
TIM3->SMCR = TIM_SMCR_TS_0 | TIM_SMCR_TS_2 | TIM_SMCR_SMS_2;
TIM3->DIER = 0; /* Disable interrupt for now */
TIM3->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_IC1F_0 | TIM_CCMR1_IC1F_3
| TIM_CCMR1_CC2S_1 | TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_3;
TIM3->CCMR2 = 0;
TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC2P;
TIM3->PSC = 72 - 1; /* 1 MHz */
TIM3->ARR = 18000; /* 18 ms */
/* Generate UEV to upload PSC and ARR */
TIM3->EGR = TIM_EGR_UG;
#elif defined(PINPAD_DIAL_SUPPORT)
/* EXTI2 <= PB2 */
AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI2_PB;
EXTI->IMR = 0;
EXTI->FTSR = EXTI_FTSR_TR2;
NVICEnableVector(EXTI2_IRQn,
CORTEX_PRIORITY_MASK(CORTEX_MINIMUM_PRIORITY));
/* TIM4 */
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
RCC->APB1RSTR = RCC_APB1RSTR_TIM4RST;
RCC->APB1RSTR = 0;
TIM4->CR1 = TIM_CR1_URS | TIM_CR1_ARPE | TIM_CR1_CKD_1;
TIM4->CR2 = 0;
TIM4->SMCR = TIM_SMCR_SMS_0;
TIM4->DIER = 0; /* no interrupt */
TIM4->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0
| TIM_CCMR1_IC1F_0 | TIM_CCMR1_IC1F_1 | TIM_CCMR1_IC1F_2 | TIM_CCMR1_IC1F_3
| TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_IC2F_2 | TIM_CCMR1_IC2F_3;
TIM4->CCMR2 = 0;
TIM4->CCER = 0;
TIM4->PSC = 0;
TIM4->ARR = 31;
/* Generate UEV to upload PSC and ARR */
TIM4->EGR = TIM_EGR_UG;
#endif
/*
* Disable JTAG and SWD, done after hwinit1_common as HAL resets AFIO
*/
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_DISABLE;
/* We use LED2 as optional "error" indicator */
palSetPad (IOPORT1, GPIOA_LED2);
}
#if defined(PINPAD_CIR_SUPPORT)
void
cir_ext_disable (void)
{
EXTI->PR = EXTI_PR_PR0;
EXTI->IMR &= ~EXTI_IMR_MR0;
}
void
cir_ext_enable (void)
{
EXTI->IMR |= EXTI_IMR_MR0;
}
extern void cir_ext_interrupt (void);
extern void cir_timer_interrupt (void);
CH_IRQ_HANDLER (EXTI0_IRQHandler)
{
CH_IRQ_PROLOGUE ();
chSysLockFromIsr ();
cir_ext_interrupt ();
chSysUnlockFromIsr ();
CH_IRQ_EPILOGUE ();
}
CH_IRQ_HANDLER (TIM3_IRQHandler)
{
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
cir_timer_interrupt ();
chSysUnlockFromIsr();
CH_IRQ_EPILOGUE();
}
#elif defined(PINPAD_DIAL_SUPPORT)
void
dial_sw_disable (void)
{
EXTI->PR = EXTI_PR_PR2;
EXTI->IMR &= ~EXTI_IMR_MR2;
}
void
dial_sw_enable (void)
{
EXTI->IMR |= EXTI_IMR_MR2;
}
extern void dial_sw_interrupt (void);
CH_IRQ_HANDLER (EXTI2_IRQHandler)
{
CH_IRQ_PROLOGUE ();
chSysLockFromIsr ();
dial_sw_interrupt ();
chSysUnlockFromIsr ();
CH_IRQ_EPILOGUE ();
}
#endif

View File

@@ -1,205 +0,0 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT 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 3 of the License, or
(at your option) any later version.
ChibiOS/RT 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, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
#ifndef _BOARD_H_
#define _BOARD_H_
#include "config.h"
/*
* Setup for the STBee Mini board.
*/
#define SET_USB_CONDITION(en) (en) /* To connect USB, call palSetPad */
#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */
#define GPIO_USB GPIOA_USB_ENABLE
#define IOPORT_USB GPIOA
#define GPIO_LED GPIOA_LED1
#define IOPORT_LED GPIOA
#define NEUG_ADC_SETTING2_SMPR1 0
#define NEUG_ADC_SETTING2_SMPR2 ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5) \
| ADC_SMPR2_SMP_AN2(ADC_SAMPLE_1P5)
#define NEUG_ADC_SETTING2_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_IN1) \
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2)
#define NEUG_ADC_SETTING2_NUM_CHANNELS 2
/*
* Board identifier.
*/
#define BOARD_STBEE_MINI
#define BOARD_NAME "STBee Mini"
#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT)
#define HAVE_7SEGLED 1
/*
* Timer assignment for CIR
*/
#define TIMx TIM3
#endif
/*
* Board frequencies.
*/
#define STM32_LSECLK 32768
#define STM32_HSECLK 12000000
/*
* MCU type, this macro is used by both the ST library and the ChibiOS/RT
* native STM32 HAL.
*/
#define STM32F10X_MD
/*
* IO pins assignments.
*/
#define GPIOA_LED1 13
#define GPIOA_USB_ENABLE 14
#define GPIOA_LED2 15
#define GPIOC_BUTTON 13
/*
* I/O ports initial setup, this configuration is established soon after reset
* in the initialization code.
*
* The digits have the following meaning:
* 0 - Analog input.
* 1 - Push Pull output 10MHz.
* 2 - Push Pull output 2MHz.
* 3 - Push Pull output 50MHz.
* 4 - Digital input.
* 5 - Open Drain output 10MHz.
* 6 - Open Drain output 2MHz.
* 7 - Open Drain output 50MHz.
* 8 - Digital input with PullUp or PullDown resistor depending on ODR.
* 9 - Alternate Push Pull output 10MHz.
* A - Alternate Push Pull output 2MHz.
* B - Alternate Push Pull output 50MHz.
* C - Reserved.
* D - Alternate Open Drain output 10MHz.
* E - Alternate Open Drain output 2MHz.
* F - Alternate Open Drain output 50MHz.
* Please refer to the STM32 Reference Manual for details.
*/
#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT)
/*
* Port A setup.
* PA1 - Digital input with PullUp. AN1 for NeuG
* PA2 - Digital input with PullUp. AN2 for NeuG
* PA6 - (TIM3_CH1) input with pull-up
* PA7 - (TIM3_CH2) input with pull-down
* PA11 - input with pull-up (USBDM)
* PA12 - input with pull-up (USBDP)
* Everything input with pull-up except:
* PA13 - Open Drain output (LED1 0:ON 1:OFF)
* PA14 - Push pull output (USB ENABLE 0:DISABLE 1:ENABLE)
* PA15 - Open Drain output (LED2 0:ON 1:OFF)
*/
#define VAL_GPIOACRL 0x88888888 /* PA7...PA0 */
#define VAL_GPIOACRH 0x63688888 /* PA15...PA8 */
#define VAL_GPIOAODR 0xFFFFFF7F
/* Port B setup. */
#define GPIOB_CIR 0
#define GPIOB_BUTTON 2
#define GPIOB_ROT_A 6
#define GPIOB_ROT_B 7
#define GPIOB_7SEG_DP 15
#define GPIOB_7SEG_A 14
#define GPIOB_7SEG_B 13
#define GPIOB_7SEG_C 12
#define GPIOB_7SEG_D 11
#define GPIOB_7SEG_E 10
#define GPIOB_7SEG_F 9
#define GPIOB_7SEG_G 8
#define VAL_GPIOBCRL 0x88888888 /* PB7...PB0 */
#define VAL_GPIOBCRH 0x66666666 /* PB15...PB8 */
#define VAL_GPIOBODR 0xFFFFFFFF
#else
/*
* Port A setup.
* PA1 - Digital input with PullUp. AN1 for NeuG
* PA2 - Digital input with PullUp. AN2 for NeuG
* PA11 - input with pull-up (USBDM)
* PA12 - input with pull-up (USBDP)
* Everything input with pull-up except:
* PA13 - Open Drain output (LED1 0:ON 1:OFF)
* PA14 - Push pull output (USB ENABLE 0:DISABLE 1:ENABLE)
* PA15 - Open Drain output (LED2 0:ON 1:OFF)
*/
#define VAL_GPIOACRL 0x88888888 /* PA7...PA0 */
#define VAL_GPIOACRH 0x63688888 /* PA15...PA8 */
#define VAL_GPIOAODR 0xFFFFFFFF
/* Port B setup. */
/* Everything input with pull-up */
#define VAL_GPIOBCRL 0x88888888 /* PB7...PB0 */
#define VAL_GPIOBCRH 0x88888888 /* PB15...PB8 */
#define VAL_GPIOBODR 0xFFFFFFFF
#endif
/*
* Port C setup.
* Everything input with pull-up except:
* PC13 - Normal input.
* PC14 - Normal input.
* PC15 - Normal input.
*/
#define VAL_GPIOCCRL 0x88888888 /* PC7...PC0 */
#define VAL_GPIOCCRH 0x44488888 /* PC15...PC8 */
#define VAL_GPIOCODR 0xFFFFFFFF
/*
* Port D setup.
* Everything input with pull-up except:
* PD0 - Normal input (XTAL).
* PD1 - Normal input (XTAL).
*/
#define VAL_GPIODCRL 0x88888844 /* PD7...PD0 */
#define VAL_GPIODCRH 0x88888888 /* PD15...PD8 */
#define VAL_GPIODODR 0xFFFFFFFF
/*
* Port E setup.
* Everything input with pull-up except:
*/
#define VAL_GPIOECRL 0x88888888 /* PE7...PE0 */
#define VAL_GPIOECRH 0x88888888 /* PE15...PE8 */
#define VAL_GPIOEODR 0xFFFFFFFF
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
#endif
void boardInit(void);
#ifdef __cplusplus
}
#endif
#endif /* _FROM_ASM_ */
#endif /* _BOARD_H_ */

View File

@@ -1,14 +0,0 @@
/*
* HAL driver system settings.
*/
#define STM32_SW STM32_SW_PLL
#define STM32_PLLSRC STM32_PLLSRC_HSE
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 6
#define STM32_HPRE STM32_HPRE_DIV1
#define STM32_PPRE1 STM32_PPRE1_DIV2
#define STM32_PPRE2 STM32_PPRE2_DIV1
#define STM32_ADCPRE STM32_ADCPRE_DIV6
#define STM32_RTCSEL STM32_RTCSEL_NOCLOCK
#include "mcuconf-common.h"

Submodule chopstx updated: f344d926c1...23893d9b73

View File

@@ -76,7 +76,6 @@ KEYPTR
----> [ P ][ Q ][ N ]
<---encrypted----><--- plain ---->
key_addr 4-byte
initial_vector (random) 16-byte
checksum_encrypted 16-byte
dek_encrypted_by_keystring_pw1 16-byte

398
misc/t-eddsa.c Normal file
View File

@@ -0,0 +1,398 @@
/*
* t-eddsa.c - testing EdDSA
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* Run following commands. The file t-ed25519.inp is available in GNU
* libgcrypt source code under 'tests' directory.
gcc -Wall -c ecc-edwards.c
gcc -Wall -c -DBN256_NO_RANDOM -DBN256_C_IMPLEMENTATION bn.c
gcc -Wall -c mod.c
gcc -Wall -c -DBN256_C_IMPLEMENTATION mod25638.c
gcc -Wall -c sha512.c
gcc -Wall -c t-eddsa.c
gcc -o t-eddsa t-eddsa.o ecc-edwards.o bn.o mod.o mod25638.o sha512.o
./t-eddsa < ./t-ed25519.inp
*
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "bn.h"
#include "affine.h"
#include "sha512.h"
static void
print_le_bn256 (const bn256 *X)
{
int i;
const uint8_t *p = (const uint8_t *)X;
for (i = 0; i < 32; i++)
printf ("%02x", p[i]);
puts ("");
}
static void
print_be_bn256 (const bn256 *X)
{
int i;
for (i = 7; i >= 0; i--)
printf ("%08x", X->word[i]);
puts ("");
}
#define MAXLINE 4096
static int lineno;
static int test_no;
static bn256 sk[1];
static bn256 pk[1];
static unsigned char msg[MAXLINE];
static size_t msglen;
static bn512 sig[1];
static const char *
skip_white_space (const char *l)
{
while (*l != '\n' && isspace (*l))
l++;
return l;
}
static int
read_hex_4bit (char c)
{
int r;
if (c >= '0' && c <= '9')
r = c - '0';
else if (c >= 'a' && c <= 'f')
r = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
r = c - 'A' + 10;
else
r = -1;
return r;
}
static int
read_hex_8bit (const char **l_p)
{
const char *l = *l_p;
int r, v;
r = read_hex_4bit (*l++);
if (r < 0)
return -1;
v = r*16;
r = read_hex_4bit (*l++);
if (r < 0)
return -1;
v += r;
*l_p = l;
return v;
}
static int
read_msg (unsigned char *msg, const char *l, int len)
{
int i, r;
for (i = 0; i < len; i++)
{
r = read_hex_8bit (&l);
if (r < 0)
return -1;
msg[i] = r;
}
return 0;
}
static int
read_le_bn256 (bn256 *sk, const char *l)
{
int i;
uint8_t *p = (uint8_t *)sk;
for (i = 0; i < sizeof (bn256); i++)
{
int r;
if (*l == '\n')
{
/* should support small input??? */
return -1;
}
r = read_hex_8bit (&l);
if (r < 0)
return -1;
p[i] = r;
}
return 0;
}
static int
read_be_bn256 (bn256 *sk, const char *l)
{
int i;
uint8_t *p = (uint8_t *)sk;
for (i = 0; i < sizeof (bn256); i++)
{
int r;
if (*l == '\n')
{
/* should support small input??? */
return -1;
}
r = read_hex_8bit (&l);
if (r < 0)
return -1;
p[31 - i] = r;
}
return 0;
}
static int
read_pk (bn256 *pk, const char *l, int len)
{
int r;
if (len == 64) /* 64 chars == 32-byte */
{ /* compressed form */
r = read_le_bn256 (pk, l);
if (r < 0)
return -1;
return 0;
}
else
{
bn256 x[1];
r = read_hex_8bit (&l);
if (r < 0)
return -1;
if (r != 4)
return -1;
r = read_be_bn256 (x, l);
if (r < 0)
return -1;
r = read_be_bn256 (pk, l+64);
if (r < 0)
return -1;
pk->word[7] ^= (x->word[0] & 1) * 0x80000000;
return 0;
}
}
static int
read_le_bn512 (bn512 *sig, const char *l)
{
int i;
uint8_t *p = (uint8_t *)sig;
for (i = 0; i < sizeof (bn512); i++)
{
int r;
if (*l == '\n')
{
/* should support small input??? */
return -1;
}
r = read_hex_8bit (&l);
if (r < 0)
return -1;
p[i] = r;
}
return 0;
}
static int
read_testcase (void)
{
ssize_t r;
size_t len = 0;
char *line = NULL;
int start = 0;
int err = 0;
test_no = 0;
memset (sk, 0, sizeof (bn256));
memset (pk, 0, sizeof (ac));
msglen = 0;
memset (sig, 0, sizeof (bn512));
while (1)
{
lineno++;
r = getline (&line, &len, stdin);
if (r < 0)
{
/* EOF */
if (!start)
err = -1;
break;
}
len = r; /* We don't need allocated size, but length. */
if (len >= MAXLINE)
{
fprintf (stderr, "Line too long: %d: >= %d\n", lineno, MAXLINE);
err = -1;
break;
}
if (r == 1 && *line == '\n')
{
if (start)
break; /* Done. */
else
continue; /* Ignore blank line before start. */
}
if (r > 0 && *line == '#') /* Ignore comment line. */
continue;
start = 1;
if (r > 4 && strncmp (line, "TST:", 4) == 0)
test_no = strtol (line+4, NULL, 10);
else if (r > 3 && strncmp (line, "SK:", 3) == 0)
{
const char *l = skip_white_space (line+3);
if (read_le_bn256 (sk, l) < 0)
{
fprintf (stderr, "read_le_bn256: %d\n", lineno);
err = -1;
break;
}
}
else if (r > 3 && strncmp (line, "PK:", 3) == 0)
{
const char *l = skip_white_space (line+3);
if (read_pk (pk, l, line+len-1-l) < 0)
{
fprintf (stderr, "read_pk: %d\n", lineno);
err = -1;
break;
}
}
else if (r > 4 && strncmp (line, "MSG:", 4) == 0)
{
const char *l = skip_white_space (line+4);
msglen = (line+len-1-l)/2;
if (read_msg (msg, l, msglen) < 0)
{
fprintf (stderr, "read_msg: %d\n", lineno);
err = -1;
break;
}
}
else if (r > 4 && strncmp (line, "SIG:", 4) == 0)
{
const char *l = skip_white_space (line+4);
if (read_le_bn512 (sig, l) < 0)
{
fprintf (stderr, "read_le_bn512: %d\n", lineno);
err = -1;
break;
}
}
else
{
fprintf (stderr, "Garbage line: %d", lineno);
err = -1;
break;
}
}
free (line);
return err;
}
int
main (int argc, char *argv[])
{
int all_good = 1;
int r;
bn256 pk_calculated[1];
uint8_t hash[64];
bn256 a[1];
bn256 *R, *S;
uint8_t out[64];
extern void eddsa_sign_25519 (const uint8_t *input, size_t ilen,
uint8_t *output,
const bn256 *a, const uint8_t *seed,
const bn256 *pk);
extern void eddsa_public_key_25519 (bn256 *pk, const bn256 *a);
R = (bn256 *)out;
S = (bn256 *)(out+32);
while (1)
{
r = read_testcase ();
if (r < 0)
break;
sha512 ((uint8_t *)sk, sizeof (bn256), hash);
hash[0] &= 248;
hash[31] &= 127;
hash[31] |= 64;
memcpy (a, hash, sizeof (bn256)); /* Lower half of hash */
eddsa_public_key_25519 (pk_calculated, a);
if (memcmp (pk, pk_calculated, sizeof (bn256)) != 0)
{
printf ("ERR PK: %d\n", test_no);
print_be_bn256 (sk);
print_be_bn256 (pk);
print_be_bn256 (pk_calculated);
all_good = 0;
continue;
}
eddsa_sign_25519 (msg, msglen, out, a, hash+32, pk);
if (memcmp (sig, R, sizeof (bn256)) != 0
|| memcmp (((const uint8_t *)sig)+32, S, sizeof (bn256)) != 0)
{
printf ("ERR SIG: %d\n", test_no);
print_le_bn256 (R);
print_le_bn256 (S);
print_le_bn256 ((const bn256 *)sig);
print_le_bn256 ((const bn256 *)(((const uint8_t *)sig)+32));
all_good = 0;
continue;
}
printf ("%d\n", test_no);
}
return all_good == 1?0:1;
}

View File

@@ -1545,7 +1545,8 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
{
int ret;
size_t i = mpi_msb( E );
size_t wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
size_t wsize = ( i > 1024 ) ? 4 : /* Because of not enough memory. */
( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
size_t wbits, one = 1;
size_t nblimbs;

View File

@@ -671,14 +671,14 @@ int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx,
size_t ilen, pad_count = 0;
unsigned char *p, *q;
unsigned char bt;
unsigned char buf[POLARSSL_MPI_MAX_SIZE];
unsigned char buf[ctx->len];
if( ctx->padding != RSA_PKCS_V15 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
ilen = ctx->len;
if( ilen < 16 || ilen > sizeof( buf ) )
if( ilen < 16)
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
ret = ( mode == RSA_PUBLIC )

View File

@@ -12,7 +12,10 @@ CSRC = main.c usb_stm32f103.c adc_stm32f103.c \
usb_desc.c usb_ctrl.c \
call-rsa.c \
usb-icc.c openpgp.c ac.c openpgp-do.c flash.c \
bn.c modp256.c jpc.c mod.c ec_p256.c call-ec_p256.c \
bn.c mod.c \
modp256r1.c jpc_p256r1.c ec_p256r1.c call-ec_p256r1.c \
modp256k1.c jpc_p256k1.c ec_p256k1.c call-ec_p256k1.c \
mod25638.c ecc-edwards.c sha512.c \
random.c neug.c sha256.c sys.c
INCDIR =
@@ -52,7 +55,7 @@ OBJCOPY = $(CROSS)objcopy
MCU = cortex-m3
CWARN = -Wall -Wextra -Wstrict-prototypes
# DEFS: Add
DEFS = -DCHX_PRIO_MAIN=5 -DRSA_AUTH @KEYGEN_SUPPORT@ @HAVE_SYS_H@
DEFS = -DCHX_PRIO_MAIN=5 @KEYGEN_SUPPORT@ @HAVE_SYS_H@
OPT = -O3 -Os -g
LIBS =
@@ -65,6 +68,8 @@ board.h:
sys.c: board.h
build/bignum.o: OPT = -O3 -g
distclean: clean
-rm -f gnuk.ld config.h board.h Makefile \
usb-strings.c.inc usb-vid-pid-ver.c.inc

8
src/affine.h Normal file
View File

@@ -0,0 +1,8 @@
/**
* @brief Affine coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
} ac;

232
src/bn.c
View File

@@ -1,7 +1,7 @@
/*
* bn.c -- 256-bit (and 512-bit) bignum calculation
*
* Copyright (C) 2011, 2013 Free Software Initiative of Japan
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -22,28 +22,32 @@
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifndef BN256_NO_RANDOM
#include "random.h"
#endif
#include "bn.h"
uint32_t
bn256_add (bn256 *X, const bn256 *A, const bn256 *B)
{
int i;
uint32_t v;
uint32_t carry = 0;
uint32_t *px;
const uint32_t *pa, *pb;
px = X->words;
pa = A->words;
pb = B->words;
px = X->word;
pa = A->word;
pb = B->word;
for (i = 0; i < BN256_WORDS; i++)
{
v = *pb;
*px = *pa + carry;
carry = (*px < carry);
*px += *pb;
carry += (*px < *pb);
*px += v;
carry += (*px < v);
px++;
pa++;
pb++;
@@ -56,21 +60,23 @@ uint32_t
bn256_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
int i;
uint32_t v;
uint32_t borrow = 0;
uint32_t *px;
const uint32_t *pa, *pb;
px = X->words;
pa = A->words;
pb = B->words;
px = X->word;
pa = A->word;
pb = B->word;
for (i = 0; i < BN256_WORDS; i++)
{
uint32_t borrow0 = (*pa < borrow);
v = *pb;
*px = *pa - borrow;
borrow = (*px < *pb) + borrow0;
*px -= *pb;
borrow = (*px < v) + borrow0;
*px -= v;
px++;
pa++;
pb++;
@@ -83,23 +89,17 @@ uint32_t
bn256_add_uint (bn256 *X, const bn256 *A, uint32_t w)
{
int i;
uint32_t carry = 0;
uint32_t carry = w;
uint32_t *px;
const uint32_t *pa;
px = X->words;
pa = A->words;
px = X->word;
pa = A->word;
for (i = 0; i < BN256_WORDS; i++)
{
*px = *pa + carry;
carry = (*px < carry);
if (i == 0)
{
*px += w;
carry += (*px < w);
}
px++;
pa++;
}
@@ -111,26 +111,19 @@ uint32_t
bn256_sub_uint (bn256 *X, const bn256 *A, uint32_t w)
{
int i;
uint32_t borrow = 0;
uint32_t borrow = w;
uint32_t *px;
const uint32_t *pa;
px = X->words;
pa = A->words;
px = X->word;
pa = A->word;
for (i = 0; i < BN256_WORDS; i++)
{
uint32_t borrow0 = (*pa < borrow);
*px = *pa - borrow;
if (i == 0)
{
borrow = (*px < w) + borrow0;
*px -= w;
}
else
borrow = borrow0;
borrow = borrow0;
px++;
pa++;
}
@@ -138,9 +131,30 @@ bn256_sub_uint (bn256 *X, const bn256 *A, uint32_t w)
return borrow;
}
#ifndef BN256_C_IMPLEMENTATION
#define ASM_IMPLEMENTATION 1
#endif
void
bn256_mul (bn512 *X, const bn256 *A, const bn256 *B)
{
#if ASM_IMPLEMENTATION
#include "muladd_256.h"
const uint32_t *s;
uint32_t *d;
uint32_t w;
uint32_t c;
memset (X->word, 0, sizeof (uint32_t)*BN256_WORDS*2);
s = A->word; d = &X->word[0]; w = B->word[0]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[1]; w = B->word[1]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[2]; w = B->word[2]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[3]; w = B->word[3]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[4]; w = B->word[4]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[5]; w = B->word[5]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[6]; w = B->word[6]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[7]; w = B->word[7]; MULADD_256 (s, d, w, c);
#else
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
@@ -167,7 +181,7 @@ bn256_mul (bn512 *X, const bn256 *A, const bn256 *B)
j = k - i;
uv = ((uint64_t )A->words[i])*((uint64_t )B->words[j]);
uv = ((uint64_t )A->word[i])*((uint64_t )B->word[j]);
v = uv;
u = (uv >> 32);
r0 += v;
@@ -179,18 +193,96 @@ bn256_mul (bn512 *X, const bn256 *A, const bn256 *B)
r2 += carry;
}
X->words[k] = r0;
X->word[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
X->words[k] = r0;
X->word[k] = r0;
#endif
}
void
bn256_sqr (bn512 *X, const bn256 *A)
{
#if ASM_IMPLEMENTATION
int i;
memset (X->word, 0, sizeof (bn512));
for (i = 0; i < BN256_WORDS; i++)
{
uint32_t *wij = &X->word[i*2];
const uint32_t *xj = &A->word[i];
uint32_t x_i = *xj++;
uint32_t c;
asm (/* (C,R4,R5) := w_i_i + x_i*x_i; w_i_i := R5; */
"mov %[c], #0\n\t"
"ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */
"mov r4, %[c]\n\t"
"umlal r5, r4, %[x_i], %[x_i]\n\t"
"str r5, [%[wij]], #4\n\t"
"cmp %[xj], %[x_max1]\n\t"
"bhi 0f\n\t"
"mov r9, %[c]\n\t" /* R9 := 0, the constant ZERO from here. */
"beq 1f\n"
"2:\n\t"
"ldmia %[xj]!, { r7, r8 }\n\t"
"ldmia %[wij], { r5, r6 }\n\t"
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
"umull r7, r12, %[x_i], r7\n\t"
"adds r5, r5, r4\n\t"
"adc r4, %[c], r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
/* (C,R4,R6) := (C,R4) + w_i_j + 2*x_i*x_j; */
"adds r6, r6, r4\n\t"
"adc r4, %[c], r9\n\t"
"umull r7, r12, %[x_i], r8\n\t"
"adds r6, r6, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r6, r6, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
/**/
"stmia %[wij]!, { r5, r6 }\n\t"
"cmp %[xj], %[x_max1]\n\t"
"bcc 2b\n\t"
"bne 0f\n"
"1:\n\t"
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
"ldr r5, [%[wij]]\n\t"
"ldr r6, [%[xj]], #4\n\t"
"adds r5, r5, r4\n\t"
"adc r4, %[c], r9\n\t"
"umull r7, r12, %[x_i], r6\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
"str r5, [%[wij]], #4\n"
"0:\n\t"
"ldr r5, [%[wij]]\n\t"
"adds r4, r4, r5\n\t"
"adc %[c], %[c], #0\n\t"
"str r4, [%[wij]], #4"
: [c] "=&r" (c), [wij] "=r" (wij), [xj] "=r" (xj)
: [x_i] "r" (x_i), [x_max1] "r" (&A->word[BN256_WORDS-1]),
"[wij]" (wij), "[xj]" (xj)
: "r4", "r5", "r6", "r7", "r8", "r9", "r12", "memory", "cc");
if (i < BN256_WORDS - 1)
*wij = c;
}
#else
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
@@ -217,11 +309,10 @@ bn256_sqr (bn512 *X, const bn256 *A)
j = k - i;
uv = ((uint64_t )A->words[i])*((uint64_t )A->words[j]);
uv = ((uint64_t )A->word[i])*((uint64_t )A->word[j]);
if (i < j)
{
if ((uv >> 63) != 0)
r2++;
r2 += ((uv >> 63) != 0);
uv <<= 1;
}
v = uv;
@@ -235,13 +326,14 @@ bn256_sqr (bn512 *X, const bn256 *A)
r2 += carry;
}
X->words[k] = r0;
X->word[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
X->words[k] = r0;
X->word[k] = r0;
#endif
}
uint32_t
@@ -254,8 +346,8 @@ bn256_shift (bn256 *X, const bn256 *A, int shift)
{
for (i = 0; i < BN256_WORDS; i++)
{
next_carry = A->words[i] >> (32 - shift);
X->words[i] = (A->words[i] << shift) | carry;
next_carry = A->word[i] >> (32 - shift);
X->word[i] = (A->word[i] << shift) | carry;
carry = next_carry;
}
}
@@ -265,8 +357,8 @@ bn256_shift (bn256 *X, const bn256 *A, int shift)
for (i = BN256_WORDS - 1; i >= 0; i--)
{
next_carry = A->words[i] & ((1 << shift) - 1);
X->words[i] = (A->words[i] >> shift) | (carry << (32 - shift));
next_carry = A->word[i] & ((1 << shift) - 1);
X->word[i] = (A->word[i] >> shift) | (carry << (32 - shift));
carry = next_carry;
}
}
@@ -278,63 +370,59 @@ int
bn256_is_zero (const bn256 *X)
{
int i;
int r = 1;
for (i = 0; i < BN256_WORDS; i++)
if (X->words[i] != 0)
return 0;
r &= (X->word[i] == 0);
return 1;
return r;
}
int
bn256_is_even (const bn256 *X)
{
return !(X->words[0] & 1);
return !(X->word[0] & 1);
}
int
bn256_is_ge (const bn256 *A, const bn256 *B)
{
int i;
uint32_t borrow;
bn256 tmp[1];
for (i = BN256_WORDS - 1; i >= 0; i--)
if (A->words[i] > B->words[i])
return 1;
else if (A->words[i] < B->words[i])
return 0;
return 1;
borrow = bn256_sub (tmp, A, B);
return borrow == 0;
}
int
bn256_cmp (const bn256 *A, const bn256 *B)
{
int i;
uint32_t borrow;
int is_zero;
bn256 tmp[1];
for (i = BN256_WORDS - 1; i >= 0; i--)
if (A->words[i] > B->words[i])
return 1;
else if (A->words[i] < B->words[i])
return -1;
return 0;
borrow = bn256_sub (tmp, A, B);
is_zero = bn256_is_zero (tmp);
return is_zero ? 0 : (borrow ? -1 : 1);
}
#ifndef BN256_NO_RANDOM
void
bn256_random (bn256 *X)
{
const uint8_t *rand = random_bytes_get ();
X->words[7] = ((uint32_t *)rand)[7];
X->words[6] = ((uint32_t *)rand)[6];
X->words[5] = ((uint32_t *)rand)[5];
X->words[4] = ((uint32_t *)rand)[4];
X->words[3] = ((uint32_t *)rand)[3];
X->words[2] = ((uint32_t *)rand)[2];
X->words[1] = ((uint32_t *)rand)[1];
X->words[0] = ((uint32_t *)rand)[0];
X->word[7] = ((uint32_t *)rand)[7];
X->word[6] = ((uint32_t *)rand)[6];
X->word[5] = ((uint32_t *)rand)[5];
X->word[4] = ((uint32_t *)rand)[4];
X->word[3] = ((uint32_t *)rand)[3];
X->word[2] = ((uint32_t *)rand)[2];
X->word[1] = ((uint32_t *)rand)[1];
X->word[0] = ((uint32_t *)rand)[0];
random_bytes_free (rand);
}
#endif

View File

@@ -1,11 +1,11 @@
#define BN256_WORDS 8
typedef struct bn256 {
uint32_t words[ BN256_WORDS ]; /* Little endian */
uint32_t word[ BN256_WORDS ]; /* Little endian */
} bn256;
#define BN512_WORDS 16
typedef struct bn512 {
uint32_t words[ BN512_WORDS ]; /* Little endian */
uint32_t word[ BN512_WORDS ]; /* Little endian */
} bn512;
uint32_t bn256_add (bn256 *X, const bn256 *A, const bn256 *B);

View File

@@ -1,7 +1,7 @@
/*
* call-ec_p256.c - interface between Gnuk and Elliptic curve over GF(p256)
* call-ec.c - interface between Gnuk and Elliptic curve over GF(prime)
*
* Copyright (C) 2013 Free Software Initiative of Japan
* Copyright (C) 2013, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -21,24 +21,16 @@
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bn.h"
#include "jpc-ac.h"
#include "ec_p256.h"
#include "field-group-select.h"
#include "config.h"
#include "gnuk.h"
/* We are little endian. */
/* We are little-endian in the computation, but the protocol is big-endian. */
#define ECDSA_BYTE_SIZE 32
#define ECDH_BYTE_SIZE 32
int
ecdsa_sign (const uint8_t *hash, uint8_t *output,
const struct key_data *kd)
FUNC(ecdsa_sign) (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data)
{
int i;
bn256 r[1], s[1], z[1], d[1];
@@ -46,13 +38,13 @@ ecdsa_sign (const uint8_t *hash, uint8_t *output,
p = (uint8_t *)d;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = kd->data[i];
p[ECDSA_BYTE_SIZE - i - 1] = key_data[i];
p = (uint8_t *)z;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = hash[i];
ecdsa (r, s, z, d);
FUNC(ecdsa) (r, s, z, d);
p = (uint8_t *)r;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
*output++ = p[ECDSA_BYTE_SIZE - i - 1];
@@ -63,7 +55,7 @@ ecdsa_sign (const uint8_t *hash, uint8_t *output,
}
uint8_t *
ecdsa_compute_public (const uint8_t *key_data)
FUNC(ecc_compute_public) (const uint8_t *key_data)
{
uint8_t *p0, *p, *p1;
ac q[1];
@@ -77,7 +69,7 @@ ecdsa_compute_public (const uint8_t *key_data)
p = (uint8_t *)k;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = key_data[i];
if (compute_kG (q, k) < 0)
if (FUNC(compute_kG) (q, k) < 0)
{
free (p0);
return NULL;
@@ -93,3 +85,42 @@ ecdsa_compute_public (const uint8_t *key_data)
return p0;
}
int
FUNC(ecdh_decrypt) (const uint8_t *input, uint8_t *output,
const uint8_t *key_data)
{
bn256 k[1];
ac X[1], P[1];
int i;
uint8_t *p0;
const uint8_t *p1;
int r;
p0 = (uint8_t *)k;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
p0[ECDH_BYTE_SIZE - i - 1] = key_data[i];
p1 = input+1; /* skip '04' */
p0 = (uint8_t *)P->x;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
p0[ECDH_BYTE_SIZE - i - 1] = *p1++;
p0 = (uint8_t *)P->y;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
p0[ECDH_BYTE_SIZE - i - 1] = *p1++;
r = FUNC(compute_kP) (X, k, P);
if (r == 0)
{
p0 = output;
p1 = (const uint8_t *)X->x;
*p0++ = 4;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
*p0++ = p1[ECDH_BYTE_SIZE - i - 1];
p1 = (const uint8_t *)X->y;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
*p0++ = p1[ECDH_BYTE_SIZE - i - 1];
}
return r;
}

35
src/call-ec_p256k1.c Normal file
View File

@@ -0,0 +1,35 @@
/*
* call-ec_p256k1.c - interface between Gnuk and Elliptic curve over
* GF(p256k1)
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bn.h"
#include "affine.h"
#include "jpc-ac_p256k1.h"
#include "ec_p256k1.h"
#define FIELD p256k1
#include "call-ec.c"

35
src/call-ec_p256r1.c Normal file
View File

@@ -0,0 +1,35 @@
/*
* call-ec_p256r1.c - interface between Gnuk and Elliptic curve over
* GF(p256r1)
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bn.h"
#include "affine.h"
#include "jpc-ac_p256r1.h"
#include "ec_p256r1.h"
#define FIELD p256r1
#include "call-ec.c"

View File

@@ -1,7 +1,8 @@
/*
* call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol
*
* Copyright (C) 2010, 2011, 2012, 2013 Free Software Initiative of Japan
* Copyright (C) 2010, 2011, 2012, 2013, 2014
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -32,29 +33,25 @@
#include "polarssl/config.h"
#include "polarssl/rsa.h"
#define RSA_SIGNATURE_LENGTH KEY_CONTENT_LEN
/* 256 byte == 2048-bit */
/* 128 byte == 1024-bit */
static rsa_context rsa_ctx;
int
rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
struct key_data *kd)
struct key_data *kd, int pubkey_len)
{
mpi P1, Q1, H;
int ret = 0;
unsigned char temp[RSA_SIGNATURE_LENGTH];
unsigned char temp[pubkey_len];
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
mpi_init (&P1); mpi_init (&Q1); mpi_init (&H);
rsa_ctx.len = KEY_CONTENT_LEN;
rsa_ctx.len = pubkey_len;
MPI_CHK( mpi_lset (&rsa_ctx.E, 0x10001) );
MPI_CHK( mpi_read_binary (&rsa_ctx.P, &kd->data[0], rsa_ctx.len / 2) );
MPI_CHK( mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2],
rsa_ctx.len / 2) );
MPI_CHK( mpi_read_binary (&rsa_ctx.P, &kd->data[0], pubkey_len / 2) );
MPI_CHK( mpi_read_binary (&rsa_ctx.Q, &kd->data[pubkey_len / 2],
pubkey_len / 2) );
#if 0
MPI_CHK( mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q) );
#endif
@@ -74,7 +71,7 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
ret = rsa_rsassa_pkcs1_v15_sign (&rsa_ctx, NULL, NULL,
RSA_PRIVATE, SIG_RSA_RAW,
msg_len, raw_message, temp);
memcpy (output, temp, RSA_SIGNATURE_LENGTH);
memcpy (output, temp, pubkey_len);
}
rsa_free (&rsa_ctx);
@@ -86,7 +83,7 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
}
else
{
res_APDU_size = RSA_SIGNATURE_LENGTH;
res_APDU_size = pubkey_len;
DEBUG_INFO ("done.\r\n");
GPG_SUCCESS ();
return 0;
@@ -139,9 +136,8 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
DEBUG_WORD (msg_len);
MPI_CHK( mpi_lset (&rsa_ctx.E, 0x10001) );
MPI_CHK( mpi_read_binary (&rsa_ctx.P, &kd->data[0], KEY_CONTENT_LEN / 2) );
MPI_CHK( mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2],
KEY_CONTENT_LEN / 2) );
MPI_CHK( mpi_read_binary (&rsa_ctx.P, &kd->data[0], msg_len / 2) );
MPI_CHK( mpi_read_binary (&rsa_ctx.Q, &kd->data[msg_len / 2], msg_len / 2) );
#if 0
MPI_CHK( mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q) );
#endif
@@ -179,14 +175,15 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
}
int
rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
rsa_verify (const uint8_t *pubkey, int pubkey_len,
const uint8_t *hash, const uint8_t *sig)
{
int ret;
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
rsa_ctx.len = KEY_CONTENT_LEN;
rsa_ctx.len = pubkey_len;
MPI_CHK( mpi_lset (&rsa_ctx.E, 0x10001) );
MPI_CHK( mpi_read_binary (&rsa_ctx.N, pubkey, KEY_CONTENT_LEN) );
MPI_CHK( mpi_read_binary (&rsa_ctx.N, pubkey, pubkey_len) );
DEBUG_INFO ("RSA verify...");
@@ -212,14 +209,14 @@ rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
#ifdef KEYGEN_SUPPORT
uint8_t *
rsa_genkey (void)
rsa_genkey (int pubkey_len)
{
int ret;
uint8_t index = 0;
uint8_t *p_q_modulus = (uint8_t *)malloc (KEY_CONTENT_LEN*2);
uint8_t *p_q_modulus = (uint8_t *)malloc (pubkey_len * 2);
uint8_t *p = p_q_modulus;
uint8_t *q = p_q_modulus + KEY_CONTENT_LEN/2;
uint8_t *modulus = p_q_modulus + KEY_CONTENT_LEN;
uint8_t *q = p_q_modulus + pubkey_len / 2;
uint8_t *modulus = p_q_modulus + pubkey_len;
extern int prng_seed (int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng);
extern void neug_flush (void);
@@ -231,8 +228,8 @@ rsa_genkey (void)
prng_seed (random_gen, &index);
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
MPI_CHK( rsa_gen_key (&rsa_ctx, random_gen, &index,
KEY_CONTENT_LEN * 8, RSA_EXPONENT) );
MPI_CHK( rsa_gen_key (&rsa_ctx, random_gen, &index, pubkey_len * 8,
RSA_EXPONENT) );
if (ret != 0)
{
free (p_q_modulus);
@@ -240,9 +237,9 @@ rsa_genkey (void)
return NULL;
}
MPI_CHK( mpi_write_binary (&rsa_ctx.P, p, KEY_CONTENT_LEN/2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.Q, q, KEY_CONTENT_LEN/2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.N, modulus, KEY_CONTENT_LEN) );
MPI_CHK( mpi_write_binary (&rsa_ctx.P, p, pubkey_len / 2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.Q, q, pubkey_len / 2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.N, modulus, pubkey_len) );
cleanup:
rsa_free (&rsa_ctx);

View File

@@ -1,74 +0,0 @@
/* ChibiOS/RT configuration file */
#ifndef _CHCONF_H_
#define _CHCONF_H_
#include <config.h>
#ifdef DFU_SUPPORT
#define CORTEX_VTOR_INIT (0x00003000+0x00001000)
#else
#define CORTEX_VTOR_INIT 0x00001000
#endif
#define CH_FREQUENCY 1000
#define CH_TIME_QUANTUM 20
#define CH_USE_NESTED_LOCKS FALSE
#define CH_MEMCORE_SIZE 0 /* Whole RAM */
#define CH_NO_IDLE_THREAD FALSE
#define CH_OPTIMIZE_SPEED TRUE
#define CH_USE_REGISTRY TRUE
#define CH_USE_WAITEXIT TRUE
#define CH_USE_SEMAPHORES TRUE
#define CH_USE_SEMAPHORES_PRIORITY FALSE
#define CH_USE_SEMSW FALSE
#define CH_USE_MUTEXES TRUE
#define CH_USE_CONDVARS TRUE
#define CH_USE_CONDVARS_TIMEOUT TRUE
#define CH_USE_EVENTS TRUE /* We use this! */
#define CH_USE_EVENTS_TIMEOUT TRUE /* We use this! */
#define CH_USE_MESSAGES FALSE
#define CH_USE_MESSAGES_PRIORITY FALSE
#define CH_USE_MAILBOXES FALSE
#define CH_USE_QUEUES FALSE
#define CH_USE_MEMCORE TRUE
#define CH_USE_HEAP TRUE
#define CH_USE_MALLOC_HEAP FALSE
#define CH_USE_MEMPOOLS FALSE
#define CH_USE_DYNAMIC TRUE
/* Debug options */
#define CH_DBG_ENABLE_CHECKS FALSE
#define CH_DBG_ENABLE_ASSERTS FALSE
#define CH_DBG_ENABLE_TRACE FALSE
#define CH_DBG_ENABLE_STACK_CHECK TRUE
#define CH_DBG_FILL_THREADS FALSE
#define CH_DBG_THREADS_PROFILING FALSE
#define THREAD_EXT_FIELDS \
/* Add threads custom fields here.*/ \
#define THREAD_EXT_INIT(tp) { \
/* Add threads initialization code here.*/ \
}
#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) { \
/* System halt code here.*/ \
}
#define THREAD_EXT_EXIT(tp) { \
/* Add threads finalization code here.*/ \
}
#define IDLE_LOOP_HOOK() { \
/* Idle loop code here.*/ \
}
#define SYSTEM_TICK_EVENT_HOOK() { \
/* System tick event code here.*/ \
}
#define SYSTEM_HALT_HOOK() { \
/* System halt code here.*/ \
}
#endif /* _CHCONF_H_ */

20
src/configure vendored
View File

@@ -3,7 +3,8 @@
#
# This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka
#
# Copyright (C) 2010, 2011, 2012, 2013 Free Software Initiative of Japan
# Copyright (C) 2010, 2011, 2012, 2013, 2014
# Free Software Initiative of Japan
#
# This file is a part of Gnuk, a GnuPG USB Token implementation.
# Gnuk is free software: you can redistribute it and/or modify it
@@ -22,7 +23,7 @@
# Default settings
help=no
vidpid=none
target=OLIMEX_STM32_H103
target=FST_01
verbose=no
with_dfu=default
debug=no
@@ -93,12 +94,13 @@ Defaults for the options are specified in brackets.
Configuration:
-h, --help display this help and exit [no]
--vidpid=VID:PID specify vendor/product ID [<NONE>]
--target=TARGET specify target [OLIMEX_STM32_H103]
--target=TARGET specify target [FST_01]
supported targets are:
OLIMEX_STM32_H103
STM8S_DISCOVERY
FST_01
FST_01_00
OLIMEX_STM32_H103
STBEE
STBEE_MINI
FST_01_00 (unreleased version with 8MHz XTAL)
--enable-debug debug with virtual COM port [no]
--enable-pinpad=cir
PIN entry support [no]
@@ -169,6 +171,10 @@ fi
# --with-dfu option
if test "$with_dfu" = "yes"; then
if test "$target" = "FST_01" -o "$target" = "FST_01_00"; then
echo "FST-01 doesn't have DFU loader, you should not enable this."
exit 1
fi
echo "Configured for DFU"
ORIGIN=0x08003000
FLASH_SIZE=`expr $FLASH_SIZE - 12`
@@ -321,6 +327,8 @@ if test "$certdo" = "yes"; then
-e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
-e "s/@MSC_SIZE@/$MSC_SIZE/" \
-e "s/@TIM_SIZE@/$TIM_SIZE/" \
-e "s/@EXT_SIZE@/$EXT_SIZE/" \
< gnuk.ld.in > gnuk.ld
else
sed -e "/^@CERTDO_SUPPORT_START@$/,/^@CERTDO_SUPPORT_END@$/ d" \

View File

@@ -1,12 +0,0 @@
/* Non-adjacent form */
typedef struct naf4_257 {
uint32_t words[ BN256_WORDS*4 ]; /* Little endian */
uint8_t last_nibble; /* most significant nibble */
} naf4_257;
void compute_naf4_257 (naf4_257 *NAF_K, const bn256 *K);
int compute_kP (ac *X, const naf4_257 *NAF_K, const ac *P);
int compute_kG (ac *X, const bn256 *K);
void ecdsa (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d);

231
src/ec_p256k1.c Normal file
View File

@@ -0,0 +1,231 @@
/* -*- coding: utf-8 -*-
* ec_p256k1.c - Elliptic curve over GF(p256k1)
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Note: we don't take advantage of the specific feature of this curve,
* but use same method of computation as NIST P-256 curve. That's due
* to some software patent(s).
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256k1.h"
#include "affine.h"
#include "jpc-ac_p256k1.h"
#include "mod.h"
#include "ec_p256k1.h"
#define FIELD p256k1
#define COEFFICIENT_A_IS_ZERO 1
/*
* a = 0, b = 7
*/
static const bn256 coefficient_a[1] = {
{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}
};
static const bn256 coefficient_b[1] = {
{{ 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}
};
static const ac precomputed_KG[15] = {
{
{{{ 0x16f81798, 0x59f2815b, 0x2dce28d9, 0x029bfcdb,
0xce870b07, 0x55a06295, 0xf9dcbbac, 0x79be667e }}},
{{{ 0xfb10d4b8, 0x9c47d08f, 0xa6855419, 0xfd17b448,
0x0e1108a8, 0x5da4fbfc, 0x26a3c465, 0x483ada77 }}}
}, {
{{{ 0x42d0e6bd, 0x13b7e0e7, 0xdb0f5e53, 0xf774d163,
0x104d6ecb, 0x82a2147c, 0x243c4e25, 0x3322d401 }}},
{{{ 0x6c28b2a0, 0x24f3a2e9, 0xa2873af6, 0x2805f63e,
0x4ddaf9b7, 0xbfb019bc, 0xe9664ef5, 0x56e70797 }}}
}, {
{{{ 0x829d122a, 0xdca81127, 0x67e99549, 0x8f17f314,
0x6a8a9e73, 0x9b889085, 0x846dd99d, 0x583fdfd9 }}},
{{{ 0x63c4eac4, 0xf3c7719e, 0xb734b37a, 0xb44685a3,
0x572a47a6, 0x9f92d2d6, 0x2ff57d81, 0xabc6232f }}}
}, {
{{{ 0x9ec4c0da, 0x1b7b444c, 0x723ea335, 0xe88c5678,
0x981f162e, 0x9239c1ad, 0xf63b5f33, 0x8f68b9d2 }}},
{{{ 0x501fff82, 0xf23cbf79, 0x95510bfd, 0xbbea2cfe,
0xb6be215d, 0xde1d90c2, 0xba063986, 0x662a9f2d }}}
}, {
{{{ 0x114cbf09, 0x63c5e885, 0x7be77e3e, 0x2f27ce93,
0xf54a3e33, 0xdaa6d12d, 0x3eff872c, 0x8b300e51 }}},
{{{ 0xb3b10a39, 0x26c6ff28, 0x9aaf7169, 0x08f6a7aa,
0x6b8238ea, 0x446f0d46, 0x7f43c0cc, 0x1cec3067 }}}
}, {
{{{ 0x075e9070, 0xba16ce6a, 0x9b5cfe37, 0xbc26893d,
0x9c510774, 0xe1ddadfe, 0xfe3ae2f4, 0x90922d88 }}},
{{{ 0x5c08824a, 0x653943cc, 0xfce8f4bc, 0x06d74475,
0x533c615d, 0x8d101fa7, 0x742108a9, 0x7b1903f6 }}}
}, {
{{{ 0x6ebdc96c, 0x1bcfa45c, 0x1c7584ba, 0xe400bc04,
0x74cf531f, 0x6395e20e, 0xc5131b30, 0x1edd0bb1 }}},
{{{ 0xe358cf9e, 0xa117161b, 0x2724d11c, 0xe490d6f0,
0xee6dd8c9, 0xf75062f6, 0xfba373e4, 0x31e03b2b }}}
}, {
{{{ 0x2120e2b3, 0x7f3b58fa, 0x7f47f9aa, 0x7a58fdce,
0x4ce6e521, 0xe7be4ae3, 0x1f51bdba, 0xeaa649f2 }}},
{{{ 0xba5ad93d, 0xd47a5305, 0xf13f7e59, 0x01a6b965,
0x9879aa5a, 0xc69a80f8, 0x5bbbb03a, 0xbe3279ed }}}
}, {
{{{ 0x27bb4d71, 0xcf291a33, 0x33524832, 0x6caf7d6b,
0x766584ee, 0x6e0ee131, 0xd064c589, 0x160cb0f6 }}},
{{{ 0x17136e8d, 0x9d5de554, 0x1aab720e, 0xe3f2d468,
0xccf75cc2, 0xd1378b49, 0xc4ff16e1, 0x6920c375 }}}
}, {
{{{ 0x1a9ee611, 0x3eef9e96, 0x9cc37faf, 0xfe4d7bf3,
0xb321d965, 0x462aa9b3, 0x208736c5, 0x1702da3e }}},
{{{ 0x3a545ceb, 0xfba57bbf, 0x7ea858f5, 0x6dbcd766,
0x680d92f1, 0x088e897c, 0xbc626c80, 0x468c1fd8 }}}
}, {
{{{ 0xb188660a, 0xb40f85c7, 0x99bc3c36, 0xc5873c19,
0x7f33b54c, 0x3c7b4541, 0x1f8c9bf8, 0x4cd3a93c }}},
{{{ 0x33099cb0, 0xf8dce380, 0x2edd2f33, 0x7a167dd6,
0x0ffe35b7, 0x576d8987, 0xc68ace5c, 0xd2de0386 }}}
}, {
{{{ 0x6658bb08, 0x9a9e0a72, 0xc589607b, 0xe23c5f2a,
0xf2bfb4c8, 0xa048ca14, 0xc62c2291, 0x4d9a0f89 }}},
{{{ 0x0f827294, 0x427b5f31, 0x9f2c35cd, 0x1ea7a8b5,
0x85a3c00f, 0x95442e56, 0x9b57975a, 0x8cb83121 }}}
}, {
{{{ 0x51f5cf67, 0x4333f0da, 0xf4f0d3cb, 0x6d3ea47c,
0xa05a831f, 0x442fda14, 0x016d3e81, 0x6a496013 }}},
{{{ 0xe52e0f48, 0xf647318c, 0x4a0d5ff1, 0x5ff3a66e,
0x61199ba8, 0x046ed81a, 0x3e79c23a, 0x578edf08 }}}
}, {
{{{ 0x3ea01ea7, 0xb8f996f8, 0x7497bb15, 0xc0045d33,
0x6205647c, 0xc4749dc9, 0x0efd22c9, 0xd8946054 }}},
{{{ 0x12774ad5, 0x062dcb09, 0x8be06e3a, 0xcb13f310,
0x235de1a9, 0xca281d35, 0x69c3645c, 0xaf8a7412 }}}
}, {
{{{ 0xbeb8b1e2, 0x8808ca5f, 0xea0dda76, 0x0262b204,
0xddeb356b, 0xb6fffffc, 0xfbb83870, 0x52de253a }}},
{{{ 0x8f8d21ea, 0x961f40c0, 0x002f03ed, 0x89686278,
0x38e421ea, 0x0ff834d7, 0xd36fb8db, 0x3a270d6f }}}
}
};
static const ac precomputed_2E_KG[15] = {
{
{{{ 0x39a48db0, 0xefd7835b, 0x9b3c03bf, 0x9f1215a2,
0x9b7bde45, 0x2791d0a0, 0x696e7167, 0x100f44da }}},
{{{ 0x2bc65a09, 0x0fbd5cd6, 0xff5195ac, 0xb7ff4a18,
0x0c090666, 0x2ec8f330, 0x92a00b77, 0xcdd9e131 }}}
}, {
{{{ 0x40fb27b6, 0x32427e28, 0xbe430576, 0xc76e3db2,
0x61686aa5, 0x10f238ad, 0xbe778b1b, 0xfea74e3d }}},
{{{ 0xf23cb96f, 0x701d3db7, 0x973f7b77, 0x126b596b,
0xccb6af93, 0x7cf674de, 0x9b0b1329, 0x6e0568db }}}
}, {
{{{ 0x2c8118bc, 0x6cac5154, 0x399ddd98, 0x19bd4b34,
0x2e9c8949, 0x47248a8d, 0x2cefa3b1, 0x734cb6a8 }}},
{{{ 0x1e410fd5, 0xf1b340ad, 0xc4873539, 0xa2982bee,
0xd4de4530, 0x7b5a3ea4, 0x42202574, 0xae46e10e }}}
}, {
{{{ 0xac1f98cd, 0xcbfc99c8, 0x4d7f0308, 0x52348905,
0x1cc66021, 0xfaed8a9c, 0x4a474870, 0x9c3919a8 }}},
{{{ 0xd4fc599d, 0xbe7e5e03, 0x6c64c8e6, 0x905326f7,
0xf260e641, 0x584f044b, 0x4a4ddd57, 0xddb84f0f }}}
}, {
{{{ 0xed7cebed, 0xc4aacaa8, 0x4fae424e, 0xb75d2dce,
0xba20735e, 0xa01585a2, 0xba122399, 0x3d75f24b }}},
{{{ 0xd5570dce, 0xcbe4606f, 0x2da192c2, 0x9d00bfd7,
0xa57b7265, 0x9c3ce86b, 0xec4edf5e, 0x987a22f1 }}}
}, {
{{{ 0x73ea0665, 0x211b9715, 0xf3a1abbb, 0x86f485d4,
0xcd076f0e, 0xabd242d8, 0x0ba5dc88, 0x862332ab }}},
{{{ 0x7b784911, 0x09af505c, 0xcaf4fae7, 0xc89544e8,
0xae9a32eb, 0x256625f6, 0x606d1a3f, 0xe2532b72 }}}
}, {
{{{ 0x0deaf885, 0x79e9f313, 0x46df21c9, 0x938ff76e,
0xa953bb2c, 0x1968f5fb, 0x29155f27, 0xdff538bf }}},
{{{ 0x31d5d020, 0xf7bae0b1, 0x1a676a8d, 0x5afdc787,
0xfa9d53ff, 0x11b4f032, 0xc5959167, 0x86ba433e }}}
}, {
{{{ 0x9475b7ba, 0x884fdff0, 0xe4918b3d, 0xe039e730,
0xf5018cdb, 0x3d3e57ed, 0x1943785c, 0x95939698 }}},
{{{ 0x7524f2fd, 0xe9b8abf8, 0xc8709385, 0x9c653f64,
0x4b9cd684, 0x8ba0386a, 0x88c331dd, 0x2e7e5528 }}}
}, {
{{{ 0xeefe79e5, 0x940bef53, 0xbe9b87f3, 0xc518d286,
0x7833042c, 0x9e0c7c76, 0x11fbe152, 0x104e2cb5 }}},
{{{ 0x50bbec83, 0xc0d35e0f, 0x4acd0fcc, 0xee4879be,
0x006085ee, 0xc8d80f5d, 0x72fe1ac1, 0x3c51bc1c }}}
}, {
{{{ 0xb2de976e, 0x06187f61, 0xf5e4b4b6, 0x52869e18,
0x38d332ca, 0x74d4facd, 0xb3a2f8d9, 0x5c1c90b4 }}},
{{{ 0xdaa37893, 0x98644d09, 0xabe39818, 0x682435a8,
0x469c53a0, 0x17e46617, 0x77dc2e64, 0x642f9632 }}}
}, {
{{{ 0x222f6c54, 0xad2101c5, 0xfa74785e, 0xb05c7a58,
0x489bcdaf, 0xce55fa79, 0xffe88d54, 0xc1f920fd }}},
{{{ 0x9065e490, 0x32553ab0, 0x35329f74, 0x7611b9af,
0xab7b24c0, 0x57df19ef, 0x6181c447, 0xb9a78749 }}}
}, {
{{{ 0xa80b7ea8, 0x392f156f, 0x8ae4a8bf, 0x57ab7ca0,
0x50c4b178, 0xac320747, 0x0e781feb, 0x146041b9 }}},
{{{ 0x845279b2, 0xd343f075, 0x7387afa5, 0x2d4fe757,
0xa72f3c39, 0x151e0948, 0x550da168, 0x41a6d54e }}}
}, {
{{{ 0x075a0010, 0xb3134ed3, 0x7ae93e23, 0x9fa76f4b,
0x7bb4daaa, 0xc0db256f, 0x464dd8a3, 0x7668dc27 }}},
{{{ 0x9f5da977, 0x150063f5, 0x05efce00, 0x3acac5c8,
0x884493fe, 0xc8e12ffc, 0x88f06bd2, 0x4ab936d8 }}}
}, {
{{{ 0x5d09ea98, 0x996fde77, 0x4145da58, 0x16ddf512,
0xdc2fb225, 0xa97a6ca8, 0xfbdcdf5a, 0xc7331f30 }}},
{{{ 0x86a86e52, 0x838f99e0, 0x77795edd, 0x68d39b29,
0x9f412aaa, 0xe4e4f97e, 0x30d25352, 0xe5cc2c0a }}}
}, {
{{{ 0x9c21ff71, 0xb3d68650, 0xddbe3884, 0x11e7589d,
0x423bac67, 0x7efd4055, 0x46957425, 0x587a7293 }}},
{{{ 0x8f5a8fc6, 0x360adc2e, 0xbd69f12e, 0x6f8bbafb,
0x0a3f3b4d, 0xf671f423, 0x59942dc3, 0xb49acb47 }}}
}
};
/*
* N: order of G
* 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
*/
static const bn256 N[1] = {
{{ 0xd0364141, 0xbfd25e8c, 0xaf48a03b, 0xbaaedce6,
0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff }}
};
/*
* MU = 2^512 / N
* MU = ( (1 << 256) | MU_lower )
*/
static const bn256 MU_lower[1] = {
{{ 0x2fc9bec0, 0x402da173, 0x50b75fc4, 0x45512319,
0x1, 0x0, 0x0, 0x0 }}
};
#include "ecc.c"

4
src/ec_p256k1.h Normal file
View File

@@ -0,0 +1,4 @@
int compute_kP_p256k1 (ac *X, const bn256 *K, const ac *P);
int compute_kG_p256k1 (ac *X, const bn256 *K);
void ecdsa_p256k1 (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d);

View File

@@ -1,7 +1,7 @@
/*
* ec_p256.c - Elliptic curve over GF(p256)
/* -*- coding: utf-8 -*-
* ec_p256r1.c - Elliptic curve over GF(p256r1)
*
* Copyright (C) 2011, 2013 Free Software Initiative of Japan
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -21,45 +21,20 @@
*
*/
/*
* References:
*
* [1] Suite B Implementer's Guide to FIPS 186-3 (ECDSA), February 3, 2010.
*
* [2] Michael Brown, Darrel Hankerson, Julio López, and Alfred Menezes,
* Software Implementation of the NIST Elliptic Curves Over Prime Fields,
* Proceedings of the 2001 Conference on Topics in Cryptology: The
* Cryptographer's Track at RSA
* Pages 250-265, Springer-Verlag London, UK, 2001
* ISBN:3-540-41898-9
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256.h"
#include "jpc-ac.h"
#include "modp256r1.h"
#include "affine.h"
#include "jpc-ac_p256r1.h"
#include "mod.h"
#include "ec_p256.h"
#if TEST
/*
* Generator of Elliptic curve over GF(p256)
*/
const bn256 Gx[1] = {
{{ 0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81,
0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2 }}
};
const bn256 Gy[1] = {
{{ 0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357,
0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2 }}
};
#endif
#include "ec_p256r1.h"
#define FIELD p256r1
#define COEFFICIENT_A_IS_MINUS_3 1
/*
* a = -3 mod p256
* a = -3 mod p256r1
*/
static const bn256 coefficient_a[1] = {
{{ 0xfffffffc, 0xffffffff, 0xffffffff, 0x00000000,
@@ -72,13 +47,6 @@ static const bn256 coefficient_b[1] = {
};
/*
* w = 4
* m = 256
* d = 64
* e = 32
*/
static const ac precomputed_KG[15] = {
{
{{{ 0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81,
@@ -237,271 +205,6 @@ static const ac precomputed_2E_KG[15] = {
}
};
/**
* @brief X = k * G
*
* @param K scalar k
*
* Return -1 on error.
* Return 0 on success.
*/
int
compute_kG (ac *X, const bn256 *K)
{
int i;
int q_is_infinite = 1;
jpc Q[1];
for (i = 31; i >= 0; i--)
{
int k_i, k_i_e;
if (!q_is_infinite)
jpc_double (Q, Q);
k_i = (((K->words[6] >> i) & 1) << 3)
| (((K->words[4] >> i) & 1) << 2)
| (((K->words[2] >> i) & 1) << 1)
| ((K->words[0] >> i) & 1);
k_i_e = (((K->words[7] >> i) & 1) << 3)
| (((K->words[5] >> i) & 1) << 2)
| (((K->words[3] >> i) & 1) << 1)
| ((K->words[1] >> i) & 1);
if (k_i)
{
if (q_is_infinite)
{
memcpy (Q->x, (&precomputed_KG[k_i - 1])->x, sizeof (bn256));
memcpy (Q->y, (&precomputed_KG[k_i - 1])->y, sizeof (bn256));
Q->z->words[0] = 1;
Q->z->words[1] = Q->z->words[2] = Q->z->words[3]
= Q->z->words[4] = Q->z->words[5] = Q->z->words[6]
= Q->z->words[7] = 0;
q_is_infinite = 0;
}
else
jpc_add_ac (Q, Q, &precomputed_KG[k_i - 1]);
}
if (k_i_e)
{
if (q_is_infinite)
{
memcpy (Q->x, (&precomputed_2E_KG[k_i_e - 1])->x, sizeof (bn256));
memcpy (Q->y, (&precomputed_2E_KG[k_i_e - 1])->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->words[0] = 1;
q_is_infinite = 0;
}
else
jpc_add_ac (Q, Q, &precomputed_2E_KG[k_i_e - 1]);
}
}
return jpc_to_ac (X, Q);
}
#define NAF_K_SIGN(k) (k&8)
#define NAF_K_INDEX(k) ((k&7)-1)
static void
naf4_257_set (naf4_257 *NAF_K, int i, int ki)
{
if (ki != 0)
{
if (ki > 0)
ki = (ki+1)/2;
else
ki = (1-ki)/2 | 8;
}
if (i == 256)
NAF_K->last_nibble = ki;
else
{
NAF_K->words[i/8] &= ~(0x0f << ((i & 0x07)*4));
NAF_K->words[i/8] |= (ki << ((i & 0x07)*4));
}
}
static int
naf4_257_get (const naf4_257 *NAF_K, int i)
{
int ki;
if (i == 256)
ki = NAF_K->last_nibble;
else
{
ki = NAF_K->words[i/8] >> ((i & 0x07)*4);
ki &= 0x0f;
}
return ki;
}
/*
* convert 256-bit bignum into non-adjacent form (NAF)
*/
void
compute_naf4_257 (naf4_257 *NAF_K, const bn256 *K)
{
int i = 0;
bn256 K_tmp[1];
uint32_t carry = 0;
memcpy (K_tmp, K, sizeof (bn256));
memset (NAF_K, 0, sizeof (naf4_257));
while (!bn256_is_zero (K_tmp))
{
if (bn256_is_even (K_tmp))
naf4_257_set (NAF_K, i, 0);
else
{
int ki = (K_tmp->words[0]) & 0x0f;
if ((ki & 0x08))
{
carry = bn256_add_uint (K_tmp, K_tmp, 16 - ki);
ki = ki - 16;
}
else
K_tmp->words[0] &= 0xfffffff0;
naf4_257_set (NAF_K, i, ki);
}
bn256_shift (K_tmp, K_tmp, -1);
if (carry)
{
K_tmp->words[7] |= 0x80000000;
carry = 0;
}
i++;
}
}
/**
* check if P is on the curve.
*
* Return -1 on error.
* Return 0 on success.
*/
static int
point_is_on_the_curve (const ac *P)
{
bn256 s[1], t[1];
/* Elliptic curve: y^2 = x^3 + a*x + b */
modp256_sqr (s, P->x);
modp256_mul (s, s, P->x);
modp256_mul (t, coefficient_a, P->x);
modp256_add (s, s, t);
modp256_add (s, s, coefficient_b);
modp256_sqr (t, P->y);
if (bn256_cmp (s, t) == 0)
return 0;
return -1;
}
/**
* @brief X = k * P
*
* @param NAF_K NAF representation of k
* @param P P in affine coordiate
*
* Return -1 on error.
* Return 0 on success.
*
* For the curve (cofactor is 1 and n is prime), possible error cases are:
*
* P is not on the curve.
* P = G, k = n
* Something wrong in the code.
*
* Mathmatically, k=1 and P=O is another possible case, but O cannot be
* represented by affine coordinate.
*/
int
compute_kP (ac *X, const naf4_257 *NAF_K, const ac *P)
{
int i;
int q_is_infinite = 1;
jpc Q[1];
ac P3[1], P5[1], P7[1];
const ac *p_Pi[4];
if (point_is_on_the_curve (P) < 0)
return -1;
p_Pi[0] = P;
p_Pi[1] = P3;
p_Pi[2] = P5;
p_Pi[3] = P7;
{
jpc Q1[1];
memcpy (Q->x, P->x, sizeof (bn256));
memcpy (Q->y, P->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->words[0] = 1;
jpc_double (Q, Q);
jpc_add_ac (Q1, Q, P);
if (jpc_to_ac (P3, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
jpc_double (Q, Q);
jpc_add_ac (Q1, Q, P);
if (jpc_to_ac (P5, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
memcpy (Q->x, P3->x, sizeof (bn256));
memcpy (Q->y, P3->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->words[0] = 1;
jpc_double (Q, Q);
jpc_add_ac (Q1, Q, P);
if (jpc_to_ac (P7, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
}
for (i = 256; i >= 0; i--)
{
int k_i;
if (!q_is_infinite)
jpc_double (Q, Q);
k_i = naf4_257_get (NAF_K, i);
if (k_i)
{
if (q_is_infinite)
{
memcpy (Q->x, p_Pi[NAF_K_INDEX(k_i)]->x, sizeof (bn256));
if (NAF_K_SIGN (k_i))
bn256_sub (Q->y, P256, p_Pi[NAF_K_INDEX(k_i)]->y);
else
memcpy (Q->y, p_Pi[NAF_K_INDEX(k_i)]->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->words[0] = 1;
q_is_infinite = 0;
}
else
jpc_add_ac_signed (Q, Q, p_Pi[NAF_K_INDEX(k_i)], NAF_K_SIGN (k_i));
}
}
return jpc_to_ac (X, Q);
}
/*
* N: order of G
*/
@@ -520,46 +223,4 @@ static const bn256 MU_lower[1] = {
};
/**
* @brief Compute signature (r,s) of hash string z with secret key d
*/
void
ecdsa (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d)
{
bn256 k[1];
ac KG[1];
bn512 tmp[1];
bn256 k_inv[1];
uint32_t carry;
#define tmp_k k_inv
do
{
do
{
bn256_random (k);
if (bn256_sub (tmp_k, k, N) == 0) /* > N, it's too big. */
continue;
if (bn256_add_uint (tmp_k, tmp_k, 2)) /* > N - 2, still big. */
continue;
bn256_add_uint (k, k, 1);
compute_kG (KG, k);
if (bn256_is_ge (KG->x, N))
bn256_sub (r, KG->x, N);
else
memcpy (r, KG->x, sizeof (bn256));
}
while (bn256_is_zero (r));
mod_inv (k_inv, k, N);
bn256_mul (tmp, r, d);
mod_reduce (s, tmp, N, MU_lower);
carry = bn256_add (s, s, z);
if (carry)
bn256_sub (s, s, N);
bn256_mul (tmp, s, k_inv);
mod_reduce (s, tmp, N, MU_lower);
}
while (bn256_is_zero (s));
}
#include "ecc.c"

5
src/ec_p256r1.h Normal file
View File

@@ -0,0 +1,5 @@
int compute_kP_p256r1 (ac *X, const bn256 *K, const ac *P);
int compute_kG_p256r1 (ac *X, const bn256 *K);
void ecdsa_p256r1 (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d);

View File

@@ -1,76 +0,0 @@
/*
* ecc-cdh.c - One-Pass Diffie-Hellman method implementation
* C(1, 1, ECC CDH) for EC DH of OpenPGP ECC
*
* Copyright (C) 2013 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* References:
*
* [1] A. Jivsov, Elliptic Curve Cryptography (ECC) in OpenPGP, RFC 6637,
* June 2012.
*
* [2] Suite B Implementer's Guide to NIST SP 800-56A, July 28, 2009.
*
*/
static const char param[] = {
/**/
curve_OID_len,
curve_OID,
public-key_alg_ID, /*ecdh*/
0x03,
0x01,
KDF_hash_ID, /*sha256*/
KEK_alg_ID, /*aes128*/
"Anonymous Sender ",
my_finger_print /*20-byte*/
};
/*
*
*/
int
ecdh (unsigned char *key,
const unsigned char *key_encrypted, const ac *P,
const naf4_257 *naf_d, const unsigned char *fp)
{
ac S[1];
sha256_context ctx;
unsigned char kek[32];
unsigned char x[32];
int i;
const unsigned char *p;
compute_kP (S, naf_d, P); /* Get shared secret. */
/* Endian change from big to little. */
p = (const unsigned char *)S->x;
for (i = 0; i < 32; i++)
x[31-i] = p[i];
/* kdf (kek, S, parameter) */
sha256_start (&ctx);
sha256_update (&ctx, "\x00\x00\x00\x01", 4);
sha256_update (&ctx, x, size of x);
sha256_update (&ctx, (const char *)param, size of param);
sha256_finish (&ctx, kek);
}

958
src/ecc-edwards.c Normal file
View File

@@ -0,0 +1,958 @@
/* -*- coding: utf-8 -*-
* ecc-edwards.c - Elliptic curve computation for
* the twisted Edwards curve: -x^2 + y^2 = 1 + d*x^2*y^2
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bn.h"
#include "mod.h"
#include "mod25638.h"
#include "sha512.h"
/*
* References:
*
* [1] Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, Bo-Yin Yang.
* High-speed high-security signatures.
* Journal of Cryptographic Engineering 2 (2012), 77--89.
* http://cr.yp.to/papers.html#ed25519
*
* [2] Daniel J. Bernstein, Peter Birkner, Marc Joye, Tanja Lange,
* Christiane Peters.
* Twisted Edwards curves.
* Pages 389--405 in Progress in cryptology---AFRICACRYPT 2008.
* http://cr.yp.to/papers.html#twisted
*/
/*
* IMPLEMENTATION NOTE
*
* (0) We assume that the processor has no cache, nor branch target
* prediction. Thus, we don't avoid indexing by secret value.
* We don't avoid conditional jump if both cases have same timing,
* either.
*
* (1) We use Radix-32 field arithmetic. It's a representation like
* 2^256-38, but it's more redundant. For example, "1" can be
* represented in three ways in 256-bit: 1, 2^255-18, and
* 2^256-37.
*
* (2) We use fixed base comb multiplication. Scalar is 252-bit.
* There are various possible choices for 252 = 2 * 2 * 3 * 3 * 7.
* Current choice of total size is 3KB. We use three tables, and
* a table has 16 points (3 * 1KB).
*
* Window size W = 4-bit, E = 21.
* <--21-bit-
* <---42-bit----------
* [ ][########][////////][ ][########][////////]
* <-------63-bit----------------
* <-----------84-bit----------------------
* <--------------105-bit----------------------------
*
* [ ][########][////////][ ][########][////////]
* <-126-bit-
* <-147-bit-
* <----168-bit--------
*
* <-------189-bit---------------
* <----------210-bit----------------------
* <-------------231-bit-----------------------------
*/
/*
* Identity element: (0,1)
* Negation: -(x,y) = (-x,y)
*
* d: -0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A
* order:
* 0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED
* Gx: 0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A
* Gy: 0x6666666666666666666666666666666666666666666666666666666666666658
*/
/* d + 2^255 - 19 */
static const bn256 coefficient_d[1] = {
{{ 0x135978a3, 0x75eb4dca, 0x4141d8ab, 0x00700a4d,
0x7779e898, 0x8cc74079, 0x2b6ffe73, 0x52036cee }} };
/**
* @brief Projective Twisted Coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} ptc;
#include "affine.h"
static int
mod25519_is_neg (const bn256 *a)
{
return (a->word[0] & 1);
}
/**
* @brief X = 2 * A
*
* Compute (X3 : Y3 : Z3) = 2 * (X1 : Y1 : Z1)
*/
static void
point_double (ptc *X, const ptc *A)
{
bn256 b[1], d[1], e[1];
/* Compute: B = (X1 + Y1)^2 */
mod25638_add (b, A->x, A->y);
mod25638_sqr (b, b);
/* Compute: C = X1^2 : E */
mod25638_sqr (e, A->x);
/* Compute: D = Y1^2 */
mod25638_sqr (d, A->y);
/* E = aC; where a = -1 */
/* Compute: D - E = D + C : Y3_tmp */
mod25638_add (X->y, e, d);
/* Compute: -F = -(E + D) = C - D; where a = -1 : E */
mod25638_sub (e, e, d);
/* Compute: H = Z1^2 : D */
mod25638_sqr (d, A->z);
/* Compute: -J = 2*H - F : D */
mod25638_add (d, d, d);
mod25638_add (d, d, e);
/* Compute: X3 = (B-C-D)*J = -J*(C+D-B) = -J*(Y3_tmp-B) */
mod25638_sub (X->x, X->y, b);
mod25638_mul (X->x, X->x, d);
/* Compute: Y3 = -F*(D-E) = -F*Y3_tmp */
mod25638_mul (X->y, X->y, e);
/* Z3 = -F*-J */
mod25638_mul (X->z, e, d);
}
/**
* @brief X = A + B
*
* @param X Destination PTC
* @param A PTC
* @param B AC
*
* Compute: (X3 : Y3 : Z3) = (X1 : Y1 : Z1) + (X2 : Y2 : 1)
*/
static void
point_add (ptc *X, const ptc *A, const ac *B)
{
bn256 c[1], d[1], e[1], tmp[1];
/* Compute: C = X1 * X2 */
mod25638_mul (c, A->x, B->x);
/* Compute: D = Y1 * Y2 */
mod25638_mul (d, A->y, B->y);
/* Compute: E = d * C * D */
mod25638_mul (e, c, d);
mod25638_mul (e, coefficient_d, e);
/* Compute: C_1 = C + D */
mod25638_add (c, c, d);
/* Compute: D_1 = Z1^2 : B */
mod25638_sqr (d, A->z);
/* tmp = D_1 - E : F */
mod25638_sub (tmp, d, e);
/* D_2 = D_1 + E : G */
mod25638_add (d, d, e);
/* X3_final = Z1 * tmp * ((X1 + Y1) * (X2 + Y2) - C_1) */
mod25638_add (X->x, A->x, A->y);
mod25638_add (e, B->x, B->y);
mod25638_mul (e, X->x, e);
mod25638_sub (e, e, c);
mod25638_mul (e, tmp, e);
mod25638_mul (X->x, A->z, e);
/* Y3_final = Z1 * D_2 * C_1 */
mod25638_mul (c, d, c);
mod25638_mul (X->y, A->z, c);
/* Z3_final = tmp * D_2 */
mod25638_mul (X->z, tmp, d);
/* A = Z1 */
/* B = A^2 */
/* C = X1 * X2 */
/* D = Y1 * Y2 */
/* E = d * C * D */
/* F = B - E */
/* G = B + E */
/* X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) */
/* Y3 = A * G * (D - aC); where a = -1 */
/* Z3 = F * G */
}
/**
* @brief X = convert A
*
* @param X Destination AC
* @param A PTC
*
* (X1:Y1:Z1) represents the affine point (x=X1/Z1, y=Y1/Z1)
*/
static void
point_ptc_to_ac (ac *X, const ptc *A)
{
bn256 z_inv[1];
/*
* A->z may be bigger than p25519, or two times bigger than p25519.
* But this is no problem for computation of mod_inv.
*/
mod_inv (z_inv, A->z, p25519);
mod25638_mul (X->x, A->x, z_inv);
mod25519_reduce (X->x);
mod25638_mul (X->y, A->y, z_inv);
mod25519_reduce (X->y);
}
static const ac precomputed_KG[16] = {
{ {{{ 0, 0, 0, 0, 0, 0, 0, 0 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}} },
{ {{{ 0x8f25d51a, 0xc9562d60, 0x9525a7b2, 0x692cc760,
0xfdd6dc5c, 0xc0a4e231, 0xcd6e53fe, 0x216936d3 }}},
{{{ 0x66666658, 0x66666666, 0x66666666, 0x66666666,
0x66666666, 0x66666666, 0x66666666, 0x66666666 }}} },
{ {{{ 0x3713af22, 0xac7137bd, 0xac634604, 0x25ed77a4,
0xa815e038, 0xce0d0064, 0xbca90151, 0x041c030f }}},
{{{ 0x0780f989, 0xe9b33fcf, 0x3d4445e7, 0xe4e97c2a,
0x655e5c16, 0xc67dc71c, 0xee43fb7a, 0x72467625 }}} },
{ {{{ 0x3ee99893, 0x76a19171, 0x7ba9b065, 0xe647edd9,
0x6aeae260, 0x31f39299, 0x5f4a9bb2, 0x6d9e4545 }}},
{{{ 0x94cae280, 0xc41433da, 0x79061211, 0x8e842de8,
0xa259dc8a, 0xaab95e0b, 0x99013cd0, 0x28bd5fc3 }}} },
{ {{{ 0x7d23ea24, 0x59e22c56, 0x0460850e, 0x1e745a88,
0xda13ef4b, 0x4583ff4c, 0x95083f85, 0x1f13202c }}},
{{{ 0x90275f48, 0xad42025c, 0xb55c4778, 0x0085087e,
0xfdfd7ffa, 0xf21109e7, 0x6c381b7e, 0x66336d35 }}} },
{ {{{ 0xd00851f2, 0xaa9476ab, 0x4a61600b, 0xe7838534,
0x1a52df87, 0x0de65625, 0xbd675870, 0x5f0dd494 }}},
{{{ 0xe23493ba, 0xf20aec1b, 0x3414b0a8, 0x8f7f2741,
0xa80e1eb6, 0x497e74bd, 0xe9365b15, 0x1648eaac }}} },
{ {{{ 0x04ac2b69, 0x5b78dcec, 0x32001a73, 0xecdb66ce,
0xb34cf697, 0xb75832f4, 0x3a2bce94, 0x7aaf57c5 }}},
{{{ 0x60fdfc6f, 0xb32ed2ce, 0x757924c6, 0x77bf20be,
0x48742dd1, 0xaebd15dd, 0x55d38439, 0x6311bb16 }}} },
{ {{{ 0x42ff5c97, 0x139cdd73, 0xdbd82964, 0xee4c359e,
0x70611a3f, 0x91c1cd94, 0x8075dbcb, 0x1d0c34f6 }}},
{{{ 0x5f931219, 0x43eaa549, 0xa23d35a6, 0x3737aba7,
0x46f167bb, 0x54b1992f, 0xb74a9944, 0x01a11f3c }}} },
{ {{{ 0xba46b161, 0x67a5310e, 0xd9d67f6c, 0x790f8527,
0x2f6cc814, 0x359c5b5f, 0x7786383d, 0x7b6a5565 }}},
{{{ 0x663ab0d3, 0xf1431b60, 0x09995826, 0x14a32d8f,
0xeddb8571, 0x61d526f6, 0x0eac739a, 0x0cb7acea }}} },
{ {{{ 0x4a2d009f, 0x5eb1a697, 0xd8df987a, 0xdacb43b4,
0x8397f958, 0x4870f214, 0x8a175fbb, 0x5aa0c67c }}},
{{{ 0x78887db3, 0x27dbbd4c, 0x64e322ab, 0xe327b707,
0x7cbe4e3b, 0x87e293fa, 0xbda72395, 0x17040799 }}} },
{ {{{ 0x99d1e696, 0xc833a5a2, 0x2d9d5877, 0x969bff8e,
0x2216fa67, 0x383a533a, 0x684d3925, 0x338bbe0a }}},
{{{ 0xd6cfb491, 0x35b5aae8, 0xaa12f3f8, 0x4a588279,
0x2e30380e, 0xa7c2e708, 0x9e4b3d62, 0x69f13e09 }}} },
{ {{{ 0x27f1cd56, 0xec0dc2ef, 0xdb11cc97, 0x1af11548,
0x9ebc7613, 0xb642f86a, 0xcb77c3b9, 0x5ce45e73 }}},
{{{ 0x3eddd6de, 0x5d128786, 0x4859eab7, 0x16f9a6b4,
0xd8782345, 0x55c53916, 0xdb7b202a, 0x6b1dfa87 }}} },
{ {{{ 0x19e30528, 0x2461a8ed, 0x665cfb1c, 0xaf756bf9,
0x3a6e8673, 0x0fcafd1d, 0x45d10f48, 0x0d264435 }}},
{{{ 0x5431db67, 0x543fd4c6, 0x60932432, 0xc153a5b3,
0xd2119aa4, 0x41d5b8eb, 0x8b09b6a5, 0x36bd9ab4 }}} },
{ {{{ 0x21e06738, 0x6d39f935, 0x3765dd86, 0x4e6a7c59,
0xa4730880, 0xefc0dd80, 0x4079fe2f, 0x40617e56 }}},
{{{ 0x921439b9, 0xbc83cdff, 0x98833c09, 0xd5cccc06,
0xda13cdcb, 0xe315c425, 0x67ff5370, 0x37bc6e84 }}} },
{ {{{ 0xf643b5f5, 0x65e7f028, 0x0ffbf5a8, 0x5b0d4831,
0xf4085f62, 0x0f540498, 0x0db7bd1b, 0x6f0bb035 }}},
{{{ 0x9733742c, 0x51f65571, 0xf513409f, 0x2fc047a0,
0x355facf6, 0x07f45010, 0x3a989a9c, 0x5cd416a9 }}} },
{ {{{ 0x748f2a67, 0x0bdd7208, 0x415b7f7f, 0x0cf0b80b,
0x57aa0119, 0x44afdd5f, 0x430dc946, 0x05d68802 }}},
{{{ 0x1a60eeb2, 0x420c46e5, 0x665024f5, 0xc60a9b33,
0x48c51347, 0x37520265, 0x00a21bfb, 0x6f4be0af }}} }
};
static const ac precomputed_2E_KG[16] = {
{ {{{ 0, 0, 0, 0, 0, 0, 0, 0 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}} },
{ {{{ 0x199c4f7d, 0xec314ac0, 0xb2ebaaf9, 0x66a39c16,
0xedd4d15f, 0xab1c92b8, 0x57d9eada, 0x482a4cdf }}},
{{{ 0x6e4eb04b, 0xbd513b11, 0x25e4fd6a, 0x3f115fa5,
0x14519298, 0x0b3c5fc6, 0x81c2f7a8, 0x7391de43 }}} },
{ {{{ 0x1254fe02, 0xa57dca18, 0x6da34368, 0xa56a2a14,
0x63e7328e, 0x44c6e34f, 0xca63ab3e, 0x3f748617 }}},
{{{ 0x7dc1641e, 0x5a13dc52, 0xee4e9ca1, 0x4cbb2899,
0x1ba9acee, 0x3938a289, 0x420fc47b, 0x0fed89e6 }}} },
{ {{{ 0x49cbad08, 0x3c193f32, 0x15e80ef5, 0xdda71ef1,
0x9d128c33, 0xda44186c, 0xbf98c24f, 0x54183ede }}},
{{{ 0x93d165c1, 0x2cb483f7, 0x177f44aa, 0x51762ace,
0xb4ab035d, 0xb3fe651b, 0xa0b0d4e5, 0x426c99c3 }}} },
{ {{{ 0xef3f3fb1, 0xb3fcf4d8, 0x065060a0, 0x7052292b,
0x24240b15, 0x18795ff8, 0x9989ffcc, 0x13aea184 }}},
{{{ 0xc2b81f44, 0x1930c101, 0x10600555, 0x672d6ca4,
0x1b25e570, 0xfbddbff2, 0x8ca12b70, 0x0884949c }}} },
{ {{{ 0x00564bbf, 0x9983a033, 0xde61b72d, 0x95587d25,
0xeb17ad71, 0xb6719dfb, 0xc0bc3517, 0x46871ad0 }}},
{{{ 0xe95a6693, 0xb034fb61, 0x76eabad9, 0x5b0d8d18,
0x884785dc, 0xad295dd0, 0x74a1276a, 0x359debad }}} },
{ {{{ 0xe89fb5ca, 0x2e5a2686, 0x5656c6c5, 0xd3d200ba,
0x9c969001, 0xef4c051e, 0x02cb45f4, 0x0d4ea946 }}},
{{{ 0x76d6e506, 0xa6f8a422, 0x63209e23, 0x454c768f,
0x2b372386, 0x5c12fd04, 0xdbfee11f, 0x1aedbd3e }}} },
{ {{{ 0x00dbf569, 0x700ab50f, 0xd335b313, 0x9553643c,
0xa17dc97e, 0xeea9bddf, 0x3350a2bd, 0x0d12fe3d }}},
{{{ 0xa16a3dee, 0xe5ac35fe, 0xf81950c3, 0x4ae4664a,
0x3dbbf921, 0x75c63df4, 0x2958a5a6, 0x545b109c }}} },
{ {{{ 0x0a61b29c, 0xd7a52a98, 0x65aca9ee, 0xe21e0acb,
0x5985dcbe, 0x57a69c0f, 0xeb87a534, 0x3c0c1e7b }}},
{{{ 0x6384bd2f, 0xf0a0b50d, 0xc6939e4b, 0xff349a34,
0x6e2f1973, 0x922c4554, 0xf1347631, 0x74e826b2 }}} },
{ {{{ 0xa655803c, 0xd7eaa066, 0x38292c5c, 0x09504e76,
0x2c874953, 0xe298a02e, 0x8932b73f, 0x225093ed }}},
{{{ 0xe69c3efd, 0xf93e2b4d, 0x8a87c799, 0xa2cbd5fc,
0x85dba986, 0xdf41da94, 0xccee8edc, 0x36fe85e7 }}} },
{ {{{ 0x7d742813, 0x78df7dc5, 0x4a193e64, 0x333bcc6d,
0x6a966d2d, 0x8242aa25, 0x4cd36d32, 0x03500a94 }}},
{{{ 0x580505d7, 0xd5d110fc, 0xfa11e1e9, 0xb2f47e16,
0x06eab6b4, 0xd0030f92, 0x62c91d46, 0x2dc80d5f }}} },
{ {{{ 0x2a75e492, 0x5788b01a, 0xbae31352, 0x992acf54,
0x8159db27, 0x4591b980, 0xd3d84740, 0x36c6533c }}},
{{{ 0x103883b5, 0xc44c7c00, 0x515d0820, 0x10329423,
0x71b9dc16, 0xbd306903, 0xf88f8d32, 0x7edd5a95 }}} },
{ {{{ 0x005523d7, 0xfd63b1ac, 0xad70dd21, 0x74482e0d,
0x02b56105, 0x67c9d9d0, 0x5971b456, 0x4d318012 }}},
{{{ 0x841106df, 0xdc9a6f6d, 0xa326987f, 0x7c52ed9d,
0x00607ea0, 0x4dbeaa6f, 0x6959e688, 0x115c221d }}} },
{ {{{ 0xc80f7c16, 0xf8718464, 0xe9930634, 0x05dc8f40,
0xc2e9d5f4, 0xefa699bb, 0x021da209, 0x2469e813 }}},
{{{ 0xc602a3c4, 0x75c02845, 0x0a200f9d, 0x49d1b2ce,
0x2fb3ec8f, 0xd21b75e4, 0xd72a7545, 0x10dd726a }}} },
{ {{{ 0x63ef1a6c, 0xeda58527, 0x051705e0, 0xb3fc0e72,
0x44f1161f, 0xbda6f3ee, 0xf339efe5, 0x7680aebf }}},
{{{ 0xb1b070a7, 0xe8d3fd01, 0xdbfbaaa0, 0xc3ff7dbf,
0xa320c916, 0xd81ef6f2, 0x62a3b54d, 0x3e22a1fb }}} },
{ {{{ 0xb1fa18c8, 0xcdbb9187, 0xcb483a17, 0x8ddb5f6b,
0xea49af98, 0xc0a880b9, 0xf2dfddd0, 0x53bf600b }}},
{{{ 0x9e25b164, 0x4217404c, 0xafb74aa7, 0xfabf06ee,
0x2b9f233c, 0xb17712ae, 0xd0eb909e, 0x71f0b344 }}} }
};
static const ac precomputed_4E_KG[16] = {
{ {{{ 0, 0, 0, 0, 0, 0, 0, 0 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}} },
{ {{{ 0xe388a820, 0xbb6ec091, 0x5182278a, 0xa928b283,
0xa9a6eb83, 0x2259174d, 0x45500054, 0x184b48cb }}},
{{{ 0x26e77c33, 0xfe324dba, 0x83faf453, 0x6679a5e3,
0x2380ef73, 0xdd60c268, 0x03dc33a9, 0x3ee0e07a }}} },
{ {{{ 0xce974493, 0x403aff28, 0x9bf6f5c4, 0x84076bf4,
0xecd898fb, 0xec57038c, 0xb663ed49, 0x2898ffaa }}},
{{{ 0xf335163d, 0xf4b3bc46, 0xfa4fb6c6, 0xe613a0f4,
0xb9934557, 0xe759d6bc, 0xab6c9477, 0x094f3b96 }}} },
{ {{{ 0x6afffe9e, 0x168bb5a0, 0xee748c29, 0x950f7ad7,
0xda17203d, 0xa4850a2b, 0x77289e0f, 0x0062f7a7 }}},
{{{ 0x4b3829fa, 0x6265d4e9, 0xbdfcd386, 0x4f155ada,
0x475795f6, 0x9f38bda4, 0xdece4a4c, 0x560ed4b3 }}} },
{ {{{ 0x141e648a, 0xdad4570a, 0x019b965c, 0x8bbf674c,
0xdb08fe30, 0xd7a8d50d, 0xa2851109, 0x7efb45d3 }}},
{{{ 0xd0c28cda, 0x52e818ac, 0xa321d436, 0x792257dd,
0x9d71f8b7, 0x867091c6, 0x11a1bf56, 0x0fe1198b }}} },
{ {{{ 0x06137ab1, 0x4e848339, 0x3e6674cc, 0x5673e864,
0x0140502b, 0xad882043, 0x6ea1e46a, 0x34b5c0cb }}},
{{{ 0x1d70aa7c, 0x29786814, 0x8cdbb8aa, 0x840ae3f9,
0xbd4801fb, 0x78b4d622, 0xcf18ae9a, 0x6cf4e146 }}} },
{ {{{ 0x36297168, 0x95c270ad, 0x942e7812, 0x2303ce80,
0x0205cf0e, 0x71908cc2, 0x32bcd754, 0x0cc15edd }}},
{{{ 0x2c7ded86, 0x1db94364, 0xf141b22c, 0xc694e39b,
0x5e5a9312, 0xf22f64ef, 0x3c5e6155, 0x649b8859 }}} },
{ {{{ 0xb6417945, 0x0d5611c6, 0xac306c97, 0x9643fdbf,
0x0df500ff, 0xe81faaa4, 0x6f50e615, 0x0792c79b }}},
{{{ 0xd2af8c8d, 0xb45bbc49, 0x84f51bfe, 0x16c615ab,
0xc1d02d32, 0xdc57c526, 0x3c8aaa55, 0x5fb9a9a6 }}} },
{ {{{ 0xdee40b98, 0x82faa8db, 0x6d520674, 0xff8a5208,
0x446ac562, 0x1f8c510f, 0x2cc6b66e, 0x4676d381 }}},
{{{ 0x2e7429f4, 0x8f1aa780, 0x8ed6bdf6, 0x2a95c1bf,
0x457fa0eb, 0x051450a0, 0x744c57b1, 0x7d89e2b7 }}} },
{ {{{ 0x3f95ea15, 0xb6bdacd2, 0x2f1a5d69, 0xc9a9d1b1,
0xf4d22d72, 0xd4c2f1a9, 0x4dc516b5, 0x73ecfdf1 }}},
{{{ 0x05391e08, 0xa1ce93cd, 0x7b8aac17, 0x98f1e99e,
0xa098cbb3, 0x9ba84f2e, 0xf9bdd37a, 0x1425aa8b }}} },
{ {{{ 0x966abfc0, 0x8a385bf4, 0xf081a640, 0x55e5e8bc,
0xee26f5ff, 0x835dff85, 0xe509e1ea, 0x4927e622 }}},
{{{ 0x352334b0, 0x164c8dbc, 0xa3fea31f, 0xcac1ad63,
0x682fd457, 0x9b87a676, 0x1a53145f, 0x75f382ff }}} },
{ {{{ 0xc3efcb46, 0x16b944f5, 0x68cb184c, 0x1fb55714,
0x9ccf2dc8, 0xf1c2b116, 0x808283d8, 0x7417e00f }}},
{{{ 0x930199ba, 0x1ea67a22, 0x718990d8, 0x9fbaf765,
0x8f3d5d57, 0x231fc664, 0xe5853194, 0x38141a19 }}} },
{ {{{ 0x2f81290d, 0xb9f00390, 0x04a9ca6c, 0x44877827,
0xe1dbdd65, 0x65d7f9b9, 0xf7c6698a, 0x7133424c }}},
{{{ 0xa7cd250f, 0x604cfb3c, 0x5acc18f3, 0x460c3c4b,
0xb518e3eb, 0xa53e50e0, 0x98a40196, 0x2b4b9267 }}} },
{ {{{ 0xc5dbd06c, 0x591b0672, 0xaa1eeb65, 0x10d43dca,
0xcd2517af, 0x420cdef8, 0x0b695a8a, 0x513a307e }}},
{{{ 0x66503215, 0xee9d6a7b, 0x088fd9a4, 0xdea58720,
0x973afe12, 0x8f3cbbea, 0x872f2538, 0x005c2350 }}} },
{ {{{ 0x35af3291, 0xe5024b70, 0x4f5e669a, 0x1d3eec2d,
0x6e79d539, 0xc1f6d766, 0x795b5248, 0x34ec043f }}},
{{{ 0x400960b6, 0xb2763511, 0x29e57df0, 0xff7a3d84,
0x1666c1f1, 0xaeac7792, 0x66084bc0, 0x72426e97 }}} },
{ {{{ 0x44f826ca, 0x5b1c3199, 0x790aa408, 0x68b00b73,
0x69e9b92b, 0xaf0984b4, 0x3ffe9093, 0x5fe6736f }}},
{{{ 0xffd49312, 0xd67f2889, 0x5cb9ed21, 0x3520d747,
0x3c65a606, 0x94f893b1, 0x2d65496f, 0x2fee5e8c }}} }
};
/**
* @brief X = k * G
*
* @param K scalar k
*
* Return -1 on error.
* Return 0 on success.
*/
static void
compute_kG_25519 (ac *X, const bn256 *K)
{
ptc Q[1];
int i;
/* identity element */
memset (Q, 0, sizeof (ptc));
Q->y->word[0] = 1;
Q->z->word[0] = 1;
for (i = 20; i >= 0; i--)
{
int k0, k1, k2;
k0 = ((K->word[0] >> i) & 1)
| (i < 1 ? ((K->word[1] >> 30) & 2)
: (((K->word[2] >> (i-1)) & 1) << 1))
| (i < 2 ? ((K->word[3] >> (i+28)) & 4)
: (((K->word[4] >> (i-2)) & 1) << 2))
| (i < 3 ? ((K->word[5] >> (i+26)) & 8)
: (((K->word[6] >> (i-3)) & 1) << 3));
k1 = (i < 11 ? ((K->word[0] >> (i+21)) & 1)
: ((K->word[1] >> (i-11)) & 1))
| (i < 12 ? ((K->word[2] >> (i+19)) & 2)
: (((K->word[3] >> (i-12)) & 1) << 1))
| (i < 13 ? ((K->word[4] >> (i+17)) & 4)
: (((K->word[5] >> (i-13)) & 1) << 2))
| (i < 14 ? ((K->word[6] >> (i+15)) & 8)
: (((K->word[7] >> (i-14)) & 1) << 3));
k2 = ((K->word[1] >> (i+10)) & 1)
| ((K->word[3] >> (i+8)) & 2)
| ((K->word[5] >> (i+6)) & 4)
| ((K->word[7] >> (i+4)) & 8);
point_double (Q, Q);
point_add (Q, Q, &precomputed_KG[k0]);
point_add (Q, Q, &precomputed_2E_KG[k1]);
point_add (Q, Q, &precomputed_4E_KG[k2]);
}
point_ptc_to_ac (X, Q);
}
#define BN416_WORDS 13
#define BN128_WORDS 4
/* M: The order of the generator G. */
static const bn256 M[1] = {
{{ 0x5CF5D3ED, 0x5812631A, 0xA2F79CD6, 0x14DEF9DE,
0x00000000, 0x00000000, 0x00000000, 0x10000000 }}
};
#define C ((const uint32_t *)M)
static void
bnX_mul_C (uint32_t *r, const uint32_t *q, int q_size)
{
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
r0 = r1 = r2 = 0;
for (k = 0; k <= q_size + BN128_WORDS - 2; k++)
{
if (q_size < BN128_WORDS)
if (k < q_size)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - q_size + 1;
i_end = k;
if (i_end > BN128_WORDS - 1)
i_end = BN128_WORDS - 1;
}
else
if (k < BN128_WORDS)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - BN128_WORDS + 1;
i_end = k;
if (i_end > q_size - 1)
i_end = q_size - 1;
}
for (i = i_beg; i <= i_end; i++)
{
uint64_t uv;
uint32_t u, v;
uint32_t carry;
j = k - i;
if (q_size < BN128_WORDS)
uv = ((uint64_t )q[j])*((uint64_t )C[i]);
else
uv = ((uint64_t )q[i])*((uint64_t )C[j]);
v = uv;
u = (uv >> 32);
r0 += v;
carry = (r0 < v);
r1 += carry;
carry = (r1 < carry);
r1 += u;
carry += (r1 < u);
r2 += carry;
}
r[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
r[k] = r0;
}
/**
* @brief R = A mod M (using M=2^252+C) (Barret reduction)
*
* See HAC 14.47.
*/
static void
mod_reduce_M (bn256 *R, const bn512 *A)
{
uint32_t q[BN256_WORDS+1];
uint32_t tmp[BN416_WORDS];
bn256 r[1];
uint32_t carry, next_carry;
int i;
#define borrow carry
q[8] = A->word[15]>>28;
carry = A->word[15] & 0x0fffffff;
for (i = BN256_WORDS - 1; i >= 0; i--)
{
next_carry = A->word[i+7] & 0x0fffffff;
q[i] = (A->word[i+7] >> 28) | (carry << 4);
carry = next_carry;
}
memcpy (R, A, sizeof (bn256));
R->word[7] &= 0x0fffffff;
/* Q_size: 9 */
bnX_mul_C (tmp, q, 9); /* TMP = Q*C */
/* Q = tmp / 2^252 */
carry = tmp[12] & 0x0fffffff;
for (i = 4; i >= 0; i--)
{
next_carry = tmp[i+7] & 0x0fffffff;
q[i] = (tmp[i+7] >> 28) | (carry << 4);
carry = next_carry;
}
/* R' = tmp % 2^252 */
memcpy (r, tmp, sizeof (bn256));
r->word[7] &= 0x0fffffff;
/* R -= R' */
borrow = bn256_sub (R, R, r);
if (borrow)
bn256_add (R, R, M);
else
bn256_add ((bn256 *)tmp, R, M);
/* Q_size: 5 */
bnX_mul_C (tmp, q, 5); /* TMP = Q*C */
carry = tmp[8] & 0x0fffffff;
q[0] = (tmp[7] >> 28) | (carry << 4);
/* R' = tmp % 2^252 */
memcpy (r, tmp, sizeof (bn256));
r->word[7] &= 0x0fffffff;
/* R += R' */
bn256_add (R, R, r);
borrow = bn256_sub (R, R, M);
if (borrow)
bn256_add (R, R, M);
else
bn256_add ((bn256 *)tmp, R, M);
/* Q_size: 1 */
bnX_mul_C (tmp, q, 1); /* TMP = Q*C */
/* R' = tmp % 2^252 */
memset (((uint8_t *)r)+(sizeof (uint32_t)*5), 0, sizeof (uint32_t)*3);
memcpy (r, tmp, sizeof (uint32_t)*5);
/* R -= R' */
borrow = bn256_sub (R, R, r);
if (borrow)
bn256_add (R, R, M);
else
bn256_add ((bn256 *)tmp, R, M);
#undef borrow
}
void
eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *out,
const bn256 *a, const uint8_t *seed, const bn256 *pk)
{
bn256 *r, *s;
sha512_context ctx;
uint8_t hash[64];
bn256 tmp[1];
ac R[1];
uint32_t carry, borrow;
r = (bn256 *)out;
s = (bn256 *)(out+(32/4));
sha512_start (&ctx);
sha512_update (&ctx, seed, sizeof (bn256)); /* It's upper half of the hash */
sha512_update (&ctx, input, ilen);
sha512_finish (&ctx, hash);
mod_reduce_M (r, (bn512 *)hash);
compute_kG_25519 (R, r);
/* EdDSA encoding. */
memcpy (tmp, R->y, sizeof (bn256));
tmp->word[7] ^= mod25519_is_neg (R->x) * 0x80000000;
sha512_start (&ctx);
sha512_update (&ctx, (uint8_t *)tmp, sizeof (bn256));
sha512_update (&ctx, (uint8_t *)pk, sizeof (bn256));
sha512_update (&ctx, input, ilen);
sha512_finish (&ctx, (uint8_t *)hash);
mod_reduce_M (s, (bn512 *)hash);
bn256_mul ((bn512 *)hash, s, a);
mod_reduce_M (s, (bn512 *)hash);
carry = bn256_add (s, s, r);
borrow = bn256_sub (s, s, M);
memcpy (r, tmp, sizeof (bn256));
if ((borrow && !carry))
bn256_add (s, s, M);
else
bn256_add (tmp, s, M);
}
void
eddsa_public_key_25519 (bn256 *pk, const bn256 *a)
{
ac R[1];
ptc X[1];
bn256 a0[1];
bn256_shift (a0, a, -3);
compute_kG_25519 (R, a0);
memcpy (X, R, sizeof (ac));
memset (X->z, 0, sizeof (bn256));
X->z->word[0] = 1;
point_double (X, X);
point_double (X, X);
point_double (X, X);
point_ptc_to_ac (R, X);
/* EdDSA encoding. */
memcpy (pk, R->y, sizeof (bn256));
pk->word[7] ^= mod25519_is_neg (R->x) * 0x80000000;
}
uint8_t *
eddsa_compute_public_25519 (const uint8_t *kd)
{
uint8_t *p0;
const bn256 *a = (const bn256 *)kd;
p0 = (uint8_t *)malloc (sizeof (bn256));
if (p0 == NULL)
return NULL;
eddsa_public_key_25519 ((bn256 *)p0, a);
return p0;
}
#if 0
/**
* check if P is on the curve.
*
* Return -1 on error.
* Return 0 on success.
*/
static int
point_is_on_the_curve (const ac *P)
{
bn256 s[1], t[1];
/* Twisted Edwards curve: a*x^2 + y^2 = 1 + d*x^2*y^2 */
}
int
compute_kP_25519 (ac *X, const bn256 *K, const ac *P);
#endif
#ifdef PRINT_OUT_TABLE
static const ptc G[1] = {{
{{{ 0x8f25d51a, 0xc9562d60, 0x9525a7b2, 0x692cc760,
0xfdd6dc5c, 0xc0a4e231, 0xcd6e53fe, 0x216936d3 }}},
{{{ 0x66666658, 0x66666666, 0x66666666, 0x66666666,
0x66666666, 0x66666666, 0x66666666, 0x66666666 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}},
}};
#include <stdio.h>
#ifdef TESTING_EDDSA
static void
print_bn256 (const bn256 *X)
{
int i;
for (i = 7; i >= 0; i--)
printf ("%08x", X->word[i]);
puts ("");
}
#endif
#if 0
static void
print_point (const ac *X)
{
int i;
#ifdef PRINT_OUT_TABLE_AS_C
fputs (" { {{{ ", stdout);
for (i = 0; i < 4; i++)
printf ("0x%08x, ", X->x->word[i]);
fputs ("\n ", stdout);
for (; i < 7; i++)
printf ("0x%08x, ", X->x->word[i]);
printf ("0x%08x }}},\n", X->x->word[i]);
fputs (" {{{ ", stdout);
for (i = 0; i < 4; i++)
printf ("0x%08x, ", X->y->word[i]);
fputs ("\n ", stdout);
for (; i < 7; i++)
printf ("0x%08x, ", X->y->word[i]);
printf ("0x%08x }}} },\n", X->y->word[i]);
#else
puts ("--");
for (i = 7; i >= 0; i--)
printf ("%08x", X->x->word[i]);
puts ("");
for (i = 7; i >= 0; i--)
printf ("%08x", X->y->word[i]);
puts ("");
puts ("--");
#endif
}
static void
print_point_ptc (const ptc *X)
{
int i;
puts ("---");
for (i = 7; i >= 0; i--)
printf ("%08x", X->x->word[i]);
puts ("");
for (i = 7; i >= 0; i--)
printf ("%08x", X->y->word[i]);
puts ("");
for (i = 7; i >= 0; i--)
printf ("%08x", X->z->word[i]);
puts ("");
puts ("---");
}
#endif
#ifndef TESTING_EDDSA
static void power_2 (ac *A, ptc *a, int N)
{
int i;
for (i = 0; i < N; i++)
ed_double_25638 (a, a);
ptc_to_ac_25519 (A, a);
}
static void print_table (ac *a0001, ac *a0010, ac *a0100, ac *a1000)
{
int i;
ptc a[1];
ac x[1];
for (i = 1; i < 16; i++)
{
/* A := Identity Element */
memset (a, 0, sizeof (ptc));
a->y->word[0] = 1;
a->z->word[0] = 1;
if ((i & 1))
ed_add_25638 (a, a, a0001);
if ((i & 2))
ed_add_25638 (a, a, a0010);
if ((i & 4))
ed_add_25638 (a, a, a0100);
if ((i & 8))
ed_add_25638 (a, a, a1000);
ptc_to_ac_25519 (x, a);
print_point (x);
}
fputs ("\n", stdout);
}
static void compute_and_print_table (ac *a0001, ac *a0010, ac *a0100, ac *a1000)
{
ptc a[1];
memcpy (a, a0001, sizeof (ac));
memset (a->z, 0, sizeof (bn256));
a->z->word[0] = 1;
power_2 (a0010, a, 63);
power_2 (a0100, a, 63);
power_2 (a1000, a, 63);
print_table (a0001, a0010, a0100, a1000);
}
#endif
int
main (int argc, char *argv[])
{
#ifdef TESTING_EDDSA
uint8_t hash[64];
bn256 a[1];
uint8_t r_s[64];
bn256 pk[1];
bn256 *r, *s;
const bn256 sk[1] = {
{{ 0x9db1619d, 0x605afdef, 0xf44a84ba, 0xc42cec92,
0x69c54944, 0x1969327b, 0x03ac3b70, 0x607fae1c }} };
const bn256 r_expected[1] = {
{{ 0x004356e5, 0x72ac60c3, 0xcce28690, 0x8a826e80,
0x1e7f8784, 0x74d9e5b8, 0x65e073d8, 0x55014922 }} };
const bn256 s_expected[1] = {
{{ 0x1582b85f, 0xac3ba390, 0x70391ec6, 0x6bb4f91c,
0xf0f55bd2, 0x24be5b59, 0x43415165, 0x0b107a8e }} };
r = (bn256 *)r_s;
s = (bn256 *)(r_s+32);
sha512 ((uint8_t *)sk, sizeof (bn256), hash);
hash[0] &= 248;
hash[31] &= 127;
hash[31] |= 64;
memcpy (a, hash, sizeof (bn256));
eddsa_public_key_25519 (pk, a);
eddsa_sign_25519 ((const uint8_t *)"", 0, r_s, a, hash+32, pk);
if (memcmp (r, r_expected, sizeof (bn256)) != 0
|| memcmp (s, s_expected, sizeof (bn256)) != 0)
{
print_bn256 (r);
print_bn256 (s);
return 1;
}
#else
ac a0001[1], a0010[1], a0100[1], a1000[1];
ptc a[1];
memcpy (a, G, sizeof (ptc));
ptc_to_ac_25519 (a0001, a);
compute_and_print_table (a0001, a0010, a0100, a1000);
memcpy (a, a0001, sizeof (ac));
memset (a->z, 0, sizeof (bn256));
a->z->word[0] = 1;
power_2 (a0001, a, 21);
compute_and_print_table (a0001, a0010, a0100, a1000);
memcpy (a, a0001, sizeof (ac));
memset (a->z, 0, sizeof (bn256));
a->z->word[0] = 1;
power_2 (a0001, a, 21);
compute_and_print_table (a0001, a0010, a0100, a1000);
#endif
return 0;
}
#endif

196
src/ecc-mont.c Normal file
View File

@@ -0,0 +1,196 @@
/* -*- coding: utf-8 -*-
* ecc-mont.c - Elliptic curve computation for
* the Montgomery curve: y^2 = x^3 + 486662*x^2 + x.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod25638.h"
#include "mod.h"
/*
* References:
*
* [1] D. J. Bernstein. Curve25519: new Diffie-Hellman speed records.
* Proceedings of PKC 2006, to appear.
* http://cr.yp.to/papers.html#curve25519. Date: 2006.02.09.
*
* [2] D. J. Bernstein. Can we avoid tests for zero in fast
* elliptic-curve arithmetic?
* http://cr.yp.to/papers.html#curvezero. Date: 2006.07.26.
*
*/
/*
* IMPLEMENTATION NOTE
*
* (0) We assume that the processor has no cache, nor branch target
* prediction. Thus, we don't avoid indexing by secret value.
* We don't avoid conditional jump if both cases have same timing,
* either.
*
* (1) We use Radix-32 field arithmetic. It's a representation like
* 2^256-38, but it's more redundant. For example, "1" can be
* represented in three ways in 256-bit: 1, 2^255-18, and
* 2^256-37.
*
* (2) We use Montgomery double-and-add.
*
*/
#ifndef BN256_C_IMPLEMENTATION
#define ASM_IMPLEMENTATION 1
#endif
/*
*
* 121665 = 0x1db41
* 1 1101 1011 0100 0001
*/
static void
mod25638_mul_121665 (bn256 *x, const bn256 *a)
{
#if ASM_IMPLEMENTATION
#include "muladd_256.h"
const uint32_t *s;
uint32_t *d;
uint32_t w;
uint32_t c;
s = a->word;
d = x->word;
w = 121665;
MULADD_256_ASM (s, d, w, c);
#else
uint32_t c, c1;
bn256 m[1];
c = c1 = bn256_shift (m, a, 6); c += bn256_add (x, a, m);
c1 <<= 2; c1 |= bn256_shift (m, m, 2); c = c + c1 + bn256_add (x, x, m);
c1 <<= 1; c1 |= bn256_shift (m, m, 1); c = c + c1 + bn256_add (x, x, m);
c1 <<= 2; c1 |= bn256_shift (m, m, 2); c = c + c1 + bn256_add (x, x, m);
c1 <<= 1; c1 |= bn256_shift (m, m, 1); c = c + c1 + bn256_add (x, x, m);
c1 <<= 2; c1 |= bn256_shift (m, m, 2); c = c + c1 + bn256_add (x, x, m);
c1 <<= 1; c1 |= bn256_shift (m, m, 1); c = c + c1 + bn256_add (x, x, m);
c1 <<= 1; c1 |= bn256_shift (m, m, 1); c = c + c1 + bn256_add (x, x, m);
#endif
c = bn256_add_uint (x, x, c*38);
x->word[0] += c * 38;
}
typedef struct
{
bn256 x[1];
bn256 z[1];
} pt;
/**
* @brief Process Montgomery double-and-add
*
* With Q0, Q1, DIF (= Q0 - Q1), compute PRD = 2Q0, SUM = Q0 + Q1
* Q0 and Q1 are clobbered.
*
*/
static void
mont_d_and_a (pt *prd, pt *sum, pt *q0, pt *q1, const bn256 *dif_x)
{
mod25638_add (sum->x, q1->x, q1->z);
mod25638_sub (q1->z, q1->x, q1->z);
mod25638_add (prd->x, q0->x, q0->z);
mod25638_sub (q0->z, q0->x, q0->z);
mod25638_mul (q1->x, q0->z, sum->x);
mod25638_mul (q1->z, prd->x, q1->z);
mod25638_sqr (q0->x, prd->x);
mod25638_sqr (q0->z, q0->z);
mod25638_add (sum->x, q1->x, q1->z);
mod25638_sub (q1->z, q1->x, q1->z);
mod25638_mul (prd->x, q0->x, q0->z);
mod25638_sub (q0->z, q0->x, q0->z);
mod25638_sqr (sum->x, sum->x);
mod25638_sqr (sum->z, q1->z);
mod25638_mul_121665 (prd->z, q0->z);
mod25638_mul (sum->z, sum->z, dif_x);
mod25638_add (prd->z, q0->x, prd->z);
mod25638_mul (prd->z, prd->z, q0->z);
}
/**
* @brief RES = x-coordinate of [n]Q
*
* @param N Scalar N (three least significant bits are 000)
* @param Q_X x-coordinate of Q
*
*/
void
compute_nQ (bn256 *res, const bn256 *n, const bn256 *q_x)
{
int i, j;
pt p0[1], p1[1], p0_[1], p1_[1];
/* P0 = O = (1:0) */
memset (p0->x, 0, sizeof (bn256));
p0->x->word[0] = 1;
memset (p0->z, 0, sizeof (bn256));
/* P1 = (X:1) */
memcpy (p1->x, q_x, sizeof (bn256));
memset (p1->z, 0, sizeof (bn256));
p1->z->word[0] = 1;
for (i = 0; i < 8; i++)
{
uint32_t u = n->word[7-i];
for (j = 0; j < 16; j++)
{
pt *q0, *q1;
pt *sum_n, *prd_n;
if ((u & 0x80000000))
q0 = p1, q1 = p0, sum_n = p0_, prd_n = p1_;
else
q0 = p0, q1 = p1, sum_n = p1_, prd_n = p0_;
mont_d_and_a (prd_n, sum_n, q0, q1, q_x);
if ((u & 0x40000000))
q0 = p1_, q1 = p0_, sum_n = p0, prd_n = p1;
else
q0 = p0_, q1 = p1_, sum_n = p1, prd_n = p0;
mont_d_and_a (prd_n, sum_n, q0, q1, q_x);
u <<= 2;
}
}
/* We know the LSB of N is always 0. Thus, result is always in P0. */
/*
* p0->z may be zero here, but our mod_inv doesn't raise error for 0,
* but returns 0 (like the implementation of z^(p-2)), thus, RES will
* be 0 in that case, which is correct value.
*/
mod_inv (res, p0->z, p25519);
mod25638_mul (res, res, p0->x);
mod25519_reduce (res);
}

368
src/ecc.c Normal file
View File

@@ -0,0 +1,368 @@
/* -*- coding: utf-8 -*-
* ecc.c - Elliptic curve over GF(prime)
*
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* References:
*
* [1] Suite B Implementer's Guide to FIPS 186-3 (ECDSA), February 3, 2010.
*
* [2] Michael Brown, Darrel Hankerson, Julio López, and Alfred Menezes,
* Software Implementation of the NIST Elliptic Curves Over Prime Fields,
* Proceedings of the 2001 Conference on Topics in Cryptology: The
* Cryptographer's Track at RSA
* Pages 250-265, Springer-Verlag London, UK, 2001
* ISBN:3-540-41898-9
*
* [3] Mustapha Hedabou, Pierre Pinel, Lucien Bénéteau,
* A comb method to render ECC resistant against Side Channel Attacks,
* 2004
*/
#include "field-group-select.h"
/*
* Coefficients
*/
/*
* static const bn256 *coefficient_a;
* static const bn256 *coefficient_b;
*/
/*
* N: order of G
*/
/*
* static const bn256 N[1];
*/
/*
* MU = 2^512 / N
* MU = ( (1 << 256) | MU_lower )
*/
/*
* static const bn256 MU_lower[1];
*/
/*
* w = 4
* m = 256
* d = 64
* e = 32
*/
/*
* static const ac precomputed_KG[15];
* static const ac precomputed_2E_KG[15];
*/
#if TEST
/*
* Generator of Elliptic curve over GF(p256)
*/
const ac *G = &precomputed_KG[0];
#endif
static int
get_vk (const bn256 *K, int i)
{
uint32_t w0, w1, w2, w3;
if (i < 32)
{
w3 = K->word[6]; w2 = K->word[4]; w1 = K->word[2]; w0 = K->word[0];
}
else
{
w3 = K->word[7]; w2 = K->word[5]; w1 = K->word[3]; w0 = K->word[1];
i -= 32;
}
w3 >>= i; w2 >>= i; w1 >>= i; w0 >>= i;
return ((w3 & 1) << 3) | ((w2 & 1) << 2) | ((w1 & 1) << 1) | (w0 & 1);
}
/**
* @brief X = k * G
*
* @param K scalar k
*
* Return -1 on error.
* Return 0 on success.
*/
int
FUNC(compute_kG) (ac *X, const bn256 *K)
{
uint8_t index[64]; /* Lower 4-bit for index absolute value, msb is
for sign (encoded as: 0 means 1, 1 means -1). */
bn256 K_dash[1];
jpc Q[1], tmp[1], *dst;
int i;
int vk;
uint32_t k_is_even = bn256_is_even (K);
bn256_sub_uint (K_dash, K, k_is_even);
/* It keeps the condition: 1 <= K' <= N - 2, and K' is odd. */
/* Fill index. */
vk = get_vk (K_dash, 0);
for (i = 1; i < 64; i++)
{
int vk_next, is_zero;
vk_next = get_vk (K_dash, i);
is_zero = (vk_next == 0);
index[i-1] = (vk - 1) | (is_zero << 7);
vk = (is_zero ? vk : vk_next);
}
index[63] = vk - 1;
memset (Q->z, 0, sizeof (bn256)); /* infinity */
for (i = 31; i >= 0; i--)
{
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac_signed) (Q, Q, &precomputed_2E_KG[index[i+32]&0x0f],
index[i+32] >> 7);
FUNC(jpc_add_ac_signed) (Q, Q, &precomputed_KG[index[i]&0x0f],
index[i] >> 7);
}
dst = k_is_even ? Q : tmp;
FUNC(jpc_add_ac) (dst, Q, &precomputed_KG[0]);
return FUNC(jpc_to_ac) (X, Q);
}
/**
* check if P is on the curve.
*
* Return -1 on error.
* Return 0 on success.
*/
static int
point_is_on_the_curve (const ac *P)
{
bn256 s[1], t[1];
/* Elliptic curve: y^2 = x^3 + a*x + b */
MFNC(sqr) (s, P->x);
MFNC(mul) (s, s, P->x);
#ifndef COEFFICIENT_A_IS_ZERO
MFNC(mul) (t, coefficient_a, P->x);
MFNC(add) (s, s, t);
#endif
MFNC(add) (s, s, coefficient_b);
MFNC(sqr) (t, P->y);
if (bn256_cmp (s, t) == 0)
return 0;
else
return -1;
}
static int
get_vk_kP (const bn256 *K, int i)
{
uint32_t w;
uint8_t blk = i/32;
uint8_t pos = i%32;
uint8_t col = 3*(pos % 11) + (pos >= 11) + (pos >= 22);
uint8_t word_index = (blk * 3) + (pos / 11);
w = ((K->word[word_index] >> col) & 7);
if (word_index < 7 && (pos == 10 || pos == 21))
{
uint8_t mask;
uint8_t shift;
word_index++;
if (pos == 10)
{
shift = 2;
mask = 4;
}
else
{
shift = 1;
mask = 6;
}
w |= ((K->word[word_index] << shift) & mask);
}
return w;
}
/**
* @brief X = k * P
*
* @param K scalar k
* @param P P in affine coordiate
*
* Return -1 on error.
* Return 0 on success.
*
* For the curve (cofactor is 1 and n is prime), possible error cases are:
*
* P is not on the curve.
* P = G, k = n
* Something wrong in the code.
*
* Mathmatically, k=1 and P=O is another possible case, but O cannot be
* represented by affine coordinate.
*/
int
FUNC(compute_kP) (ac *X, const bn256 *K, const ac *P)
{
uint8_t index[86]; /* Lower 2-bit for index absolute value, msb is
for sign (encoded as: 0 means 1, 1 means -1). */
bn256 K_dash[1];
uint32_t k_is_even = bn256_is_even (K);
jpc Q[1], tmp[1], *dst;
int i;
int vk;
ac P3[1], P5[1], P7[1];
const ac *p_Pi[4];
if (point_is_on_the_curve (P) < 0)
return -1;
if (bn256_sub (K_dash, K, N) == 0) /* >= N, it's too big. */
return -1;
bn256_sub_uint (K_dash, K, k_is_even);
/* It keeps the condition: 1 <= K' <= N - 2, and K' is odd. */
p_Pi[0] = P;
p_Pi[1] = P3;
p_Pi[2] = P5;
p_Pi[3] = P7;
{
jpc Q1[1];
memcpy (Q->x, P->x, sizeof (bn256));
memcpy (Q->y, P->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->word[0] = 1;
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac) (Q1, Q, P);
if (FUNC(jpc_to_ac) (P3, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac) (Q1, Q, P);
if (FUNC(jpc_to_ac) (P5, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
memcpy (Q->x, P3->x, sizeof (bn256));
memcpy (Q->y, P3->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->word[0] = 1;
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac) (Q1, Q, P);
if (FUNC(jpc_to_ac) (P7, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
}
/* Fill index. */
vk = get_vk_kP (K_dash, 0);
for (i = 1; i < 86; i++)
{
int vk_next, is_even;
vk_next = get_vk_kP (K_dash, i);
is_even = ((vk_next & 1) == 0);
index[i-1] = (is_even << 7) | ((is_even?7-vk:vk-1) >> 1);
vk = vk_next + is_even;
}
index[85] = ((vk - 1) >> 1);
memset (Q->z, 0, sizeof (bn256)); /* infinity */
for (i = 85; i >= 0; i--)
{
FUNC(jpc_double) (Q, Q);
FUNC(jpc_double) (Q, Q);
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac_signed) (Q, Q, p_Pi[index[i]&0x03], index[i] >> 7);
}
dst = k_is_even ? Q : tmp;
FUNC(jpc_add_ac) (dst, Q, P);
return FUNC(jpc_to_ac) (X, Q);
}
/**
* @brief Compute signature (r,s) of hash string z with secret key d
*/
void
FUNC(ecdsa) (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d)
{
bn256 k[1];
ac KG[1];
bn512 tmp[1];
bn256 k_inv[1];
uint32_t carry;
#define borrow carry
#define tmp_k k_inv
do
{
do
{
bn256_random (k);
if (bn256_add_uint (k, k, 1))
continue;
if (bn256_sub (tmp_k, k, N) == 0) /* >= N, it's too big. */
continue;
/* 1 <= k <= N - 1 */
FUNC(compute_kG) (KG, k);
borrow = bn256_sub (r, KG->x, N);
if (borrow)
memcpy (r, KG->x, sizeof (bn256));
else
memcpy (KG->x, r, sizeof (bn256));
}
while (bn256_is_zero (r));
mod_inv (k_inv, k, N);
bn256_mul (tmp, r, d);
mod_reduce (s, tmp, N, MU_lower);
carry = bn256_add (s, s, z);
if (carry)
bn256_sub (s, s, N);
else
bn256_sub ((bn256 *)tmp, s, N);
bn256_mul (tmp, s, k_inv);
mod_reduce (s, tmp, N, MU_lower);
}
while (bn256_is_zero (s));
#undef tmp_k
#undef borrow
}

7
src/field-group-select.h Normal file
View File

@@ -0,0 +1,7 @@
#define CONCAT0(a,b) a##b
#define CONCAT1(a,b) CONCAT0(a,b)
#define CONCAT2(a,b,c) CONCAT1(a,b##c)
#define CONCAT3(a,b,c) CONCAT2(a,b,c)
#define FUNC(func) CONCAT1(func##_,FIELD)
#define MFNC(func) CONCAT3(mod,FIELD,_##func)

View File

@@ -1,7 +1,7 @@
/*
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
*
* Copyright (C) 2010, 2011, 2012, 2013
* Copyright (C) 2010, 2011, 2012, 2013, 2014
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -57,13 +57,15 @@
* _data_pool
* <two pages>
* _keystore_pool
* three flash pages for keystore (single: 512-byte (p, q and N))
* Three flash pages for keystore
* a page contains a key data of:
* For RSA-2048: 512-byte (p, q and N)
* For RSA-4096: 1024-byte (p, q and N)
* For ECDSA/ECDH and EdDSA, there are padding after public key
*/
#define KEY_SIZE 512 /* P, Q and N */
#define FLASH_DATA_POOL_HEADER_SIZE 2
#define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2)
#define FLASH_KEYSTORE_SIZE (FLASH_PAGE_SIZE*3)
static const uint8_t *data_pool;
extern uint8_t _keystore_pool;
@@ -78,6 +80,25 @@ const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
/* Linker set this symbol */
extern uint8_t _data_pool;
static int key_available_at (const uint8_t *k, int key_size)
{
int i;
for (i = 0; i < key_size; i++)
if (k[i])
break;
if (i == key_size) /* It's ZERO. Released key. */
return 0;
for (i = 0; i < key_size; i++)
if (k[i] != 0xff)
break;
if (i == key_size) /* It's FULL. Unused key. */
return 0;
return 1;
}
const uint8_t *
flash_init (void)
{
@@ -100,6 +121,33 @@ flash_init (void)
return data_pool + FLASH_DATA_POOL_HEADER_SIZE;
}
void
flash_init_keys (void)
{
const uint8_t *p;
int i;
/* For each key, find its address. */
p = &_keystore_pool;
for (i = 0; i < 3; i++)
{
const uint8_t *k;
int key_size = gpg_get_algo_attr_key_size (i, GPG_KEY_STORAGE);
kd[i].pubkey = NULL;
for (k = p; k < p + FLASH_PAGE_SIZE; k += key_size)
if (key_available_at (k, key_size))
{
int prv_len = gpg_get_algo_attr_key_size (i, GPG_KEY_PRIVATE);
kd[i].pubkey = k + prv_len;
break;
}
p += FLASH_PAGE_SIZE;
}
}
/*
* Flash data pool managenent
*
@@ -114,6 +162,7 @@ flash_init (void)
* 123-counter
* 14-bit counter
* bool object
* small enum
*
* Format of a Data Object:
* NR: 8-bit tag_number
@@ -269,34 +318,41 @@ flash_do_release (const uint8_t *do_data)
}
uint8_t *
flash_key_alloc (void)
static uint8_t *
flash_key_getpage (enum kind_of_key kk)
{
uint8_t *k;
int i;
/* There is a page for each KK. */
return &_keystore_pool + (FLASH_PAGE_SIZE * kk);
}
/* Seek empty keystore. */
k = &_keystore_pool;
while (k < &_keystore_pool + FLASH_KEYSTORE_SIZE)
uint8_t *
flash_key_alloc (enum kind_of_key kk)
{
uint8_t *k, *k0 = flash_key_getpage (kk);
int i;
int key_size = gpg_get_algo_attr_key_size (kk, GPG_KEY_STORAGE);
/* Seek free space in the page. */
for (k = k0; k < k0 + FLASH_PAGE_SIZE; k += key_size)
{
const uint32_t *p = (const uint32_t *)k;
for (i = 0; i < KEY_SIZE/4; i++)
for (i = 0; i < key_size/4; i++)
if (p[i] != 0xffffffff)
break;
if (i == KEY_SIZE/4) /* Yes, it's empty. */
if (i == key_size/4) /* Yes, it's empty. */
return k;
k += KEY_SIZE;
}
/* Should not happen as we have enough space, but just in case. */
/* Should not happen as we have enough free space all time, but just
in case. */
return NULL;
}
int
flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
flash_key_write (uint8_t *key_addr,
const uint8_t *key_data, int key_data_len,
const uint8_t *pubkey, int pubkey_len)
{
uint16_t hw;
@@ -304,7 +360,7 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
int i;
addr = (uint32_t)key_addr;
for (i = 0; i < KEY_CONTENT_LEN/2; i ++)
for (i = 0; i < key_data_len/2; i ++)
{
hw = key_data[i*2] | (key_data[i*2+1]<<8);
if (flash_program_halfword (addr, hw) != 0)
@@ -324,14 +380,14 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
}
static int
flash_check_all_other_keys_released (const uint8_t *key_addr)
flash_check_all_other_keys_released (const uint8_t *key_addr, int key_size)
{
uint32_t start = (uint32_t)key_addr & ~(FLASH_PAGE_SIZE - 1);
const uint32_t *p = (const uint32_t *)start;
while (p < (const uint32_t *)(start + FLASH_PAGE_SIZE))
if (p == (const uint32_t *)key_addr)
p += KEY_SIZE/4;
p += key_size/4;
else
if (*p)
return 0;
@@ -342,22 +398,28 @@ flash_check_all_other_keys_released (const uint8_t *key_addr)
}
static void
flash_key_fill_zero_as_released (uint8_t *key_addr)
flash_key_fill_zero_as_released (uint8_t *key_addr, int key_size)
{
int i;
uint32_t addr = (uint32_t)key_addr;
for (i = 0; i < KEY_SIZE/2; i++)
for (i = 0; i < key_size/2; i++)
flash_program_halfword (addr + i*2, 0);
}
void
flash_key_release (uint8_t *key_addr)
flash_key_release (uint8_t *key_addr, int key_size)
{
if (flash_check_all_other_keys_released (key_addr))
if (flash_check_all_other_keys_released (key_addr, key_size))
flash_erase_page (((uint32_t)key_addr & ~(FLASH_PAGE_SIZE - 1)));
else
flash_key_fill_zero_as_released (key_addr);
flash_key_fill_zero_as_released (key_addr, key_size);
}
void
flash_key_release_page (enum kind_of_key kk)
{
flash_erase_page ((uint32_t)flash_key_getpage (kk));
}
@@ -425,6 +487,38 @@ flash_bool_write (uint8_t nr)
}
void
flash_enum_clear (const uint8_t **addr_p)
{
flash_bool_clear (addr_p);
}
void
flash_enum_write_internal (const uint8_t *p, int nr, uint8_t v)
{
uint16_t hw = nr | (v << 8);
flash_program_halfword ((uint32_t)p, hw);
}
const uint8_t *
flash_enum_write (uint8_t nr, uint8_t v)
{
uint8_t *p;
uint16_t hw = nr | (v << 8);
p = flash_data_pool_allocate (2);
if (p == NULL)
{
DEBUG_INFO ("enum allocation failure.\r\n");
return NULL;
}
flash_program_halfword ((uint32_t)p, hw);
return p;
}
int
flash_cnt123_get_value (const uint8_t *p)
{
@@ -552,7 +646,7 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
}
else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
{
maxsize = KEY_CONTENT_LEN;
maxsize = FIRMWARE_UPDATE_KEY_CONTENT_LEN;
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
if (len == 0 && offset == 0)
{ /* This means removal of update key. */

View File

@@ -36,10 +36,10 @@ void ccid_card_change_signal (int how);
#define EV_VERIFY_CMD_AVAILABLE (8)
#define EV_MODIFY_CMD_AVAILABLE (16)
/* Maximum cmd apdu data is key import 22+4+128+128 (proc_key_import) */
#define MAX_CMD_APDU_DATA_SIZE (22+4+128+128) /* without header */
/* Maximum res apdu data is public key 5+9+256 (gpg_do_public_key) */
#define MAX_RES_APDU_DATA_SIZE (5+9+256) /* without trailer */
/* Maximum cmd apdu data is key import 24+4+256+256 (proc_key_import) */
#define MAX_CMD_APDU_DATA_SIZE (24+4+256+256) /* without header */
/* Maximum res apdu data is public key 5+9+512 (gpg_do_public_key) */
#define MAX_RES_APDU_DATA_SIZE (5+9+512) /* without trailer */
#define ICC_MSG_HEADER_SIZE 10
@@ -49,8 +49,7 @@ void ccid_card_change_signal (int how);
/* USB buffer size of LL (Low-level): size of single Bulk transaction */
#define USB_LL_BUF_SIZE 64
enum icc_state
{
enum icc_state {
ICC_STATE_NOCARD, /* No card available */
ICC_STATE_START, /* Initial */
ICC_STATE_WAIT, /* Waiting APDU */
@@ -76,40 +75,46 @@ extern volatile uint8_t auth_status;
#define PW_ERR_PW1 0
#define PW_ERR_RC 1
#define PW_ERR_PW3 2
extern int gpg_pw_get_retry_counter (int who);
extern int gpg_pw_locked (uint8_t which);
extern void gpg_pw_reset_err_counter (uint8_t which);
extern void gpg_pw_increment_err_counter (uint8_t which);
int gpg_pw_get_retry_counter (int who);
int gpg_pw_locked (uint8_t which);
void gpg_pw_reset_err_counter (uint8_t which);
void gpg_pw_increment_err_counter (uint8_t which);
extern int ac_check_status (uint8_t ac_flag);
extern int verify_pso_cds (const uint8_t *pw, int pw_len);
extern int verify_other (const uint8_t *pw, int pw_len);
extern int verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len,
int pw_len_known, const uint8_t *ks_pw1, int saveks);
extern int verify_admin (const uint8_t *pw, int pw_len);
extern int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known,
const uint8_t *ks_pw3, int saveks);
int ac_check_status (uint8_t ac_flag);
int verify_pso_cds (const uint8_t *pw, int pw_len);
int verify_other (const uint8_t *pw, int pw_len);
int verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len,
int pw_len_known, const uint8_t *ks_pw1, int saveks);
int verify_admin (const uint8_t *pw, int pw_len);
int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known,
const uint8_t *ks_pw3, int saveks);
extern void ac_reset_pso_cds (void);
extern void ac_reset_other (void);
extern void ac_reset_admin (void);
extern void ac_fini (void);
void ac_reset_pso_cds (void);
void ac_reset_other (void);
void ac_reset_admin (void);
void ac_fini (void);
extern void set_res_sw (uint8_t sw1, uint8_t sw2);
void set_res_sw (uint8_t sw1, uint8_t sw2);
extern uint16_t data_objects_number_of_bytes;
#define CHALLENGE_LEN 32
extern void gpg_data_scan (const uint8_t *p);
extern void gpg_data_copy (const uint8_t *p);
extern void gpg_do_get_data (uint16_t tag, int with_tag);
extern void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
extern void gpg_do_public_key (uint8_t kk_byte);
extern void gpg_do_keygen (uint8_t kk_byte);
void gpg_data_scan (const uint8_t *p);
void gpg_data_copy (const uint8_t *p);
void gpg_do_get_data (uint16_t tag, int with_tag);
void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
void gpg_do_public_key (uint8_t kk_byte);
void gpg_do_keygen (uint8_t kk_byte);
extern const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
/* Constants: algo+size */
#define ALGO_RSA4K 0
#define ALGO_NISTP256R1 1
#define ALGO_SECP256K1 2
#define ALGO_ED25519 3
#define ALGO_RSA2K 255
enum kind_of_key {
GPG_KEY_FOR_SIGNING = 0,
@@ -117,17 +122,29 @@ enum kind_of_key {
GPG_KEY_FOR_AUTHENTICATION,
};
extern const uint8_t *flash_init (void);
extern void flash_do_release (const uint8_t *);
extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
extern uint8_t *flash_key_alloc (void);
extern void flash_key_release (uint8_t *);
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
const uint8_t *pubkey, int pubkey_len);
extern void flash_set_data_pool_last (const uint8_t *p);
extern void flash_clear_halfword (uint32_t addr);
extern void flash_increment_counter (uint8_t counter_tag_nr);
extern void flash_reset_counter (uint8_t counter_tag_nr);
enum size_of_key {
GPG_KEY_STORAGE = 0, /* PUBKEY + PRVKEY rounded to 2^N */
GPG_KEY_PUBLIC,
GPG_KEY_PRIVATE,
};
int gpg_get_algo_attr (enum kind_of_key kk);
int gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s);
const uint8_t *flash_init (void);
void flash_init_keys (void);
void flash_do_release (const uint8_t *);
const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
uint8_t *flash_key_alloc (enum kind_of_key);
void flash_key_release (uint8_t *, int);
void flash_key_release_page (enum kind_of_key);
int flash_key_write (uint8_t *key_addr,
const uint8_t *key_data, int key_data_len,
const uint8_t *pubkey, int pubkey_len);
void flash_set_data_pool_last (const uint8_t *p);
void flash_clear_halfword (uint32_t addr);
void flash_increment_counter (uint8_t counter_tag_nr);
void flash_reset_counter (uint8_t counter_tag_nr);
#define FILEID_SERIAL_NO 0
#define FILEID_UPDATE_KEY_0 1
@@ -135,8 +152,9 @@ extern void flash_reset_counter (uint8_t counter_tag_nr);
#define FILEID_UPDATE_KEY_2 3
#define FILEID_UPDATE_KEY_3 4
#define FILEID_CH_CERTIFICATE 5
extern int flash_erase_binary (uint8_t file_id);
extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t len, uint16_t offset);
int flash_erase_binary (uint8_t file_id);
int flash_write_binary (uint8_t file_id, const uint8_t *data,
uint16_t len, uint16_t offset);
#define FLASH_CH_CERTIFICATE_SIZE 2048
@@ -144,22 +162,19 @@ extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t le
extern uint8_t ch_certificate_start;
extern uint8_t random_bits_start;
#define KEY_CONTENT_LEN 256 /* p and q */
#define FIRMWARE_UPDATE_KEY_CONTENT_LEN 256 /* RSA-2048 (p and q) */
#define INITIAL_VECTOR_SIZE 16
#define DATA_ENCRYPTION_KEY_SIZE 16
/* encrypted data content */
struct key_data {
uint8_t data[KEY_CONTENT_LEN]; /* p and q */
};
#define MAX_PRVKEY_LEN 512 /* Maximum is the case for RSA 4096-bit. */
struct key_data_internal {
uint32_t data[KEY_CONTENT_LEN/4]; /* p and q */
uint32_t checksum[DATA_ENCRYPTION_KEY_SIZE/4];
struct key_data {
const uint8_t *pubkey; /* Pointer to public key */
uint8_t data[MAX_PRVKEY_LEN]; /* decrypted private key data content */
};
struct prvkey_data {
const uint8_t *key_addr;
/*
* IV: Initial Vector
*/
@@ -202,14 +217,14 @@ void s2k (const unsigned char *salt, size_t slen,
#define KS_GET_SALT(ks) (ks + KEYSTRING_PASSLEN_SIZE)
#define KS_GET_KEYSTRING(ks) (ks + KS_META_SIZE)
extern void gpg_do_clear_prvkey (enum kind_of_key kk);
extern int gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring);
extern int gpg_do_chks_prvkey (enum kind_of_key kk,
int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks);
void gpg_do_clear_prvkey (enum kind_of_key kk);
int gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring);
int gpg_do_chks_prvkey (enum kind_of_key kk,
int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks);
extern int gpg_change_keystring (int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks);
int gpg_change_keystring (int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks);
extern struct key_data kd[3];
@@ -218,13 +233,13 @@ extern struct key_data kd[3];
/*
* Debug functions in debug.c
*/
extern void put_byte (uint8_t b);
extern void put_byte_with_no_nl (uint8_t b);
extern void put_short (uint16_t x);
extern void put_word (uint32_t x);
extern void put_int (uint32_t x);
extern void put_string (const char *s);
extern void put_binary (const char *s, int len);
void put_byte (uint8_t b);
void put_byte_with_no_nl (uint8_t b);
void put_short (uint16_t x);
void put_word (uint32_t x);
void put_int (uint32_t x);
void put_string (const char *s);
void put_binary (const char *s, int len);
#define DEBUG_INFO(msg) put_string (msg)
#define DEBUG_WORD(w) put_word (w)
@@ -239,23 +254,35 @@ extern void put_binary (const char *s, int len);
#define DEBUG_BINARY(s,len)
#endif
extern int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *);
extern uint8_t *modulus_calc (const uint8_t *, int);
extern int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *);
extern int rsa_verify (const uint8_t *pubkey, const uint8_t *hash,
const uint8_t *signature);
extern uint8_t *rsa_genkey (void);
int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *, int);
uint8_t *modulus_calc (const uint8_t *, int);
int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *);
int rsa_verify (const uint8_t *, int, const uint8_t *, const uint8_t *);
uint8_t *rsa_genkey (int);
extern int ecdsa_sign (const uint8_t *hash, uint8_t *output,
const struct key_data *kd);
extern uint8_t *ecdsa_compute_public (const uint8_t *key_data);
int ecdsa_sign_p256r1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data);
uint8_t *ecc_compute_public_p256r1 (const uint8_t *key_data);
int ecdh_decrypt_p256r1 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data);
extern const uint8_t *gpg_do_read_simple (uint8_t);
extern void gpg_do_write_simple (uint8_t, const uint8_t *, int);
extern void gpg_increment_digital_signature_counter (void);
int ecdsa_sign_p256k1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data);
uint8_t *ecc_compute_public_p256k1 (const uint8_t *key_data);
int ecdh_decrypt_p256k1 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data);
int eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *output,
const uint8_t *sk_a, const uint8_t *seed,
const uint8_t *pk);
uint8_t *eddsa_compute_public_25519 (const uint8_t *a);
const uint8_t *gpg_do_read_simple (uint8_t);
void gpg_do_write_simple (uint8_t, const uint8_t *, int);
void gpg_increment_digital_signature_counter (void);
extern void fatal (uint8_t code) __attribute__ ((noreturn));
void fatal (uint8_t code) __attribute__ ((noreturn));
#define FATAL_FLASH 1
#define FATAL_RANDOM 2
@@ -263,7 +290,6 @@ extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
extern uint8_t admin_authorized;
/*** Flash memory tag values ***/
#define NR_NONE 0x00
/* Data objects */
/*
* Representation of data object:
@@ -271,28 +297,27 @@ extern uint8_t admin_authorized;
* <-1 halfword-> <--len/2 halfwords->
* <-tag-><-len-> <---data content--->
*/
#define NR_DO__FIRST__ 0x01
#define NR_DO_SEX 0x01
#define NR_DO_FP_SIG 0x02
#define NR_DO_FP_DEC 0x03
#define NR_DO_FP_AUT 0x04
#define NR_DO_CAFP_1 0x05
#define NR_DO_CAFP_2 0x06
#define NR_DO_CAFP_3 0x07
#define NR_DO_KGTIME_SIG 0x08
#define NR_DO_KGTIME_DEC 0x09
#define NR_DO_KGTIME_AUT 0x0a
#define NR_DO_LOGIN_DATA 0x0b
#define NR_DO_URL 0x0c
#define NR_DO_NAME 0x0d
#define NR_DO_LANGUAGE 0x0e
#define NR_DO_PRVKEY_SIG 0x0f
#define NR_DO_PRVKEY_DEC 0x10
#define NR_DO_PRVKEY_AUT 0x11
#define NR_DO_KEYSTRING_PW1 0x12
#define NR_DO_KEYSTRING_RC 0x13
#define NR_DO_KEYSTRING_PW3 0x14
#define NR_DO__LAST__ 21 /* == 0x15 */
#define NR_DO_SEX 0x00
#define NR_DO_FP_SIG 0x01
#define NR_DO_FP_DEC 0x02
#define NR_DO_FP_AUT 0x03
#define NR_DO_CAFP_1 0x04
#define NR_DO_CAFP_2 0x05
#define NR_DO_CAFP_3 0x06
#define NR_DO_KGTIME_SIG 0x07
#define NR_DO_KGTIME_DEC 0x08
#define NR_DO_KGTIME_AUT 0x09
#define NR_DO_LOGIN_DATA 0x0a
#define NR_DO_URL 0x0b
#define NR_DO_NAME 0x0c
#define NR_DO_LANGUAGE 0x0d
#define NR_DO_PRVKEY_SIG 0x0e
#define NR_DO_PRVKEY_DEC 0x0f
#define NR_DO_PRVKEY_AUT 0x10
#define NR_DO_KEYSTRING_PW1 0x11
#define NR_DO_KEYSTRING_RC 0x12
#define NR_DO_KEYSTRING_PW3 0x13
#define NR_DO__LAST__ 20 /* == 0x14 */
/* 14-bit counter for DS: Recorded in flash memory by 1-halfword (2-byte). */
/*
* Representation of 14-bit counter:
@@ -311,7 +336,10 @@ extern uint8_t admin_authorized;
* 1023: 0xc3ff
*/
#define NR_COUNTER_DS_LSB 0xc0 /* ..0xc3 */
/* 8-bit int or Boolean objects: Recorded in flash memory by 1-halfword (2-byte) */
/*
* Boolean object, small enum, or 8-bit integer:
* Recorded in flash memory by 1-halfword (2-byte)
*/
/*
* Representation of Boolean object:
* 0: No record in flash memory
@@ -319,7 +347,20 @@ extern uint8_t admin_authorized;
*/
#define NR_BOOL_PW1_LIFETIME 0xf0
/*
* NR_BOOL_SOMETHING, NR_UINT_SOMETHING could be here... Use 0xf?
* Representation of algorithm attribute object:
* RSA-2048: No record in flash memory
* RSA-4096: 0xf?00
* ECC p256r1: 0xf?01
* ECC p256k1: 0xf?02
* ECC Ed25519: 0xf?03
* ECC Curve25519: 0xf?04
* where <?> == 1 (signature), 2 (decryption) or 3 (authentication)
*/
#define NR_KEY_ALGO_ATTR_SIG 0xf1
#define NR_KEY_ALGO_ATTR_DEC 0xf2
#define NR_KEY_ALGO_ATTR_AUT 0xf3
/*
* NR_UINT_SOMETHING could be here... Use 0xf[456789abcd]
*/
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
/*
@@ -348,18 +389,22 @@ extern uint8_t admin_authorized;
extern const uint8_t openpgpcard_aid[14];
extern void flash_bool_clear (const uint8_t **addr_p);
extern const uint8_t *flash_bool_write (uint8_t nr);
extern int flash_cnt123_get_value (const uint8_t *p);
extern void flash_cnt123_increment (uint8_t which, const uint8_t **addr_p);
extern void flash_cnt123_clear (const uint8_t **addr_p);
extern void flash_put_data (uint16_t hw);
extern void flash_warning (const char *msg);
void flash_bool_clear (const uint8_t **addr_p);
const uint8_t *flash_bool_write (uint8_t nr);
void flash_enum_clear (const uint8_t **addr_p);
const uint8_t *flash_enum_write (uint8_t nr, uint8_t v);
int flash_cnt123_get_value (const uint8_t *p);
void flash_cnt123_increment (uint8_t which, const uint8_t **addr_p);
void flash_cnt123_clear (const uint8_t **addr_p);
void flash_put_data (uint16_t hw);
void flash_warning (const char *msg);
extern void flash_put_data_internal (const uint8_t *p, uint16_t hw);
extern void flash_bool_write_internal (const uint8_t *p, int nr);
extern void flash_cnt123_write_internal (const uint8_t *p, int which, int v);
extern void flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len);
void flash_put_data_internal (const uint8_t *p, uint16_t hw);
void flash_bool_write_internal (const uint8_t *p, int nr);
void flash_enum_write_internal (const uint8_t *p, int nr, uint8_t v);
void flash_cnt123_write_internal (const uint8_t *p, int which, int v);
void flash_do_write_internal (const uint8_t *p, int nr,
const uint8_t *data, int len);
extern const uint8_t gnukStringSerial[];
@@ -369,20 +414,20 @@ extern const uint8_t gnukStringSerial[];
#define LED_START_COMMAND (8)
#define LED_FINISH_COMMAND (16)
#define LED_FATAL (32)
extern void led_blink (int spec);
void led_blink (int spec);
#if defined(PINPAD_SUPPORT)
# if defined(PINPAD_CIR_SUPPORT)
extern void cir_init (void);
void cir_init (void);
# elif defined(PINPAD_DIAL_SUPPORT)
extern void dial_sw_disable (void);
extern void dial_sw_enable (void);
void dial_sw_disable (void);
void dial_sw_enable (void);
# elif defined(PINPAD_DND_SUPPORT)
extern void msc_init (void);
extern void msc_media_insert_change (int available);
extern int msc_scsi_write (uint32_t lba, const uint8_t *buf, size_t size);
extern int msc_scsi_read (uint32_t lba, const uint8_t **sector_p);
extern void msc_scsi_stop (uint8_t code);
void msc_init (void);
void msc_media_insert_change (int available);
int msc_scsi_write (uint32_t lba, const uint8_t *buf, size_t size);
int msc_scsi_read (uint32_t lba, const uint8_t **sector_p);
void msc_scsi_stop (uint8_t code);
# endif
#define PIN_INPUT_CURRENT 1
#define PIN_INPUT_NEW 2
@@ -391,7 +436,7 @@ extern void msc_scsi_stop (uint8_t code);
extern uint8_t pin_input_buffer[MAX_PIN_CHARS];
extern uint8_t pin_input_len;
extern int pinpad_getline (int msg_code, uint32_t timeout_usec);
int pinpad_getline (int msg_code, uint32_t timeout_usec);
#endif

View File

@@ -1,29 +0,0 @@
/* HAL configuration file for ChibiOS/RT */
#ifndef _HALCONF_H_
#define _HALCONF_H_
#include "mcuconf.h"
#define HAL_USE_PAL TRUE
#define HAL_USE_ADC FALSE
#define HAL_USE_CAN FALSE
#define HAL_USE_EXT FALSE
#define HAL_USE_GPT FALSE
#define HAL_USE_I2C FALSE
#define HAL_USE_ICU FALSE
#define HAL_USE_MAC FALSE
#define HAL_USE_MMC_SPI FALSE
#define HAL_USE_PWM FALSE
#define HAL_USE_RTC FALSE
#define HAL_USE_SDC FALSE
#define HAL_USE_SERIAL FALSE
#define HAL_USE_SERIAL_USB FALSE
#define HAL_USE_SPI FALSE
#define HAL_USE_UART FALSE
#define HAL_USE_USB FALSE
/* Define manually, as we implement ADC driver by ourselves. */
#define STM32_DMA_REQUIRED 1
#endif /* _HALCONF_H_ */

View File

@@ -1,23 +0,0 @@
/**
* @brief Jacobian projective coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} jpc;
/**
* @brief Affin coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
} ac;
void jpc_double (jpc *X, const jpc *A);
void jpc_add_ac (jpc *X, const jpc *A, const ac *B);
void jpc_add_ac_signed (jpc *X, const jpc *A, const ac *B, int minus);
int jpc_to_ac (ac *X, const jpc *A);

14
src/jpc-ac_p256k1.h Normal file
View File

@@ -0,0 +1,14 @@
/**
* @brief Jacobian projective coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} jpc;
void jpc_double_p256k1 (jpc *X, const jpc *A);
void jpc_add_ac_p256k1 (jpc *X, const jpc *A, const ac *B);
void jpc_add_ac_signed_p256k1 (jpc *X, const jpc *A, const ac *B, int minus);
int jpc_to_ac_p256k1 (ac *X, const jpc *A);

14
src/jpc-ac_p256r1.h Normal file
View File

@@ -0,0 +1,14 @@
/**
* @brief Jacobian projective coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} jpc;
void jpc_double_p256r1 (jpc *X, const jpc *A);
void jpc_add_ac_p256r1 (jpc *X, const jpc *A, const ac *B);
void jpc_add_ac_signed_p256r1 (jpc *X, const jpc *A, const ac *B, int minus);
int jpc_to_ac_p256r1 (ac *X, const jpc *A);

152
src/jpc.c
View File

@@ -1,5 +1,5 @@
/*
* jpc.c -- arithmetic on Jacobian projective coordinates and Affin coordinates
* jpc.c -- arithmetic on Jacobian projective coordinates.
*
* Copyright (C) 2011, 2013 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -21,11 +21,7 @@
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256.h"
#include "jpc-ac.h"
#include "field-group-select.h"
/**
* @brief X = 2 * A
@@ -34,36 +30,48 @@
* @param A JPC
*/
void
jpc_double (jpc *X, const jpc *A)
FUNC(jpc_double) (jpc *X, const jpc *A)
{
bn256 a[1], b[1], c[1], tmp0[1];
bn256 *d = X->x;
bn256 *d;
modp256_sqr (a, A->y);
if (bn256_is_zero (A->z)) /* A is infinite */
return;
d = X->x;
MFNC(sqr) (a, A->y);
memcpy (b, a, sizeof (bn256));
modp256_mul (a, a, A->x);
modp256_shift (a, a, 2);
MFNC(mul) (a, a, A->x);
MFNC(shift) (a, a, 2);
modp256_sqr (b, b);
modp256_shift (b, b, 3);
MFNC(sqr) (b, b);
MFNC(shift) (b, b, 3);
modp256_sqr (tmp0, A->z);
modp256_sub (c, A->x, tmp0);
modp256_add (tmp0, tmp0, A->x);
modp256_mul (tmp0, tmp0, c);
modp256_shift (c, tmp0, 1);
modp256_add (c, c, tmp0);
#if defined(COEFFICIENT_A_IS_MINUS_3)
MFNC(sqr) (tmp0, A->z);
MFNC(sub) (c, A->x, tmp0);
MFNC(add) (tmp0, tmp0, A->x);
MFNC(mul) (tmp0, tmp0, c);
MFNC(shift) (c, tmp0, 1);
MFNC(add) (c, c, tmp0);
#elif defined (COEFFICIENT_A_IS_ZERO)
MFNC(sqr) (tmp0, A->x);
MFNC(shift) (c, tmp0, 1);
MFNC(add) (c, c, tmp0);
#else
#error "not supported."
#endif
modp256_sqr (d, c);
modp256_shift (tmp0, a, 1);
modp256_sub (d, d, tmp0);
MFNC(sqr) (d, c);
MFNC(shift) (tmp0, a, 1);
MFNC(sub) (d, d, tmp0);
modp256_mul (X->z, A->y, A->z);
modp256_shift (X->z, X->z, 1);
MFNC(mul) (X->z, A->y, A->z);
MFNC(shift) (X->z, X->z, 1);
modp256_sub (tmp0, a, d);
modp256_mul (tmp0, c, tmp0);
modp256_sub (X->y, tmp0, b);
MFNC(sub) (tmp0, a, d);
MFNC(mul) (tmp0, c, tmp0);
MFNC(sub) (X->y, tmp0, b);
}
/**
@@ -75,9 +83,9 @@ jpc_double (jpc *X, const jpc *A)
* @param MINUS if 1 subtraction, addition otherwise.
*/
void
jpc_add_ac_signed (jpc *X, const jpc *A, const ac *B, int minus)
FUNC(jpc_add_ac_signed) (jpc *X, const jpc *A, const ac *B, int minus)
{
bn256 a[1], b[1], c[1], d[1];
bn256 a[1], b[1], c[1], d[1], tmp[1];
#define minus_B_y c
#define c_sqr a
#define c_cube b
@@ -88,58 +96,66 @@ jpc_add_ac_signed (jpc *X, const jpc *A, const ac *B, int minus)
#define y3_tmp c
#define y1_c_cube a
if (A->z == 0) /* A is infinite */
if (bn256_is_zero (A->z)) /* A is infinite */
{
memcpy (X->x, B->x, sizeof (bn256));
if (minus)
bn256_sub (X->y, P256, B->y);
{
memcpy (tmp, B->y, sizeof (bn256));
bn256_sub (X->y, CONST_P256, B->y);
}
else
memcpy (X->y, B->y, sizeof (bn256));
{
memcpy (X->y, B->y, sizeof (bn256));
bn256_sub (tmp, CONST_P256, B->y);
}
memset (X->z, 0, sizeof (bn256));
X->z->words[0] = 1;
X->z->word[0] = 1;
return;
}
modp256_sqr (a, A->z);
MFNC(sqr) (a, A->z);
memcpy (b, a, sizeof (bn256));
modp256_mul (a, a, B->x);
MFNC(mul) (a, a, B->x);
modp256_mul (b, b, A->z);
MFNC(mul) (b, b, A->z);
if (minus)
{
bn256_sub (minus_B_y, P256, B->y);
modp256_mul (b, b, minus_B_y);
bn256_sub (minus_B_y, CONST_P256, B->y);
MFNC(mul) (b, b, minus_B_y);
}
else
modp256_mul (b, b, B->y);
{
bn256_sub (tmp, CONST_P256, B->y);
MFNC(mul) (b, b, B->y);
}
if (bn256_cmp (A->x, a) == 0)
if (bn256_cmp (A->y, b) == 0)
{
jpc_double (X, A);
return;
}
if (bn256_cmp (A->x, a) == 0 && bn256_cmp (A->y, b) == 0)
{
FUNC(jpc_double) (X, A);
return;
}
modp256_sub (c, a, A->x);
modp256_sub (d, b, A->y);
MFNC(sub) (c, a, A->x);
MFNC(sub) (d, b, A->y);
modp256_mul (X->z, A->z, c);
MFNC(mul) (X->z, A->z, c);
modp256_sqr (c_sqr, c);
modp256_mul (c_cube, c_sqr, c);
MFNC(sqr) (c_sqr, c);
MFNC(mul) (c_cube, c_sqr, c);
modp256_mul (x1_c_sqr, A->x, c_sqr);
MFNC(mul) (x1_c_sqr, A->x, c_sqr);
modp256_sqr (X->x, d);
MFNC(sqr) (X->x, d);
memcpy (x1_c_sqr_copy, x1_c_sqr, sizeof (bn256));
modp256_shift (x1_c_sqr_2, x1_c_sqr, 1);
modp256_add (c_cube_plus_x1_c_sqr_2, x1_c_sqr_2, c_cube);
modp256_sub (X->x, X->x, c_cube_plus_x1_c_sqr_2);
MFNC(shift) (x1_c_sqr_2, x1_c_sqr, 1);
MFNC(add) (c_cube_plus_x1_c_sqr_2, x1_c_sqr_2, c_cube);
MFNC(sub) (X->x, X->x, c_cube_plus_x1_c_sqr_2);
modp256_sub (y3_tmp, x1_c_sqr_copy, X->x);
modp256_mul (y3_tmp, y3_tmp, d);
modp256_mul (y1_c_cube, A->y, c_cube);
modp256_sub (X->y, y3_tmp, y1_c_cube);
MFNC(sub) (y3_tmp, x1_c_sqr_copy, X->x);
MFNC(mul) (y3_tmp, y3_tmp, d);
MFNC(mul) (y1_c_cube, A->y, c_cube);
MFNC(sub) (X->y, y3_tmp, y1_c_cube);
}
/**
@@ -150,9 +166,9 @@ jpc_add_ac_signed (jpc *X, const jpc *A, const ac *B, int minus)
* @param B AC
*/
void
jpc_add_ac (jpc *X, const jpc *A, const ac *B)
FUNC(jpc_add_ac) (jpc *X, const jpc *A, const ac *B)
{
jpc_add_ac_signed (X, A, B, 0);
FUNC(jpc_add_ac_signed) (X, A, B, 0);
}
/**
@@ -165,17 +181,19 @@ jpc_add_ac (jpc *X, const jpc *A, const ac *B)
* Return 0 on success.
*/
int
jpc_to_ac (ac *X, const jpc *A)
FUNC(jpc_to_ac) (ac *X, const jpc *A)
{
bn256 z_inv[1], z_inv_sqr[1];
if (modp256_inv (z_inv, A->z) < 0)
if (bn256_is_zero (A->z))
return -1;
modp256_sqr (z_inv_sqr, z_inv);
modp256_mul (z_inv, z_inv, z_inv_sqr);
mod_inv (z_inv, A->z, CONST_P256);
modp256_mul (X->x, A->x, z_inv_sqr);
modp256_mul (X->y, A->y, z_inv);
MFNC(sqr) (z_inv_sqr, z_inv);
MFNC(mul) (z_inv, z_inv, z_inv_sqr);
MFNC(mul) (X->x, A->x, z_inv_sqr);
MFNC(mul) (X->y, A->y, z_inv);
return 0;
}

36
src/jpc_p256k1.c Normal file
View File

@@ -0,0 +1,36 @@
/*
* jpc_p256k1.c -- arithmetic on Jacobian projective coordinates for p256k1.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod.h"
#include "modp256k1.h"
#include "affine.h"
#include "jpc-ac_p256k1.h"
#define FIELD p256k1
#define CONST_P256 P256K1
#define COEFFICIENT_A_IS_ZERO 1
#include "jpc.c"

36
src/jpc_p256r1.c Normal file
View File

@@ -0,0 +1,36 @@
/*
* jpc_p256r1.c -- arithmetic on Jacobian projective coordinates for p256r1.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod.h"
#include "modp256r1.h"
#include "affine.h"
#include "jpc-ac_p256r1.h"
#define FIELD p256r1
#define CONST_P256 P256R1
#define COEFFICIENT_A_IS_MINUS_3 1
#include "jpc.c"

367
src/mod.c
View File

@@ -1,7 +1,7 @@
/*
* mod.c -- modulo arithmetic
*
* Copyright (C) 2011 Free Software Initiative of Japan
* Copyright (C) 2011, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -39,157 +39,316 @@ mod_reduce (bn256 *X, const bn512 *A, const bn256 *B, const bn256 *MU_lower)
uint32_t borrow_next;
memset (q, 0, sizeof (bn256));
q->words[0] = A->words[15];
q->word[0] = A->word[15];
bn256_mul (tmp, q, MU_lower);
tmp->words[8] += A->words[15];
carry = (tmp->words[8] < A->words[15]);
tmp->words[9] += carry;
tmp->word[8] += A->word[15];
carry = (tmp->word[8] < A->word[15]);
tmp->word[9] += carry;
q->words[7] = A->words[14];
q->words[6] = A->words[13];
q->words[5] = A->words[12];
q->words[4] = A->words[11];
q->words[3] = A->words[10];
q->words[2] = A->words[9];
q->words[1] = A->words[8];
q->words[0] = A->words[7];
q->word[7] = A->word[14];
q->word[6] = A->word[13];
q->word[5] = A->word[12];
q->word[4] = A->word[11];
q->word[3] = A->word[10];
q->word[2] = A->word[9];
q->word[1] = A->word[8];
q->word[0] = A->word[7];
bn256_mul (q_big, q, MU_lower);
bn256_add ((bn256 *)&q_big->words[8], (bn256 *)&q_big->words[8], q);
bn256_add ((bn256 *)&q_big->word[8], (bn256 *)&q_big->word[8], q);
q->words[0] = q_big->words[9] + tmp->words[1];
carry = (q->words[0] < tmp->words[1]);
q->word[0] = q_big->word[9] + tmp->word[1];
carry = (q->word[0] < tmp->word[1]);
q->words[1] = q_big->words[10] + carry;
carry = (q->words[1] < carry);
q->words[1] += tmp->words[2];
carry += (q->words[1] < tmp->words[2]);
q->word[1] = q_big->word[10] + carry;
carry = (q->word[1] < carry);
q->word[1] += tmp->word[2];
carry += (q->word[1] < tmp->word[2]);
q->words[2] = q_big->words[11] + carry;
carry = (q->words[2] < carry);
q->words[2] += tmp->words[3];
carry += (q->words[2] < tmp->words[3]);
q->word[2] = q_big->word[11] + carry;
carry = (q->word[2] < carry);
q->word[2] += tmp->word[3];
carry += (q->word[2] < tmp->word[3]);
q->words[3] = q_big->words[12] + carry;
carry = (q->words[3] < carry);
q->words[3] += tmp->words[4];
carry += (q->words[3] < tmp->words[4]);
q->word[3] = q_big->word[12] + carry;
carry = (q->word[3] < carry);
q->word[3] += tmp->word[4];
carry += (q->word[3] < tmp->word[4]);
q->words[4] = q_big->words[13] + carry;
carry = (q->words[4] < carry);
q->words[4] += tmp->words[5];
carry += (q->words[4] < tmp->words[5]);
q->word[4] = q_big->word[13] + carry;
carry = (q->word[4] < carry);
q->word[4] += tmp->word[5];
carry += (q->word[4] < tmp->word[5]);
q->words[5] = q_big->words[14] + carry;
carry = (q->words[5] < carry);
q->words[5] += tmp->words[6];
carry += (q->words[5] < tmp->words[6]);
q->word[5] = q_big->word[14] + carry;
carry = (q->word[5] < carry);
q->word[5] += tmp->word[6];
carry += (q->word[5] < tmp->word[6]);
q->words[6] = q_big->words[15] + carry;
carry = (q->words[6] < carry);
q->words[6] += tmp->words[7];
carry += (q->words[6] < tmp->words[7]);
q->word[6] = q_big->word[15] + carry;
carry = (q->word[6] < carry);
q->word[6] += tmp->word[7];
carry += (q->word[6] < tmp->word[7]);
q->words[7] = carry;
q->words[7] += tmp->words[8];
carry = (q->words[7] < tmp->words[8]);
q->word[7] = carry;
q->word[7] += tmp->word[8];
carry = (q->word[7] < tmp->word[8]);
memset (q_big, 0, sizeof (bn512));
q_big->words[8] = A->words[8];
q_big->words[7] = A->words[7];
q_big->words[6] = A->words[6];
q_big->words[5] = A->words[5];
q_big->words[4] = A->words[4];
q_big->words[3] = A->words[3];
q_big->words[2] = A->words[2];
q_big->words[1] = A->words[1];
q_big->words[0] = A->words[0];
q_big->word[8] = A->word[8];
q_big->word[7] = A->word[7];
q_big->word[6] = A->word[6];
q_big->word[5] = A->word[5];
q_big->word[4] = A->word[4];
q_big->word[3] = A->word[3];
q_big->word[2] = A->word[2];
q_big->word[1] = A->word[1];
q_big->word[0] = A->word[0];
bn256_mul (tmp, q, B);
tmp->word[8] += carry * B->word[0];
tmp->word[15] = tmp->word[14] = tmp->word[13] = tmp->word[12]
= tmp->word[11] = tmp->word[10] = tmp->word[9] = 0;
borrow = bn256_sub (X, (bn256 *)&q_big->word[0], (bn256 *)&tmp->word[0]);
borrow_next = (q_big->word[8] < borrow);
q_big->word[8] -= borrow;
borrow_next += (q_big->word[8] < tmp->word[8]);
q_big->word[8] -= tmp->word[8];
carry = q_big->word[8];
if (carry)
tmp->words[8] += B->words[0];
tmp->words[15] = tmp->words[14] = tmp->words[13] = tmp->words[12]
= tmp->words[11] = tmp->words[10] = tmp->words[9] = 0;
carry -= bn256_sub (X, X, B);
else
bn256_sub (q, X, B);
borrow = bn256_sub (X, (bn256 *)&q_big->words[0], (bn256 *)&tmp->words[0]);
borrow_next = (q_big->words[8] < borrow);
q_big->words[8] -= borrow;
borrow_next += (q_big->words[8] < tmp->words[8]);
q_big->words[8] -= tmp->words[8];
if (carry)
carry -= bn256_sub (X, X, B);
else
bn256_sub (q, X, B);
carry = q_big->words[8];
while (carry)
{
borrow_next = bn256_sub (X, X, B);
carry -= borrow_next;
}
if (bn256_is_ge (X, B))
bn256_sub (X, X, B);
borrow = bn256_sub (q, X, B);
if (borrow)
memcpy (q, X, sizeof (bn256));
else
memcpy (X, q, sizeof (bn256));
#undef borrow
}
/*
* Reference:
* Donald E. Knuth, The Art of Computer Programming, Vol. 2:
* Seminumerical Algorithms, 3rd ed. Reading, MA: Addison-Wesley, 1998
*
* Max loop: X=0x8000...0000 and N=0xffff...ffff
*/
#define MAX_GCD_STEPS_BN256 (3*256-2)
/**
* @brief C = X^(-1) mod N
*
* Assume X and N are co-prime (or N is prime).
* NOTE: If X==0, it return 0.
*
*/
void
mod_inv (bn256 *C, const bn256 *X, const bn256 *N)
{
bn256 u[1], v[1];
bn256 u[1], v[1], tmp[1];
bn256 A[1] = { { { 1, 0, 0, 0, 0, 0, 0, 0 } } };
uint32_t carry;
#define borrow carry
int n = MAX_GCD_STEPS_BN256;
memset (C, 0, sizeof (bn256));
memcpy (u, X, sizeof (bn256));
memcpy (v, N, sizeof (bn256));
while (!bn256_is_zero (u))
while (n--)
{
while (bn256_is_even (u))
int c = (bn256_is_even (u) << 1) + bn256_is_even (v);
switch (c)
{
case 3:
bn256_shift (u, u, -1);
if (bn256_is_even (A))
bn256_shift (A, A, -1);
else
{
int carry = bn256_add (A, A, N);
bn256_shift (A, A, -1);
if (carry)
A->words[7] |= 0x80000000;
bn256_add (tmp, A, N);
carry = 0;
}
}
else
carry = bn256_add (A, A, N);
bn256_shift (A, A, -1);
A->word[7] |= carry * 0x80000000;
while (bn256_is_even (v))
{
bn256_shift (v, v, -1);
if (bn256_is_even (C))
bn256_shift (C, C, -1);
{
bn256_add (tmp, C, N);
carry = 0;
}
else
carry = bn256_add (C, C, N);
bn256_shift (C, C, -1);
C->word[7] |= carry * 0x80000000;
if (bn256_is_ge (tmp, tmp))
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, A, N);
}
else
{
int carry = bn256_add (C, C, N);
bn256_shift (C, C, -1);
if (carry)
C->words[7] |= 0x80000000;
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, tmp, N);
}
}
break;
if (bn256_is_ge (u, v))
{
int borrow;
case 1:
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_sub (u, u, v);
borrow = bn256_sub (A, A, C);
if (borrow)
bn256_add (A, A, N);
}
else
{
int borrow;
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
bn256_sub (v, v, u);
borrow = bn256_sub (C, C, A);
if (borrow)
bn256_add (C, C, N);
bn256_shift (v, v, -1);
if (bn256_is_even (C))
{
bn256_add (tmp, C, N);
carry = 0;
}
else
carry = bn256_add (C, C, N);
bn256_shift (C, C, -1);
C->word[7] |= carry * 0x80000000;
if (bn256_is_ge (tmp, tmp))
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, tmp, N);
}
break;
case 2:
bn256_shift (u, u, -1);
if (bn256_is_even (A))
{
bn256_add (tmp, A, N);
carry = 0;
}
else
carry = bn256_add (A, A, N);
bn256_shift (A, A, -1);
A->word[7] |= carry * 0x80000000;
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
if (bn256_is_ge (tmp, tmp))
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, tmp, N);
}
break;
case 0:
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
if (bn256_is_ge (u, v))
{
bn256_sub (u, u, v);
borrow = bn256_sub (A, A, C);
if (borrow)
bn256_add (A, A, N);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (v, v, u);
borrow = bn256_sub (C, C, A);
if (borrow)
bn256_add (C, C, N);
else
bn256_add (tmp, C, N);
}
break;
}
}
#undef borrow
}

287
src/mod25638.c Normal file
View File

@@ -0,0 +1,287 @@
/*
* mod25638.c -- modulo arithmetic of 2^256-38 for 2^255-19 field
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* The field is \Z/(2^255-19)
*
* We use radix-32. During computation, it's not reduced to 2^255-19,
* but it is represented in 256-bit (it is redundant representation),
* that is, something like 2^256-38.
*
* The idea is, keeping within 256-bit until it will be converted to
* affine coordinates.
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod25638.h"
#ifndef BN256_C_IMPLEMENTATION
#define ASM_IMPLEMENTATION 1
#endif
#if ASM_IMPLEMENTATION
#include "muladd_256.h"
#define ADDWORD_256(d_,s_,w_,c_) \
asm ( "ldmia %[s]!, { r4, r5, r6, r7 } \n\t" \
"adds r4, r4, %[w] \n\t" \
"adcs r5, r5, #0 \n\t" \
"adcs r6, r6, #0 \n\t" \
"adcs r7, r7, #0 \n\t" \
"stmia %[d]!, { r4, r5, r6, r7 }\n\t" \
"ldmia %[s]!, { r4, r5, r6, r7 } \n\t" \
"adcs r4, r4, #0 \n\t" \
"adcs r5, r5, #0 \n\t" \
"adcs r6, r6, #0 \n\t" \
"adcs r7, r7, #0 \n\t" \
"stmia %[d]!, { r4, r5, r6, r7 }\n\t" \
"mov %[c], #0 \n\t" \
"adc %[c], %[c], #0" \
: [s] "=&r" (s_), [d] "=&r" (d_), [c] "=&r" (c_) \
: "[s]" (s_), "[d]" (d_), [w] "r" (w_) \
: "r4", "r5", "r6", "r7", "memory", "cc" )
#endif
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 16
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffff0
2^256 - 16 - 2
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffee
2^256 - 16 - 2 - 1
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffed
*/
const bn256 p25519[1] = {
{{ 0xffffffed, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff }} };
/*
* Implementation Note.
*
* It's not always modulo n25638. The representation is redundant
* during computation. For example, when we add the number - 1 and 1,
* it won't overflow to 2^256, and the result is represented within
* 256-bit.
*/
/**
* @brief X = (A + B) mod 2^256-38
*/
void
mod25638_add (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t carry;
carry = bn256_add (X, A, B);
carry = bn256_add_uint (X, X, carry*38);
X->word[0] += carry * 38;
}
/**
* @brief X = (A - B) mod 2^256-38
*/
void
mod25638_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
borrow = bn256_sub (X, A, B);
borrow = bn256_sub_uint (X, X, borrow*38);
X->word[0] -= borrow * 38;
}
/**
* @brief X = A mod 2^256-38
*
* Note that the second argument is not "const bn512 *".
* A is modified during the computation of modulo.
*
* It's not precisely modulo 2^256-38 for all cases,
* but result may be redundant.
*/
static void
mod25638_reduce (bn256 *X, bn512 *A)
{
const uint32_t *s;
uint32_t *d;
uint32_t w;
#if ASM_IMPLEMENTATION
uint32_t c, c0;
s = &A->word[8]; d = &A->word[0]; w = 38; MULADD_256 (s, d, w, c);
c0 = A->word[8] * 38;
d = &X->word[0];
s = &A->word[0];
ADDWORD_256 (d, s, c0, c);
X->word[0] += c * 38;
#else
s = &A->word[8]; d = &A->word[0]; w = 38;
{
int i;
uint64_t r;
uint32_t carry;
r = 0;
for (i = 0; i < BN256_WORDS; i++)
{
uint64_t uv;
r += d[i];
carry = (r < d[i]);
uv = ((uint64_t)s[i])*w;
r += uv;
carry += (r < uv);
d[i] = (uint32_t)r;
r = ((r >> 32) | ((uint64_t)carry << 32));
}
carry = bn256_add_uint (X, (bn256 *)A, r * 38);
X->word[0] += carry * 38;
}
#endif
}
/**
* @brief X = (A * B) mod 2^256-38
*/
void
mod25638_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 tmp[1];
bn256_mul (tmp, A, B);
mod25638_reduce (X, tmp);
}
/**
* @brief X = A * A mod 2^256-38
*/
void
mod25638_sqr (bn256 *X, const bn256 *A)
{
bn512 tmp[1];
bn256_sqr (tmp, A);
mod25638_reduce (X, tmp);
}
/**
* @brief X = (A << shift) mod 2^256-38
* @note shift < 32
*/
void
mod25638_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->word[0] = (carry << 1);
/* tmp->word[1] = (carry >> 31); always zero. */
tmp->word[0] = tmp->word[0] + (carry << 2);
tmp->word[1] = (tmp->word[0] < (carry << 2)) + (carry >> 30);
tmp->word[0] = tmp->word[0] + (carry << 5);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 5)) + (carry >> 27);
mod25638_add (X, X, tmp);
}
/*
* @brief X = A mod 2^255-19
*
* It's precisely modulo 2^255-19 (unlike mod25638_reduce).
*/
void
mod25519_reduce (bn256 *X)
{
uint32_t q;
bn256 r0[1], r1[1];
int flag;
memcpy (r0, X, sizeof (bn256));
q = (r0->word[7] >> 31);
r0->word[7] &= 0x7fffffff;
if (q)
{
bn256_add_uint (r0, r0, 19);
q = (r0->word[7] >> 31);
r0->word[7] &= 0x7fffffff;
if (q)
{
bn256_add_uint (r1, r0, 19);
q = (r1->word[7] >> 31);
r1->word[7] &= 0x7fffffff;
flag = 0;
}
else
flag = 1;
}
else
{
bn256_add_uint (r1, r0, 19);
q = (r1->word[7] >> 31); /* dummy */
r1->word[7] &= 0x7fffffff; /* dummy */
if (q)
flag = 2;
else
flag = 3;
}
if (flag)
{
bn256_add_uint (r1, r0, 19);
q = (r1->word[7] >> 31);
r1->word[7] &= 0x7fffffff;
if (q)
memcpy (X, r1, sizeof (bn256));
else
memcpy (X, r0, sizeof (bn256));
}
else
{
if (q)
{
asm volatile ("" : : "r" (q) : "memory");
memcpy (X, r1, sizeof (bn256));
asm volatile ("" : : "r" (q) : "memory");
}
else
memcpy (X, r1, sizeof (bn256));
}
}

7
src/mod25638.h Normal file
View File

@@ -0,0 +1,7 @@
extern const bn256 p25519[1];
void mod25638_add (bn256 *X, const bn256 *A, const bn256 *B);
void mod25638_sub (bn256 *X, const bn256 *A, const bn256 *B);
void mod25638_mul (bn256 *X, const bn256 *A, const bn256 *B);
void mod25638_sqr (bn256 *X, const bn256 *A);
void mod25519_reduce (bn256 *X);

View File

@@ -1,305 +0,0 @@
/*
* modp256.c -- modulo P256 arithmetic
*
* Copyright (C) 2011, 2013 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* p256 = 2^256 - 2^224 + 2^192 + 2^96 - 1
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256.h"
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224
0 ffffffff 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224 + 2^192
0 ffffffff 00000001 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224 + 2^192 + 2^96
0 ffffffff 00000001 00000000 00000000 00000001 00000000 00000000 00000000
2^256 - 2^224 + 2^192 + 2^96 - 1
0 ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff
*/
const bn256 p256 = { {0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
0x00000000, 0x00000000, 0x00000001, 0xffffffff} };
/**
* @brief X = (A + B) mod p256
*/
void
modp256_add (bn256 *X, const bn256 *A, const bn256 *B)
{
int carry;
carry = bn256_add (X, A, B);
if (carry)
bn256_sub (X, X, P256);
}
/**
* @brief X = (A - B) mod p256
*/
void
modp256_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
int borrow;
borrow = bn256_sub (X, A, B);
if (borrow)
bn256_add (X, X, P256);
}
/**
* @brief X = A mod p256
*/
void
modp256_reduce (bn256 *X, const bn512 *A)
{
bn256 tmp[1];
#define S1 X
#define S2 tmp
#define S3 tmp
#define S4 tmp
#define S5 tmp
#define S6 tmp
#define S7 tmp
#define S8 tmp
#define S9 tmp
S1->words[7] = A->words[7];
S1->words[6] = A->words[6];
S1->words[5] = A->words[5];
S1->words[4] = A->words[4];
S1->words[3] = A->words[3];
S1->words[2] = A->words[2];
S1->words[1] = A->words[1];
S1->words[0] = A->words[0];
/* X = S1 */
S2->words[7] = A->words[15];
S2->words[6] = A->words[14];
S2->words[5] = A->words[13];
S2->words[4] = A->words[12];
S2->words[3] = A->words[11];
S2->words[2] = S2->words[1] = S2->words[0] = 0;
/* X += 2 * S2 */
modp256_add (X, X, S2);
modp256_add (X, X, S2);
S3->words[7] = 0;
S3->words[6] = A->words[15];
S3->words[5] = A->words[14];
S3->words[4] = A->words[13];
S3->words[3] = A->words[12];
S3->words[2] = S3->words[1] = S3->words[0] = 0;
/* X += 2 * S3 */
modp256_add (X, X, S3);
modp256_add (X, X, S3);
S4->words[7] = A->words[15];
S4->words[6] = A->words[14];
S4->words[5] = S4->words[4] = S4->words[3] = 0;
S4->words[2] = A->words[10];
S4->words[1] = A->words[9];
S4->words[0] = A->words[8];
/* X += S4 */
modp256_add (X, X, S4);
S5->words[7] = A->words[8];
S5->words[6] = A->words[13];
S5->words[5] = A->words[15];
S5->words[4] = A->words[14];
S5->words[3] = A->words[13];
S5->words[2] = A->words[11];
S5->words[1] = A->words[10];
S5->words[0] = A->words[9];
/* X += S5 */
modp256_add (X, X, S5);
S6->words[7] = A->words[10];
S6->words[6] = A->words[8];
S6->words[5] = S6->words[4] = S6->words[3] = 0;
S6->words[2] = A->words[13];
S6->words[1] = A->words[12];
S6->words[0] = A->words[11];
/* X -= S6 */
modp256_sub (X, X, S6);
S7->words[7] = A->words[11];
S7->words[6] = A->words[9];
S7->words[5] = S7->words[4] = 0;
S7->words[3] = A->words[15];
S7->words[2] = A->words[14];
S7->words[1] = A->words[13];
S7->words[0] = A->words[12];
/* X -= S7 */
modp256_sub (X, X, S7);
S8->words[7] = A->words[12];
S8->words[6] = 0;
S8->words[5] = A->words[10];
S8->words[4] = A->words[9];
S8->words[3] = A->words[8];
S8->words[2] = A->words[15];
S8->words[1] = A->words[14];
S8->words[0] = A->words[13];
/* X -= S8 */
modp256_sub (X, X, S8);
S9->words[7] = A->words[13];
S9->words[6] = 0;
S9->words[5] = A->words[11];
S9->words[4] = A->words[10];
S9->words[3] = A->words[9];
S9->words[2] = 0;
S9->words[1] = A->words[15];
S9->words[0] = A->words[14];
/* X -= S9 */
modp256_sub (X, X, S9);
if (bn256_is_ge (X, P256))
bn256_sub (X, X, P256);
}
/**
* @brief X = (A * B) mod p256
*/
void
modp256_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 AB[1];
bn256_mul (AB, A, B);
modp256_reduce (X, AB);
}
/**
* @brief X = A * A mod p256
*/
void
modp256_sqr (bn256 *X, const bn256 *A)
{
bn512 AA[1];
bn256_sqr (AA, A);
modp256_reduce (X, AA);
}
/**
* @brief C = (1 / a) mod p256
*
* Return -1 on error.
* Return 0 on success.
*/
int
modp256_inv (bn256 *C, const bn256 *a)
{
bn256 u[1], v[1];
bn256 A[1] = { { { 1, 0, 0, 0, 0, 0, 0, 0 } } };
if (bn256_is_zero (a))
return -1;
memset (C, 0, sizeof (bn256));
memcpy (u, a, sizeof (bn256));
memcpy (v, P256, sizeof (bn256));
while (!bn256_is_zero (u))
{
while (bn256_is_even (u))
{
bn256_shift (u, u, -1);
if (bn256_is_even (A))
bn256_shift (A, A, -1);
else
{
int carry = bn256_add (A, A, P256);
bn256_shift (A, A, -1);
if (carry)
A->words[7] |= 0x80000000;
}
}
while (bn256_is_even (v))
{
bn256_shift (v, v, -1);
if (bn256_is_even (C))
bn256_shift (C, C, -1);
else
{
int carry = bn256_add (C, C, P256);
bn256_shift (C, C, -1);
if (carry)
C->words[7] |= 0x80000000;
}
}
if (bn256_is_ge (u, v))
{
bn256_sub (u, u, v);
modp256_sub (A, A, C);
}
else
{
bn256_sub (v, v, u);
modp256_sub (C, C, A);
}
}
return 0;
}
/**
* @brief X = (A << shift) mod p256
* @note shift <= 32
*/
void
modp256_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->words[7] = carry;
tmp->words[0] = carry;
modp256_add (X, X, tmp);
tmp->words[7] = 0;
tmp->words[0] = 0;
tmp->words[6] = carry;
tmp->words[3] = carry;
modp256_sub (X, X, tmp);
if (bn256_is_ge (X, P256))
bn256_sub (X, X, P256);
}

View File

@@ -1,10 +0,0 @@
extern const bn256 p256;
#define P256 (&p256)
void modp256_add (bn256 *X, const bn256 *A, const bn256 *B);
void modp256_sub (bn256 *X, const bn256 *A, const bn256 *B);
void modp256_reduce (bn256 *X, const bn512 *A);
void modp256_mul (bn256 *X, const bn256 *A, const bn256 *B);
void modp256_sqr (bn256 *X, const bn256 *A);
void modp256_shift (bn256 *X, const bn256 *A, int shift);
int modp256_inv (bn256 *C, const bn256 *a);

315
src/modp256k1.c Normal file
View File

@@ -0,0 +1,315 @@
/*
* modp256k1.c -- modulo arithmetic for p256k1
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* p256k1 = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256k1.h"
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^32
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 00000000
2^256 - 2^32 - 2^9
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffe00
2^256 - 2^32 - 2^9 - 2^8
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffd00
2^256 - 2^32 - 2^9 - 2^8 - 2^7
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc80
2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc40
2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc30
2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f
*/
const bn256 p256k1 = { {0xfffffc2f, 0xfffffffe, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } };
/*
* Implementation Note.
*
* It's not always modulo p256k1. The representation is redundant
* during computation. For example, when we add the prime - 1 and 1,
* it won't overflow to 2^256, and the result is represented within
* 256-bit.
*
* It is guaranteed that modp256k1_reduce reduces to modulo p256k1.
*/
/**
* @brief X = (A + B) mod p256k1
*/
void
modp256k1_add (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_add (X, A, B);
if (carry)
bn256_sub (X, X, P256K1);
else
bn256_sub (tmp, X, P256K1);
}
/**
* @brief X = (A - B) mod p256
*/
void
modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
bn256 tmp[1];
borrow = bn256_sub (X, A, B);
if (borrow)
bn256_add (X, X, P256K1);
else
bn256_add (tmp, X, P256K1);
}
/**
* @brief X = A mod p256k1
*/
void
modp256k1_reduce (bn256 *X, const bn512 *A)
{
bn256 tmp[1];
uint32_t carry;
#define borrow carry
uint32_t s0, s1;
#define s00 tmp->word[0]
#define s01 tmp->word[1]
#define s02 tmp->word[2]
#define W0 X
#define W1 tmp
#define W2 tmp
#define W3 tmp
#define W4 tmp
#define W5 tmp
#define W6 tmp
#define W7 tmp
#define S tmp
/*
* Suppose: P256K1 = 2^256 - CONST
* Then, compute: W = A_low + A_high * CONST
* 256-bit W0 = W mod 2^256
* 64-bit (S1, S0) = W / 2^256
* where: CONST = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1
*/
/* W0 = A_low */
/* W7 = A_high */
/* W0 += W7 */
carry = bn256_add (W0, (const bn256 *)&A->word[8], (const bn256 *)A);
/* W6 = W7 << 4 */
/* W0 += W6 */
bn256_shift (W6, (const bn256 *)&A->word[8], 4);
carry += bn256_add (W0, W0, W6);
/* W5 = W6 << 2 */
/* W0 += W5 */
bn256_shift (W5, W6, 2);
carry += bn256_add (W0, W0, W5);
/* W4 = W5 << 1 */
/* W0 += W4 */
bn256_shift (W4, W5, 1);
carry += bn256_add (W0, W0, W4);
/* W3 = W4 << 1 */
/* W0 += W3 */
bn256_shift (W3, W4, 1);
carry += bn256_add (W0, W0, W3);
/* W2 = W3 << 1 */
/* W0 += W2 */
bn256_shift (W2, W3, 1);
carry += bn256_add (W0, W0, W2);
/* W1 = A_high << 32 */
/* W0 += W1 */
W1->word[7] = A->word[14];
W1->word[6] = A->word[13];
W1->word[5] = A->word[12];
W1->word[4] = A->word[11];
W1->word[3] = A->word[10];
W1->word[2] = A->word[9];
W1->word[1] = A->word[8];
W1->word[0] = 0;
carry += bn256_add (W0, W0, W1);
/* (S1, S0) = W / 2^256 */
s0 = A->word[15];
carry += (s0 >> 28) + (s0 >> 26) + (s0 >> 25) + (s0 >> 24) + (s0 >> 23);
carry += s0;
s1 = (carry < s0) ? 1 : 0;
s0 = carry;
/*
* Compute: S:=(S02, S01, S00), S = (S1,S0)*CONST
*/
S->word[7] = S->word[6] = S->word[5] = S->word[4] = S->word[3] = 0;
/* (S02, S01, S00) = (S1, S0) + (S1, S0)*2^32 */
s00 = s0;
s01 = s0 + s1;
s02 = s1 + ((s01 < s0)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^9 */
carry = (s0 >> 23) + s01;
s02 += (s1 >> 23) + ((carry < s01)? 1 : 0);
s01 = (s1 << 9) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 9);
carry = ((s00 < (s0 << 9))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^8 */
carry = (s0 >> 24) + s01;
s02 += (s1 >> 24) + ((carry < s01)? 1 : 0);
s01 = (s1 << 8) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 8);
carry = ((s00 < (s0 << 8))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^7 */
carry = (s0 >> 25) + s01;
s02 += (s1 >> 25) + ((carry < s01)? 1 : 0);
s01 = (s1 << 7) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 7);
carry = ((s00 < (s0 << 7))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^6 */
carry = (s0 >> 26) + s01;
s02 += (s1 >> 26) + ((carry < s01)? 1 : 0);
s01 = (s1 << 6) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 6);
carry = ((s00 < (s0 << 6))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^4 */
carry = (s0 >> 28) + s01;
s02 += (s1 >> 28) + ((carry < s01)? 1 : 0);
s01 = (s1 << 4) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 4);
carry = ((s00 < (s0 << 4))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* W0 += S */
modp256k1_add (W0, W0, S);
borrow = bn256_sub (tmp, W0, P256K1);
if (borrow)
memcpy (tmp, W0, sizeof (bn256));
else
memcpy (W0, tmp, sizeof (bn256));
#undef W0
#undef W1
#undef W2
#undef W3
#undef W4
#undef W5
#undef W6
#undef W7
#undef S
#undef s00
#undef s01
#undef s02
#undef borrow
}
/**
* @brief X = (A * B) mod p256k1
*/
void
modp256k1_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 AB[1];
bn256_mul (AB, A, B);
modp256k1_reduce (X, AB);
}
/**
* @brief X = A * A mod p256k1
*/
void
modp256k1_sqr (bn256 *X, const bn256 *A)
{
bn512 AA[1];
bn256_sqr (AA, A);
modp256k1_reduce (X, AA);
}
/**
* @brief X = (A << shift) mod p256k1
* @note shift < 32
*/
void
modp256k1_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->word[0] = carry + (carry << 9);
tmp->word[1] = carry + (tmp->word[0] < (carry << 9)) + (carry >> 23);
tmp->word[0] = tmp->word[0] + (carry << 8);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 8)) + (carry >> 24);
tmp->word[0] = tmp->word[0] + (carry << 7);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 7)) + (carry >> 25);
tmp->word[0] = tmp->word[0] + (carry << 6);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 6)) + (carry >> 26);
tmp->word[0] = tmp->word[0] + (carry << 4);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 4)) + (carry >> 28);
modp256k1_add (X, X, tmp);
}

9
src/modp256k1.h Normal file
View File

@@ -0,0 +1,9 @@
extern const bn256 p256k1;
#define P256K1 (&p256k1)
void modp256k1_add (bn256 *X, const bn256 *A, const bn256 *B);
void modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B);
void modp256k1_reduce (bn256 *X, const bn512 *A);
void modp256k1_mul (bn256 *X, const bn256 *A, const bn256 *B);
void modp256k1_sqr (bn256 *X, const bn256 *A);
void modp256k1_shift (bn256 *X, const bn256 *A, int shift);

276
src/modp256r1.c Normal file
View File

@@ -0,0 +1,276 @@
/*
* modp256r1.c -- modulo arithmetic for p256r1
*
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* p256 = 2^256 - 2^224 + 2^192 + 2^96 - 1
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256r1.h"
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224
0 ffffffff 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224 + 2^192
0 ffffffff 00000001 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224 + 2^192 + 2^96
0 ffffffff 00000001 00000000 00000000 00000001 00000000 00000000 00000000
2^256 - 2^224 + 2^192 + 2^96 - 1
0 ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff
*/
const bn256 p256r1 = { {0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
0x00000000, 0x00000000, 0x00000001, 0xffffffff} };
/*
* Implementation Note.
*
* It's not always modulo p256r1. The representation is redundant
* during computation. For example, when we add the prime - 1 and 1,
* it won't overflow to 2^256, and the result is represented within
* 256-bit.
*
* It is guaranteed that modp256r1_reduce reduces to modulo p256r1.
*/
/**
* @brief X = (A + B) mod p256r1
*/
void
modp256r1_add (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_add (X, A, B);
if (carry)
bn256_sub (X, X, P256R1);
else
bn256_sub (tmp, X, P256R1);
}
/**
* @brief X = (A - B) mod p256r1
*/
void
modp256r1_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
bn256 tmp[1];
borrow = bn256_sub (X, A, B);
if (borrow)
bn256_add (X, X, P256R1);
else
bn256_add (tmp, X, P256R1);
}
/**
* @brief X = A mod p256r1
*/
void
modp256r1_reduce (bn256 *X, const bn512 *A)
{
bn256 tmp[1];
uint32_t borrow;
#define S1 X
#define S2 tmp
#define S3 tmp
#define S4 tmp
#define S5 tmp
#define S6 tmp
#define S7 tmp
#define S8 tmp
#define S9 tmp
S1->word[7] = A->word[7];
S1->word[6] = A->word[6];
S1->word[5] = A->word[5];
S1->word[4] = A->word[4];
S1->word[3] = A->word[3];
S1->word[2] = A->word[2];
S1->word[1] = A->word[1];
S1->word[0] = A->word[0];
/* X = S1 */
S2->word[7] = A->word[15];
S2->word[6] = A->word[14];
S2->word[5] = A->word[13];
S2->word[4] = A->word[12];
S2->word[3] = A->word[11];
S2->word[2] = S2->word[1] = S2->word[0] = 0;
/* X += 2 * S2 */
modp256r1_add (X, X, S2);
modp256r1_add (X, X, S2);
S3->word[7] = 0;
S3->word[6] = A->word[15];
S3->word[5] = A->word[14];
S3->word[4] = A->word[13];
S3->word[3] = A->word[12];
S3->word[2] = S3->word[1] = S3->word[0] = 0;
/* X += 2 * S3 */
modp256r1_add (X, X, S3);
modp256r1_add (X, X, S3);
S4->word[7] = A->word[15];
S4->word[6] = A->word[14];
S4->word[5] = S4->word[4] = S4->word[3] = 0;
S4->word[2] = A->word[10];
S4->word[1] = A->word[9];
S4->word[0] = A->word[8];
/* X += S4 */
modp256r1_add (X, X, S4);
S5->word[7] = A->word[8];
S5->word[6] = A->word[13];
S5->word[5] = A->word[15];
S5->word[4] = A->word[14];
S5->word[3] = A->word[13];
S5->word[2] = A->word[11];
S5->word[1] = A->word[10];
S5->word[0] = A->word[9];
/* X += S5 */
modp256r1_add (X, X, S5);
S6->word[7] = A->word[10];
S6->word[6] = A->word[8];
S6->word[5] = S6->word[4] = S6->word[3] = 0;
S6->word[2] = A->word[13];
S6->word[1] = A->word[12];
S6->word[0] = A->word[11];
/* X -= S6 */
modp256r1_sub (X, X, S6);
S7->word[7] = A->word[11];
S7->word[6] = A->word[9];
S7->word[5] = S7->word[4] = 0;
S7->word[3] = A->word[15];
S7->word[2] = A->word[14];
S7->word[1] = A->word[13];
S7->word[0] = A->word[12];
/* X -= S7 */
modp256r1_sub (X, X, S7);
S8->word[7] = A->word[12];
S8->word[6] = 0;
S8->word[5] = A->word[10];
S8->word[4] = A->word[9];
S8->word[3] = A->word[8];
S8->word[2] = A->word[15];
S8->word[1] = A->word[14];
S8->word[0] = A->word[13];
/* X -= S8 */
modp256r1_sub (X, X, S8);
S9->word[7] = A->word[13];
S9->word[6] = 0;
S9->word[5] = A->word[11];
S9->word[4] = A->word[10];
S9->word[3] = A->word[9];
S9->word[2] = 0;
S9->word[1] = A->word[15];
S9->word[0] = A->word[14];
/* X -= S9 */
modp256r1_sub (X, X, S9);
borrow = bn256_sub (tmp, X, P256R1);
if (borrow)
memcpy (tmp, X, sizeof (bn256));
else
memcpy (X, tmp, sizeof (bn256));
#undef S1
#undef S2
#undef S3
#undef S4
#undef S5
#undef S6
#undef S7
#undef S8
#undef S9
}
/**
* @brief X = (A * B) mod p256r1
*/
void
modp256r1_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 AB[1];
bn256_mul (AB, A, B);
modp256r1_reduce (X, AB);
}
/**
* @brief X = A * A mod p256r1
*/
void
modp256r1_sqr (bn256 *X, const bn256 *A)
{
bn512 AA[1];
bn256_sqr (AA, A);
modp256r1_reduce (X, AA);
}
/**
* @brief X = (A << shift) mod p256r1
* @note shift < 32
*/
void
modp256r1_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
#define borrow carry
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->word[7] = carry;
tmp->word[0] = carry;
modp256r1_add (X, X, tmp);
tmp->word[7] = 0;
tmp->word[0] = 0;
tmp->word[6] = carry;
tmp->word[3] = carry;
modp256r1_sub (X, X, tmp);
borrow = bn256_sub (tmp, X, P256R1);
if (borrow)
memcpy (tmp, X, sizeof (bn256));
else
memcpy (X, tmp, sizeof (bn256));
#undef borrow
}

9
src/modp256r1.h Normal file
View File

@@ -0,0 +1,9 @@
extern const bn256 p256r1;
#define P256R1 (&p256r1)
void modp256r1_add (bn256 *X, const bn256 *A, const bn256 *B);
void modp256r1_sub (bn256 *X, const bn256 *A, const bn256 *B);
void modp256r1_reduce (bn256 *X, const bn512 *A);
void modp256r1_mul (bn256 *X, const bn256 *A, const bn256 *B);
void modp256r1_sqr (bn256 *X, const bn256 *A);
void modp256r1_shift (bn256 *X, const bn256 *A, int shift);

50
src/muladd_256.h Normal file
View File

@@ -0,0 +1,50 @@
#define MULADD_256_ASM(s_,d_,w_,c_) \
asm ( "ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"umull r4, r8, %[w], r8 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, r8 \n\t" \
"umull r4, r8, %[w], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, %[w], r10 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t" \
"ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, %[w], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[w], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, %[w], r10 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t" \
"ldmia %[s]!, { r8, r9 } \n\t" \
"ldmia %[d], { r5, r6 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, %[w], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[w], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adc %[c], %[c], #0 \n\t" \
"stmia %[d]!, { r5, r6 }" \
: [s] "=&r" (s_), [d] "=&r" (d_), [c] "=&r" (c_) \
: "[s]" (s_), "[d]" (d_), [w] "r" (w_) \
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
"memory", "cc" )
#define MULADD_256(s__,d__,w__,c__) do { \
MULADD_256_ASM(s__,d__,w__,c__); \
*d__ = c__; \
} while (0)

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* openpgp.c -- OpenPGP card protocol support
*
* Copyright (C) 2010, 2011, 2012, 2013
* Copyright (C) 2010, 2011, 2012, 2013, 2014
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -107,6 +107,7 @@ gpg_init (void)
file_selection = FILE_NONE;
flash_data_start = flash_init ();
gpg_data_scan (flash_data_start);
flash_init_keys ();
}
static void
@@ -634,7 +635,7 @@ gpg_get_firmware_update_key (uint8_t keyno)
extern uint8_t _updatekey_store;
const uint8_t *p;
p = &_updatekey_store + keyno * KEY_CONTENT_LEN;
p = &_updatekey_store + keyno * FIRMWARE_UPDATE_KEY_CONTENT_LEN;
return p;
}
@@ -693,8 +694,8 @@ cmd_read_binary (void)
else
{
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
res_APDU_size = KEY_CONTENT_LEN;
memcpy (res_APDU, p, KEY_CONTENT_LEN);
res_APDU_size = FIRMWARE_UPDATE_KEY_CONTENT_LEN;
memcpy (res_APDU, p, FIRMWARE_UPDATE_KEY_CONTENT_LEN);
GPG_SUCCESS ();
}
}
@@ -805,18 +806,31 @@ cmd_get_data (void)
gpg_do_get_data (tag, 0);
}
#define ECDSA_HASH_LEN 32
#define ECDSA_SIGNATURE_LENGTH 64
#define EDDSA_HASH_LEN_MAX 256
#define EDDSA_SIGNATURE_LENGTH 64
static void
cmd_pso (void)
{
int len = apdu.cmd_apdu_data_len;
int r;
int r = -1;
int attr;
int pubkey_len;
DEBUG_INFO (" - PSO: ");
DEBUG_WORD ((uint32_t)&r);
DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
DEBUG_SHORT (len);
if (P1 (apdu) == 0x9e && P2 (apdu) == 0x9a)
{
attr = gpg_get_algo_attr (GPG_KEY_FOR_SIGNING);
pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_SIGNING,
GPG_KEY_PUBLIC);
if (!ac_check_status (AC_PSO_CDS_AUTHORIZED))
{
DEBUG_INFO ("security error.");
@@ -824,39 +838,81 @@ cmd_pso (void)
return;
}
/* Check size of digestInfo */
if (len != 34 /* MD5 */
&& len != 35 /* SHA1 / RIPEMD-160 */
&& len != 47 /* SHA224 */
&& len != 51 /* SHA256 */
&& len != 67 /* SHA384 */
&& len != 83) /* SHA512 */
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
DEBUG_INFO (" wrong length: ");
DEBUG_SHORT (len);
GPG_ERROR ();
}
else
{
DEBUG_SHORT (len);
DEBUG_BINARY (&kd[GPG_KEY_FOR_SIGNING], KEY_CONTENT_LEN);
/* Check size of digestInfo */
if (len != 34 /* MD5 */
&& len != 35 /* SHA1 / RIPEMD-160 */
&& len != 47 /* SHA224 */
&& len != 51 /* SHA256 */
&& len != 67 /* SHA384 */
&& len != 83) /* SHA512 */
{
DEBUG_INFO (" wrong length");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
DEBUG_BINARY (kd[GPG_KEY_FOR_SIGNING].data, pubkey_len);
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
&kd[GPG_KEY_FOR_SIGNING]);
&kd[GPG_KEY_FOR_SIGNING], pubkey_len);
if (r < 0)
{
ac_reset_pso_cds ();
GPG_ERROR ();
}
ac_reset_pso_cds ();
else
/* Success */
gpg_increment_digital_signature_counter ();
}
else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
{
/* ECDSA with p256r1/p256k1 for signature */
if (len != ECDSA_HASH_LEN)
{
DEBUG_INFO (" wrong length");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
if (attr == ALGO_NISTP256R1)
r = ecdsa_sign_p256r1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_SIGNING].data);
else /* ALGO_SECP256K1 */
r = ecdsa_sign_p256k1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_SIGNING].data);
if (r < 0)
ac_reset_pso_cds ();
else
{ /* Success */
gpg_increment_digital_signature_counter ();
res_APDU_size = ECDSA_SIGNATURE_LENGTH;
}
}
else if (attr == ALGO_ED25519)
{
uint32_t output[64/4]; /* Require 4-byte alignment. */
if (len > EDDSA_HASH_LEN_MAX)
{
DEBUG_INFO ("wrong hash length.");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
res_APDU_size = EDDSA_SIGNATURE_LENGTH;
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
kd[GPG_KEY_FOR_AUTHENTICATION].data,
kd[GPG_KEY_FOR_AUTHENTICATION].data+32,
kd[GPG_KEY_FOR_AUTHENTICATION].pubkey);
memcpy (res_APDU, output, EDDSA_SIGNATURE_LENGTH);
}
}
else if (P1 (apdu) == 0x80 && P2 (apdu) == 0x86)
{
DEBUG_SHORT (len);
DEBUG_BINARY (&kd[GPG_KEY_FOR_DECRYPTION], KEY_CONTENT_LEN);
attr = gpg_get_algo_attr (GPG_KEY_FOR_DECRYPTION);
pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_DECRYPTION,
GPG_KEY_PUBLIC);
DEBUG_BINARY (kd[GPG_KEY_FOR_DECRYPTION].data, pubkey_len);
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
@@ -865,19 +921,40 @@ cmd_pso (void)
return;
}
/* Skip padding 0x00 */
len--;
if (len != KEY_CONTENT_LEN)
GPG_CONDITION_NOT_SATISFIED ();
else
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
/* Skip padding 0x00 */
len--;
if (len != pubkey_len)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
&kd[GPG_KEY_FOR_DECRYPTION]);
if (r < 0)
GPG_ERROR ();
}
else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
{
/* Format is in big endian MPI: 04 || x || y */
if (len != 65 || apdu.cmd_apdu_data[0] != 4)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
if (attr == ALGO_NISTP256R1)
r = ecdh_decrypt_p256r1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_DECRYPTION].data);
else
r = ecdh_decrypt_p256k1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_DECRYPTION].data);
if (r == 0)
res_APDU_size = 65;
}
}
else
if (r < 0)
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
@@ -890,28 +967,39 @@ cmd_pso (void)
}
#ifdef RSA_AUTH
#define MAX_DIGEST_INFO_LEN 102 /* 40% */
#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
static void
cmd_internal_authenticate (void)
{
int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
GPG_KEY_PUBLIC);
int len = apdu.cmd_apdu_data_len;
int r;
int r = -1;
DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
if (P1 (apdu) != 0x00 || P2 (apdu) != 0x00)
{
DEBUG_SHORT (len);
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (P2 (apdu));
GPG_CONDITION_NOT_SATISFIED ();
return;
}
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE ();
return;
}
DEBUG_SHORT (len);
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE ();
return;
}
if (len > MAX_DIGEST_INFO_LEN)
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
if (len > MAX_RSA_DIGEST_INFO_LEN)
{
DEBUG_INFO ("input is too long.");
GPG_CONDITION_NOT_SATISFIED ();
@@ -919,45 +1007,11 @@ cmd_internal_authenticate (void)
}
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
&kd[GPG_KEY_FOR_AUTHENTICATION]);
if (r < 0)
GPG_ERROR ();
}
else
&kd[GPG_KEY_FOR_AUTHENTICATION], pubkey_len);
}
else if (attr == ALGO_NISTP256R1)
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (P2 (apdu));
GPG_ERROR ();
}
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
}
#else
#define ECDSA_P256_HASH_LEN 32
#define ECDSA_SIGNATURE_LENGTH 64
static void
cmd_internal_authenticate (void)
{
int len = apdu.cmd_apdu_data_len;
int r;
DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
{
DEBUG_SHORT (len);
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE ();
return;
}
if (len != ECDSA_P256_HASH_LEN)
if (len != ECDSA_HASH_LEN)
{
DEBUG_INFO ("wrong hash length.");
GPG_CONDITION_NOT_SATISFIED ();
@@ -965,23 +1019,47 @@ cmd_internal_authenticate (void)
}
res_APDU_size = ECDSA_SIGNATURE_LENGTH;
r = ecdsa_sign (apdu.cmd_apdu_data, res_APDU,
&kd[GPG_KEY_FOR_AUTHENTICATION]);
if (r < 0)
GPG_ERROR ();
r = ecdsa_sign_p256r1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_AUTHENTICATION].data);
}
else
else if (attr == ALGO_SECP256K1)
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (P2 (apdu));
GPG_ERROR ();
if (len != ECDSA_HASH_LEN)
{
DEBUG_INFO ("wrong hash length.");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
res_APDU_size = ECDSA_SIGNATURE_LENGTH;
r = ecdsa_sign_p256k1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_AUTHENTICATION].data);
}
else if (attr == ALGO_ED25519)
{
uint32_t output[64/4]; /* Require 4-byte alignment. */
if (len > EDDSA_HASH_LEN_MAX)
{
DEBUG_INFO ("wrong hash length.");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
res_APDU_size = EDDSA_SIGNATURE_LENGTH;
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
kd[GPG_KEY_FOR_AUTHENTICATION].data,
kd[GPG_KEY_FOR_AUTHENTICATION].data+32,
kd[GPG_KEY_FOR_AUTHENTICATION].pubkey);
memcpy (res_APDU, output, EDDSA_SIGNATURE_LENGTH);
}
if (r < 0)
GPG_ERROR ();
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
}
#endif
#define MBD_OPRATION_WRITE 0
#define MBD_OPRATION_UPDATE 1
@@ -1132,7 +1210,8 @@ cmd_external_authenticate (void)
return;
}
r = rsa_verify (pubkey, challenge, signature);
r = rsa_verify (pubkey, FIRMWARE_UPDATE_KEY_CONTENT_LEN,
challenge, signature);
random_bytes_free (challenge);
challenge = NULL;

View File

@@ -52,13 +52,17 @@
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)
static void memcpy_bswap32 (void *dst, const uint32_t *p, int n)
static void memcpy_output_bswap32 (unsigned char *dst, const uint32_t *p)
{
uint32_t *q = (uint32_t *)dst;
int i;
uint32_t q = 0;
n >>= 2;
while (n--)
q[n] = __builtin_bswap32 (p[n]); /* bswap32 is GCC extention */
for (i = 0; i < 32; i++)
{
if ((i & 3) == 0)
q = __builtin_bswap32 (p[i >> 2]); /* bswap32 is GCC extention */
dst[i] = q >> ((i & 3) * 8);
}
}
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
@@ -193,11 +197,11 @@ sha256_finish (sha256_context *ctx, unsigned char output[32])
ctx->wbuf[15] = __builtin_bswap32 (ctx->total[0] << 3);
sha256_process (ctx);
memcpy_bswap32 (output, ctx->state, SHA256_DIGEST_SIZE);
memcpy_output_bswap32 (output, ctx->state);
memset (ctx, 0, sizeof (sha256_context));
}
const uint32_t initial_state[8] =
static const uint32_t initial_state[8] =
{
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19

216
src/sha512.c Normal file
View File

@@ -0,0 +1,216 @@
/*
* sha512.c -- Compute SHA-512 hash (for little endian architecture).
*
* This module is written by gniibe, following the API of sha256.c.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk 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 3 of the License, or
* (at your option) any later version.
*
* Gnuk 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Reference:
*
* [1] FIPS PUB 180-4: Secure hash Standard (SHS), March, 2012.
*
*/
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include "sha512.h"
#define SHA512_MASK (SHA512_BLOCK_SIZE - 1)
static void memcpy_output_bswap64 (unsigned char dst[64], const uint64_t *p)
{
int i;
uint64_t q = 0;
for (i = 0; i < 64; i++)
{
if ((i & 7) == 0)
q = __builtin_bswap64 (p[i >> 3]); /* bswap64 is GCC extention */
dst[i] = q >> ((i & 7) * 8);
}
}
#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n)))
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
/* round transforms for SHA512 compression functions */
#define vf(n,i) v[(n - i) & 7]
#define hf(i) (p[i & 15] += \
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
#define v_cycle0(i) \
p[i] = __builtin_bswap64 (p[i]); \
vf(7,i) += p[i] + k_0[i] \
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
vf(3,i) += vf(7,i); \
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
#define v_cycle(i, j) \
vf(7,i) += hf(i) + k_0[i+j] \
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
vf(3,i) += vf(7,i); \
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
#define s_0(x) (rotr64((x), 28) ^ rotr64((x), 34) ^ rotr64((x), 39))
#define s_1(x) (rotr64((x), 14) ^ rotr64((x), 18) ^ rotr64((x), 41))
#define g_0(x) (rotr64((x), 1) ^ rotr64((x), 8) ^ ((x) >> 7))
#define g_1(x) (rotr64((x), 19) ^ rotr64((x), 61) ^ ((x) >> 6))
#define k_0 k512
/* Taken from section 4.2.3 of [1]. */
static const uint64_t k512[80] = {
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
};
void
sha512_process (sha512_context *ctx)
{
uint32_t i;
uint64_t *p = ctx->wbuf;
uint64_t v[8];
memcpy (v, ctx->state, 8 * sizeof (uint64_t));
v_cycle0 ( 0); v_cycle0 ( 1); v_cycle0 ( 2); v_cycle0 ( 3);
v_cycle0 ( 4); v_cycle0 ( 5); v_cycle0 ( 6); v_cycle0 ( 7);
v_cycle0 ( 8); v_cycle0 ( 9); v_cycle0 (10); v_cycle0 (11);
v_cycle0 (12); v_cycle0 (13); v_cycle0 (14); v_cycle0 (15);
for (i = 16; i < 80; i += 16)
{
v_cycle ( 0, i); v_cycle ( 1, i); v_cycle ( 2, i); v_cycle ( 3, i);
v_cycle ( 4, i); v_cycle ( 5, i); v_cycle ( 6, i); v_cycle ( 7, i);
v_cycle ( 8, i); v_cycle ( 9, i); v_cycle (10, i); v_cycle (11, i);
v_cycle (12, i); v_cycle (13, i); v_cycle (14, i); v_cycle (15, i);
}
ctx->state[0] += v[0];
ctx->state[1] += v[1];
ctx->state[2] += v[2];
ctx->state[3] += v[3];
ctx->state[4] += v[4];
ctx->state[5] += v[5];
ctx->state[6] += v[6];
ctx->state[7] += v[7];
}
void
sha512_update (sha512_context *ctx, const unsigned char *input,
unsigned int ilen)
{
uint32_t left = (ctx->total[0] & SHA512_MASK);
uint32_t fill = SHA512_BLOCK_SIZE - left;
ctx->total[0] += ilen;
if (ctx->total[0] < ilen)
ctx->total[1]++;
while (ilen >= fill)
{
memcpy (((unsigned char*)ctx->wbuf) + left, input, fill);
sha512_process (ctx);
input += fill;
ilen -= fill;
left = 0;
fill = SHA512_BLOCK_SIZE;
}
memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen);
}
void
sha512_finish (sha512_context *ctx, unsigned char output[64])
{
uint32_t last = (ctx->total[0] & SHA512_MASK);
ctx->wbuf[last >> 3] = __builtin_bswap64 (ctx->wbuf[last >> 3]);
ctx->wbuf[last >> 3] &= 0xffffffffffffff80LL << (8 * (~last & 7));
ctx->wbuf[last >> 3] |= 0x0000000000000080LL << (8 * (~last & 7));
ctx->wbuf[last >> 3] = __builtin_bswap64 (ctx->wbuf[last >> 3]);
if (last > SHA512_BLOCK_SIZE - 17)
{
if (last < 120)
ctx->wbuf[15] = 0;
sha512_process (ctx);
last = 0;
}
else
last = (last >> 3) + 1;
while (last < 14)
ctx->wbuf[last++] = 0;
ctx->wbuf[14] = __builtin_bswap64 ((ctx->total[0] >> 61) | (ctx->total[1] << 3));
ctx->wbuf[15] = __builtin_bswap64 (ctx->total[0] << 3);
sha512_process (ctx);
memcpy_output_bswap64 (output, ctx->state);
memset (ctx, 0, sizeof (sha512_context));
}
/* Taken from section 5.3.5 of [1]. */
static const uint64_t initial_state[8] = {
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
};
void
sha512_start (sha512_context *ctx)
{
ctx->total[0] = ctx->total[1] = 0;
memcpy (ctx->state, initial_state, 8 * sizeof(uint64_t));
}
void
sha512 (const unsigned char *input, unsigned int ilen,
unsigned char output[64])
{
sha512_context ctx;
sha512_start (&ctx);
sha512_update (&ctx, input, ilen);
sha512_finish (&ctx, output);
}

17
src/sha512.h Normal file
View File

@@ -0,0 +1,17 @@
#define SHA512_DIGEST_SIZE 64
#define SHA512_BLOCK_SIZE 128
typedef struct
{
uint64_t total[2];
uint64_t state[8];
uint64_t wbuf[16];
} sha512_context;
void sha512 (const unsigned char *input, unsigned int ilen,
unsigned char output[64]);
void sha512_start (sha512_context *ctx);
void sha512_finish (sha512_context *ctx, unsigned char output[64]);
void sha512_update (sha512_context *ctx, const unsigned char *input,
unsigned int ilen);
void sha512_process (sha512_context *ctx);

View File

@@ -1,7 +1,7 @@
/*
* sys.c - system routines for the initial page for STM32F103.
*
* Copyright (C) 2013 Flying Stone Technology
* Copyright (C) 2013, 2014 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* Copying and distribution of this file, with or without modification,
@@ -24,7 +24,9 @@
#define STM32_USB_IRQ_PRIORITY 11
#define STM32_SW_HSI (0 << 0)
#define STM32_SW_PLL (2 << 0)
#define STM32_PLLSRC_HSI (0 << 16)
#define STM32_PLLSRC_HSE (1 << 16)
#define STM32_PLLXTPRE_DIV1 (0 << 17)
@@ -32,6 +34,7 @@
#define STM32_HPRE_DIV1 (0 << 4)
#define STM32_PPRE1_DIV1 (0 << 8)
#define STM32_PPRE1_DIV2 (4 << 8)
#define STM32_PPRE2_DIV1 (0 << 11)
@@ -44,23 +47,23 @@
#define STM32_MCO_NOCLOCK (0 << 24)
#define STM32_SW STM32_SW_PLL
#define STM32_PLLSRC STM32_PLLSRC_HSE
#define STM32_HPRE STM32_HPRE_DIV1
#define STM32_PPRE1 STM32_PPRE1_DIV2
#define STM32_PLLSRC STM32_PLLSRC_HSE
#define STM32_FLASHBITS 0x00000012
#define STM32_PLLCLKIN (STM32_HSECLK / 1)
#define STM32_SW STM32_SW_PLL
#define STM32_HPRE STM32_HPRE_DIV1
#define STM32_PPRE2 STM32_PPRE2_DIV1
#define STM32_ADCPRE STM32_ADCPRE_DIV6
#define STM32_MCOSEL STM32_MCO_NOCLOCK
#define STM32_USBPRE STM32_USBPRE_DIV1P5
#define STM32_PLLCLKIN (STM32_HSECLK / 1)
#define STM32_PLLMUL ((STM32_PLLMUL_VALUE - 2) << 18)
#define STM32_PLLCLKOUT (STM32_PLLCLKIN * STM32_PLLMUL_VALUE)
#define STM32_SYSCLK STM32_PLLCLKOUT
#define STM32_HCLK (STM32_SYSCLK / 1)
#define STM32_FLASHBITS 0x00000012
struct NVIC {
uint32_t ISER[8];
uint32_t unused1[24];
@@ -92,8 +95,10 @@ nvic_enable_vector (uint32_t n, uint32_t prio)
#define PERIPH_BASE 0x40000000
#define APBPERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
struct RCC {
volatile uint32_t CR;
@@ -127,6 +132,18 @@ static struct RCC *const RCC = ((struct RCC *const)RCC_BASE);
#define RCC_AHBENR_CRCEN 0x0040
#define RCC_APB2RSTR_AFIORST 0x00000001
#define RCC_APB2RSTR_IOPARST 0x00000004
#define RCC_APB2RSTR_IOPBRST 0x00000008
#define RCC_APB2RSTR_IOPCRST 0x00000010
#define RCC_APB2RSTR_IOPDRST 0x00000020
#define RCC_APB2ENR_AFIOEN 0x00000001
#define RCC_APB2ENR_IOPAEN 0x00000004
#define RCC_APB2ENR_IOPBEN 0x00000008
#define RCC_APB2ENR_IOPCEN 0x00000010
#define RCC_APB2ENR_IOPDEN 0x00000020
struct FLASH {
volatile uint32_t ACR;
volatile uint32_t KEYR;
@@ -149,7 +166,8 @@ clock_init (void)
RCC->CR |= RCC_CR_HSION;
while (!(RCC->CR & RCC_CR_HSIRDY))
;
RCC->CR &= RCC_CR_HSITRIM | RCC_CR_HSION;
/* Reset HSEON, HSEBYP, CSSON, and PLLON, not touching RCC_CR_HSITRIM */
RCC->CR &= (RCC_CR_HSITRIM | RCC_CR_HSION);
RCC->CFGR = 0;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
;
@@ -169,6 +187,10 @@ clock_init (void)
RCC->CFGR = STM32_MCOSEL | STM32_USBPRE | STM32_PLLMUL | STM32_PLLXTPRE
| STM32_PLLSRC | STM32_ADCPRE | STM32_PPRE2 | STM32_PPRE1 | STM32_HPRE;
/*
* We don't touch RCC->CR2, RCC->CFGR2, RCC->CFGR3, and RCC->CIR.
*/
/* Flash setup */
FLASH->ACR = STM32_FLASHBITS;
@@ -181,18 +203,6 @@ clock_init (void)
;
}
#define RCC_APB2RSTR_AFIORST 0x00000001
#define RCC_APB2RSTR_IOPARST 0x00000004
#define RCC_APB2RSTR_IOPBRST 0x00000008
#define RCC_APB2RSTR_IOPCRST 0x00000010
#define RCC_APB2RSTR_IOPDRST 0x00000020
#define RCC_APB2ENR_AFIOEN 0x00000001
#define RCC_APB2ENR_IOPAEN 0x00000004
#define RCC_APB2ENR_IOPBEN 0x00000008
#define RCC_APB2ENR_IOPCEN 0x00000010
#define RCC_APB2ENR_IOPDEN 0x00000020
struct AFIO
{
@@ -231,8 +241,10 @@ struct GPIO {
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define GPIOE ((struct GPIO *) GPIOE_BASE)
static struct GPIO *const GPIO_USB = ((struct GPIO *const) GPIO_USB_BASE);
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
#ifdef GPIO_USB_BASE
static struct GPIO *const GPIO_USB = ((struct GPIO *const) GPIO_USB_BASE);
#endif
#ifdef GPIO_OTHER_BASE
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
#endif
@@ -241,8 +253,8 @@ static void
gpio_init (void)
{
/* Enable GPIO clock. */
RCC->APB2ENR |= RCC_APB2ENR_IOP_EN;
RCC->APB2RSTR = RCC_APB2RSTR_IOP_RST;
RCC->APB2ENR |= RCC_ENR_IOP_EN;
RCC->APB2RSTR = RCC_RSTR_IOP_RST;
RCC->APB2RSTR = 0;
#ifdef AFIO_MAPR_SOMETHING
@@ -578,10 +590,13 @@ reset (void)
{
extern const unsigned long *FT0, *FT1, *FT2;
/*
* This code may not be at the start of flash ROM, because of DFU.
* So, we take the address from PC.
*/
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
"mov.w r0, #0xed00\n\t" /* r0 = SCR */
"movt r0, #0xe000\n\t"
"mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */
"ldr r0, 1f\n\t" /* r0 = SCR */
"mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */
"mov r2, #0x1000\n\t"
"add r1, r1, r2\n\t"
"sub r2, r2, #1\n\t"
@@ -590,7 +605,9 @@ reset (void)
"ldr r0, [r1], #4\n\t"
"msr MSP, r0\n\t" /* Main (exception handler) stack. */
"ldr r0, [r1]\n\t" /* Reset handler. */
"bx r0\n"
"bx r0\n\t"
".align 2\n"
"1: .word 0xe000ed00"
: /* no output */ : /* no input */ : "memory");
/* Never reach here. */

View File

@@ -1,7 +1,8 @@
/*
* usb-icc.c -- USB CCID protocol handling
*
* Copyright (C) 2010, 2011, 2012, 2013 Free Software Initiative of Japan
* Copyright (C) 2010, 2011, 2012, 2013, 2014
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -467,21 +468,18 @@ static int end_cmd_apdu_head (struct ep_out *epo, size_t orig_len)
}
if (epo->cnt == 4)
{
/* No Lc and Le */
c->a->cmd_apdu_data_len = 0;
c->a->expected_res_size = 0;
}
/* No Lc and Le */
c->a->expected_res_size = 0;
else if (epo->cnt == 5)
{
/* No Lc but Le */
c->a->cmd_apdu_data_len = 0;
c->a->expected_res_size = c->a->cmd_apdu_head[4];
if (c->a->expected_res_size == 0)
c->a->expected_res_size = 256;
c->a->cmd_apdu_head[4] = 0;
}
c->a->cmd_apdu_data_len = 0;
return 0;
}
@@ -516,6 +514,8 @@ static int end_cmd_apdu_data (struct ep_out *epo, size_t orig_len)
{
/* it has Le field*/
c->a->expected_res_size = epo->buf[-1];
if (c->a->expected_res_size == 0)
c->a->expected_res_size = 256;
len--;
}
else

View File

@@ -90,50 +90,33 @@ enum DEVICE_STATE
};
extern void usb_lld_init (uint8_t feature);
extern void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n);
extern void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n);
extern void usb_lld_stall_tx (int ep_num);
extern void usb_lld_stall_rx (int ep_num);
extern int usb_lld_tx_data_len (int ep_num);
extern void usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len);
extern void usb_lld_tx_enable (int ep_num, size_t len);
extern void usb_lld_write (uint8_t ep_num, const void *buf, size_t len);
extern void usb_lld_rx_enable (int ep_num);
extern int usb_lld_rx_data_len (int ep_num);
extern void usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len);
extern void usb_lld_reset (void);
extern void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
int ep_rx_addr, int ep_tx_addr,
int ep_rx_memory_size);
extern void usb_lld_set_configuration (uint8_t config);
extern uint8_t usb_lld_current_configuration (void);
extern void usb_lld_set_feature (uint8_t feature);
extern void usb_lld_set_data_to_send (const void *p, size_t len);
void usb_lld_init (uint8_t feature);
void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n);
void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n);
void usb_lld_stall_tx (int ep_num);
void usb_lld_stall_rx (int ep_num);
int usb_lld_tx_data_len (int ep_num);
void usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len);
void usb_lld_tx_enable (int ep_num, size_t len);
void usb_lld_write (uint8_t ep_num, const void *buf, size_t len);
void usb_lld_rx_enable (int ep_num);
int usb_lld_rx_data_len (int ep_num);
void usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len);
void usb_lld_reset (void);
void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
int ep_rx_addr, int ep_tx_addr,
int ep_rx_memory_size);
void usb_lld_set_configuration (uint8_t config);
uint8_t usb_lld_current_configuration (void);
void usb_lld_set_feature (uint8_t feature);
void usb_lld_set_data_to_send (const void *p, size_t len);
extern inline void usb_lld_set_data_to_recv (void *p, size_t len)
{
usb_lld_set_data_to_send ((const void *)p, len);
}
extern void usb_lld_prepare_shutdown (void);
extern void usb_lld_shutdown (void);
void usb_lld_prepare_shutdown (void);
void usb_lld_shutdown (void);
extern void usb_interrupt_handler (void);
void usb_interrupt_handler (void);

View File

@@ -8,7 +8,7 @@ Feature: command GET DATA
Scenario: data object extended capabilities
When requesting extended capabilities: c0
Then data should match: \x70\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
Then data should match: [\x70\x74]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
Scenario: data object algorithm attributes 1
When requesting algorithm attributes 1: c1

View File

@@ -0,0 +1,28 @@
@keyattr
Feature: key attribute change
In order to use a token with multiple different kind of key algorighm
A token should support key attribute change
Scenario: key attribute data object write: algorithm for signature (RSA-4K)
Given cmd_put_data with c1 and "\x01\x10\x00\x00\x20\x00"
Then it should get success
Scenario: key attribute data object write: algorithm for signature (RSA-2K)
Given cmd_put_data with c1 and "\x01\x08\x00\x00\x20\x00"
Then it should get success
Scenario: key attribute data object write: algorithm for decryption (RSA-4K)
Given cmd_put_data with c2 and "\x01\x10\x00\x00\x20\x00"
Then it should get success
Scenario: key attribute data object write: algorithm for decryption (RSA-2K)
Given cmd_put_data with c2 and "\x01\x08\x00\x00\x20\x00"
Then it should get success
Scenario: key attribute data object write: algorithm for authentication (RSA-4K)
Given cmd_put_data with c3 and "\x01\x10\x00\x00\x20\x00"
Then it should get success
Scenario: key attribute data object write: algorithm for authentication (RSA-2K)
Given cmd_put_data with c3 and "\x01\x08\x00\x00\x20\x00"
Then it should get success

View File

@@ -8,7 +8,7 @@ Feature: command GET DATA
Scenario: data object extended capabilities
When requesting extended capabilities: c0
Then data should match: \x70\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
Then data should match: [\x70\x74]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
Scenario: data object algorithm attributes 1
When requesting algorithm attributes 1: c1

View File

@@ -8,7 +8,7 @@ Feature: command GET DATA
Scenario: data object extended capabilities
When requesting extended capabilities: c0
Then data should match: \x70\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
Then data should match: [\x70\x74]\x00\x00\x20[\x00\x08]\x00\x00\xff\x01\x00
Scenario: data object algorithm attributes 1
When requesting algorithm attributes 1: c1

View File

@@ -0,0 +1,189 @@
"""
add_openpgp_authkey_from_gpgssh.py
Copyright (C) 2014 Free Software Initiative of Japan
Author: NIIBE Yutaka <gniibe@fsij.org>
This file is a part of Gnuk, a GnuPG USB Token implementation.
Gnuk 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 3 of the License, or
(at your option) any later version.
Gnuk 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, see <http://www.gnu.org/licenses/>.
"""
from gpg_agent import gpg_agent
from binascii import hexlify, unhexlify
from sexp import sexp
from time import time
from struct import pack, unpack
from hashlib import sha1, sha256
import re
ALGO_RSA=1
DIGEST_SHA256=8
OPENPGP_VERSION=4
def count_bits(mpi_bytes):
return ord(mpi_bytes[0]).bit_length()+(len(mpi_bytes)-1)*8
class rsa_key(object):
def __init__(self, timestamp, n, e):
self.__timestamp = timestamp
self.__n = n
self.__e = e
def hash_pubkey_key(self, md):
hl = 6 + len(self.__n) + 2 + len(self.__e) + 2
md.update(pack('>BHBLB', 0x99, hl, 4, self.__timestamp, ALGO_RSA))
md.update(pack('>H', count_bits(self.__n)) + self.__n)
md.update(pack('>H', count_bits(self.__e)) + self.__e)
def compose_public_subkey_packet(self):
psp = pack('>BLB', OPENPGP_VERSION, self.__timestamp, ALGO_RSA)
psp += pack('>H', count_bits(self.__n)) + self.__n
psp += pack('>H', count_bits(self.__e)) + self.__e
return '\xB9' + pack('>H', len(psp)) + psp
def compute_keygrip(self):
md = sha1("\x00" + self.__n)
return md.digest()
def compute_fpr(self):
md = sha1()
self.hash_pubkey_key(md)
return md.digest()
def compose_binding_signature_packet(g, primary_key, subkey, sig_timestamp):
# Binding signature packet consists of: subpackets of hashed and unhashed
# (1) hashed subpacket: this subpacket is the target to calculate digest
sig_subp_hashed = pack('>B', 5) + '\x02' + pack('>L', sig_timestamp)
sig_subp_hashed += pack('>B', 2) + '\x1b' + '\x20' # Usage AUTH
# (2) unhashed subpacket: this subpacket is _not_ the target for digest
sig_subp_unhashed = pack('>B', 9) + '\x10' + primary_key.compute_fpr()[-8:]
#
md = sha256()
primary_key.hash_pubkey_key(md)
subkey.hash_pubkey_key(md)
# Start building binding signature packet, starting OPENPGP_VERSION...
sigp = pack('>BBBB', OPENPGP_VERSION, 0x18, ALGO_RSA, DIGEST_SHA256)
sigp += pack('>H', len(sig_subp_hashed)) + sig_subp_hashed
# And feed it to digest calculator
md.update(sigp)
md.update(pack('>BBL', OPENPGP_VERSION, 0xff, len(sig_subp_hashed)+6))
digest = md.digest()
# Then, add unhashed subpacket and first two bytes of digest
sigp += pack('>H', len(sig_subp_unhashed)) + sig_subp_unhashed
sigp += digest[0:2]
print("Digest 2-byte: %s" % hexlify(digest[0:2]))
# Ask signing to this digest by the corresponding secret key to PRIMARY_KEY
signature = do_sign(g, primary_key, DIGEST_SHA256, digest)
# Then, add the signature to the binding signature packet
sigp += pack('>H', count_bits(signature)) + signature
# Prepending header, it's the binding signature packet
return '\x89' + pack('>H', len(sigp)) + sigp
def build_rsakey_from_ssh_key_under_gpg_agent(g, timestamp=None):
# (1) Get the list of available key specifying '--with-ssh'
g.send_command("KEYINFO --list --with-ssh --data\n")
kl_str = g.get_response()
kl_str = kl_str[0:-1]
kl = kl_str.split('\n')
# (2) Select SSH key(s)
kl_ssh = [kg for kg in kl if re.search("S$", kg)] # Select SSH key
# (3) Use the first entry of the list (in future, use all???)
print("KEYINFO: %s" % kl_ssh[0])
# KG: The keygrip of key in question
kg = kl_ssh[0].split(' ')[0]
# By READKEY command, get the public key information of KG
g.send_command("READKEY %s\n" % kg)
pubkey_info_str = g.get_response()
# The information is in SEXP format, extract N and E
s = sexp(pubkey_info_str)
if s[0] != 'public-key':
print s
exit(1)
rsa = s[1]
if rsa[0] != 'rsa':
print rsa
exit(1)
n_x = rsa[1]
if n_x[0] != 'n':
print n_x
exit(1)
n_byte_str = n_x[1]
while n_byte_str[0] == '\x00':
n_byte_str = n_byte_str[1:]
n = n_byte_str
e_x = rsa[2]
if e_x[0] != 'e':
print e_x
exit(1)
e = e_x[1]
if not timestamp:
timestamp = int(time())
# Compose our RSA_KEY by TIMESTAMP, N, and E
return rsa_key(timestamp,n,e)
BUFSIZE=1024
def build_rsakey_from_openpgp_file(filename):
f = open(filename, "rb")
openpgp_bytes = f.read(BUFSIZE)
f.close()
header_tag, packet_len, version, timestamp, algo, n_bitlen = \
unpack('>BHBLBH', openpgp_bytes[:11])
if header_tag != 0x99:
print ("openpgp: 0x99 expected (0x%02x)" % header_tag)
exit(1)
n_len = (n_bitlen + 7) / 8
n = openpgp_bytes[11:11+n_len]
e_bitlen = unpack('>H', openpgp_bytes[11+n_len:11+n_len+2])[0]
e_len = (e_bitlen + 7) / 8
e = openpgp_bytes[11+n_len+2:11+n_len+2+e_len]
return rsa_key(timestamp,n,e)
def do_sign(g, pubkey, digest_algo, digest):
g.send_command('SIGKEY %s\n' % hexlify(pubkey.compute_keygrip()))
if digest_algo == DIGEST_SHA256:
g.send_command('SETHASH --hash=sha256 %s\n' % hexlify(digest))
else:
raise('Unknown digest algorithm', digest_algo)
g.send_command('PKSIGN\n')
sig_result_str = g.get_response()
sig_sexp = sexp(sig_result_str) # [ "sig-val" [ "rsa" [ "s" "xxx" ] ] ]
return sig_sexp[1][1][1]
import sys
if __name__ == '__main__':
#
filename = sys.argv[1]
# Connect to GPG-agent:
g = gpg_agent()
print("GPG-agent says: %s" % g.read_line())
#
primary_key = build_rsakey_from_openpgp_file(filename)
print("Primary key fingerprint: %s" % hexlify(primary_key.compute_fpr()))
print("Primary keygrip: %s" % hexlify(primary_key.compute_keygrip()))
#
subkey = build_rsakey_from_ssh_key_under_gpg_agent(g)
print("Subkey fingerprint: %s" % hexlify(subkey.compute_fpr()))
print("Subkey keygrip: %s" % hexlify(subkey.compute_keygrip()))
#
openpgp_subkey_packet = subkey.compose_public_subkey_packet()
openpgp_sig_packet = compose_binding_signature_packet(g, primary_key, subkey, int(time()))
# Query to GPG-agent finished
g.close()
# Append OpenPGP packets to file
f = open(filename, "ab")
f.write(openpgp_subkey_packet)
f.write(openpgp_sig_packet)
f.close()

View File

@@ -0,0 +1,28 @@
from ecdsa import curves, ecdsa
G = ecdsa.generator_secp256k1
# G = ecdsa.generator_256
def print_nG(n):
nG = n*G
nGx_str = "%064x" % nG.x()
nGy_str = "%064x" % nG.y()
print256(nGx_str)
print256(nGy_str)
print
def print256(s):
print("0x%s, 0x%s, 0x%s, 0x%s," % (s[56:64], s[48:56], s[40:48], s[32:40]))
print("0x%s, 0x%s, 0x%s, 0x%s" % (s[24:32], s[16:24], s[8:16], s[0:8]))
print
for i in range(1,16):
n = (i & 1) + (i & 2) * 0x8000000000000000L + (i & 4) * 0x40000000000000000000000000000000L + (i & 8) * 0x200000000000000000000000000000000000000000000000L
print "%064x" % n
print_nG(n)
for i in range(1,16):
n = (i & 1) + (i & 2) * 0x8000000000000000L + (i & 4) * 0x40000000000000000000000000000000L + (i & 8) * 0x200000000000000000000000000000000000000000000000L
n = n * 0x100000000L
print "%064x" % n
print_nG(n)