Compare commits
19 Commits
release/0.
...
release/0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2181c1a428 | ||
|
|
48f552b69b | ||
|
|
6aca64b664 | ||
|
|
3ec2df97b9 | ||
|
|
94f2c25c3b | ||
|
|
b1bb1354f8 | ||
|
|
1ef7813a53 | ||
|
|
9528867c2a | ||
|
|
241f62238d | ||
|
|
dee75314fc | ||
|
|
8bf1019df7 | ||
|
|
e0b70894db | ||
|
|
8c930952f2 | ||
|
|
09748fc046 | ||
|
|
450807e8bf | ||
|
|
ede8bdc2c0 | ||
|
|
4e1126f88c | ||
|
|
c620b73202 | ||
|
|
2d07cd6f0d |
109
ChangeLog
109
ChangeLog
@@ -1,3 +1,112 @@
|
||||
2011-10-07 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.14.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
* src/random.c (random_init): Call neug_prng_reseed.
|
||||
|
||||
2011-10-06 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/Makefile.in (random_bits): Remove.
|
||||
|
||||
* src/openpgp.c (GPGthread): Remove unused event message.
|
||||
|
||||
* src/main.c (main): Call random_init.
|
||||
|
||||
* src/gnuk.ld.in (__process_stack_size__): Fix.
|
||||
(.gnuk_random): Removed.
|
||||
|
||||
* src/flash.c (flash_erase_binary, flash_write_binary): Remove
|
||||
support of random_byte in flash ROM.
|
||||
|
||||
* src/neug.c (adccb): Use old API (was: chEvtSignalFlagsI).
|
||||
(adccb_err): Remove.
|
||||
(rng_gen, rng): Add the last argument adccb for adcStartConversion:
|
||||
This is old API of ADC driver.
|
||||
(adcgrpcfg): Remove callbacks, add CONT and SWSTART: This is old
|
||||
API of ADC driver.
|
||||
(adccb): Remove the first argument: This is old API of ADC driver.
|
||||
(neug_wait_full): New.
|
||||
|
||||
* ChibiOS_2.0.8/os/hal/platforms/STM32/adc_lld.h (ADC_SAMPLE_1P5):
|
||||
Add (from new API).
|
||||
|
||||
* src/random.c (random_init): New.
|
||||
(random_bytes_get, random_bytes_free, get_salt): Use NeuG.
|
||||
|
||||
* src/Makefile.in (CSRC): Add neug.c.
|
||||
|
||||
* src/neug.c: New. Verbatim copy of NeuG/src/random.c.
|
||||
|
||||
* boards/common/mcuconf-common.h (USE_STM32_ADC1): TRUE for NewG RNG.
|
||||
* src/chconf.h (CH_USE_SEMAPHORES): TRUE as ADC driver requires it.
|
||||
* src/halconf.h (CH_HAL_USE_ADC); TRUE for NewG RNG.
|
||||
|
||||
2011-07-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* boards/OLIMEX_STM32_H103/board.h (BOARD_NAME): Fixed.
|
||||
|
||||
* boards/STBEE_MINI/mcuconf.h: Added missing include of
|
||||
mcuconf-common.h.
|
||||
|
||||
2011-07-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* ChibiOS_2.0.8/os/ports/GCC/ARMCMx/chcore_v7m.c
|
||||
(_port_irq_epilogue, _port_switch_from_isr): Apply a patch of 2.2.6.
|
||||
|
||||
* ChibiOS_2.0.8/os/hal/platforms/STM32/adc_lld.h: Apply a patch of
|
||||
ADC from the branch of ChibiOS_2.0.X.
|
||||
|
||||
2011-06-15 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.13.
|
||||
* src/usb_desc.c (gnukStringSerial): Updated.
|
||||
|
||||
2011-06-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* polarssl-0.14.0/include/polarssl/bn_mul.h [__arm__]
|
||||
(MULADDC_1024_CORE, MULADDC_1024_LOOP): New.
|
||||
* polarssl-0.14.0/library/bignum.c (mpi_mul_hlp): Use
|
||||
MULADDC_1024_LOOP.
|
||||
|
||||
2011-05-31 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* polarssl-0.14.0/include/polarssl/bn_mul.h [__arm__]
|
||||
(MULADDC_HUIT, MULADDC_INIT, MULADDC_CORE, MULADDC_STOP): Tweak.
|
||||
|
||||
2011-05-27 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_put_binary.py (main): Confirm Serial ID is written
|
||||
correctly.
|
||||
|
||||
* src/openpgp.c (cmd_write_binary): Fix FILE_EF_SERIAL comparison.
|
||||
|
||||
* src/gnuk.ld.in (.gnuk_random, .gnuk_ch_certificate): Put LONG to
|
||||
have CONTENTS.
|
||||
|
||||
* polarssl-0.14.0/include/polarssl/bn_mul.h [__arm__]
|
||||
(MULADDC_HUIT): New.
|
||||
|
||||
2011-05-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* polarssl-0.14.0/include/polarssl/bn_mul.h [__arm__]
|
||||
(MULADDC_INIT): Add ADDS instruction to clear of carry flag.
|
||||
(MULADDC_CORE): Tune to 6 instructions and less registers.
|
||||
(MULADDC_STOP): Add ADC instruction to save carry flag.
|
||||
|
||||
2011-05-25 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/hub_ctrl.py: New. Port of original C implementation.
|
||||
|
||||
2011-05-16 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* src/main.c (main): Call flash_unlock at the beginning.
|
||||
(device_initialize_once): Don't call flash_unlock here.
|
||||
* src/flash.c (flash_init): Likewise.
|
||||
|
||||
* src/openpgp.c (cmd_select_file): Don't use write_res_apdu.
|
||||
(set_res_apdu): Rename from write_res_apdu. Just SW1 and SW2.
|
||||
|
||||
2011-05-13 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.12.
|
||||
|
||||
@@ -62,6 +62,20 @@
|
||||
#define ADC_CHANNEL_SENSOR 16 /**< @brief Internal temperature sensor.*/
|
||||
#define ADC_CHANNEL_VREFINT 17 /**< @brief Internal reference. */
|
||||
|
||||
/**
|
||||
* @name Sampling rates
|
||||
* @{
|
||||
*/
|
||||
#define ADC_SAMPLE_1P5 0 /**< @brief 1.5 cycles sampling time. */
|
||||
#define ADC_SAMPLE_7P5 1 /**< @brief 7.5 cycles sampling time. */
|
||||
#define ADC_SAMPLE_13P5 2 /**< @brief 13.5 cycles sampling time. */
|
||||
#define ADC_SAMPLE_28P5 3 /**< @brief 28.5 cycles sampling time. */
|
||||
#define ADC_SAMPLE_41P5 4 /**< @brief 41.5 cycles sampling time. */
|
||||
#define ADC_SAMPLE_55P5 5 /**< @brief 55.5 cycles sampling time. */
|
||||
#define ADC_SAMPLE_71P5 6 /**< @brief 71.5 cycles sampling time. */
|
||||
#define ADC_SAMPLE_239P5 7 /**< @brief 239.5 cycles sampling time. */
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
@@ -238,26 +252,51 @@ typedef struct {
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Number of channels in a conversion sequence.
|
||||
*/
|
||||
#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20)
|
||||
|
||||
#define ADC_SQR3_SQ0_N(n) ((n) << 0)
|
||||
#define ADC_SQR3_SQ1_N(n) ((n) << 5)
|
||||
#define ADC_SQR3_SQ2_N(n) ((n) << 10)
|
||||
#define ADC_SQR3_SQ3_N(n) ((n) << 15)
|
||||
#define ADC_SQR3_SQ4_N(n) ((n) << 20)
|
||||
#define ADC_SQR3_SQ5_N(n) ((n) << 25)
|
||||
#define ADC_SQR3_SQ1_N(n) ((n) << 0) /**< @brief 1st channel in seq. */
|
||||
#define ADC_SQR3_SQ2_N(n) ((n) << 5) /**< @brief 2nd channel in seq. */
|
||||
#define ADC_SQR3_SQ3_N(n) ((n) << 10) /**< @brief 3rd channel in seq. */
|
||||
#define ADC_SQR3_SQ4_N(n) ((n) << 15) /**< @brief 4th channel in seq. */
|
||||
#define ADC_SQR3_SQ5_N(n) ((n) << 20) /**< @brief 5th channel in seq. */
|
||||
#define ADC_SQR3_SQ6_N(n) ((n) << 25) /**< @brief 6th channel in seq. */
|
||||
|
||||
#define ADC_SQR2_SQ6_N(n) ((n) << 0)
|
||||
#define ADC_SQR2_SQ7_N(n) ((n) << 5)
|
||||
#define ADC_SQR2_SQ8_N(n) ((n) << 10)
|
||||
#define ADC_SQR2_SQ9_N(n) ((n) << 15)
|
||||
#define ADC_SQR2_SQ10_N(n) ((n) << 20)
|
||||
#define ADC_SQR2_SQ11_N(n) ((n) << 25)
|
||||
#define ADC_SQR2_SQ7_N(n) ((n) << 0) /**< @brief 7th channel in seq. */
|
||||
#define ADC_SQR2_SQ8_N(n) ((n) << 5) /**< @brief 8th channel in seq. */
|
||||
#define ADC_SQR2_SQ9_N(n) ((n) << 10) /**< @brief 9th channel in seq. */
|
||||
#define ADC_SQR2_SQ10_N(n) ((n) << 15) /**< @brief 10th channel in seq.*/
|
||||
#define ADC_SQR2_SQ11_N(n) ((n) << 20) /**< @brief 11th channel in seq.*/
|
||||
#define ADC_SQR2_SQ12_N(n) ((n) << 25) /**< @brief 12th channel in seq.*/
|
||||
|
||||
#define ADC_SQR1_SQ13_N(n) ((n) << 0)
|
||||
#define ADC_SQR1_SQ14_N(n) ((n) << 5)
|
||||
#define ADC_SQR1_SQ15_N(n) ((n) << 10)
|
||||
#define ADC_SQR1_SQ16_N(n) ((n) << 15)
|
||||
#define ADC_SQR1_SQ13_N(n) ((n) << 0) /**< @brief 13th channel in seq.*/
|
||||
#define ADC_SQR1_SQ14_N(n) ((n) << 5) /**< @brief 14th channel in seq.*/
|
||||
#define ADC_SQR1_SQ15_N(n) ((n) << 10) /**< @brief 15th channel in seq.*/
|
||||
#define ADC_SQR1_SQ16_N(n) ((n) << 15) /**< @brief 16th channel in seq.*/
|
||||
|
||||
#define ADC_SMPR2_SMP_AN0(n) ((n) << 0) /**< @brief AN0 sampling time. */
|
||||
#define ADC_SMPR2_SMP_AN1(n) ((n) << 3) /**< @brief AN1 sampling time. */
|
||||
#define ADC_SMPR2_SMP_AN2(n) ((n) << 6) /**< @brief AN2 sampling time. */
|
||||
#define ADC_SMPR2_SMP_AN3(n) ((n) << 9) /**< @brief AN3 sampling time. */
|
||||
#define ADC_SMPR2_SMP_AN4(n) ((n) << 12) /**< @brief AN4 sampling time. */
|
||||
#define ADC_SMPR2_SMP_AN5(n) ((n) << 15) /**< @brief AN5 sampling time. */
|
||||
#define ADC_SMPR2_SMP_AN6(n) ((n) << 18) /**< @brief AN6 sampling time. */
|
||||
#define ADC_SMPR2_SMP_AN7(n) ((n) << 21) /**< @brief AN7 sampling time. */
|
||||
#define ADC_SMPR2_SMP_AN8(n) ((n) << 24) /**< @brief AN8 sampling time. */
|
||||
#define ADC_SMPR2_SMP_AN9(n) ((n) << 27) /**< @brief AN9 sampling time. */
|
||||
|
||||
#define ADC_SMPR1_SMP_AN10(n) ((n) << 0) /**< @brief AN10 sampling time. */
|
||||
#define ADC_SMPR1_SMP_AN11(n) ((n) << 3) /**< @brief AN11 sampling time. */
|
||||
#define ADC_SMPR1_SMP_AN12(n) ((n) << 6) /**< @brief AN12 sampling time. */
|
||||
#define ADC_SMPR1_SMP_AN13(n) ((n) << 9) /**< @brief AN13 sampling time. */
|
||||
#define ADC_SMPR1_SMP_AN14(n) ((n) << 12) /**< @brief AN14 sampling time. */
|
||||
#define ADC_SMPR1_SMP_AN15(n) ((n) << 15) /**< @brief AN15 sampling time. */
|
||||
#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18) /**< @brief Temperature Sensor
|
||||
sampling time. */
|
||||
#define ADC_SMPR1_SMP_VREF(n) ((n) << 21) /**< @brief Voltage Reference
|
||||
sampling time. */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
|
||||
@@ -107,12 +107,12 @@ void SVCallVector(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reschedule verification and setup after an IRQ.
|
||||
* @brief Exception exit redirection to _port_switch_from_isr().
|
||||
*/
|
||||
void _port_irq_epilogue(void) {
|
||||
|
||||
port_lock_from_isr();
|
||||
if ((SCB_ICSR & ICSR_RETTOBASE) && chSchIsRescRequiredExI()) {
|
||||
if ((SCB_ICSR & ICSR_RETTOBASE)) {
|
||||
register struct extctx *ctxp;
|
||||
|
||||
/* Adding an artificial exception return context, there is no need to
|
||||
@@ -126,7 +126,6 @@ void _port_irq_epilogue(void) {
|
||||
order to keep the rest of the context switching atomic.*/
|
||||
return;
|
||||
}
|
||||
/* ISR exit without context switching.*/
|
||||
port_unlock_from_isr();
|
||||
}
|
||||
|
||||
@@ -139,7 +138,8 @@ __attribute__((naked))
|
||||
#endif
|
||||
void _port_switch_from_isr(void) {
|
||||
|
||||
chSchDoRescheduleI();
|
||||
if (chSchIsRescRequiredExI())
|
||||
chSchDoRescheduleI();
|
||||
asm volatile ("svc #0");
|
||||
}
|
||||
|
||||
|
||||
23
NEWS
23
NEWS
@@ -1,5 +1,28 @@
|
||||
Gnuk NEWS - User visible changes
|
||||
|
||||
* Major changes in Gnuk 0.14
|
||||
|
||||
Released 2011-10-07, by NIIBE Yutaka
|
||||
|
||||
** Random number generator change
|
||||
NeuG, Gniibe's True RNG implementation for STM32F103, has been
|
||||
integrated to Gnuk. It is not needed to put random number bytes
|
||||
(generated by host) to Token any more.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.13
|
||||
|
||||
Released 2011-06-15, by NIIBE Yutaka
|
||||
|
||||
** Improved RSA routine.
|
||||
About 20% speed improvement.
|
||||
|
||||
** New tool: hub_ctrl.
|
||||
It is a Python implementation ported from original C implementation.
|
||||
It is useful for development of USB target if you have a good hub.
|
||||
You can power off/on the port to reset Gnuk Token.
|
||||
|
||||
|
||||
* Major changes in Gnuk 0.12
|
||||
|
||||
Released 2011-05-13, by NIIBE Yutaka
|
||||
|
||||
63
README
63
README
@@ -1,7 +1,7 @@
|
||||
Gnuk - software for GnuPG USB Token
|
||||
|
||||
Version 0.12
|
||||
2011-05-13
|
||||
Version 0.14
|
||||
2011-10-07
|
||||
Niibe Yutaka
|
||||
Free Software Initiative of Japan
|
||||
|
||||
@@ -19,15 +19,15 @@ me to bring a card reader all the time. With Gnuk, this issue will be
|
||||
solved by a USB token which is small enough.
|
||||
|
||||
Please look at the graphics of "gnuk.svg" for the software name. My
|
||||
son used to be with his NUK(R), always, everywhere. I will be with a
|
||||
USB Token by "Gnuk" everywhere.
|
||||
son used to be with his NUK(R), always, everywhere. I am with a USB
|
||||
Token by "Gnuk", always, everywhere.
|
||||
|
||||
|
||||
FAQ
|
||||
===
|
||||
|
||||
Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
|
||||
card 2.0, GPF Crypto Stick, etc) ?
|
||||
card 2.0, GPF Crypto Stick, etc.) ?
|
||||
http://www.g10code.de/p-card.html
|
||||
http://www.privacyfoundation.de/crypto_stick/
|
||||
A0: IMRHO, not quite. There is no ready-to-use out-of-box product.
|
||||
@@ -44,16 +44,18 @@ A0: IMRHO, not quite. There is no ready-to-use out-of-box product.
|
||||
(GNU Toolchain, Python, etc.),
|
||||
"for Free Software"; Gnuk supports GnuPG.
|
||||
|
||||
Q1: What's kind of key algorithm is supported?
|
||||
Q1: What kind of key algorithm is supported?
|
||||
A1: Gnuk only supports 2048-bit RSA.
|
||||
|
||||
Q2: How long does it take for digital signing?
|
||||
A2: It takes two seconds or so.
|
||||
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.
|
||||
Currently FST-01 (Flying Stone Tiny 01) is under development,
|
||||
it will be the best choice, hopefully.
|
||||
|
||||
Q4: What's version of GnuPG are you using?
|
||||
A4: In Debian GNU/Linux system, I use gnupg 1.4.11-3 and gnupg-agent
|
||||
@@ -92,13 +94,9 @@ A9: GnuPG's SCDaemon has problems for handling insertion/removal of
|
||||
Release notes
|
||||
=============
|
||||
|
||||
This is thirteenth release of Gnuk. While it works well for specific
|
||||
This is fifteenth release of Gnuk. While it works well for specific
|
||||
usages and it is considered stable, it is still somewhat experimental.
|
||||
|
||||
Note that you need to write random bits after installation of gnuk
|
||||
executable to the chip. This procedure is required to share a single
|
||||
executable among multiple devices.
|
||||
|
||||
Tested features are:
|
||||
|
||||
* Personalization of the card
|
||||
@@ -129,7 +127,7 @@ It is known not-working well:
|
||||
Not supported feature(s):
|
||||
|
||||
* Overriding key import. You need to remove all keys first.
|
||||
* Key generation
|
||||
* Key generation on device side
|
||||
|
||||
|
||||
Targets
|
||||
@@ -179,8 +177,8 @@ The author(s) of Gnuk expect users of Gnuk will be able to access the
|
||||
source code of Gnuk, so that users can study the code and can modify
|
||||
if needed. This doesn't mean person who has a USB Token by Gnuk
|
||||
should be able to acess everything on the Token, regardless of its
|
||||
protections. Private keys, random bytes, and other information should
|
||||
be protected properly.
|
||||
protections. Private keys, and other information should be protected
|
||||
properly.
|
||||
|
||||
|
||||
External source code
|
||||
@@ -200,6 +198,9 @@ Gnuk is distributed with external source code.
|
||||
We use PolarSSL for RSA computation, AES encryption/decryption
|
||||
and SHA-1 computation.
|
||||
|
||||
The file include/polarssl/bn_mul.h is heavily modified for ARM
|
||||
Cortex-M3.
|
||||
|
||||
* STM32_USB-FS-Device_Driver/ -- a part of USB-FS-Device_Lib
|
||||
* Virtual_COM_Port/ -- a part of USB-FS-Device_Lib
|
||||
|
||||
@@ -229,8 +230,8 @@ How to compile
|
||||
|
||||
You need GNU toolchain and newlib for 'arm-none-eabi' target.
|
||||
|
||||
See http://github.com/esden/summon-arm-toolchain/ for preparation of
|
||||
GNU Toolchain for 'arm-none-eabi' target.
|
||||
See http://github.com/uwehermann/summon-arm-toolchain/ for preparation
|
||||
of GNU Toolchain for 'arm-none-eabi' target.
|
||||
|
||||
Change directory to `src':
|
||||
|
||||
@@ -338,19 +339,7 @@ How to configure
|
||||
You need python and pyscard (python-pyscard package in Debian) or
|
||||
PyUSB (python-usb package in Debian).
|
||||
|
||||
(1) In the 'src' directory, type
|
||||
|
||||
$ make random_bits
|
||||
|
||||
In this process, it takes time for the command of
|
||||
|
||||
dd if=/dev/random bs=1 of=random_bits count=1024
|
||||
|
||||
Don't just wait, but do some other works on your PC.
|
||||
/dev/random needs entropy to finish.
|
||||
|
||||
|
||||
(2) [pyscard] Stop scdaemon
|
||||
(1) [pyscard] Stop scdaemon
|
||||
[PyUSB] Stop the pcsc daemon.
|
||||
|
||||
If scdaemon is running, please kill it, or you will get "Smartcard
|
||||
@@ -363,17 +352,7 @@ In case of PyUSB tool, you need to stop pcscd.
|
||||
# /etc/init.d/pcscd stop
|
||||
|
||||
|
||||
(3) Write the random bits to the device
|
||||
|
||||
Connect your board to USB port of your PC. And invoke gnuk_put_binary.py:
|
||||
|
||||
$ ../tool/gnuk_put_binary.py -r random_bits
|
||||
random_bits: 1024
|
||||
Updating random bits
|
||||
...
|
||||
|
||||
|
||||
(4) [Optional] Write fixed serial number
|
||||
(2) [Optional] Write fixed serial number
|
||||
|
||||
If you use fixed serial number in the file 'GNUK_SERIAL_NUMBER', you can do:
|
||||
|
||||
@@ -381,7 +360,7 @@ If you use fixed serial number in the file 'GNUK_SERIAL_NUMBER', you can do:
|
||||
Writing serial number
|
||||
...
|
||||
|
||||
(5) [Optional] Write card holder certificate
|
||||
(3) [Optional] Write card holder certificate
|
||||
|
||||
If you have card holder certificate binary file, you can do:
|
||||
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
#define _BOARD_H_
|
||||
|
||||
/*
|
||||
* Setup for the Olimex STM32-P103 proto board.
|
||||
* Setup for the Olimex STM32-H103 proto board.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
*/
|
||||
#define BOARD_OLIMEX_STM32_P103
|
||||
#define BOARD_NAME "Olimex STM32-P103"
|
||||
#define BOARD_OLIMEX_STM32_H103
|
||||
#define BOARD_NAME "Olimex STM32-H103"
|
||||
|
||||
/*
|
||||
* Board frequencies.
|
||||
|
||||
@@ -10,3 +10,5 @@
|
||||
#define STM32_PPRE2 STM32_PPRE2_DIV2
|
||||
#define STM32_ADCPRE STM32_ADCPRE_DIV4
|
||||
#define STM32_MCO STM32_MCO_NOCLOCK
|
||||
|
||||
#include "mcuconf-common.h"
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
/*
|
||||
* ADC driver system settings.
|
||||
*/
|
||||
#define USE_STM32_ADC1 FALSE
|
||||
#define USE_STM32_ADC1 TRUE
|
||||
#define STM32_ADC1_DMA_PRIORITY 3
|
||||
#define STM32_ADC1_IRQ_PRIORITY 5
|
||||
#define STM32_ADC1_DMA_ERROR_HOOK() chSysHalt()
|
||||
|
||||
@@ -495,27 +495,130 @@
|
||||
#endif /* TriCore */
|
||||
|
||||
#if defined(__arm__)
|
||||
#define MULADDC_1024_CORE \
|
||||
"ldmia %0!, { r5, r6, r7 } \n" \
|
||||
"ldmia %1, { r8, r9, r10 } \n" \
|
||||
"umull r11, r12, %2, r5 \n" \
|
||||
"adcs r11, r11, %3 \n" \
|
||||
"adc %3, r12, #0 \n" \
|
||||
"adds r8, r8, r11 \n" \
|
||||
"umull r11, r12, %2, r6 \n" \
|
||||
"adcs r11, r11, %3 \n" \
|
||||
"adc %3, r12, #0 \n" \
|
||||
"adds r9, r9, r11 \n" \
|
||||
"umull r11, r12, %2, r7 \n" \
|
||||
"adcs r11, r11, %3 \n" \
|
||||
"adc %3, r12, #0 \n" \
|
||||
"adds r10, r10, r11 \n" \
|
||||
"stmia %1!, { r8, r9, r10 } \n"
|
||||
|
||||
#define MULADDC_INIT \
|
||||
asm( "ldr r0, %0 " :: "m" (s)); \
|
||||
asm( "ldr r1, %0 " :: "m" (d)); \
|
||||
asm( "ldr r2, %0 " :: "m" (c)); \
|
||||
asm( "ldr r3, %0 " :: "m" (b));
|
||||
#define MULADDC_1024_LOOP \
|
||||
asm( "tst %4, #0xfe0 \n" \
|
||||
"beq 0f \n" \
|
||||
"1: sub %4, %4, #32 \n" \
|
||||
"ldmia %0!, { r5, r6, r7 } \n" \
|
||||
"ldmia %1, { r8, r9, r10 } \n" \
|
||||
"umull r11, r12, %2, r5 \n" \
|
||||
"adds r11, r11, %3 \n" \
|
||||
"adc %3, r12, #0 \n" \
|
||||
"adds r8, r8, r11 \n" \
|
||||
"umull r11, r12, %2, r6 \n" \
|
||||
"adcs r11, r11, %3 \n" \
|
||||
"adc %3, r12, #0 \n" \
|
||||
"adds r9, r9, r11 \n" \
|
||||
"umull r11, r12, %2, r7 \n" \
|
||||
"adcs r11, r11, %3 \n" \
|
||||
"adc %3, r12, #0 \n" \
|
||||
"adds r10, r10, r11 \n" \
|
||||
"stmia %1!, { r8, r9, r10 } \n" \
|
||||
MULADDC_1024_CORE MULADDC_1024_CORE \
|
||||
MULADDC_1024_CORE MULADDC_1024_CORE \
|
||||
MULADDC_1024_CORE MULADDC_1024_CORE \
|
||||
MULADDC_1024_CORE MULADDC_1024_CORE \
|
||||
MULADDC_1024_CORE \
|
||||
"ldmia %0!, { r5, r6 } \n" \
|
||||
"ldmia %1, { r8, r9 } \n" \
|
||||
"umull r11, r12, %2, r5 \n" \
|
||||
"adcs r11, r11, %3 \n" \
|
||||
"adc %3, r12, #0 \n" \
|
||||
"adds r8, r8, r11 \n" \
|
||||
"umull r11, r12, %2, r6 \n" \
|
||||
"adcs r11, r11, %3 \n" \
|
||||
"adc %3, r12, #0 \n" \
|
||||
"adds r9, r9, r11 \n" \
|
||||
"stmia %1!, { r8, r9 } \n" \
|
||||
"adc %3, %3, #0 \n" \
|
||||
"tst %4, #0xfe0 \n" \
|
||||
"bne 1b \n" \
|
||||
"0:" \
|
||||
: "=r" (s), "=r" (d), "=r" (b), "=r" (c), "=r" (i) \
|
||||
: "0" (s), "1" (d), "2" (b), "3" (c), "4" (i) \
|
||||
: "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "memory", "cc" );
|
||||
|
||||
#define MULADDC_CORE \
|
||||
asm( "ldr r4, [r0], #4 " ); \
|
||||
asm( "mov r5, #0 " ); \
|
||||
asm( "ldr r6, [r1] " ); \
|
||||
asm( "umlal r2, r5, r3, r4 " ); \
|
||||
asm( "adds r7, r6, r2 " ); \
|
||||
asm( "adc r2, r5, #0 " ); \
|
||||
asm( "str r7, [r1], #4 " );
|
||||
/* Just for reference (dead code) */
|
||||
#define MULADDC_HUIT \
|
||||
"ldmia %0!, { r4, r5 } \n" \
|
||||
"ldmia %1, { r8, r9 } \n" \
|
||||
"umull r6, r7, %2, r4 \n" \
|
||||
"adcs r6, r6, %3 \n" \
|
||||
"adc %3, r7, #0 \n" \
|
||||
"adds r8, r8, r6 \n" \
|
||||
"umull r6, r7, %2, r5 \n" \
|
||||
"adcs r6, r6, %3 \n" \
|
||||
"adc %3, r7, #0 \n" \
|
||||
"adds r9, r9, r6 \n" \
|
||||
"stmia %1!, { r8, r9 } \n" \
|
||||
"ldmia %0!, { r4, r5 } \n" \
|
||||
"ldmia %1, { r8, r9 } \n" \
|
||||
"umull r6, r7, %2, r4 \n" \
|
||||
"adcs r6, r6, %3 \n" \
|
||||
"adc %3, r7, #0 \n" \
|
||||
"adds r8, r8, r6 \n" \
|
||||
"umull r6, r7, %2, r5 \n" \
|
||||
"adcs r6, r6, %3 \n" \
|
||||
"adc %3, r7, #0 \n" \
|
||||
"adds r9, r9, r6 \n" \
|
||||
"stmia %1!, { r8, r9 } \n" \
|
||||
"ldmia %0!, { r4, r5 } \n" \
|
||||
"ldmia %1, { r8, r9 } \n" \
|
||||
"umull r6, r7, %2, r4 \n" \
|
||||
"adcs r6, r6, %3 \n" \
|
||||
"adc %3, r7, #0 \n" \
|
||||
"adds r8, r8, r6 \n" \
|
||||
"umull r6, r7, %2, r5 \n" \
|
||||
"adcs r6, r6, %3 \n" \
|
||||
"adc %3, r7, #0 \n" \
|
||||
"adds r9, r9, r6 \n" \
|
||||
"stmia %1!, { r8, r9 } \n" \
|
||||
"ldmia %0!, { r4, r5 } \n" \
|
||||
"ldmia %1, { r8, r9 } \n" \
|
||||
"umull r6, r7, %2, r4 \n" \
|
||||
"adcs r6, r6, %3 \n" \
|
||||
"adc %3, r7, #0 \n" \
|
||||
"adds r8, r8, r6 \n" \
|
||||
"umull r6, r7, %2, r5 \n" \
|
||||
"adcs r6, r6, %3 \n" \
|
||||
"adc %3, r7, #0 \n" \
|
||||
"adds r9, r9, r6 \n" \
|
||||
"stmia %1!, { r8, r9 } \n"
|
||||
|
||||
#define MULADDC_STOP \
|
||||
asm( "str r2, %0 " : "=m" (c)); \
|
||||
asm( "str r1, %0 " : "=m" (d)); \
|
||||
asm( "str r0, %0 " : "=m" (s) :: \
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" );
|
||||
#define MULADDC_INIT \
|
||||
asm( "adds %0, #0 \n"
|
||||
|
||||
#define MULADDC_CORE \
|
||||
"ldr r5, [%1] \n" \
|
||||
"ldr r4, [%0], #4 \n" \
|
||||
"umull r6, r7, %2, r4 \n" \
|
||||
"adcs r6, r6, %3 \n" \
|
||||
"adc %3, r7, #0 \n" \
|
||||
"adds r5, r5, r6 \n" \
|
||||
"str r5, [%1], #4 \n"
|
||||
|
||||
#define MULADDC_STOP \
|
||||
"adc %3, %3, #0 " \
|
||||
: "=r" (s), "=r" (d), "=r" (b), "=r" (c) \
|
||||
: "0" (s), "1" (d), "2" (b), "3" (c) \
|
||||
: "r4", "r5", "r6", "r7", "r8", "r9", "memory", "cc" );
|
||||
|
||||
#endif /* ARMv3 */
|
||||
|
||||
|
||||
@@ -894,7 +894,16 @@ static void mpi_mul_hlp( int i, t_int *s, t_int *d, t_int b )
|
||||
{
|
||||
t_int c = 0, t = 0;
|
||||
|
||||
#if defined(MULADDC_HUIT)
|
||||
#if defined(MULADDC_1024_LOOP)
|
||||
MULADDC_1024_LOOP
|
||||
|
||||
for( ; i > 0; i-- )
|
||||
{
|
||||
MULADDC_INIT
|
||||
MULADDC_CORE
|
||||
MULADDC_STOP
|
||||
}
|
||||
#elif defined(MULADDC_HUIT)
|
||||
for( ; i >= 8; i -= 8 )
|
||||
{
|
||||
MULADDC_INIT
|
||||
|
||||
@@ -91,7 +91,7 @@ CSRC = $(PORTSRC) \
|
||||
main.c usb_lld.c \
|
||||
usb_desc.c usb_prop.c \
|
||||
usb-icc.c openpgp.c ac.c openpgp-do.c flash.c hardclock.c \
|
||||
random.c
|
||||
random.c neug.c
|
||||
|
||||
ifneq ($(ENABLE_DEBUG),)
|
||||
CSRC += debug.c
|
||||
@@ -206,8 +206,5 @@ endif
|
||||
|
||||
include $(CHIBIOS)/os/ports/GCC/ARM/rules.mk
|
||||
|
||||
random_bits:
|
||||
dd if=/dev/random bs=1 of=random_bits count=1024
|
||||
|
||||
distclean: clean
|
||||
-rm -f Makefile gnuk.ld config.h random_bits
|
||||
-rm -f Makefile gnuk.ld config.h
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#define CH_OPTIMIZE_SPEED TRUE
|
||||
#define CH_USE_REGISTRY TRUE
|
||||
#define CH_USE_WAITEXIT TRUE
|
||||
#define CH_USE_SEMAPHORES FALSE
|
||||
#define CH_USE_SEMAPHORES TRUE
|
||||
#define CH_USE_SEMAPHORES_PRIORITY FALSE
|
||||
#define CH_USE_SEMSW FALSE
|
||||
#define CH_USE_MUTEXES TRUE
|
||||
|
||||
17
src/flash.c
17
src/flash.c
@@ -147,8 +147,6 @@ flash_erase_page (uint32_t addr)
|
||||
* .bss
|
||||
* _end
|
||||
* <alignment to page>
|
||||
* random_bits_start
|
||||
* <one page>
|
||||
* ch_certificate_startp
|
||||
* <2048 bytes>
|
||||
* _data_pool
|
||||
@@ -206,7 +204,6 @@ flash_init (void)
|
||||
|
||||
keystore = p;
|
||||
|
||||
flash_unlock ();
|
||||
return data_pool + FLASH_DATA_POOL_HEADER_SIZE;
|
||||
}
|
||||
|
||||
@@ -614,15 +611,6 @@ flash_erase_binary (uint8_t file_id)
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (file_id == FILEID_RANDOM)
|
||||
{
|
||||
p = &random_bits_start;
|
||||
|
||||
if (flash_check_blank (p, FLASH_PAGE_SIZE) == 0)
|
||||
flash_erase_page ((uint32_t)p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -642,11 +630,6 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
|
||||
maxsize = FLASH_CH_CERTIFICATE_SIZE;
|
||||
p = &ch_certificate_start;
|
||||
}
|
||||
else if (file_id == FILEID_RANDOM)
|
||||
{
|
||||
maxsize = FLASH_PAGE_SIZE;
|
||||
p = &random_bits_start;
|
||||
}
|
||||
else if (file_id == FILEID_SERIAL_NO)
|
||||
{
|
||||
maxsize = 6;
|
||||
|
||||
@@ -90,8 +90,7 @@ extern void ac_reset_admin (void);
|
||||
extern void ac_fini (void);
|
||||
|
||||
|
||||
extern void write_res_apdu (const uint8_t *p, int len,
|
||||
uint8_t sw1, uint8_t sw2);
|
||||
extern void set_res_apdu (uint8_t sw1, uint8_t sw2);
|
||||
extern uint16_t data_objects_number_of_bytes;
|
||||
|
||||
extern void gpg_data_scan (const uint8_t *p);
|
||||
@@ -108,6 +107,7 @@ enum kind_of_key {
|
||||
GPG_KEY_FOR_AUTHENTICATION,
|
||||
};
|
||||
|
||||
extern void flash_unlock (void);
|
||||
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);
|
||||
@@ -292,6 +292,7 @@ extern uint8_t admin_authorized;
|
||||
|
||||
#define SIZE_PW_STATUS_BYTES 7
|
||||
|
||||
extern void random_init (void);
|
||||
/* 16-byte random bytes */
|
||||
extern const uint8_t *random_bytes_get (void);
|
||||
extern void random_bytes_free (const uint8_t *);
|
||||
|
||||
@@ -27,8 +27,9 @@
|
||||
/*
|
||||
* ST32F103 memory setup.
|
||||
*/
|
||||
__main_stack_size__ = 0x0400;
|
||||
__stacks_total_size__ = __main_stack_size__;
|
||||
__main_stack_size__ = 0x0200;
|
||||
__process_stack_size__ = 0x0200;
|
||||
__stacks_total_size__ = __main_stack_size__ + __process_stack_size__;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
@@ -114,18 +115,11 @@ SECTIONS
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
|
||||
.gnuk_random :
|
||||
{
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
random_bits_start = .;
|
||||
. += 1;
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
} > flash =0xffffffff
|
||||
|
||||
.gnuk_ch_certificate :
|
||||
{
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
ch_certificate_start = .;
|
||||
LONG(0xffffffff);
|
||||
. += 1920;
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
} > flash =0xffffffff
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "mcuconf.h"
|
||||
|
||||
#define CH_HAL_USE_PAL TRUE
|
||||
#define CH_HAL_USE_ADC FALSE
|
||||
#define CH_HAL_USE_ADC TRUE
|
||||
#define CH_HAL_USE_CAN FALSE
|
||||
#define CH_HAL_USE_MAC FALSE
|
||||
#define CH_HAL_USE_PWM FALSE
|
||||
|
||||
@@ -172,7 +172,6 @@ device_initialize_once (void)
|
||||
|
||||
if (p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff)
|
||||
{
|
||||
extern void flash_unlock (void);
|
||||
/*
|
||||
* This is the first time invocation.
|
||||
* Setup serial number by unique device ID.
|
||||
@@ -180,7 +179,6 @@ device_initialize_once (void)
|
||||
const uint8_t *u = unique_device_id ();
|
||||
int i;
|
||||
|
||||
flash_unlock ();
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
uint8_t b = u[i];
|
||||
@@ -212,9 +210,11 @@ main (int argc, char **argv)
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
flash_unlock ();
|
||||
device_initialize_once ();
|
||||
usb_lld_init ();
|
||||
USB_Init();
|
||||
USB_Init ();
|
||||
random_init ();
|
||||
|
||||
#ifdef DEBUG
|
||||
stdout_init ();
|
||||
|
||||
453
src/neug.c
Normal file
453
src/neug.c
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* neug.c - random number generation (from NeuG/src/random.c)
|
||||
*
|
||||
* Copyright (C) 2011 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of NeuG, a Random Number Generator
|
||||
* implementation (for STM32F103).
|
||||
*
|
||||
* NeuG 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 "config.h"
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
static Thread *rng_thread;
|
||||
#define ADC_DATA_AVAILABLE ((eventmask_t)1)
|
||||
|
||||
/* Total number of channels to be sampled by a single ADC operation.*/
|
||||
#define ADC_GRP1_NUM_CHANNELS 2
|
||||
|
||||
/* Depth of the conversion buffer, channels are sampled one time each.*/
|
||||
#define ADC_GRP1_BUF_DEPTH 4
|
||||
|
||||
/*
|
||||
* ADC samples buffer.
|
||||
*/
|
||||
static adcsample_t samp[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
|
||||
|
||||
static void adccb (adcsample_t *buffer, size_t n);
|
||||
|
||||
/*
|
||||
* ADC conversion group.
|
||||
* Mode: Linear buffer, 4 samples of 2 channels, SW triggered.
|
||||
* Channels: Vref (1.5 cycles sample time, violating the spec.)
|
||||
* Sensor (1.5 cycles sample time, violating the spec.)
|
||||
*/
|
||||
static const ADCConversionGroup adcgrpcfg = {
|
||||
FALSE,
|
||||
ADC_GRP1_NUM_CHANNELS,
|
||||
0,
|
||||
ADC_CR2_EXTSEL_SWSTART | ADC_CR2_TSVREFE | ADC_CR2_CONT,
|
||||
ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_1P5) | ADC_SMPR1_SMP_VREF(ADC_SAMPLE_1P5),
|
||||
0,
|
||||
ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),
|
||||
0,
|
||||
ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR) | ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT)
|
||||
};
|
||||
|
||||
/*
|
||||
* ADC end conversion callback.
|
||||
*/
|
||||
static void adccb (adcsample_t *buffer, size_t n)
|
||||
{
|
||||
ADCDriver *adcp = &ADCD1;
|
||||
|
||||
(void) buffer; (void) n;
|
||||
if (adcp->ad_state == ADC_COMPLETE)
|
||||
chEvtSignalI (rng_thread, ADC_DATA_AVAILABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* TinyMT routines.
|
||||
*
|
||||
* See
|
||||
* "Tiny Mersenne Twister (TinyMT): A small-sized variant of Mersenne Twister"
|
||||
* by Mutsuo Saito and Makoto Matsumoto
|
||||
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/
|
||||
*/
|
||||
|
||||
/* Use the first example of TinyMT */
|
||||
#define TMT_MAT1 0x8f7011ee
|
||||
#define TMT_MAT2 0xfc78ff1f
|
||||
#define TMT_TMAT 0x3793fdff
|
||||
|
||||
static uint32_t tmt[4];
|
||||
|
||||
static void tmt_one_step (void);
|
||||
|
||||
#define TMT_INIT_MIN_LOOP 8
|
||||
#define TMT_INIT_PRE_LOOP 8
|
||||
|
||||
/**
|
||||
* @brief TinyMT initialize function.
|
||||
*/
|
||||
static void tmt_init (uint32_t seed)
|
||||
{
|
||||
int i;
|
||||
|
||||
tmt[0] = seed;
|
||||
tmt[1] = TMT_MAT1;
|
||||
tmt[2] = TMT_MAT2;
|
||||
tmt[3] = TMT_TMAT;
|
||||
|
||||
for (i = 1; i < TMT_INIT_MIN_LOOP; i++)
|
||||
tmt[i & 3] ^= i + UINT32_C(1812433253) * (tmt[(i - 1) & 3]
|
||||
^ (tmt[(i - 1) & 3] >> 30));
|
||||
|
||||
if ((tmt[0] & 0x7fffffff) == 0 && tmt[1] == 0 && tmt[2] == 0 && tmt[3] == 0)
|
||||
{ /* Prevent all zero */
|
||||
tmt[0] = 'T';
|
||||
tmt[1] = 'I';
|
||||
tmt[2] = 'N';
|
||||
tmt[3] = 'Y';
|
||||
}
|
||||
|
||||
for (i = 0; i < TMT_INIT_PRE_LOOP; i++)
|
||||
tmt_one_step ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyMT one step function, call this every time before tmt_value.
|
||||
*/
|
||||
static void tmt_one_step (void)
|
||||
{
|
||||
uint32_t x, y;
|
||||
|
||||
y = tmt[3];
|
||||
x = (tmt[0] & 0x7fffffff) ^ tmt[1] ^ tmt[2];
|
||||
x ^= (x << 1);
|
||||
y ^= (y >> 1) ^ x;
|
||||
tmt[0] = tmt[1];
|
||||
tmt[1] = tmt[2];
|
||||
tmt[2] = x ^ (y << 10);
|
||||
tmt[3] = y;
|
||||
if ((y & 1))
|
||||
{
|
||||
tmt[1] ^= TMT_MAT1;
|
||||
tmt[2] ^= TMT_MAT2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a random word (32-bit).
|
||||
*/
|
||||
static uint32_t tmt_value (void)
|
||||
{
|
||||
uint32_t t0, t1;
|
||||
|
||||
t0 = tmt[3];
|
||||
t1 = tmt[0] + (tmt[2] >> 8);
|
||||
t0 ^= t1;
|
||||
if ((t1 & 1))
|
||||
t0 ^= TMT_TMAT;
|
||||
return t0;
|
||||
}
|
||||
|
||||
/* 8 parallel CRC-16 shift registers, with randomly rotated feedback */
|
||||
#define EPOOL_SIZE 16
|
||||
static uint8_t epool[EPOOL_SIZE]; /* Big-endian */
|
||||
static uint8_t ep_count;
|
||||
|
||||
/*
|
||||
* Magic number seven.
|
||||
*
|
||||
* We did an experiment of measuring entropy of ADC output with MUST.
|
||||
* The entropy of a byte by raw sampling of LSBs has more than 6.0 bit/byte.
|
||||
* So, it is considered OK to get 4-byte from 7-byte (6x7 = 42 > 32).
|
||||
*/
|
||||
#define NUM_NOISE_INPUTS 7
|
||||
|
||||
#define SHIFT_RIGHT(f) ((f)>>1)
|
||||
|
||||
static void ep_add (uint8_t entropy_bits, uint8_t another_random_bit)
|
||||
{
|
||||
uint8_t v = epool[ep_count];
|
||||
|
||||
/* CRC-16-CCITT's Polynomial is: x^16 + x^12 + x^5 + 1 */
|
||||
epool[(ep_count - 12)& 0x0f] ^= v;
|
||||
epool[(ep_count - 5)& 0x0f] ^= v;
|
||||
epool[ep_count] = SHIFT_RIGHT (v) ^ entropy_bits;
|
||||
|
||||
if ((v&1) || another_random_bit)
|
||||
epool[ep_count] ^= 0xff;
|
||||
|
||||
ep_count = (ep_count + 1) & 0x0f;
|
||||
}
|
||||
|
||||
#define FNV_INIT 2166136261U
|
||||
#define FNV_PRIME 16777619
|
||||
|
||||
static uint32_t fnv32_hash (const uint8_t *buf, int len)
|
||||
{
|
||||
uint32_t v = FNV_INIT;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
v ^= buf[i];
|
||||
v *= FNV_PRIME;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#define PROBABILITY_50_BY_TICK() ((SysTick->VAL & 0x02) != 0)
|
||||
|
||||
static uint32_t ep_output (void)
|
||||
{
|
||||
int i;
|
||||
uint8_t buf[NUM_NOISE_INPUTS];
|
||||
uint8_t *p = buf;
|
||||
|
||||
/*
|
||||
* NUM_NOISE_INPUTS is seven.
|
||||
*
|
||||
* There are sixteen bytes in the CRC-16 buffer. We use seven
|
||||
* outputs of CRC-16 buffer for final output. There are two parts;
|
||||
* former 4 outputs which will be used directly, and latter 3
|
||||
* outputs which will be used with feedback loop.
|
||||
*/
|
||||
|
||||
/* At some probability, use latter 3 outputs of CRC-16 buffer */
|
||||
for (i = NUM_NOISE_INPUTS - 1; i >= 4; i--)
|
||||
if (PROBABILITY_50_BY_TICK ())
|
||||
*p++ = epool[(ep_count+i) & 0x0f] ^ epool[(ep_count+i-4) & 0x0f];
|
||||
|
||||
/* Use former 4 outputs of CRC-16 buffer */
|
||||
for (i = 3; i >= 0; i--)
|
||||
*p++ = epool[(ep_count+i) & 0x0f];
|
||||
|
||||
return fnv32_hash (buf, p - buf);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Ring buffer, filled by generator, consumed by neug_get routine.
|
||||
*/
|
||||
struct rng_rb {
|
||||
uint32_t *buf;
|
||||
Mutex m;
|
||||
CondVar data_available;
|
||||
CondVar space_available;
|
||||
uint8_t head, tail;
|
||||
uint8_t size;
|
||||
unsigned int full :1;
|
||||
unsigned int empty :1;
|
||||
};
|
||||
|
||||
static void rb_init (struct rng_rb *rb, uint32_t *p, uint8_t size)
|
||||
{
|
||||
rb->buf = p;
|
||||
rb->size = size;
|
||||
chMtxInit (&rb->m);
|
||||
chCondInit (&rb->data_available);
|
||||
chCondInit (&rb->space_available);
|
||||
rb->head = rb->tail = 0;
|
||||
rb->full = 0;
|
||||
rb->empty = 1;
|
||||
}
|
||||
|
||||
static void rb_add (struct rng_rb *rb, uint32_t v)
|
||||
{
|
||||
rb->buf[rb->tail++] = v;
|
||||
if (rb->tail == rb->size)
|
||||
rb->tail = 0;
|
||||
if (rb->tail == rb->head)
|
||||
rb->full = 1;
|
||||
rb->empty = 0;
|
||||
}
|
||||
|
||||
static uint32_t rb_del (struct rng_rb *rb)
|
||||
{
|
||||
uint32_t v = rb->buf[rb->head++];
|
||||
|
||||
if (rb->head == rb->size)
|
||||
rb->head = 0;
|
||||
if (rb->head == rb->tail)
|
||||
rb->empty = 1;
|
||||
rb->full = 0;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Random number generation from ADC sampling.
|
||||
* @param RB: Pointer to ring buffer structure
|
||||
* @return -1 when failure, 0 otherwise.
|
||||
* @note Called holding the mutex, with RB->full == 0.
|
||||
* Keep generating until RB->full == 1.
|
||||
*/
|
||||
static int rng_gen (struct rng_rb *rb)
|
||||
{
|
||||
static uint8_t round = 0;
|
||||
uint8_t b;
|
||||
|
||||
while (1)
|
||||
{
|
||||
chEvtWaitOne (ADC_DATA_AVAILABLE);
|
||||
|
||||
/* Got, ADC sampling data */
|
||||
round++;
|
||||
b = (((samp[0] & 0x01) << 0) | ((samp[1] & 0x01) << 1)
|
||||
| ((samp[2] & 0x01) << 2) | ((samp[3] & 0x01) << 3)
|
||||
| ((samp[4] & 0x01) << 4) | ((samp[5] & 0x01) << 5)
|
||||
| ((samp[6] & 0x01) << 6) | ((samp[7] & 0x01) << 7));
|
||||
|
||||
adcStartConversion (&ADCD1, &adcgrpcfg, samp, ADC_GRP1_BUF_DEPTH, adccb);
|
||||
|
||||
/*
|
||||
* Put a random byte to entropy pool.
|
||||
*/
|
||||
ep_add (b, PROBABILITY_50_BY_TICK ());
|
||||
|
||||
if ((round % NUM_NOISE_INPUTS) == 0)
|
||||
{ /* We have enough entropy in the pool. */
|
||||
uint32_t v = ep_output (); /* Get the random bits from the pool. */
|
||||
|
||||
/* Mix the random bits from the pool with the output of PRNG. */
|
||||
tmt_one_step ();
|
||||
v ^= tmt_value ();
|
||||
|
||||
/* We got the final random bits, add it to the ring buffer. */
|
||||
rb_add (rb, v);
|
||||
round = 0;
|
||||
if (rb->full)
|
||||
/* fully generated */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Random number generation thread.
|
||||
*/
|
||||
static msg_t rng (void *arg)
|
||||
{
|
||||
struct rng_rb *rb = (struct rng_rb *)arg;
|
||||
|
||||
rng_thread = chThdSelf ();
|
||||
|
||||
adcStart (&ADCD1, NULL);
|
||||
adcStartConversion (&ADCD1, &adcgrpcfg, samp, ADC_GRP1_BUF_DEPTH, adccb);
|
||||
|
||||
while (1)
|
||||
{
|
||||
chMtxLock (&rb->m);
|
||||
while (rb->full)
|
||||
chCondWait (&rb->space_available);
|
||||
rng_gen (rb);
|
||||
chCondSignal (&rb->data_available);
|
||||
chMtxUnlock ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rng_rb the_ring_buffer;
|
||||
static WORKING_AREA(wa_rng, 128);
|
||||
|
||||
/**
|
||||
* @brief Initialize NeuG.
|
||||
*/
|
||||
void
|
||||
neug_init (uint32_t *buf, uint8_t size)
|
||||
{
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
|
||||
tmt_init (0);
|
||||
rb_init (rb, buf, size);
|
||||
chThdCreateStatic (wa_rng, sizeof (wa_rng), NORMALPRIO, rng, rb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @breif Flush random bytes.
|
||||
*/
|
||||
void
|
||||
neug_flush (void)
|
||||
{
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
|
||||
chMtxLock (&rb->m);
|
||||
while (!rb->empty)
|
||||
(void)rb_del (rb);
|
||||
chCondSignal (&rb->space_available);
|
||||
chMtxUnlock ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @breif Set seed to PRNG
|
||||
*/
|
||||
void
|
||||
neug_prng_reseed (void)
|
||||
{
|
||||
uint32_t seed = ep_output ();
|
||||
|
||||
tmt_init (seed);
|
||||
neug_flush ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wakes up RNG thread to generate random numbers.
|
||||
*/
|
||||
void
|
||||
neug_kick_filling (void)
|
||||
{
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
|
||||
chMtxLock (&rb->m);
|
||||
if (!rb->full)
|
||||
chCondSignal (&rb->space_available);
|
||||
chMtxUnlock ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get random word (32-bit) from NeuG.
|
||||
* @detail With NEUG_KICK_FILLING, it wakes up RNG thread.
|
||||
* With NEUG_NO_KICK, it doesn't wake up RNG thread automatically,
|
||||
* it is needed to call neug_kick_filling later.
|
||||
*/
|
||||
uint32_t
|
||||
neug_get (int kick)
|
||||
{
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
uint32_t v;
|
||||
|
||||
chMtxLock (&rb->m);
|
||||
while (rb->empty)
|
||||
chCondWait (&rb->data_available);
|
||||
v = rb_del (rb);
|
||||
if (kick)
|
||||
chCondSignal (&rb->space_available);
|
||||
chMtxUnlock ();
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
neug_wait_full (void)
|
||||
{
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
|
||||
chMtxLock (&rb->m);
|
||||
while (!rb->full)
|
||||
chCondWait (&rb->data_available);
|
||||
chMtxUnlock ();
|
||||
}
|
||||
11
src/neug.h
Normal file
11
src/neug.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#define NEUG_NO_KICK 0
|
||||
#define NEUG_KICK_FILLING 1
|
||||
|
||||
#define NEUG_PRE_LOOP 16
|
||||
|
||||
void neug_init (uint32_t *buf, uint8_t size);
|
||||
void neug_prng_reseed (void);
|
||||
uint32_t neug_get (int kick);
|
||||
void neug_kick_filling (void);
|
||||
void neug_flush (void);
|
||||
void neug_wait_full (void);
|
||||
@@ -62,13 +62,11 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = {
|
||||
};
|
||||
|
||||
void
|
||||
write_res_apdu (const uint8_t *p, int len, uint8_t sw1, uint8_t sw2)
|
||||
set_res_apdu (uint8_t sw1, uint8_t sw2)
|
||||
{
|
||||
res_APDU_size = 2 + len;
|
||||
if (len)
|
||||
memcpy (res_APDU, p, len);
|
||||
res_APDU[len] = sw1;
|
||||
res_APDU[len+1] = sw2;
|
||||
res_APDU_size = 2;
|
||||
res_APDU[0] = sw1;
|
||||
res_APDU[1] = sw2;
|
||||
}
|
||||
|
||||
#define FILE_NONE 0
|
||||
@@ -678,10 +676,14 @@ cmd_select_file (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
write_res_apdu (select_file_TOP_result,
|
||||
sizeof (select_file_TOP_result), 0x90, 0x00);
|
||||
int len = sizeof (select_file_TOP_result);
|
||||
|
||||
res_APDU_size = 2 + len;
|
||||
memcpy (res_APDU, select_file_TOP_result, len);
|
||||
res_APDU[2] = (data_objects_number_of_bytes & 0xff);
|
||||
res_APDU[3] = (data_objects_number_of_bytes >> 8);
|
||||
res_APDU[len] = 0x90;
|
||||
res_APDU[len+1] = 0x00;
|
||||
}
|
||||
|
||||
file_selection = FILE_MF;
|
||||
@@ -946,7 +948,7 @@ cmd_write_binary (void)
|
||||
{
|
||||
if (file_selection != FILE_EF_CH_CERTIFICATE
|
||||
&& file_selection != FILE_EF_RANDOM
|
||||
&& file_selection != FILEID_SERIAL_NO)
|
||||
&& file_selection != FILE_EF_SERIAL)
|
||||
{
|
||||
GPG_COMMAND_NOT_ALLOWED ();
|
||||
return;
|
||||
@@ -1026,12 +1028,9 @@ GPGthread (void *arg)
|
||||
|
||||
while (!chThdShouldTerminate ())
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
m = chEvtWaitOne (ALL_EVENTS);
|
||||
chEvtWaitOne (ALL_EVENTS);
|
||||
|
||||
DEBUG_INFO ("GPG!: ");
|
||||
DEBUG_WORD ((uint32_t)&m);
|
||||
|
||||
res_APDU_pointer = NULL; /* default */
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#define GPG_MEMORY_FAILURE() write_res_apdu (NULL, 0, 0x65, 0x81)
|
||||
#define GPG_SECURITY_FAILURE() write_res_apdu (NULL, 0, 0x69, 0x82)
|
||||
#define GPG_SECURITY_AUTH_BLOCKED() write_res_apdu (NULL, 0, 0x69, 0x83)
|
||||
#define GPG_COMMAND_NOT_ALLOWED() write_res_apdu (NULL, 0, 0x69, 0x86)
|
||||
#define GPG_NO_FILE() write_res_apdu (NULL, 0, 0x6a, 0x82)
|
||||
#define GPG_NO_RECORD() write_res_apdu (NULL, 0, 0x6a, 0x88)
|
||||
#define GPG_BAD_P0_P1() write_res_apdu (NULL, 0, 0x6b, 0x00)
|
||||
#define GPG_NO_INS() write_res_apdu (NULL, 0, 0x6d, 0x00)
|
||||
#define GPG_ERROR() write_res_apdu (NULL, 0, 0x6f, 0x00)
|
||||
#define GPG_SUCCESS() write_res_apdu (NULL, 0, 0x90, 0x00)
|
||||
#define GPG_MEMORY_FAILURE() set_res_apdu (0x65, 0x81)
|
||||
#define GPG_SECURITY_FAILURE() set_res_apdu (0x69, 0x82)
|
||||
#define GPG_SECURITY_AUTH_BLOCKED() set_res_apdu (0x69, 0x83)
|
||||
#define GPG_COMMAND_NOT_ALLOWED() set_res_apdu (0x69, 0x86)
|
||||
#define GPG_NO_FILE() set_res_apdu (0x6a, 0x82)
|
||||
#define GPG_NO_RECORD() set_res_apdu (0x6a, 0x88)
|
||||
#define GPG_BAD_P0_P1() set_res_apdu (0x6b, 0x00)
|
||||
#define GPG_NO_INS() set_res_apdu (0x6d, 0x00)
|
||||
#define GPG_ERROR() set_res_apdu (0x6f, 0x00)
|
||||
#define GPG_SUCCESS() set_res_apdu (0x90, 0x00)
|
||||
|
||||
57
src/random.c
57
src/random.c
@@ -24,6 +24,23 @@
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "gnuk.h"
|
||||
#include "neug.h"
|
||||
|
||||
#define RANDOM_BYTES_LENGTH 16
|
||||
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
|
||||
|
||||
void
|
||||
random_init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
|
||||
|
||||
for (i = 0; i < NEUG_PRE_LOOP; i++)
|
||||
(void)neug_get (NEUG_KICK_FILLING);
|
||||
|
||||
neug_prng_reseed ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointer to random 16-byte
|
||||
@@ -31,25 +48,8 @@
|
||||
const uint8_t *
|
||||
random_bytes_get (void)
|
||||
{
|
||||
uint32_t addr, addr0;
|
||||
|
||||
addr = (uint32_t)&random_bits_start + ((hardclock () << 4) & 0x3f0);
|
||||
addr0 = addr;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (*(uint32_t *)addr != 0 && *(uint32_t *)addr != 0xffffffff)
|
||||
break;
|
||||
|
||||
addr += 16;
|
||||
if (addr >= ((uint32_t)&random_bits_start) + 1024)
|
||||
addr = ((uint32_t)&random_bits_start);
|
||||
|
||||
if (addr == addr0)
|
||||
fatal (FATAL_RANDOM);
|
||||
}
|
||||
|
||||
return (const uint8_t *)addr;
|
||||
neug_wait_full ();
|
||||
return (const uint8_t *)random_word;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -58,11 +58,8 @@ random_bytes_get (void)
|
||||
void
|
||||
random_bytes_free (const uint8_t *p)
|
||||
{
|
||||
int i;
|
||||
uint32_t addr = (uint32_t)p;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
flash_clear_halfword (addr+i*2);
|
||||
(void)p;
|
||||
neug_flush ();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -71,15 +68,5 @@ random_bytes_free (const uint8_t *p)
|
||||
uint32_t
|
||||
get_salt (void)
|
||||
{
|
||||
const uint8_t *u = unique_device_id (); /* 12-byte unique id */
|
||||
uint32_t r = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
r <<= 8;
|
||||
r |= u[hardclock () % 12];
|
||||
}
|
||||
|
||||
return r;
|
||||
return neug_get (NEUG_KICK_FILLING);
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ static const uint8_t gnukStringProduct[] = {
|
||||
const uint8_t gnukStringSerial[] = {
|
||||
13*2+2, /* bLength */
|
||||
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
'0', 0, '.', 0, '1', 0, '2', 0, /* Version number of Gnuk */
|
||||
'0', 0, '.', 0, '1', 0, '4', 0, /* Version number of Gnuk */
|
||||
'-', 0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
||||
@@ -107,6 +107,13 @@ def main(fileid, is_update, data, passwd):
|
||||
gnuk.cmd_select_openpgp()
|
||||
data_in_device = gnuk.cmd_get_data(0x7f, 0x21)
|
||||
compare(data[:-2], data_in_device)
|
||||
elif fileid == 2:
|
||||
gnuk.cmd_select_openpgp()
|
||||
data_in_device = gnuk.cmd_get_data(0x00, 0x4f)
|
||||
for d in data_in_device:
|
||||
print "%02x" % d,
|
||||
print
|
||||
compare(data, data_in_device[8:])
|
||||
|
||||
gnuk.connection.disconnect()
|
||||
return 0
|
||||
|
||||
256
tool/hub_ctrl.py
Executable file
256
tool/hub_ctrl.py
Executable file
@@ -0,0 +1,256 @@
|
||||
#! /usr/bin/python
|
||||
|
||||
"""
|
||||
hub_ctrl.py - a tool to control port power/led of USB hub
|
||||
|
||||
Copyright (C) 2006, 2011 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/>.
|
||||
"""
|
||||
|
||||
import usb
|
||||
|
||||
USB_RT_HUB = (usb.TYPE_CLASS | usb.RECIP_DEVICE)
|
||||
USB_RT_PORT = (usb.TYPE_CLASS | usb.RECIP_OTHER)
|
||||
USB_PORT_FEAT_RESET = 4
|
||||
USB_PORT_FEAT_POWER = 8
|
||||
USB_PORT_FEAT_INDICATOR = 22
|
||||
USB_DIR_IN = 0x80 # device to host
|
||||
|
||||
COMMAND_SET_NONE = 0
|
||||
COMMAND_SET_LED = 1
|
||||
COMMAND_SET_POWER = 2
|
||||
|
||||
HUB_LED_GREEN = 2
|
||||
|
||||
def find_hubs(listing, verbose, busnum=None, devnum=None, hub=None):
|
||||
number_of_hubs_with_feature = 0
|
||||
hubs = []
|
||||
busses = usb.busses()
|
||||
if not busses:
|
||||
raise ValueError, "can't access USB"
|
||||
|
||||
for bus in busses:
|
||||
devices = bus.devices
|
||||
for dev in devices:
|
||||
if dev.deviceClass != usb.CLASS_HUB:
|
||||
continue
|
||||
|
||||
printout_enable = 0
|
||||
if (listing
|
||||
or (verbose
|
||||
and ((bus.dirname == busnum and dev.devnum == devnumd)
|
||||
or hub == number_of_hubs_with_feature))):
|
||||
printout_enable = 1
|
||||
|
||||
uh = dev.open()
|
||||
|
||||
desc = None
|
||||
try:
|
||||
# Get USB Hub descriptor
|
||||
desc = uh.controlMsg(requestType = USB_DIR_IN | USB_RT_HUB,
|
||||
request = usb.REQ_GET_DESCRIPTOR,
|
||||
value = usb.DT_HUB << 8,
|
||||
index = 0, buffer = 1024, timeout = 1000)
|
||||
finally:
|
||||
del uh
|
||||
|
||||
if not desc:
|
||||
continue
|
||||
|
||||
# desc[3] is lower byte of wHubCharacteristics
|
||||
if (desc[3] & 0x80) == 0 and (desc[3] & 0x03) >= 2:
|
||||
# Hub doesn't have features of controling port power/indicator
|
||||
continue
|
||||
|
||||
if printout_enable:
|
||||
print "Hub #%d at %s:%03d" % (number_of_hubs_with_feature,
|
||||
bus.dirname, dev.devnum)
|
||||
if (desc[3] & 0x03) == 0:
|
||||
print " INFO: ganged power switching."
|
||||
elif (desc[3] & 0x03) == 1:
|
||||
print " INFO: individual power switching."
|
||||
elif (desc[3] & 0x03) == 2 or (desc[3] & 0x03) == 3:
|
||||
print " WARN: no power switching."
|
||||
|
||||
if (desc[3] & 0x80) == 0:
|
||||
print " WARN: Port indicators are NOT supported."
|
||||
|
||||
hubs.append({ 'busnum' : bus.dirname, 'devnum' : dev.devnum,
|
||||
'indicator_support' : (desc[3] & 0x80) == 0x80,
|
||||
'dev' : dev, 'num_ports' : desc[2] })
|
||||
number_of_hubs_with_feature += 1
|
||||
|
||||
return hubs
|
||||
|
||||
def hub_port_status(handle, num_ports):
|
||||
print " Hub Port Status:"
|
||||
for i in range(num_ports):
|
||||
port = i + 1
|
||||
status = handle.controlMsg(requestType = USB_RT_PORT | usb.ENDPOINT_IN,
|
||||
request = usb.REQ_GET_STATUS,
|
||||
value = 0,
|
||||
index = port, buffer = 4,
|
||||
timeout = 1000)
|
||||
|
||||
print " Port %d: %02x%02x.%02x%02x" % (port, status[3], status[2],
|
||||
status[1], status[0]),
|
||||
if status[1] & 0x10:
|
||||
print " indicator",
|
||||
if status[1] & 0x08:
|
||||
print " test" ,
|
||||
if status[1] & 0x04:
|
||||
print " highspeed",
|
||||
if status[1] & 0x02:
|
||||
print " lowspeed",
|
||||
if status[1] & 0x01:
|
||||
print " power",
|
||||
|
||||
if status[0] & 0x10:
|
||||
print " RESET",
|
||||
if status[0] & 0x08:
|
||||
print " oc",
|
||||
if status[0] & 0x04:
|
||||
print " suspend",
|
||||
if status[0] & 0x02:
|
||||
print " enable",
|
||||
if status[0] & 0x01:
|
||||
print " connect",
|
||||
|
||||
print
|
||||
|
||||
import sys
|
||||
|
||||
COMMAND_SET_NONE = 0
|
||||
COMMAND_SET_LED = 1
|
||||
COMMAND_SET_POWER = 2
|
||||
HUB_LED_GREEN = 2
|
||||
|
||||
def usage(progname):
|
||||
print >> sys.stderr, """Usage: %s [{-h HUBNUM | -b BUSNUM -d DEVNUM}]
|
||||
[-P PORT] [{-p [VALUE]|-l [VALUE]}]
|
||||
""" % progname
|
||||
|
||||
def exit_with_usage(progname):
|
||||
usage(progname)
|
||||
exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
busnum = None
|
||||
devnum = None
|
||||
listing = False
|
||||
verbose = False
|
||||
hub = None
|
||||
port = 1
|
||||
cmd = COMMAND_SET_NONE
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
listing = True
|
||||
else:
|
||||
try:
|
||||
while len(sys.argv) >= 2:
|
||||
option = sys.argv[1]
|
||||
sys.argv.pop(1)
|
||||
if option == '-h':
|
||||
if bunum != None or devnum != None:
|
||||
exit_with_usage(sys.argv[0])
|
||||
hub = int(sys.argv[1])
|
||||
sys.argv.pop(1)
|
||||
elif option == '-b':
|
||||
busnum = int(sys.argv[1])
|
||||
sys.argv.pop(1)
|
||||
elif option == '-d':
|
||||
devnum = int(sys.argv[1])
|
||||
sys.argv.pop(1)
|
||||
elif option == '-P':
|
||||
port = int(sys.argv[1])
|
||||
sys.argv.pop(1)
|
||||
elif option == '-l':
|
||||
if cmd != COMMAND_SET_NONE:
|
||||
exit_with_usage(sys.argv[0])
|
||||
if len(sys.argv) > 1:
|
||||
value = int(sys.argv[1])
|
||||
sys.argv.pop(1)
|
||||
else:
|
||||
value = HUB_LED_GREEN
|
||||
cmd = COMMAND_SET_LED
|
||||
elif option == '-p':
|
||||
if cmd != COMMAND_SET_NONE:
|
||||
exit_with_usage(sys.argv[0])
|
||||
if len(sys.argv) > 1:
|
||||
value = int(sys.argv[1])
|
||||
sys.argv.pop(1)
|
||||
else:
|
||||
value = 0
|
||||
cmd = COMMAND_SET_POWER
|
||||
elif option == '-v':
|
||||
verbose = True
|
||||
if len(sys.argv) == 1:
|
||||
listing = True
|
||||
else:
|
||||
exit_with_usage(sys.argv[0])
|
||||
except:
|
||||
exit_with_usage(sys.argv[0])
|
||||
|
||||
if ((busnum != None and devnum == None)
|
||||
or (busnum == None and devnum != None)):
|
||||
exit_with_usage(sys.argv[0])
|
||||
|
||||
if hub == None and busnum == None:
|
||||
hub = 0 # Default hub = 0
|
||||
|
||||
if cmd == COMMAND_SET_NONE:
|
||||
cmd = COMMAND_SET_POWER
|
||||
|
||||
hubs = find_hubs(listing, verbose, busnum, devnum, hub)
|
||||
if len(hubs) == 0:
|
||||
print >> sys.stderr, "No hubs found."
|
||||
exit(1)
|
||||
if listing:
|
||||
exit(0)
|
||||
|
||||
if hub == None:
|
||||
for h in hubs:
|
||||
if h['busnum'] == busnum and h['devnum'] == devnum:
|
||||
dev_hub = h['dev']
|
||||
nports = h['num_ports']
|
||||
else:
|
||||
dev_hub = hubs[hub]['dev']
|
||||
nports = hubs[hub]['num_ports']
|
||||
|
||||
uh = dev_hub.open()
|
||||
if cmd == COMMAND_SET_POWER:
|
||||
feature = USB_PORT_FEAT_POWER
|
||||
index = port
|
||||
if value:
|
||||
request = usb.REQ_SET_FEATURE
|
||||
else:
|
||||
request = usb.REQ_CLEAR_FEATURE
|
||||
else:
|
||||
request = usb.REQ_SET_FEATURE
|
||||
feature = USB_PORT_FEAT_INDICATOR
|
||||
index = (value << 8) | port
|
||||
if verbose:
|
||||
print "Send control message (REQUEST=%d, FEATURE=%d, INDEX=%d) " % (request, feature, index)
|
||||
|
||||
uh.controlMsg(requestType = USB_RT_PORT, request = request, value = feature,
|
||||
index = index, buffer = None, timeout = 1000)
|
||||
if verbose:
|
||||
hub_port_status(uh,nports)
|
||||
|
||||
del uh
|
||||
Reference in New Issue
Block a user