Compare commits
117 Commits
Author | SHA1 | Date | |
---|---|---|---|
2af747ddaa | |||
9ead11de8d | |||
f17faca689 | |||
ca66b6e43b | |||
1cd1b3c295 | |||
df2cff2350 | |||
f5d50e001d | |||
235785b225 | |||
303c42901a | |||
df2f950e69 | |||
10bf4242e1 | |||
9e95b0075c | |||
ddbe31776c | |||
645ca6a5a0 | |||
15fc39faed | |||
a1eedc0048 | |||
89e00482e4 | |||
533ce39237 | |||
63ee003535 | |||
fa9408d5d6 | |||
ed9689435d | |||
24a006068d | |||
315b6564ab | |||
4d9285085f | |||
2272e69e15 | |||
151e1d0e9b | |||
d1df8b8b77 | |||
cb76c34ed2 | |||
f2ebaf6abe | |||
4845d2c172 | |||
75b1d9cd01 | |||
26bc8a2889 | |||
88a8eba424 | |||
d2c85881e6 | |||
236498ee03 | |||
a51c9192b1 | |||
4dc6bcf771 | |||
cce81b23d9 | |||
8c2e2386a9 | |||
c783a1442a | |||
b61e5db736 | |||
b41cd5d5b8 | |||
b42e990f67 | |||
ff53bb1e32 | |||
2d72e02051 | |||
91c77da179 | |||
795cf5c4a1 | |||
d1722b85af | |||
2c500fe25a | |||
751b2fd69c | |||
c2216929a9 | |||
3f225f362f | |||
dd4ff920ad | |||
bddd60c080 | |||
5f878ff022 | |||
14f91a6e15 | |||
cd29a0e0fe | |||
46b7f9a778 | |||
31328fe7e7 | |||
035b1a8632 | |||
b1563dbe94 | |||
2a9e3ac576 | |||
e1474e8e8e | |||
1564df5305 | |||
1f3db3fe51 | |||
36876e1528 | |||
0f50ae7d63 | |||
4854192c63 | |||
e105afd647 | |||
9fb02d4da3 | |||
e402d36bf1 | |||
54792b345c | |||
84740f3d6a | |||
4ac61f7f18 | |||
30cfa46186 | |||
aca28fde61 | |||
60e3d01e0d | |||
aff8d10432 | |||
898d45f871 | |||
2b2835b823 | |||
f9202b2b6a | |||
1b74f6a93b | |||
0dfda6fce2 | |||
09b73d694f | |||
9ab5e761c3 | |||
b3604f49ba | |||
6ae1cd3865 | |||
f9d3b9561d | |||
ec98af115f | |||
fecf258116 | |||
437f691d12 | |||
55aadfd78e | |||
813eb97d2f | |||
32afdccfb3 | |||
41ae0e4a2c | |||
b0baace2e7 | |||
6ff4200f5d | |||
1fab0b8f1f | |||
ce96fffddd | |||
4fb25e165a | |||
8fc0da7934 | |||
494e856198 | |||
472b094acb | |||
e0ce23034f | |||
5f3974a4e6 | |||
26adac1730 | |||
eab8b81c95 | |||
325396d518 | |||
6d04c86018 | |||
56d6624e4e | |||
3094c87b0a | |||
212f98e384 | |||
73f538dd0e | |||
a5f794c0ff | |||
f28cf9c6d0 | |||
6a288243c1 | |||
955d4f76ef |
2
.gitignore
vendored
2
.gitignore
vendored
@ -83,3 +83,5 @@ targets/*/docs/
|
||||
main
|
||||
|
||||
builds/*
|
||||
tools/testing/.idea/*
|
||||
tools/testing/tests/__pycache__/*
|
||||
|
35
CHANGELOG.md
35
CHANGELOG.md
@ -1,35 +0,0 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.0] - 2019-02-17
|
||||
### Added
|
||||
- Code cleanup
|
||||
- Buffer over-read bug fix
|
||||
- U2F counter endianness bug fix
|
||||
- More testing
|
||||
- Extension interface to U2F and FIDO2
|
||||
- Read firmware version
|
||||
- Read RNG bytes
|
||||
|
||||
## [1.1.1] - 2019-03-01
|
||||
|
||||
- This version fixes an incorrect error code returned in U2F.
|
||||
|
||||
## [2.0.0] - 2019-03-01
|
||||
|
||||
- Merge of NFC functionality branch
|
||||
- Bug fix with compiled USB name being too long causing buffer overrun
|
||||
- Change upper byte of counter from `0xff` to `0x7f` to fix issues with some websites.
|
||||
|
||||
## [2.1.0] - 2019-03-31
|
||||
|
||||
WARNING: This update may break previous registrations! This is because we fixed the U2F counter for good (rather than arbitrarily set the upper byte high for backwards-compatibility reasons, which ends up causing other issues).
|
||||
|
||||
- Adds hmac-secret extension support. This extension is used for generating 32 or 64 byte symmetric keys using parameters from the platform and secrets on the authenticator. It's used by Windows Hello - - for offline authentication.
|
||||
- Fix bug in FIDO auth, where setting the pin requires all previous registrations to use pin. Only UV bit needs to be cleared.
|
||||
- Slightly change serial emulation USB descriptor to make it less abused by Linux Modem Manager.
|
4
Makefile
4
Makefile
@ -32,7 +32,7 @@ VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
|
||||
VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \
|
||||
-DSOLO_VERSION_PATCH=$(VERSION_PAT) -DSOLO_VERSION=\"$(VERSION_FULL)\"
|
||||
|
||||
CFLAGS = -O2 -fdata-sections -ffunction-sections $(VERSION_FLAGS)
|
||||
CFLAGS = -O2 -fdata-sections -ffunction-sections $(VERSION_FLAGS) -g
|
||||
|
||||
INCLUDES = -I./tinycbor/src -I./crypto/sha256 -I./crypto/micro-ecc/ -Icrypto/tiny-AES-c/ -I./fido2/ -I./pc -I./fido2/extensions
|
||||
INCLUDES += -I./crypto/cifra/src
|
||||
@ -53,7 +53,7 @@ tinycbor/Makefile crypto/tiny-AES-c/aes.c:
|
||||
cbor: $(LIBCBOR)
|
||||
|
||||
$(LIBCBOR):
|
||||
cd tinycbor/ && $(MAKE) clean && $(MAKE) -j8
|
||||
cd tinycbor/ && $(MAKE) clean && $(MAKE) LDFLAGS='' -j8
|
||||
|
||||
version:
|
||||
@git describe
|
||||
|
@ -17,7 +17,7 @@ Solo is an open source security key, and you can get one at [solokeys.com](https
|
||||
|
||||
Solo supports FIDO2 and U2F standards for strong two-factor authentication and password-less login, and it will protect you against phishing and other online attacks. With colored cases and multilingual guides we want to make secure login more personable and accessible to everyone around the globe.
|
||||
|
||||
<img src="https://solokeys.com/images/photos/hero-on-white-cropped.png" width="600">
|
||||
<img src="https://static.solokeys.com/images/photos/hero-on-white-cropped.png" width="600">
|
||||
|
||||
This repo contains the Solo firmware, including implementations of FIDO2 and U2F (CTAP2 and CTAP) over USB and NFC. The main implementation is for STM32L432, but it is easily portable.
|
||||
|
||||
|
32
SECURITY.md
Normal file
32
SECURITY.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We fix security issues as soon as they are found, and release firmware updates.
|
||||
Each such release is accompanied by release notes, see <https://github.com/solokeys/solo/releases>.
|
||||
|
||||
The latest version can be determined using the file <https://github.com/solokeys/solo/blob/master/STABLE_VERSION>.
|
||||
|
||||
To update your key:
|
||||
- either visit <https://update.solokeys.com>, or
|
||||
- use our commandline tool <https://github.com/solokeys/solo-python>:
|
||||
```
|
||||
solo key update [--secure|--hacker]
|
||||
```
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report vulnerabilities you have found:
|
||||
|
||||
- preferably contact [@conor1](https://keybase.io/conor1), [@0x0ece](https://keybase.io/0x0ece) or [@nickray](https://keybase.io/nickray) via Keybase, or
|
||||
- send us e-mail using OpenPGP to [security@solokeys.com](mailto:security@solokeys.com).
|
||||
|
||||
<https://keys.openpgp.org/vks/v1/by-fingerprint/85AFA2769F4381E5712C36A04DDFC46FEF1F7F3F>
|
||||
|
||||
We do not currently run a paid bug bounty program, but are happy to provide you with a bunch of Solo keys in recognition of your findings.
|
||||
|
||||
## Mailing List
|
||||
|
||||
Join our release notification mailing list to be informed about each release:
|
||||
|
||||
https://sendy.solokeys.com/subscription?f=9MLIqMDmox1Ucz89C892Kq09IqYMM7OB8UrBrkvtTkDI763QF3L5PMYlRhlVNo2AI892mO
|
@ -1 +1 @@
|
||||
2.1.0
|
||||
2.4.0
|
||||
|
@ -1,22 +1,40 @@
|
||||
# Building solo
|
||||
|
||||
To build, develop and debug the firmware for the STM32L432. This will work
|
||||
for Solo Hacker, the Nucleo development board, or your own homemade Solo.
|
||||
|
||||
There exists a development board [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) you can use; The board does contain a debugger, so all you need is a USB cable (and some [udev](/udev) [rules](https://rust-embedded.github.io/book/intro/install/linux.html#udev-rules)).
|
||||
|
||||
# Prerequisites
|
||||
## Prerequisites
|
||||
|
||||
Install the [latest ARM compiler toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) for your system. We recommend getting the latest compilers from ARM.
|
||||
|
||||
You can also install the ARM toolchain using a package manager like `apt-get` or `pacman`,
|
||||
but be warned they might be out of date. Typically it will be called `gcc-arm-none-eabi binutils-arm-none-eabi`.
|
||||
|
||||
Install `solo-python` usually with `pip3 install solo-python`. The `solo` python application may also be used for [programming](#programming).
|
||||
|
||||
To program your build, you'll need one of the following programs.
|
||||
|
||||
- [openocd](http://openocd.org)
|
||||
- [stlink](https://github.com/texane/stlink)
|
||||
- [STM32CubeProg](https://www.st.com/en/development-tools/stm32cubeprog.html)
|
||||
- [openocd](http://openocd.org)
|
||||
- [stlink](https://github.com/texane/stlink)
|
||||
- [STM32CubeProg](https://www.st.com/en/development-tools/stm32cubeprog.html)
|
||||
|
||||
# Compilation
|
||||
## Obtain source code and solo tool
|
||||
|
||||
Source code can be downloaded from:
|
||||
|
||||
- [github releases list](https://github.com/solokeys/solo/releases)
|
||||
- [github repository](https://github.com/solokeys/solo)
|
||||
|
||||
**solo** tool can be downloaded from:
|
||||
|
||||
- from python programs [repository](https://pypi.org/project/solo-python/) `pip install solo-python`
|
||||
- from installing prerequisites `pip3 install -r tools/requirements.txt`
|
||||
- github repository: [repository](https://github.com/solokeys/solo-python)
|
||||
- installation python enviroment witn command `make venv` from root directory of source code
|
||||
|
||||
## Compilation
|
||||
|
||||
Enter the `stm32l4xx` target directory.
|
||||
|
||||
@ -80,8 +98,7 @@ make build-release-locked
|
||||
|
||||
Programming `all.hex` will cause the device to permanently lock itself.
|
||||
|
||||
|
||||
# Programming
|
||||
## Programming
|
||||
|
||||
It's recommended to test a debug/hacker build first to make sure Solo is working as expected.
|
||||
Then you can switch to a locked down build, which cannot be reprogrammed as easily (or not at all!).
|
||||
@ -95,7 +112,7 @@ pip3 install -r tools/requirements.txt
|
||||
|
||||
If you're on Windows, you must also install [libusb](https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/).
|
||||
|
||||
## Pre-programmed Solo Hacker
|
||||
### Pre-programmed Solo Hacker
|
||||
|
||||
If your Solo device is already programmed (it flashes green when powered), we recommend
|
||||
programming it using the Solo bootloader.
|
||||
@ -118,7 +135,7 @@ If something bad happens, you can always boot the Solo bootloader by doing the f
|
||||
If you hold the button for an additional 5 seconds, it will boot to the ST DFU (device firmware update).
|
||||
Don't use the ST DFU unless you know what you're doing.
|
||||
|
||||
## ST USB DFU
|
||||
### ST USB DFU
|
||||
|
||||
If your Solo has never been programmed, it will boot the ST USB DFU. The LED is turned
|
||||
off and it enumerates as "STM BOOTLOADER".
|
||||
@ -136,7 +153,7 @@ Make sure to program `all.hex`, as this contains both the bootloader and the Sol
|
||||
|
||||
If all goes well, you should see a slow-flashing green light.
|
||||
|
||||
## Solo Hacker vs Solo
|
||||
### Solo Hacker vs Solo
|
||||
|
||||
A Solo hacker device doesn't need to be in bootloader mode to be programmed, it will automatically switch.
|
||||
|
||||
@ -144,7 +161,7 @@ Solo (locked) needs the button to be held down when plugged in to boot to the bo
|
||||
|
||||
A locked Solo will only accept signed updates.
|
||||
|
||||
## Signed updates
|
||||
### Signed updates
|
||||
|
||||
If this is not a device with a hacker build, you can only program signed updates.
|
||||
|
||||
@ -162,7 +179,7 @@ solo sign /path/to/signing-key.pem /path/to/solo.hex /output-path/to/firmware.js
|
||||
If your Solo isn't locked, you can always reprogram it using a debugger connected directly
|
||||
to the token.
|
||||
|
||||
# Permanently locking the device
|
||||
## Permanently locking the device
|
||||
|
||||
If you plan to be using your Solo for real, you should lock it permanently. This prevents
|
||||
someone from connecting a debugger to your token and stealing credentials.
|
||||
|
BIN
docs/solo/images/conforms.PNG
Normal file
BIN
docs/solo/images/conforms.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
BIN
docs/solo/images/solo_conforms.PNG
Normal file
BIN
docs/solo/images/solo_conforms.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 129 KiB |
122
fido2/apdu.c
Normal file
122
fido2/apdu.c
Normal file
@ -0,0 +1,122 @@
|
||||
// Copyright 2019 SoloKeys Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
// iso7816:2013. 5.3.2 Decoding conventions for command bodies
|
||||
|
||||
#include "apdu.h"
|
||||
|
||||
int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
|
||||
{
|
||||
EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data;
|
||||
|
||||
apdu->cla = hapdu->cla;
|
||||
apdu->ins = hapdu->ins;
|
||||
apdu->p1 = hapdu->p1;
|
||||
apdu->p2 = hapdu->p2;
|
||||
|
||||
apdu->lc = 0;
|
||||
apdu->data = NULL;
|
||||
apdu->le = 0;
|
||||
apdu->extended_apdu = false;
|
||||
apdu->case_type = 0x00;
|
||||
|
||||
uint8_t b0 = hapdu->lc[0];
|
||||
|
||||
// case 1
|
||||
if (len == 4)
|
||||
{
|
||||
apdu->case_type = 0x01;
|
||||
}
|
||||
|
||||
// case 2S (Le)
|
||||
if (len == 5)
|
||||
{
|
||||
apdu->case_type = 0x02;
|
||||
apdu->le = b0;
|
||||
if (!apdu->le)
|
||||
apdu->le = 0x100;
|
||||
}
|
||||
|
||||
// case 3S (Lc + data)
|
||||
if (len == 5U + b0 && b0 != 0)
|
||||
{
|
||||
apdu->case_type = 0x03;
|
||||
apdu->lc = b0;
|
||||
}
|
||||
|
||||
// case 4S (Lc + data + Le)
|
||||
if (len == 5U + b0 + 1U && b0 != 0)
|
||||
{
|
||||
apdu->case_type = 0x04;
|
||||
apdu->lc = b0;
|
||||
apdu->le = data[len - 1];
|
||||
if (!apdu->le)
|
||||
apdu->le = 0x100;
|
||||
}
|
||||
|
||||
// extended length apdu
|
||||
if (len >= 7 && b0 == 0)
|
||||
{
|
||||
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
|
||||
|
||||
// case 2E (Le) - extended
|
||||
if (len == 7)
|
||||
{
|
||||
apdu->case_type = 0x12;
|
||||
apdu->extended_apdu = true;
|
||||
apdu->le = extlen;
|
||||
if (!apdu->le)
|
||||
apdu->le = 0x10000;
|
||||
}
|
||||
|
||||
// case 3E (Lc + data) - extended
|
||||
if (len == 7U + extlen)
|
||||
{
|
||||
apdu->case_type = 0x13;
|
||||
apdu->extended_apdu = true;
|
||||
apdu->lc = extlen;
|
||||
}
|
||||
|
||||
// case 4E (Lc + data + Le) - extended 2-byte Le
|
||||
if (len == 7U + extlen + 2U)
|
||||
{
|
||||
apdu->case_type = 0x14;
|
||||
apdu->extended_apdu = true;
|
||||
apdu->lc = extlen;
|
||||
apdu->le = (data[len - 2] << 8) + data[len - 1];
|
||||
if (!apdu->le)
|
||||
apdu->le = 0x10000;
|
||||
}
|
||||
|
||||
// case 4E (Lc + data + Le) - extended 3-byte Le
|
||||
if (len == 7U + extlen + 3U && data[len - 3] == 0)
|
||||
{
|
||||
apdu->case_type = 0x24;
|
||||
apdu->extended_apdu = true;
|
||||
apdu->lc = extlen;
|
||||
apdu->le = (data[len - 2] << 8) + data[len - 1];
|
||||
if (!apdu->le)
|
||||
apdu->le = 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
if (!apdu->case_type)
|
||||
return 1;
|
||||
|
||||
if (apdu->lc)
|
||||
{
|
||||
if (apdu->extended_apdu)
|
||||
{
|
||||
apdu->data = data + 7;
|
||||
} else {
|
||||
apdu->data = data + 5;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
27
fido2/apdu.h
27
fido2/apdu.h
@ -2,6 +2,8 @@
|
||||
#define _APDU_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -12,6 +14,30 @@ typedef struct
|
||||
uint8_t lc;
|
||||
} __attribute__((packed)) APDU_HEADER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cla;
|
||||
uint8_t ins;
|
||||
uint8_t p1;
|
||||
uint8_t p2;
|
||||
uint8_t lc[3];
|
||||
} __attribute__((packed)) EXT_APDU_HEADER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cla;
|
||||
uint8_t ins;
|
||||
uint8_t p1;
|
||||
uint8_t p2;
|
||||
uint16_t lc;
|
||||
uint8_t *data;
|
||||
uint32_t le;
|
||||
bool extended_apdu;
|
||||
uint8_t case_type;
|
||||
} __attribute__((packed)) APDU_STRUCT;
|
||||
|
||||
extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
|
||||
|
||||
#define APDU_FIDO_U2F_REGISTER 0x01
|
||||
#define APDU_FIDO_U2F_AUTHENTICATE 0x02
|
||||
#define APDU_FIDO_U2F_VERSION 0x03
|
||||
@ -25,6 +51,7 @@ typedef struct
|
||||
#define SW_COND_USE_NOT_SATISFIED 0x6985
|
||||
#define SW_FILE_NOT_FOUND 0x6a82
|
||||
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
|
||||
#define SW_CLA_INVALID 0x6e00
|
||||
#define SW_INTERNAL_EXCEPTION 0x6f00
|
||||
|
||||
#endif //_APDU_H_
|
||||
|
@ -16,7 +16,7 @@
|
||||
#define COSE_KEY_KTY_EC2 2
|
||||
#define COSE_KEY_CRV_P256 1
|
||||
|
||||
|
||||
#define COSE_ALG_ES256 -7
|
||||
#define COSE_ALG_ES256 -7
|
||||
#define COSE_ALG_ECDH_ES_HKDF_256 -25
|
||||
|
||||
#endif
|
||||
|
@ -38,6 +38,7 @@ void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, ui
|
||||
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey);
|
||||
void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret);
|
||||
|
||||
#define CRYPTO_TRANSPORT_KEY2 ((uint8_t*)2)
|
||||
#define CRYPTO_TRANSPORT_KEY ((uint8_t*)1)
|
||||
#define CRYPTO_MASTER_KEY ((uint8_t*)0)
|
||||
|
||||
|
108
fido2/ctap.c
108
fido2/ctap.c
@ -36,16 +36,7 @@ AuthenticatorState STATE;
|
||||
|
||||
static void ctap_reset_key_agreement();
|
||||
|
||||
static struct {
|
||||
CTAP_authDataHeader authData;
|
||||
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
||||
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE-1];
|
||||
uint8_t lastcmd;
|
||||
uint32_t count;
|
||||
uint32_t index;
|
||||
uint32_t time;
|
||||
uint8_t user_verified;
|
||||
} getAssertionState;
|
||||
struct _getAssertionState getAssertionState;
|
||||
|
||||
uint8_t verify_pin_auth(uint8_t * pinAuth, uint8_t * clientDataHash)
|
||||
{
|
||||
@ -279,6 +270,7 @@ static int ctap_generate_cose_key(CborEncoder * cose_key, uint8_t * hmac_input,
|
||||
void make_auth_tag(uint8_t * rpIdHash, uint8_t * nonce, uint32_t count, uint8_t * tag)
|
||||
{
|
||||
uint8_t hashbuf[32];
|
||||
memset(hashbuf,0,sizeof(hashbuf));
|
||||
crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY, 0, hashbuf);
|
||||
crypto_sha256_update(rpIdHash, 32);
|
||||
crypto_sha256_update(nonce, CREDENTIAL_NONCE_SIZE);
|
||||
@ -363,9 +355,9 @@ static int ctap_make_extensions(CTAP_extensions * ext, uint8_t * ext_encoder_buf
|
||||
}
|
||||
|
||||
// Generate credRandom
|
||||
crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY, 0, credRandom);
|
||||
crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY2, 0, credRandom);
|
||||
crypto_sha256_update((uint8_t*)&ext->hmac_secret.credential->id, sizeof(CredentialId));
|
||||
crypto_sha256_hmac_final(CRYPTO_TRANSPORT_KEY, 0, credRandom);
|
||||
crypto_sha256_hmac_final(CRYPTO_TRANSPORT_KEY2, 0, credRandom);
|
||||
|
||||
// Decrypt saltEnc
|
||||
crypto_aes256_init(shared_secret, NULL);
|
||||
@ -388,7 +380,6 @@ static int ctap_make_extensions(CTAP_extensions * ext, uint8_t * ext_encoder_buf
|
||||
crypto_aes256_encrypt(output, ext->hmac_secret.saltLen);
|
||||
|
||||
// output
|
||||
printf1(TAG_GREEN, "have %d bytes for Extenstions encoder\r\n",*ext_encoder_buf_size);
|
||||
cbor_encoder_init(&extensions, ext_encoder_buf, *ext_encoder_buf_size, 0);
|
||||
{
|
||||
CborEncoder hmac_secret_map;
|
||||
@ -436,6 +427,8 @@ static unsigned int get_credential_id_size(CTAP_credentialDescriptor * cred)
|
||||
{
|
||||
if (cred->type == PUB_KEY_CRED_CTAP1)
|
||||
return U2F_KEY_HANDLE_SIZE;
|
||||
if (cred->type == PUB_KEY_CRED_CUSTOM)
|
||||
return getAssertionState.customCredIdSize;
|
||||
return sizeof(CredentialId);
|
||||
}
|
||||
|
||||
@ -450,6 +443,10 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
||||
|
||||
uint8_t * cose_key_buf = auth_data_buf + sizeof(CTAP_authData);
|
||||
|
||||
// memset(&cose_key, 0, sizeof(CTAP_residentKey));
|
||||
memset(&rk, 0, sizeof(CTAP_residentKey));
|
||||
memset(&rk2, 0, sizeof(CTAP_residentKey));
|
||||
|
||||
if((sizeof(CTAP_authDataHeader)) > *len)
|
||||
{
|
||||
printf1(TAG_ERR,"assertion fail, auth_data_buf must be at least %d bytes\n", sizeof(CTAP_authData) - sizeof(CTAP_attestHeader));
|
||||
@ -460,18 +457,13 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
||||
crypto_sha256_update(rp->id, rp->size);
|
||||
crypto_sha256_final(authData->head.rpIdHash);
|
||||
|
||||
printf1(TAG_RED, "rpId: "); dump_hex1(TAG_RED, rp->id, rp->size);
|
||||
printf1(TAG_RED, "hash: "); dump_hex1(TAG_RED, authData->head.rpIdHash, 32);
|
||||
|
||||
count = auth_data_update_count(&authData->head);
|
||||
|
||||
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
||||
// if NFC - not need to click a button
|
||||
int but = 1;
|
||||
if(!device_is_nfc())
|
||||
{
|
||||
but = ctap_user_presence_test();
|
||||
}
|
||||
|
||||
int but;
|
||||
|
||||
but = ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||
|
||||
if (!but)
|
||||
{
|
||||
@ -613,7 +605,6 @@ int ctap_calculate_signature(uint8_t * data, int datalen, uint8_t * clientDataHa
|
||||
crypto_sha256_final(hashbuf);
|
||||
|
||||
crypto_ecc256_sign(hashbuf, 32, sigbuf);
|
||||
|
||||
return ctap_encode_der_sig(sigbuf,sigder);
|
||||
}
|
||||
|
||||
@ -672,12 +663,17 @@ int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * d
|
||||
return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
|
||||
break;
|
||||
case PUB_KEY_CRED_CTAP1:
|
||||
printf1(TAG_CTAP,"PUB_KEY_CRED_CTAP1\r\n");
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(rp->id, rp->size);
|
||||
crypto_sha256_final(rpIdHash);
|
||||
return u2f_authenticate_credential((struct u2f_key_handle *)&desc->credential.id, rpIdHash);
|
||||
break;
|
||||
case PUB_KEY_CRED_CUSTOM:
|
||||
return is_extension_request(getAssertionState.customCredId, getAssertionState.customCredIdSize);
|
||||
break;
|
||||
default:
|
||||
printf1(TAG_ERR, "PUB_KEY_CRED_UNKNOWN %x\r\n",desc->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -702,6 +698,14 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
printf2(TAG_ERR,"error, parse_make_credential failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (MC.pinAuthEmpty)
|
||||
{
|
||||
if (!ctap_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||
{
|
||||
return CTAP2_ERR_OPERATION_DENIED;
|
||||
}
|
||||
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
||||
}
|
||||
if ((MC.paramsParsed & MC_requiredMask) != MC_requiredMask)
|
||||
{
|
||||
printf2(TAG_ERR,"error, required parameter(s) for makeCredential are missing\n");
|
||||
@ -738,9 +742,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
check_retr(ret);
|
||||
|
||||
printf1(TAG_GREEN, "checking credId: "); dump_hex1(TAG_GREEN, (uint8_t*) &excl_cred->credential.id, sizeof(CredentialId));
|
||||
// DELETE
|
||||
// crypto_aes256_reset_iv(NULL);
|
||||
// crypto_aes256_decrypt((uint8_t*)& excl_cred->credential.enc, CREDENTIAL_ENC_SIZE);
|
||||
|
||||
if (ctap_authenticate_credential(&MC.rp, excl_cred))
|
||||
{
|
||||
printf1(TAG_MC, "Cred %d failed!\r\n",i);
|
||||
@ -861,7 +863,6 @@ uint8_t ctap_add_user_entity(CborEncoder * map, CTAP_userEntity * user)
|
||||
ret = cbor_encoder_create_map(map, &entity, 1);
|
||||
check_ret(ret);
|
||||
|
||||
printf1(TAG_GREEN,"id_size: %d\r\n", user->id_size);
|
||||
{
|
||||
ret = cbor_encode_text_string(&entity, "id", 2);
|
||||
check_ret(ret);
|
||||
@ -1054,7 +1055,7 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
|
||||
else
|
||||
#endif
|
||||
{
|
||||
sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||
sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_buf_sz, clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1103,7 +1104,6 @@ uint8_t ctap_get_next_assertion(CborEncoder * encoder)
|
||||
}
|
||||
|
||||
check_ret(ret);
|
||||
printf1(TAG_RED, "RPID hash: "); dump_hex1(TAG_RED, authData.rpIdHash, 32);
|
||||
|
||||
// if only one account for this RP, null out the user details
|
||||
if (!getAssertionState.user_verified)
|
||||
@ -1124,6 +1124,7 @@ uint8_t ctap_get_next_assertion(CborEncoder * encoder)
|
||||
uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
{
|
||||
CTAP_getAssertion GA;
|
||||
|
||||
uint8_t auth_data_buf[sizeof(CTAP_authDataHeader) + 80];
|
||||
int ret = ctap_parse_get_assertion(&GA,request,length);
|
||||
|
||||
@ -1133,6 +1134,14 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (GA.pinAuthEmpty)
|
||||
{
|
||||
if (!ctap_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||
{
|
||||
return CTAP2_ERR_OPERATION_DENIED;
|
||||
}
|
||||
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
||||
}
|
||||
if (GA.pinAuthPresent)
|
||||
{
|
||||
ret = verify_pin_auth(GA.pinAuth, GA.clientDataHash);
|
||||
@ -1155,16 +1164,21 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
printf1(TAG_GA, "ALLOW_LIST has %d creds\n", GA.credLen);
|
||||
int validCredCount = ctap_filter_invalid_credentials(&GA);
|
||||
|
||||
if (validCredCount > 1)
|
||||
if (validCredCount == 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, no authentic credential\n");
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
}
|
||||
else if (validCredCount > 1)
|
||||
{
|
||||
map_size += 1;
|
||||
}
|
||||
|
||||
|
||||
if (GA.creds[validCredCount - 1].credential.user.id_size)
|
||||
{
|
||||
map_size += 1;
|
||||
}
|
||||
|
||||
if (GA.extensions.hmac_secret_present == EXT_HMAC_SECRET_PARSED)
|
||||
{
|
||||
printf1(TAG_GA, "hmac-secret is present\r\n");
|
||||
@ -1173,12 +1187,6 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
ret = cbor_encoder_create_map(encoder, &map, map_size);
|
||||
check_ret(ret);
|
||||
|
||||
if (validCredCount == 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, no authentic credential\n");
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
}
|
||||
|
||||
// if only one account for this RP, null out the user details
|
||||
if (validCredCount < 2 || !getAssertionState.user_verified)
|
||||
{
|
||||
@ -1202,8 +1210,14 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
#ifdef ENABLE_U2F_EXTENSIONS
|
||||
if ( is_extension_request((uint8_t*)&GA.creds[validCredCount - 1].credential.id, sizeof(CredentialId)) )
|
||||
{
|
||||
memset(auth_data_buf,0,sizeof(CTAP_authDataHeader));
|
||||
auth_data_buf_sz = sizeof(CTAP_authDataHeader);
|
||||
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(GA.rp.id, GA.rp.size);
|
||||
crypto_sha256_final(((CTAP_authDataHeader *)auth_data_buf)->rpIdHash);
|
||||
|
||||
((CTAP_authDataHeader *)auth_data_buf)->flags = (1 << 0);
|
||||
((CTAP_authDataHeader *)auth_data_buf)->flags |= (1 << 2);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -1212,8 +1226,8 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, &auth_data_buf_sz, NULL);
|
||||
check_retr(ret);
|
||||
|
||||
((CTAP_authData *)auth_data_buf)->head.flags &= ~(1 << 2);
|
||||
((CTAP_authData *)auth_data_buf)->head.flags |= (getAssertionState.user_verified << 2);
|
||||
((CTAP_authDataHeader *)auth_data_buf)->flags &= ~(1 << 2);
|
||||
((CTAP_authDataHeader *)auth_data_buf)->flags |= (getAssertionState.user_verified << 2);
|
||||
|
||||
{
|
||||
unsigned int ext_encoder_buf_size = sizeof(auth_data_buf) - auth_data_buf_sz;
|
||||
@ -1223,7 +1237,7 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
check_retr(ret);
|
||||
if (ext_encoder_buf_size)
|
||||
{
|
||||
((CTAP_authData *)auth_data_buf)->head.flags |= (1 << 7);
|
||||
((CTAP_authDataHeader *)auth_data_buf)->flags |= (1 << 7);
|
||||
auth_data_buf_sz += ext_encoder_buf_size;
|
||||
}
|
||||
}
|
||||
@ -1460,7 +1474,7 @@ uint8_t ctap_client_pin(CborEncoder * encoder, uint8_t * request, int length)
|
||||
|
||||
ret = cbor_encode_int(&map, RESP_keyAgreement);
|
||||
check_ret(ret);
|
||||
ret = ctap_add_cose_key(&map, KEY_AGREEMENT_PUB, KEY_AGREEMENT_PUB+32, PUB_KEY_CRED_PUB_KEY, COSE_ALG_ES256);
|
||||
ret = ctap_add_cose_key(&map, KEY_AGREEMENT_PUB, KEY_AGREEMENT_PUB+32, PUB_KEY_CRED_PUB_KEY, COSE_ALG_ECDH_ES_HKDF_256);
|
||||
check_retr(ret);
|
||||
|
||||
break;
|
||||
@ -1556,6 +1570,7 @@ void ctap_response_init(CTAP_RESPONSE * resp)
|
||||
uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
{
|
||||
CborEncoder encoder;
|
||||
memset(&encoder,0,sizeof(CborEncoder));
|
||||
uint8_t status = 0;
|
||||
uint8_t cmd = *pkt_raw;
|
||||
pkt_raw++;
|
||||
@ -1631,7 +1646,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
break;
|
||||
case CTAP_RESET:
|
||||
printf1(TAG_CTAP,"CTAP_RESET\n");
|
||||
if (ctap_user_presence_test())
|
||||
if (ctap_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||
{
|
||||
ctap_reset();
|
||||
}
|
||||
@ -1655,7 +1670,6 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
else
|
||||
{
|
||||
printf2(TAG_ERR, "unwanted GET_NEXT_ASSERTION. lastcmd == 0x%02x\n", getAssertionState.lastcmd);
|
||||
dump_hex1(TAG_GREEN, (uint8_t*)&getAssertionState, sizeof(getAssertionState));
|
||||
status = CTAP2_ERR_NOT_ALLOWED;
|
||||
}
|
||||
break;
|
||||
@ -1750,7 +1764,7 @@ void ctap_init()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (! device_is_nfc())
|
||||
if (device_is_nfc() != NFC_IS_ACTIVE)
|
||||
{
|
||||
ctap_reset_key_agreement();
|
||||
}
|
||||
@ -1972,5 +1986,5 @@ void ctap_reset()
|
||||
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||
ctap_reset_key_agreement();
|
||||
|
||||
crypto_reset_master_secret();
|
||||
crypto_load_master_secret(STATE.key_space);
|
||||
}
|
||||
|
28
fido2/ctap.h
28
fido2/ctap.h
@ -113,6 +113,7 @@
|
||||
|
||||
#define PUB_KEY_CRED_PUB_KEY 0x01
|
||||
#define PUB_KEY_CRED_CTAP1 0x41
|
||||
#define PUB_KEY_CRED_CUSTOM 0x42
|
||||
#define PUB_KEY_CRED_UNKNOWN 0x3F
|
||||
|
||||
#define CREDENTIAL_IS_SUPPORTED 1
|
||||
@ -130,6 +131,8 @@
|
||||
#define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total
|
||||
#define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot
|
||||
|
||||
#define CTAP2_UP_DELAY_MS 5000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t id[USER_ID_MAX_SIZE];
|
||||
@ -243,6 +246,11 @@ typedef struct
|
||||
|
||||
uint8_t pinAuth[16];
|
||||
uint8_t pinAuthPresent;
|
||||
// pinAuthEmpty is true iff an empty bytestring was provided as pinAuth.
|
||||
// This is exclusive with |pinAuthPresent|. It exists because an empty
|
||||
// pinAuth is a special signal to block for touch. See
|
||||
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#using-pinToken-in-authenticatorMakeCredential
|
||||
uint8_t pinAuthEmpty;
|
||||
int pinProtocol;
|
||||
CTAP_extensions extensions;
|
||||
|
||||
@ -266,9 +274,14 @@ typedef struct
|
||||
|
||||
uint8_t pinAuth[16];
|
||||
uint8_t pinAuthPresent;
|
||||
// pinAuthEmpty is true iff an empty bytestring was provided as pinAuth.
|
||||
// This is exclusive with |pinAuthPresent|. It exists because an empty
|
||||
// pinAuth is a special signal to block for touch. See
|
||||
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#using-pinToken-in-authenticatorGetAssertion
|
||||
uint8_t pinAuthEmpty;
|
||||
int pinProtocol;
|
||||
|
||||
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
|
||||
CTAP_credentialDescriptor * creds;
|
||||
uint8_t allowListPresent;
|
||||
|
||||
CTAP_extensions extensions;
|
||||
@ -292,6 +305,19 @@ typedef struct
|
||||
} CTAP_clientPin;
|
||||
|
||||
|
||||
struct _getAssertionState {
|
||||
CTAP_authDataHeader authData;
|
||||
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
||||
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
|
||||
uint8_t lastcmd;
|
||||
uint32_t count;
|
||||
uint32_t index;
|
||||
uint32_t time;
|
||||
uint8_t user_verified;
|
||||
uint8_t customCredId[256];
|
||||
uint8_t customCredIdSize;
|
||||
};
|
||||
|
||||
void ctap_response_init(CTAP_RESPONSE * resp);
|
||||
|
||||
uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
|
||||
extern struct _getAssertionState getAssertionState;
|
||||
|
||||
void _check_ret(CborError ret, int line, const char * filename)
|
||||
{
|
||||
@ -136,7 +137,6 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
||||
return CTAP2_ERR_LIMIT_EXCEEDED;
|
||||
}
|
||||
MC->credInfo.user.id_size = sz;
|
||||
printf1(TAG_GREEN,"parsed id_size: %d\r\n", MC->credInfo.user.id_size);
|
||||
check_ret(ret);
|
||||
}
|
||||
else if (strcmp((const char *)key, "name") == 0)
|
||||
@ -823,14 +823,22 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
|
||||
ret = parse_options(&map, &MC->credInfo.rk, &MC->uv, &MC->up);
|
||||
check_retr(ret);
|
||||
break;
|
||||
case MC_pinAuth:
|
||||
case MC_pinAuth: {
|
||||
printf1(TAG_MC,"CTAP_pinAuth\n");
|
||||
|
||||
size_t pinSize;
|
||||
if (cbor_value_get_type(&map) == CborByteStringType &&
|
||||
cbor_value_get_string_length(&map, &pinSize) == CborNoError &&
|
||||
pinSize == 0)
|
||||
{
|
||||
MC->pinAuthEmpty = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = parse_fixed_byte_string(&map, MC->pinAuth, 16);
|
||||
if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft
|
||||
{
|
||||
check_retr(ret);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -838,6 +846,7 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
|
||||
}
|
||||
MC->pinAuthPresent = 1;
|
||||
break;
|
||||
}
|
||||
case MC_pinProtocol:
|
||||
printf1(TAG_MC,"CTAP_pinProtocol\n");
|
||||
if (cbor_value_get_type(&map) == CborIntegerType)
|
||||
@ -874,6 +883,8 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
|
||||
size_t buflen;
|
||||
char type[12];
|
||||
CborValue val;
|
||||
cred->type = 0;
|
||||
|
||||
if (cbor_value_get_type(arr) != CborMapType)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, CborMapType expected in credential\n");
|
||||
@ -890,8 +901,8 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
|
||||
}
|
||||
|
||||
buflen = sizeof(CredentialId);
|
||||
cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL);
|
||||
|
||||
ret = cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL);
|
||||
|
||||
if (buflen == U2F_KEY_HANDLE_SIZE)
|
||||
{
|
||||
printf2(TAG_PARSE,"CTAP1 credential\n");
|
||||
@ -899,8 +910,13 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
|
||||
}
|
||||
else if (buflen != sizeof(CredentialId))
|
||||
{
|
||||
printf2(TAG_ERR,"Ignoring credential is incorrect length\n");
|
||||
printf2(TAG_ERR,"Ignoring credential is incorrect length, treating as custom\n");
|
||||
cred->type = PUB_KEY_CRED_CUSTOM;
|
||||
buflen = 256;
|
||||
ret = cbor_value_copy_byte_string(&val, getAssertionState.customCredId, &buflen, NULL);
|
||||
getAssertionState.customCredIdSize = buflen;
|
||||
}
|
||||
check_ret(ret);
|
||||
|
||||
ret = cbor_value_map_find_value(arr, "type", &val);
|
||||
check_ret(ret);
|
||||
@ -913,11 +929,19 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
|
||||
|
||||
buflen = sizeof(type);
|
||||
ret = cbor_value_copy_text_string(&val, type, &buflen, NULL);
|
||||
check_ret(ret);
|
||||
if (ret == CborErrorOutOfMemory)
|
||||
{
|
||||
cred->type = PUB_KEY_CRED_UNKNOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
check_ret(ret);
|
||||
}
|
||||
|
||||
|
||||
if (strncmp(type, "public-key",11) == 0)
|
||||
{
|
||||
if (PUB_KEY_CRED_CTAP1 != cred->type)
|
||||
if (0 == cred->type)
|
||||
{
|
||||
cred->type = PUB_KEY_CRED_PUB_KEY;
|
||||
}
|
||||
@ -985,6 +1009,8 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
||||
CborValue it,map;
|
||||
|
||||
memset(GA, 0, sizeof(CTAP_getAssertion));
|
||||
GA->creds = getAssertionState.creds; // Save stack memory
|
||||
|
||||
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
||||
check_ret(ret);
|
||||
|
||||
@ -1055,9 +1081,18 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
||||
ret = parse_options(&map, &GA->rk, &GA->uv, &GA->up);
|
||||
check_retr(ret);
|
||||
break;
|
||||
case GA_pinAuth:
|
||||
case GA_pinAuth: {
|
||||
printf1(TAG_GA,"CTAP_pinAuth\n");
|
||||
|
||||
size_t pinSize;
|
||||
if (cbor_value_get_type(&map) == CborByteStringType &&
|
||||
cbor_value_get_string_length(&map, &pinSize) == CborNoError &&
|
||||
pinSize == 0)
|
||||
{
|
||||
GA->pinAuthEmpty = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = parse_fixed_byte_string(&map, GA->pinAuth, 16);
|
||||
if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft
|
||||
{
|
||||
@ -1073,6 +1108,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
||||
GA->pinAuthPresent = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
case GA_pinProtocol:
|
||||
printf1(TAG_GA,"CTAP_pinProtocol\n");
|
||||
if (cbor_value_get_type(&map) == CborIntegerType)
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "storage.h"
|
||||
|
||||
void device_init();
|
||||
void device_init(int argc, char *argv[]);
|
||||
|
||||
uint32_t millis();
|
||||
|
||||
@ -53,11 +53,11 @@ int device_is_button_pressed();
|
||||
|
||||
// Test for user presence
|
||||
// Return 1 for user is present, 0 user not present, -1 if cancel is requested.
|
||||
extern int ctap_user_presence_test();
|
||||
int ctap_user_presence_test(uint32_t delay);
|
||||
|
||||
// Generate @num bytes of random numbers to @dest
|
||||
// return 1 if success, error otherwise
|
||||
extern int ctap_generate_rng(uint8_t * dst, size_t num);
|
||||
int ctap_generate_rng(uint8_t * dst, size_t num);
|
||||
|
||||
// Increment atomic counter and return it.
|
||||
// Must support two counters, @sel selects counter0 or counter1.
|
||||
@ -65,11 +65,11 @@ uint32_t ctap_atomic_count(int sel);
|
||||
|
||||
// Verify the user
|
||||
// return 1 if user is verified, 0 if not
|
||||
extern int ctap_user_verification(uint8_t arg);
|
||||
int ctap_user_verification(uint8_t arg);
|
||||
|
||||
// Must be implemented by application
|
||||
// data is HID_MESSAGE_SIZE long in bytes
|
||||
extern void ctaphid_write_block(uint8_t * data);
|
||||
void ctaphid_write_block(uint8_t * data);
|
||||
|
||||
|
||||
// Resident key
|
||||
@ -99,9 +99,14 @@ typedef enum {
|
||||
// 2: fastest clock rate. Generally for USB interface.
|
||||
void device_set_clock_rate(DEVICE_CLOCK_RATE param);
|
||||
|
||||
// Returns 1 if operating in NFC mode.
|
||||
// 0 otherwise.
|
||||
bool device_is_nfc();
|
||||
// Returns NFC_IS_NA, NFC_IS_ACTIVE, or NFC_IS_AVAILABLE
|
||||
#define NFC_IS_NA 0
|
||||
#define NFC_IS_ACTIVE 1
|
||||
#define NFC_IS_AVAILABLE 2
|
||||
int device_is_nfc();
|
||||
|
||||
void request_from_nfc(bool request_active);
|
||||
|
||||
void device_init_button();
|
||||
|
||||
#endif
|
||||
|
@ -35,6 +35,28 @@ int extension_needs_atomic_count(uint8_t klen, uint8_t * keyh)
|
||||
|| ((wallet_request *) keyh)->operation == WalletSign;
|
||||
}
|
||||
|
||||
static uint8_t * output_buffer_ptr;
|
||||
uint8_t output_buffer_offset;
|
||||
uint8_t output_buffer_size;
|
||||
|
||||
void extension_writeback_init(uint8_t * buffer, uint8_t size)
|
||||
{
|
||||
output_buffer_ptr = buffer;
|
||||
output_buffer_offset = 0;
|
||||
output_buffer_size = size;
|
||||
}
|
||||
|
||||
void extension_writeback(uint8_t * buf, uint8_t size)
|
||||
{
|
||||
if ((output_buffer_offset + size) > output_buffer_size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
memmove(output_buffer_ptr + output_buffer_offset, buf, size);
|
||||
output_buffer_offset += size;
|
||||
}
|
||||
|
||||
|
||||
int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh)
|
||||
{
|
||||
int8_t ret = 0;
|
||||
@ -55,8 +77,6 @@ int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen
|
||||
u2f_response_writeback((uint8_t *)&ret,1);
|
||||
#ifdef IS_BOOTLOADER
|
||||
ret = bootloader_bridge(klen, keyh);
|
||||
#elif defined(WALLET_EXTENSION)
|
||||
ret = bridge_u2f_to_wallet(_chal, _appid, klen, keyh);
|
||||
#else
|
||||
ret = bridge_u2f_to_solo(sig, keyh, klen);
|
||||
u2f_response_writeback(sig,72);
|
||||
@ -82,6 +102,7 @@ int16_t extend_fido2(CredentialId * credid, uint8_t * output)
|
||||
{
|
||||
if (is_extension_request((uint8_t*)credid, sizeof(CredentialId)))
|
||||
{
|
||||
printf1(TAG_EXT,"IS EXT REQ\r\n");
|
||||
output[0] = bridge_u2f_to_solo(output+1, (uint8_t*)credid, sizeof(CredentialId));
|
||||
return 1;
|
||||
}
|
||||
|
@ -9,6 +9,11 @@
|
||||
#include "u2f.h"
|
||||
#include "apdu.h"
|
||||
|
||||
int16_t bridge_u2f_to_extensions(uint8_t * chal, uint8_t * appid, uint8_t klen, uint8_t * keyh);
|
||||
|
||||
// return 1 if request is a wallet request
|
||||
int is_extension_request(uint8_t * req, int len);
|
||||
|
||||
int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len);
|
||||
|
||||
int16_t extend_fido2(CredentialId * credid, uint8_t * output);
|
||||
@ -17,4 +22,8 @@ int bootloader_bridge(int klen, uint8_t * keyh);
|
||||
|
||||
int is_extension_request(uint8_t * kh, int len);
|
||||
|
||||
|
||||
void extension_writeback_init(uint8_t * buffer, uint8_t size);
|
||||
void extension_writeback(uint8_t * buf, uint8_t size);
|
||||
|
||||
#endif /* EXTENSIONS_H_ */
|
||||
|
@ -31,12 +31,15 @@
|
||||
#include "log.h"
|
||||
#include APP_CONFIG
|
||||
|
||||
|
||||
|
||||
// output must be at least 71 bytes
|
||||
int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen)
|
||||
{
|
||||
int8_t ret = 0;
|
||||
|
||||
wallet_request * req = (wallet_request *) keyh;
|
||||
extension_writeback_init(output, 71);
|
||||
|
||||
printf1(TAG_WALLET, "u2f-solo [%d]: ", keylen); dump_hex1(TAG_WALLET, keyh, keylen);
|
||||
|
||||
@ -61,6 +64,14 @@ int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen)
|
||||
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
case WalletSign:
|
||||
case WalletRegister:
|
||||
case WalletPin:
|
||||
case WalletReset:
|
||||
return bridge_to_wallet(keyh, keylen);
|
||||
#endif
|
||||
|
||||
default:
|
||||
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);
|
||||
ret = CTAP1_ERR_INVALID_COMMAND;
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include "util.h"
|
||||
#include "storage.h"
|
||||
#include "device.h"
|
||||
#include "extensions.h"
|
||||
|
||||
#if defined(USING_PC) || defined(IS_BOOTLOADER)
|
||||
typedef enum
|
||||
{
|
||||
MBEDTLS_ECP_DP_NONE = 0,
|
||||
@ -32,9 +32,7 @@ typedef enum
|
||||
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
|
||||
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
|
||||
} mbedtls_ecp_group_id;
|
||||
#else
|
||||
#include "ecp.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// return 1 if hash is valid, 0 otherwise
|
||||
@ -70,14 +68,14 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
||||
return CTAP2_ERR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
u2f_response_writeback(KEY_AGREEMENT_PUB,sizeof(KEY_AGREEMENT_PUB));
|
||||
extension_writeback(KEY_AGREEMENT_PUB,sizeof(KEY_AGREEMENT_PUB));
|
||||
printf1(TAG_WALLET,"pubkey: "); dump_hex1(TAG_WALLET,KEY_AGREEMENT_PUB,64);
|
||||
|
||||
break;
|
||||
case CP_cmdGetRetries:
|
||||
printf1(TAG_WALLET,"cmdGetRetries\n");
|
||||
pinTokenEnc[0] = ctap_leftover_pin_attempts();
|
||||
u2f_response_writeback(pinTokenEnc,1);
|
||||
extension_writeback(pinTokenEnc,1);
|
||||
|
||||
break;
|
||||
case CP_cmdSetPin:
|
||||
@ -87,7 +85,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
||||
return CTAP2_ERR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
if (!ctap_user_presence_test())
|
||||
if (!ctap_user_presence_test(5000))
|
||||
{
|
||||
return CTAP2_ERR_OPERATION_DENIED;
|
||||
}
|
||||
@ -113,7 +111,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
||||
return CTAP2_ERR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
if (!ctap_user_presence_test())
|
||||
if (!ctap_user_presence_test(5000))
|
||||
{
|
||||
return CTAP2_ERR_OPERATION_DENIED;
|
||||
}
|
||||
@ -135,7 +133,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
||||
return CTAP2_ERR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
if (!ctap_user_presence_test())
|
||||
if (!ctap_user_presence_test(5000))
|
||||
{
|
||||
return CTAP2_ERR_OPERATION_DENIED;
|
||||
}
|
||||
@ -145,7 +143,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
||||
return ret;
|
||||
|
||||
printf1(TAG_WALLET,"pinToken: "); dump_hex1(TAG_WALLET, PIN_TOKEN, 16);
|
||||
u2f_response_writeback(pinTokenEnc, PIN_TOKEN_SIZE);
|
||||
extension_writeback(pinTokenEnc, PIN_TOKEN_SIZE);
|
||||
|
||||
break;
|
||||
|
||||
@ -159,7 +157,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh)
|
||||
int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen)
|
||||
{
|
||||
static uint8_t msg_buf[WALLET_MAX_BUFFER];
|
||||
int reqlen = klen;
|
||||
@ -259,7 +257,7 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
||||
crypto_load_external_key(key, keysize);
|
||||
crypto_ecdsa_sign(args[0], lens[0], sig, MBEDTLS_ECP_DP_SECP256K1);
|
||||
|
||||
u2f_response_writeback(sig,64);
|
||||
extension_writeback(sig,64);
|
||||
|
||||
break;
|
||||
case WalletRegister:
|
||||
@ -361,7 +359,7 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
||||
}
|
||||
}
|
||||
|
||||
if (ctap_user_presence_test())
|
||||
if (ctap_user_presence_test(5000))
|
||||
{
|
||||
printf1(TAG_WALLET,"Reseting device!\n");
|
||||
ctap_reset();
|
||||
@ -374,39 +372,7 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
||||
|
||||
|
||||
break;
|
||||
case WalletVersion:
|
||||
u2f_response_writeback((uint8_t*)WALLET_VERSION, sizeof(WALLET_VERSION)-1);
|
||||
break;
|
||||
case WalletRng:
|
||||
printf1(TAG_WALLET,"WalletRng\n");
|
||||
if ( ctap_device_locked() )
|
||||
{
|
||||
printf1(TAG_ERR,"device locked\n");
|
||||
ret = CTAP2_ERR_NOT_ALLOWED;
|
||||
goto cleanup;
|
||||
}
|
||||
if ( ctap_is_pin_set() )
|
||||
{
|
||||
if ( ! check_pinhash(req->pinAuth, msg_buf, reqlen))
|
||||
{
|
||||
printf2(TAG_ERR,"pinAuth is NOT valid\n");
|
||||
dump_hex1(TAG_ERR,msg_buf,reqlen);
|
||||
ret = CTAP2_ERR_PIN_AUTH_INVALID;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ctap_generate_rng(sig, 72);
|
||||
if (ret != 1)
|
||||
{
|
||||
printf1(TAG_WALLET,"Rng failed\n");
|
||||
ret = CTAP2_ERR_PROCESSING;
|
||||
goto cleanup;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
u2f_response_writeback((uint8_t *)sig,72);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);
|
||||
|
@ -87,10 +87,7 @@ typedef enum
|
||||
} WalletOperation;
|
||||
|
||||
|
||||
int16_t bridge_u2f_to_extensions(uint8_t * chal, uint8_t * appid, uint8_t klen, uint8_t * keyh);
|
||||
|
||||
// return 1 if request is a wallet request
|
||||
int is_extension_request(uint8_t * req, int len);
|
||||
int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen);
|
||||
|
||||
void wallet_init();
|
||||
|
||||
|
24
fido2/main.c
24
fido2/main.c
@ -7,6 +7,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
@ -19,7 +21,8 @@
|
||||
|
||||
#if !defined(TEST)
|
||||
|
||||
int main()
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
uint8_t hidmsg[64];
|
||||
uint32_t t1 = 0;
|
||||
@ -27,32 +30,29 @@ int main()
|
||||
set_logging_mask(
|
||||
/*0*/
|
||||
//TAG_GEN|
|
||||
//TAG_MC |
|
||||
//TAG_GA |
|
||||
//TAG_WALLET |
|
||||
// TAG_MC |
|
||||
// TAG_GA |
|
||||
TAG_WALLET |
|
||||
TAG_STOR |
|
||||
//TAG_NFC_APDU |
|
||||
TAG_NFC |
|
||||
//TAG_CP |
|
||||
//TAG_CTAP|
|
||||
// TAG_CTAP|
|
||||
//TAG_HID|
|
||||
//TAG_U2F|
|
||||
TAG_U2F|
|
||||
//TAG_PARSE |
|
||||
//TAG_TIME|
|
||||
//TAG_DUMP|
|
||||
// TAG_DUMP|
|
||||
TAG_GREEN|
|
||||
TAG_RED|
|
||||
TAG_EXT|
|
||||
TAG_ERR
|
||||
);
|
||||
|
||||
device_init();
|
||||
|
||||
|
||||
device_init(argc, argv);
|
||||
|
||||
memset(hidmsg,0,sizeof(hidmsg));
|
||||
|
||||
// printf1(TAG_GEN,"recv'ing hid msg \n");
|
||||
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
27
fido2/u2f.c
27
fido2/u2f.c
@ -7,6 +7,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "u2f.h"
|
||||
#include "ctap.h"
|
||||
#include "ctaphid.h"
|
||||
#include "crypto.h"
|
||||
#include "log.h"
|
||||
#include "device.h"
|
||||
@ -95,6 +96,8 @@ void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPO
|
||||
#endif
|
||||
}
|
||||
|
||||
device_set_status(CTAPHID_STATUS_IDLE);
|
||||
|
||||
end:
|
||||
if (rcode != U2F_SW_NO_ERROR)
|
||||
{
|
||||
@ -110,14 +113,14 @@ end:
|
||||
printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length);
|
||||
}
|
||||
|
||||
void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp)
|
||||
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp)
|
||||
{
|
||||
if (len < 5 || !req)
|
||||
if (!header)
|
||||
return;
|
||||
|
||||
uint32_t alen = req[4];
|
||||
|
||||
u2f_request_ex((APDU_HEADER *)req, &req[5], alen, resp);
|
||||
request_from_nfc(true); // disable presence test
|
||||
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
|
||||
request_from_nfc(false); // enable presence test
|
||||
}
|
||||
|
||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
@ -202,7 +205,6 @@ int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control)
|
||||
{
|
||||
|
||||
@ -238,9 +240,9 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
|
||||
if (control == U2F_AUTHENTICATE_SIGN_NO_USER)
|
||||
up = 0;
|
||||
|
||||
if(!device_is_nfc() && up)
|
||||
if(up)
|
||||
{
|
||||
if (ctap_user_presence_test() == 0)
|
||||
if (ctap_user_presence_test(750) == 0)
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
@ -286,12 +288,9 @@ static int16_t u2f_register(struct u2f_register_request * req)
|
||||
|
||||
const uint16_t attest_size = attestation_cert_der_size;
|
||||
|
||||
if(!device_is_nfc())
|
||||
if ( ! ctap_user_presence_test(750))
|
||||
{
|
||||
if ( ! ctap_user_presence_test())
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
|
||||
if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1)
|
||||
@ -326,8 +325,6 @@ static int16_t u2f_register(struct u2f_register_request * req)
|
||||
|
||||
dump_signature_der(sig);
|
||||
|
||||
/*printf1(TAG_U2F, "dersig: "); dump_hex1(TAG_U2F,sig,74);*/
|
||||
|
||||
|
||||
return U2F_SW_NO_ERROR;
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp);
|
||||
// u2f_request send a U2F message to NFC protocol
|
||||
// @req data with iso7816 apdu message
|
||||
// @len data length
|
||||
void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp);
|
||||
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp);
|
||||
|
||||
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid);
|
||||
|
||||
|
@ -20,6 +20,9 @@
|
||||
],
|
||||
"userVerificationDetails": [
|
||||
[
|
||||
{
|
||||
"userVerification": 1
|
||||
},
|
||||
{
|
||||
"userVerification": 4
|
||||
}
|
||||
|
3
pc/app.h
3
pc/app.h
@ -7,6 +7,7 @@
|
||||
|
||||
#ifndef SRC_APP_H_
|
||||
#define SRC_APP_H_
|
||||
#include <stdbool.h>
|
||||
|
||||
#define USING_DEV_BOARD
|
||||
|
||||
@ -20,6 +21,8 @@
|
||||
|
||||
void printing_init();
|
||||
|
||||
extern bool use_udp;
|
||||
|
||||
// 0xRRGGBB
|
||||
#define LED_INIT_VALUE 0x000800
|
||||
#define LED_WINK_VALUE 0x000008
|
||||
|
107
pc/device.c
107
pc/device.c
@ -15,6 +15,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "cbor.h"
|
||||
@ -24,6 +25,8 @@
|
||||
|
||||
#define RK_NUM 50
|
||||
|
||||
bool use_udp = true;
|
||||
|
||||
struct ResidentKeyStore {
|
||||
CTAP_residentKey rks[RK_NUM];
|
||||
} RK_STORE;
|
||||
@ -118,12 +121,6 @@ void udp_send(int fd, uint8_t * buf, int size)
|
||||
}
|
||||
}
|
||||
|
||||
void udp_close(int fd)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t millis()
|
||||
{
|
||||
@ -134,18 +131,42 @@ uint32_t millis()
|
||||
}
|
||||
|
||||
|
||||
static int serverfd = 0;
|
||||
static int fd = 0;
|
||||
|
||||
void usbhid_init()
|
||||
{
|
||||
// just bridge to UDP for now for pure software testing
|
||||
serverfd = udp_server();
|
||||
if (use_udp)
|
||||
{
|
||||
fd = udp_server();
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open("/dev/hidg0", O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("hidg open");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Receive 64 byte USB HID message, don't block, return size of packet, return 0 if nothing
|
||||
int usbhid_recv(uint8_t * msg)
|
||||
{
|
||||
int l = udp_recv(serverfd, msg, HID_MESSAGE_SIZE);
|
||||
int l = 0;
|
||||
if (use_udp)
|
||||
{
|
||||
l = udp_recv(fd, msg, HID_MESSAGE_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
l = read(fd, msg, HID_MESSAGE_SIZE); /* Flawfinder: ignore */
|
||||
if (l < 0)
|
||||
{
|
||||
perror("hidg read");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
uint8_t magic_cmd[] = "\xac\x10\x52\xca\x95\xe5\x69\xde\x69\xe0\x2e\xbf"
|
||||
"\xf3\x33\x48\x5f\x13\xf9\xb2\xda\x34\xc5\xa8\xa3"
|
||||
"\x40\x52\x66\x97\xa9\xab\x2e\x0b\x39\x4d\x8d\x04"
|
||||
@ -166,12 +187,23 @@ int usbhid_recv(uint8_t * msg)
|
||||
// Send 64 byte USB HID message
|
||||
void usbhid_send(uint8_t * msg)
|
||||
{
|
||||
udp_send(serverfd, msg, HID_MESSAGE_SIZE);
|
||||
if (use_udp)
|
||||
{
|
||||
udp_send(fd, msg, HID_MESSAGE_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (write(fd, msg, HID_MESSAGE_SIZE) < 0)
|
||||
{
|
||||
perror("hidg write");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void usbhid_close()
|
||||
{
|
||||
udp_close(serverfd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void int_handler(int i)
|
||||
@ -181,10 +213,47 @@ void int_handler(int i)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void device_init()
|
||||
|
||||
|
||||
void usage(const char * cmd)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-b udp|hidg]\n", cmd);
|
||||
fprintf(stderr, " -b backing implementation: udp(default) or hidg\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void device_init(int argc, char *argv[])
|
||||
{
|
||||
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "b:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'b':
|
||||
if (strcmp("udp", optarg) == 0)
|
||||
{
|
||||
use_udp = true;
|
||||
}
|
||||
else if (strcmp("hidg", optarg) == 0)
|
||||
{
|
||||
use_udp = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
usage(argv[0]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
signal(SIGINT, int_handler);
|
||||
|
||||
printf1(TAG_GREEN, "Using %s backing\n", use_udp ? "UDP" : "hidg");
|
||||
usbhid_init();
|
||||
|
||||
authenticator_initialize();
|
||||
@ -203,6 +272,14 @@ void main_loop_delay()
|
||||
nanosleep(&ts,NULL);
|
||||
}
|
||||
|
||||
void delay(uint32_t ms)
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000*1000*ms;
|
||||
nanosleep(&ts,NULL);
|
||||
}
|
||||
|
||||
|
||||
void heartbeat()
|
||||
{
|
||||
@ -216,7 +293,7 @@ void ctaphid_write_block(uint8_t * data)
|
||||
}
|
||||
|
||||
|
||||
int ctap_user_presence_test()
|
||||
int ctap_user_presence_test(uint32_t d)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@ -547,7 +624,7 @@ void device_wink()
|
||||
printf("*WINK*\n");
|
||||
}
|
||||
|
||||
bool device_is_nfc()
|
||||
int device_is_nfc()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -83,6 +83,8 @@ int main()
|
||||
init_debug_uart();
|
||||
#endif
|
||||
|
||||
device_init_button();
|
||||
|
||||
printf1(TAG_GEN,"init device\n");
|
||||
|
||||
t1 = millis();
|
||||
|
@ -2,15 +2,16 @@ include build/common.mk
|
||||
|
||||
# ST related
|
||||
SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
|
||||
SRC += src/fifo.c src/crypto.c src/attestation.c src/nfc.c src/ams.c
|
||||
SRC += src/fifo.c src/crypto.c src/attestation.c src/nfc.c src/ams.c src/sense.c
|
||||
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
||||
SRC += $(DRIVER_LIBS) $(USB_LIB)
|
||||
|
||||
# FIDO2 lib
|
||||
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
|
||||
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
|
||||
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
|
||||
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
|
||||
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c
|
||||
SRC += ../../fido2/extensions/wallet.c
|
||||
|
||||
# Crypto libs
|
||||
SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c ../../crypto/tiny-AES-c/aes.c
|
||||
@ -81,4 +82,4 @@ cbor:
|
||||
cd ../../tinycbor/ && make clean
|
||||
cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \
|
||||
LDFLAGS="$(LDFLAGS_LIB)" \
|
||||
CFLAGS="$(CFLAGS)"
|
||||
CFLAGS="$(CFLAGS) -Os"
|
||||
|
@ -3,7 +3,7 @@ include build/common.mk
|
||||
# ST related
|
||||
SRC = bootloader/main.c bootloader/bootloader.c
|
||||
SRC += src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
|
||||
SRC += src/fifo.c src/crypto.c src/attestation.c
|
||||
SRC += src/fifo.c src/crypto.c src/attestation.c src/sense.c
|
||||
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
||||
SRC += $(DRIVER_LIBS) $(USB_LIB)
|
||||
|
||||
|
844
targets/stm32l432/lib/stm32l4xx_hal_tsc.h
Normal file
844
targets/stm32l432/lib/stm32l4xx_hal_tsc.h
Normal file
@ -0,0 +1,844 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32l4xx_hal_tsc.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header file of TSC HAL module.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef STM32L4xx_HAL_TSC_H
|
||||
#define STM32L4xx_HAL_TSC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32l4xx_hal_def.h"
|
||||
|
||||
/** @addtogroup STM32L4xx_HAL_Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup TSC
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/** @defgroup TSC_Exported_Types TSC Exported Types
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief TSC state structure definition
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
HAL_TSC_STATE_RESET = 0x00UL, /*!< TSC registers have their reset value */
|
||||
HAL_TSC_STATE_READY = 0x01UL, /*!< TSC registers are initialized or acquisition is completed with success */
|
||||
HAL_TSC_STATE_BUSY = 0x02UL, /*!< TSC initialization or acquisition is on-going */
|
||||
HAL_TSC_STATE_ERROR = 0x03UL /*!< Acquisition is completed with max count error */
|
||||
} HAL_TSC_StateTypeDef;
|
||||
|
||||
/**
|
||||
* @brief TSC group status structure definition
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
TSC_GROUP_ONGOING = 0x00UL, /*!< Acquisition on group is on-going or not started */
|
||||
TSC_GROUP_COMPLETED = 0x01UL /*!< Acquisition on group is completed with success (no max count error) */
|
||||
} TSC_GroupStatusTypeDef;
|
||||
|
||||
/**
|
||||
* @brief TSC init structure definition
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t CTPulseHighLength; /*!< Charge-transfer high pulse length
|
||||
This parameter can be a value of @ref TSC_CTPulseHL_Config */
|
||||
uint32_t CTPulseLowLength; /*!< Charge-transfer low pulse length
|
||||
This parameter can be a value of @ref TSC_CTPulseLL_Config */
|
||||
uint32_t SpreadSpectrum; /*!< Spread spectrum activation
|
||||
This parameter can be a value of @ref TSC_CTPulseLL_Config */
|
||||
uint32_t SpreadSpectrumDeviation; /*!< Spread spectrum deviation
|
||||
This parameter must be a number between Min_Data = 0 and Max_Data = 127 */
|
||||
uint32_t SpreadSpectrumPrescaler; /*!< Spread spectrum prescaler
|
||||
This parameter can be a value of @ref TSC_SpreadSpec_Prescaler */
|
||||
uint32_t PulseGeneratorPrescaler; /*!< Pulse generator prescaler
|
||||
This parameter can be a value of @ref TSC_PulseGenerator_Prescaler */
|
||||
uint32_t MaxCountValue; /*!< Max count value
|
||||
This parameter can be a value of @ref TSC_MaxCount_Value */
|
||||
uint32_t IODefaultMode; /*!< IO default mode
|
||||
This parameter can be a value of @ref TSC_IO_Default_Mode */
|
||||
uint32_t SynchroPinPolarity; /*!< Synchro pin polarity
|
||||
This parameter can be a value of @ref TSC_Synchro_Pin_Polarity */
|
||||
uint32_t AcquisitionMode; /*!< Acquisition mode
|
||||
This parameter can be a value of @ref TSC_Acquisition_Mode */
|
||||
uint32_t MaxCountInterrupt; /*!< Max count interrupt activation
|
||||
This parameter can be set to ENABLE or DISABLE. */
|
||||
uint32_t ChannelIOs; /*!< Channel IOs mask */
|
||||
uint32_t ShieldIOs; /*!< Shield IOs mask */
|
||||
uint32_t SamplingIOs; /*!< Sampling IOs mask */
|
||||
} TSC_InitTypeDef;
|
||||
|
||||
/**
|
||||
* @brief TSC IOs configuration structure definition
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t ChannelIOs; /*!< Channel IOs mask */
|
||||
uint32_t ShieldIOs; /*!< Shield IOs mask */
|
||||
uint32_t SamplingIOs; /*!< Sampling IOs mask */
|
||||
} TSC_IOConfigTypeDef;
|
||||
|
||||
/**
|
||||
* @brief TSC handle Structure definition
|
||||
*/
|
||||
typedef struct __TSC_HandleTypeDef
|
||||
{
|
||||
TSC_TypeDef *Instance; /*!< Register base address */
|
||||
TSC_InitTypeDef Init; /*!< Initialization parameters */
|
||||
__IO HAL_TSC_StateTypeDef State; /*!< Peripheral state */
|
||||
HAL_LockTypeDef Lock; /*!< Lock feature */
|
||||
__IO uint32_t ErrorCode; /*!< I2C Error code */
|
||||
|
||||
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
|
||||
void (* ConvCpltCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Conversion complete callback */
|
||||
void (* ErrorCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Error callback */
|
||||
|
||||
void (* MspInitCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Msp Init callback */
|
||||
void (* MspDeInitCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Msp DeInit callback */
|
||||
|
||||
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
|
||||
} TSC_HandleTypeDef;
|
||||
|
||||
/**
|
||||
* @brief TSC Group Index Structure definition
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
TSC_GROUP1_IDX = 0x00UL,
|
||||
TSC_GROUP2_IDX,
|
||||
TSC_GROUP3_IDX,
|
||||
TSC_GROUP4_IDX,
|
||||
#if defined(TSC_IOCCR_G5_IO1)
|
||||
TSC_GROUP5_IDX,
|
||||
#endif
|
||||
#if defined(TSC_IOCCR_G6_IO1)
|
||||
TSC_GROUP6_IDX,
|
||||
#endif
|
||||
#if defined(TSC_IOCCR_G7_IO1)
|
||||
TSC_GROUP7_IDX,
|
||||
#endif
|
||||
#if defined(TSC_IOCCR_G8_IO1)
|
||||
TSC_GROUP8_IDX,
|
||||
#endif
|
||||
TSC_NB_OF_GROUPS
|
||||
}TSC_GroupIndexTypeDef;
|
||||
|
||||
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
|
||||
/**
|
||||
* @brief HAL TSC Callback ID enumeration definition
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
HAL_TSC_CONV_COMPLETE_CB_ID = 0x00UL, /*!< TSC Conversion completed callback ID */
|
||||
HAL_TSC_ERROR_CB_ID = 0x01UL, /*!< TSC Error callback ID */
|
||||
|
||||
HAL_TSC_MSPINIT_CB_ID = 0x02UL, /*!< TSC Msp Init callback ID */
|
||||
HAL_TSC_MSPDEINIT_CB_ID = 0x03UL /*!< TSC Msp DeInit callback ID */
|
||||
|
||||
} HAL_TSC_CallbackIDTypeDef;
|
||||
|
||||
/**
|
||||
* @brief HAL TSC Callback pointer definition
|
||||
*/
|
||||
typedef void (*pTSC_CallbackTypeDef)(TSC_HandleTypeDef *htsc); /*!< pointer to an TSC callback function */
|
||||
|
||||
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/** @defgroup TSC_Exported_Constants TSC Exported Constants
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_Error_Code_definition TSC Error Code definition
|
||||
* @brief TSC Error Code definition
|
||||
* @{
|
||||
*/
|
||||
#define HAL_TSC_ERROR_NONE 0x00000000UL /*!< No error */
|
||||
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
|
||||
#define HAL_TSC_ERROR_INVALID_CALLBACK 0x00000001UL /*!< Invalid Callback error */
|
||||
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_CTPulseHL_Config CTPulse High Length
|
||||
* @{
|
||||
*/
|
||||
#define TSC_CTPH_1CYCLE 0x00000000UL /*!< Charge transfer pulse high during 1 cycle (PGCLK) */
|
||||
#define TSC_CTPH_2CYCLES TSC_CR_CTPH_0 /*!< Charge transfer pulse high during 2 cycles (PGCLK) */
|
||||
#define TSC_CTPH_3CYCLES TSC_CR_CTPH_1 /*!< Charge transfer pulse high during 3 cycles (PGCLK) */
|
||||
#define TSC_CTPH_4CYCLES (TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 4 cycles (PGCLK) */
|
||||
#define TSC_CTPH_5CYCLES TSC_CR_CTPH_2 /*!< Charge transfer pulse high during 5 cycles (PGCLK) */
|
||||
#define TSC_CTPH_6CYCLES (TSC_CR_CTPH_2 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 6 cycles (PGCLK) */
|
||||
#define TSC_CTPH_7CYCLES (TSC_CR_CTPH_2 | TSC_CR_CTPH_1) /*!< Charge transfer pulse high during 7 cycles (PGCLK) */
|
||||
#define TSC_CTPH_8CYCLES (TSC_CR_CTPH_2 | TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 8 cycles (PGCLK) */
|
||||
#define TSC_CTPH_9CYCLES TSC_CR_CTPH_3 /*!< Charge transfer pulse high during 9 cycles (PGCLK) */
|
||||
#define TSC_CTPH_10CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 10 cycles (PGCLK) */
|
||||
#define TSC_CTPH_11CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_1) /*!< Charge transfer pulse high during 11 cycles (PGCLK) */
|
||||
#define TSC_CTPH_12CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 12 cycles (PGCLK) */
|
||||
#define TSC_CTPH_13CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2) /*!< Charge transfer pulse high during 13 cycles (PGCLK) */
|
||||
#define TSC_CTPH_14CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 14 cycles (PGCLK) */
|
||||
#define TSC_CTPH_15CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2 | TSC_CR_CTPH_1) /*!< Charge transfer pulse high during 15 cycles (PGCLK) */
|
||||
#define TSC_CTPH_16CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2 | TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 16 cycles (PGCLK) */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_CTPulseLL_Config CTPulse Low Length
|
||||
* @{
|
||||
*/
|
||||
#define TSC_CTPL_1CYCLE 0x00000000UL /*!< Charge transfer pulse low during 1 cycle (PGCLK) */
|
||||
#define TSC_CTPL_2CYCLES TSC_CR_CTPL_0 /*!< Charge transfer pulse low during 2 cycles (PGCLK) */
|
||||
#define TSC_CTPL_3CYCLES TSC_CR_CTPL_1 /*!< Charge transfer pulse low during 3 cycles (PGCLK) */
|
||||
#define TSC_CTPL_4CYCLES (TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 4 cycles (PGCLK) */
|
||||
#define TSC_CTPL_5CYCLES TSC_CR_CTPL_2 /*!< Charge transfer pulse low during 5 cycles (PGCLK) */
|
||||
#define TSC_CTPL_6CYCLES (TSC_CR_CTPL_2 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 6 cycles (PGCLK) */
|
||||
#define TSC_CTPL_7CYCLES (TSC_CR_CTPL_2 | TSC_CR_CTPL_1) /*!< Charge transfer pulse low during 7 cycles (PGCLK) */
|
||||
#define TSC_CTPL_8CYCLES (TSC_CR_CTPL_2 | TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 8 cycles (PGCLK) */
|
||||
#define TSC_CTPL_9CYCLES TSC_CR_CTPL_3 /*!< Charge transfer pulse low during 9 cycles (PGCLK) */
|
||||
#define TSC_CTPL_10CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 10 cycles (PGCLK) */
|
||||
#define TSC_CTPL_11CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_1) /*!< Charge transfer pulse low during 11 cycles (PGCLK) */
|
||||
#define TSC_CTPL_12CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 12 cycles (PGCLK) */
|
||||
#define TSC_CTPL_13CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2) /*!< Charge transfer pulse low during 13 cycles (PGCLK) */
|
||||
#define TSC_CTPL_14CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 14 cycles (PGCLK) */
|
||||
#define TSC_CTPL_15CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2 | TSC_CR_CTPL_1) /*!< Charge transfer pulse low during 15 cycles (PGCLK) */
|
||||
#define TSC_CTPL_16CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2 | TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 16 cycles (PGCLK) */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_SpreadSpec_Prescaler Spread Spectrum Prescaler
|
||||
* @{
|
||||
*/
|
||||
#define TSC_SS_PRESC_DIV1 0x00000000UL /*!< Spread Spectrum Prescaler Div1 */
|
||||
#define TSC_SS_PRESC_DIV2 TSC_CR_SSPSC /*!< Spread Spectrum Prescaler Div2 */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_PulseGenerator_Prescaler Pulse Generator Prescaler
|
||||
* @{
|
||||
*/
|
||||
#define TSC_PG_PRESC_DIV1 0x00000000UL /*!< Pulse Generator HCLK Div1 */
|
||||
#define TSC_PG_PRESC_DIV2 TSC_CR_PGPSC_0 /*!< Pulse Generator HCLK Div2 */
|
||||
#define TSC_PG_PRESC_DIV4 TSC_CR_PGPSC_1 /*!< Pulse Generator HCLK Div4 */
|
||||
#define TSC_PG_PRESC_DIV8 (TSC_CR_PGPSC_1 | TSC_CR_PGPSC_0) /*!< Pulse Generator HCLK Div8 */
|
||||
#define TSC_PG_PRESC_DIV16 TSC_CR_PGPSC_2 /*!< Pulse Generator HCLK Div16 */
|
||||
#define TSC_PG_PRESC_DIV32 (TSC_CR_PGPSC_2 | TSC_CR_PGPSC_0) /*!< Pulse Generator HCLK Div32 */
|
||||
#define TSC_PG_PRESC_DIV64 (TSC_CR_PGPSC_2 | TSC_CR_PGPSC_1) /*!< Pulse Generator HCLK Div64 */
|
||||
#define TSC_PG_PRESC_DIV128 (TSC_CR_PGPSC_2 | TSC_CR_PGPSC_1 | TSC_CR_PGPSC_0) /*!< Pulse Generator HCLK Div128 */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_MaxCount_Value Max Count Value
|
||||
* @{
|
||||
*/
|
||||
#define TSC_MCV_255 0x00000000UL /*!< 255 maximum number of charge transfer pulses */
|
||||
#define TSC_MCV_511 TSC_CR_MCV_0 /*!< 511 maximum number of charge transfer pulses */
|
||||
#define TSC_MCV_1023 TSC_CR_MCV_1 /*!< 1023 maximum number of charge transfer pulses */
|
||||
#define TSC_MCV_2047 (TSC_CR_MCV_1 | TSC_CR_MCV_0) /*!< 2047 maximum number of charge transfer pulses */
|
||||
#define TSC_MCV_4095 TSC_CR_MCV_2 /*!< 4095 maximum number of charge transfer pulses */
|
||||
#define TSC_MCV_8191 (TSC_CR_MCV_2 | TSC_CR_MCV_0) /*!< 8191 maximum number of charge transfer pulses */
|
||||
#define TSC_MCV_16383 (TSC_CR_MCV_2 | TSC_CR_MCV_1) /*!< 16383 maximum number of charge transfer pulses */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_IO_Default_Mode IO Default Mode
|
||||
* @{
|
||||
*/
|
||||
#define TSC_IODEF_OUT_PP_LOW 0x00000000UL /*!< I/Os are forced to output push-pull low */
|
||||
#define TSC_IODEF_IN_FLOAT TSC_CR_IODEF /*!< I/Os are in input floating */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_Synchro_Pin_Polarity Synchro Pin Polarity
|
||||
* @{
|
||||
*/
|
||||
#define TSC_SYNC_POLARITY_FALLING 0x00000000UL /*!< Falling edge only */
|
||||
#define TSC_SYNC_POLARITY_RISING TSC_CR_SYNCPOL /*!< Rising edge and high level */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_Acquisition_Mode Acquisition Mode
|
||||
* @{
|
||||
*/
|
||||
#define TSC_ACQ_MODE_NORMAL 0x00000000UL /*!< Normal acquisition mode (acquisition starts as soon as START bit is set) */
|
||||
#define TSC_ACQ_MODE_SYNCHRO TSC_CR_AM /*!< Synchronized acquisition mode (acquisition starts if START bit is set and when the selected signal is detected on the SYNC input pin) */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_interrupts_definition Interrupts definition
|
||||
* @{
|
||||
*/
|
||||
#define TSC_IT_EOA TSC_IER_EOAIE /*!< End of acquisition interrupt enable */
|
||||
#define TSC_IT_MCE TSC_IER_MCEIE /*!< Max count error interrupt enable */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_flags_definition Flags definition
|
||||
* @{
|
||||
*/
|
||||
#define TSC_FLAG_EOA TSC_ISR_EOAF /*!< End of acquisition flag */
|
||||
#define TSC_FLAG_MCE TSC_ISR_MCEF /*!< Max count error flag */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup TSC_Group_definition Group definition
|
||||
* @{
|
||||
*/
|
||||
#define TSC_GROUP1 (uint32_t)(0x1UL << TSC_GROUP1_IDX)
|
||||
#define TSC_GROUP2 (uint32_t)(0x1UL << TSC_GROUP2_IDX)
|
||||
#define TSC_GROUP3 (uint32_t)(0x1UL << TSC_GROUP3_IDX)
|
||||
#define TSC_GROUP4 (uint32_t)(0x1UL << TSC_GROUP4_IDX)
|
||||
#if defined(TSC_IOCCR_G5_IO1)
|
||||
#define TSC_GROUP5 (uint32_t)(0x1UL << TSC_GROUP5_IDX)
|
||||
#endif
|
||||
#if defined(TSC_IOCCR_G6_IO1)
|
||||
#define TSC_GROUP6 (uint32_t)(0x1UL << TSC_GROUP6_IDX)
|
||||
#endif
|
||||
#if defined(TSC_IOCCR_G7_IO1)
|
||||
#define TSC_GROUP7 (uint32_t)(0x1UL << TSC_GROUP7_IDX)
|
||||
#endif
|
||||
#if defined(TSC_IOCCR_G8_IO1)
|
||||
#define TSC_GROUP8 (uint32_t)(0x1UL << TSC_GROUP8_IDX)
|
||||
#endif
|
||||
|
||||
#define TSC_GROUPX_NOT_SUPPORTED 0xFF000000UL /*!< TSC GroupX not supported */
|
||||
|
||||
#define TSC_GROUP1_IO1 TSC_IOCCR_G1_IO1 /*!< TSC Group1 IO1 */
|
||||
#define TSC_GROUP1_IO2 TSC_IOCCR_G1_IO2 /*!< TSC Group1 IO2 */
|
||||
#define TSC_GROUP1_IO3 TSC_IOCCR_G1_IO3 /*!< TSC Group1 IO3 */
|
||||
#define TSC_GROUP1_IO4 TSC_IOCCR_G1_IO4 /*!< TSC Group1 IO4 */
|
||||
|
||||
#define TSC_GROUP2_IO1 TSC_IOCCR_G2_IO1 /*!< TSC Group2 IO1 */
|
||||
#define TSC_GROUP2_IO2 TSC_IOCCR_G2_IO2 /*!< TSC Group2 IO2 */
|
||||
#define TSC_GROUP2_IO3 TSC_IOCCR_G2_IO3 /*!< TSC Group2 IO3 */
|
||||
#define TSC_GROUP2_IO4 TSC_IOCCR_G2_IO4 /*!< TSC Group2 IO4 */
|
||||
|
||||
#define TSC_GROUP3_IO1 TSC_IOCCR_G3_IO1 /*!< TSC Group3 IO1 */
|
||||
#define TSC_GROUP3_IO2 TSC_IOCCR_G3_IO2 /*!< TSC Group3 IO2 */
|
||||
#define TSC_GROUP3_IO3 TSC_IOCCR_G3_IO3 /*!< TSC Group3 IO3 */
|
||||
#define TSC_GROUP3_IO4 TSC_IOCCR_G3_IO4 /*!< TSC Group3 IO4 */
|
||||
|
||||
#define TSC_GROUP4_IO1 TSC_IOCCR_G4_IO1 /*!< TSC Group4 IO1 */
|
||||
#define TSC_GROUP4_IO2 TSC_IOCCR_G4_IO2 /*!< TSC Group4 IO2 */
|
||||
#define TSC_GROUP4_IO3 TSC_IOCCR_G4_IO3 /*!< TSC Group4 IO3 */
|
||||
#define TSC_GROUP4_IO4 TSC_IOCCR_G4_IO4 /*!< TSC Group4 IO4 */
|
||||
#if defined(TSC_IOCCR_G5_IO1)
|
||||
|
||||
#define TSC_GROUP5_IO1 TSC_IOCCR_G5_IO1 /*!< TSC Group5 IO1 */
|
||||
#define TSC_GROUP5_IO2 TSC_IOCCR_G5_IO2 /*!< TSC Group5 IO2 */
|
||||
#define TSC_GROUP5_IO3 TSC_IOCCR_G5_IO3 /*!< TSC Group5 IO3 */
|
||||
#define TSC_GROUP5_IO4 TSC_IOCCR_G5_IO4 /*!< TSC Group5 IO4 */
|
||||
#else
|
||||
|
||||
#define TSC_GROUP5_IO1 (uint32_t)(0x00000010UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group5 IO1 not supported */
|
||||
#define TSC_GROUP5_IO2 TSC_GROUP5_IO1 /*!< TSC Group5 IO2 not supported */
|
||||
#define TSC_GROUP5_IO3 TSC_GROUP5_IO1 /*!< TSC Group5 IO3 not supported */
|
||||
#define TSC_GROUP5_IO4 TSC_GROUP5_IO1 /*!< TSC Group5 IO4 not supported */
|
||||
#endif
|
||||
#if defined(TSC_IOCCR_G6_IO1)
|
||||
|
||||
#define TSC_GROUP6_IO1 TSC_IOCCR_G6_IO1 /*!< TSC Group6 IO1 */
|
||||
#define TSC_GROUP6_IO2 TSC_IOCCR_G6_IO2 /*!< TSC Group6 IO2 */
|
||||
#define TSC_GROUP6_IO3 TSC_IOCCR_G6_IO3 /*!< TSC Group6 IO3 */
|
||||
#define TSC_GROUP6_IO4 TSC_IOCCR_G6_IO4 /*!< TSC Group6 IO4 */
|
||||
#else
|
||||
|
||||
#define TSC_GROUP6_IO1 (uint32_t)(0x00000020UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group6 IO1 not supported */
|
||||
#define TSC_GROUP6_IO2 TSC_GROUP6_IO1 /*!< TSC Group6 IO2 not supported */
|
||||
#define TSC_GROUP6_IO3 TSC_GROUP6_IO1 /*!< TSC Group6 IO3 not supported */
|
||||
#define TSC_GROUP6_IO4 TSC_GROUP6_IO1 /*!< TSC Group6 IO4 not supported */
|
||||
#endif
|
||||
#if defined(TSC_IOCCR_G7_IO1)
|
||||
|
||||
#define TSC_GROUP7_IO1 TSC_IOCCR_G7_IO1 /*!< TSC Group7 IO1 */
|
||||
#define TSC_GROUP7_IO2 TSC_IOCCR_G7_IO2 /*!< TSC Group7 IO2 */
|
||||
#define TSC_GROUP7_IO3 TSC_IOCCR_G7_IO3 /*!< TSC Group7 IO3 */
|
||||
#define TSC_GROUP7_IO4 TSC_IOCCR_G7_IO4 /*!< TSC Group7 IO4 */
|
||||
#else
|
||||
|
||||
#define TSC_GROUP7_IO1 (uint32_t)(0x00000040UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group7 IO1 not supported */
|
||||
#define TSC_GROUP7_IO2 TSC_GROUP7_IO1 /*!< TSC Group7 IO2 not supported */
|
||||
#define TSC_GROUP7_IO3 TSC_GROUP7_IO1 /*!< TSC Group7 IO3 not supported */
|
||||
#define TSC_GROUP7_IO4 TSC_GROUP7_IO1 /*!< TSC Group7 IO4 not supported */
|
||||
#endif
|
||||
#if defined(TSC_IOCCR_G8_IO1)
|
||||
|
||||
#define TSC_GROUP8_IO1 TSC_IOCCR_G8_IO1 /*!< TSC Group8 IO1 */
|
||||
#define TSC_GROUP8_IO2 TSC_IOCCR_G8_IO2 /*!< TSC Group8 IO2 */
|
||||
#define TSC_GROUP8_IO3 TSC_IOCCR_G8_IO3 /*!< TSC Group8 IO3 */
|
||||
#define TSC_GROUP8_IO4 TSC_IOCCR_G8_IO4 /*!< TSC Group8 IO4 */
|
||||
#else
|
||||
|
||||
#define TSC_GROUP8_IO1 (uint32_t)(0x00000080UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group8 IO1 not supported */
|
||||
#define TSC_GROUP8_IO2 TSC_GROUP8_IO1 /*!< TSC Group8 IO2 not supported */
|
||||
#define TSC_GROUP8_IO3 TSC_GROUP8_IO1 /*!< TSC Group8 IO3 not supported */
|
||||
#define TSC_GROUP8_IO4 TSC_GROUP8_IO1 /*!< TSC Group8 IO4 not supported */
|
||||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Exported macros -----------------------------------------------------------*/
|
||||
|
||||
/** @defgroup TSC_Exported_Macros TSC Exported Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Reset TSC handle state.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @retval None
|
||||
*/
|
||||
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
|
||||
#define __HAL_TSC_RESET_HANDLE_STATE(__HANDLE__) do{ \
|
||||
(__HANDLE__)->State = HAL_TSC_STATE_RESET; \
|
||||
(__HANDLE__)->MspInitCallback = NULL; \
|
||||
(__HANDLE__)->MspDeInitCallback = NULL; \
|
||||
} while(0)
|
||||
#else
|
||||
#define __HAL_TSC_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_TSC_STATE_RESET)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable the TSC peripheral.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_TSCE)
|
||||
|
||||
/**
|
||||
* @brief Disable the TSC peripheral.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_TSCE))
|
||||
|
||||
/**
|
||||
* @brief Start acquisition.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_START_ACQ(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_START)
|
||||
|
||||
/**
|
||||
* @brief Stop acquisition.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_STOP_ACQ(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_START))
|
||||
|
||||
/**
|
||||
* @brief Set IO default mode to output push-pull low.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_SET_IODEF_OUTPPLOW(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_IODEF))
|
||||
|
||||
/**
|
||||
* @brief Set IO default mode to input floating.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_SET_IODEF_INFLOAT(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_IODEF)
|
||||
|
||||
/**
|
||||
* @brief Set synchronization polarity to falling edge.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_SET_SYNC_POL_FALL(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_SYNCPOL))
|
||||
|
||||
/**
|
||||
* @brief Set synchronization polarity to rising edge and high level.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_SET_SYNC_POL_RISE_HIGH(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_SYNCPOL)
|
||||
|
||||
/**
|
||||
* @brief Enable TSC interrupt.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __INTERRUPT__ TSC interrupt
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->IER |= (__INTERRUPT__))
|
||||
|
||||
/**
|
||||
* @brief Disable TSC interrupt.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __INTERRUPT__ TSC interrupt
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->IER &= (uint32_t)(~(__INTERRUPT__)))
|
||||
|
||||
/** @brief Check whether the specified TSC interrupt source is enabled or not.
|
||||
* @param __HANDLE__ TSC Handle
|
||||
* @param __INTERRUPT__ TSC interrupt
|
||||
* @retval SET or RESET
|
||||
*/
|
||||
#define __HAL_TSC_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->IER & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET)
|
||||
|
||||
/**
|
||||
* @brief Check whether the specified TSC flag is set or not.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __FLAG__ TSC flag
|
||||
* @retval SET or RESET
|
||||
*/
|
||||
#define __HAL_TSC_GET_FLAG(__HANDLE__, __FLAG__) ((((__HANDLE__)->Instance->ISR & (__FLAG__)) == (__FLAG__)) ? SET : RESET)
|
||||
|
||||
/**
|
||||
* @brief Clear the TSC's pending flag.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __FLAG__ TSC flag
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->ICR = (__FLAG__))
|
||||
|
||||
/**
|
||||
* @brief Enable schmitt trigger hysteresis on a group of IOs.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_IOY_MASK__ IOs mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_ENABLE_HYSTERESIS(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOHCR |= (__GX_IOY_MASK__))
|
||||
|
||||
/**
|
||||
* @brief Disable schmitt trigger hysteresis on a group of IOs.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_IOY_MASK__ IOs mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_DISABLE_HYSTERESIS(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOHCR &= (uint32_t)(~(__GX_IOY_MASK__)))
|
||||
|
||||
/**
|
||||
* @brief Open analog switch on a group of IOs.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_IOY_MASK__ IOs mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_OPEN_ANALOG_SWITCH(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOASCR &= (uint32_t)(~(__GX_IOY_MASK__)))
|
||||
|
||||
/**
|
||||
* @brief Close analog switch on a group of IOs.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_IOY_MASK__ IOs mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_CLOSE_ANALOG_SWITCH(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOASCR |= (__GX_IOY_MASK__))
|
||||
|
||||
/**
|
||||
* @brief Enable a group of IOs in channel mode.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_IOY_MASK__ IOs mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_ENABLE_CHANNEL(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOCCR |= (__GX_IOY_MASK__))
|
||||
|
||||
/**
|
||||
* @brief Disable a group of channel IOs.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_IOY_MASK__ IOs mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_DISABLE_CHANNEL(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOCCR &= (uint32_t)(~(__GX_IOY_MASK__)))
|
||||
|
||||
/**
|
||||
* @brief Enable a group of IOs in sampling mode.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_IOY_MASK__ IOs mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_ENABLE_SAMPLING(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOSCR |= (__GX_IOY_MASK__))
|
||||
|
||||
/**
|
||||
* @brief Disable a group of sampling IOs.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_IOY_MASK__ IOs mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_DISABLE_SAMPLING(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOSCR &= (uint32_t)(~(__GX_IOY_MASK__)))
|
||||
|
||||
/**
|
||||
* @brief Enable acquisition groups.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_MASK__ Groups mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_ENABLE_GROUP(__HANDLE__, __GX_MASK__) ((__HANDLE__)->Instance->IOGCSR |= (__GX_MASK__))
|
||||
|
||||
/**
|
||||
* @brief Disable acquisition groups.
|
||||
* @param __HANDLE__ TSC handle
|
||||
* @param __GX_MASK__ Groups mask
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TSC_DISABLE_GROUP(__HANDLE__, __GX_MASK__) ((__HANDLE__)->Instance->IOGCSR &= (uint32_t)(~(__GX_MASK__)))
|
||||
|
||||
/** @brief Gets acquisition group status.
|
||||
* @param __HANDLE__ TSC Handle
|
||||
* @param __GX_INDEX__ Group index
|
||||
* @retval SET or RESET
|
||||
*/
|
||||
#define __HAL_TSC_GET_GROUP_STATUS(__HANDLE__, __GX_INDEX__) \
|
||||
((((__HANDLE__)->Instance->IOGCSR & (uint32_t)(1UL << (((__GX_INDEX__) & (uint32_t)TSC_NB_OF_GROUPS) + 16UL))) == (uint32_t)(1UL << (((__GX_INDEX__) & (uint32_t)TSC_NB_OF_GROUPS) + 16UL))) ? TSC_GROUP_COMPLETED : TSC_GROUP_ONGOING)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Private macros ------------------------------------------------------------*/
|
||||
|
||||
/** @defgroup TSC_Private_Macros TSC Private Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define IS_TSC_CTPH(__VALUE__) (((__VALUE__) == TSC_CTPH_1CYCLE) || \
|
||||
((__VALUE__) == TSC_CTPH_2CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_3CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_4CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_5CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_6CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_7CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_8CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_9CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_10CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_11CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_12CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_13CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_14CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_15CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPH_16CYCLES))
|
||||
|
||||
#define IS_TSC_CTPL(__VALUE__) (((__VALUE__) == TSC_CTPL_1CYCLE) || \
|
||||
((__VALUE__) == TSC_CTPL_2CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_3CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_4CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_5CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_6CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_7CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_8CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_9CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_10CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_11CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_12CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_13CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_14CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_15CYCLES) || \
|
||||
((__VALUE__) == TSC_CTPL_16CYCLES))
|
||||
|
||||
#define IS_TSC_SS(__VALUE__) (((FunctionalState)(__VALUE__) == DISABLE) || ((FunctionalState)(__VALUE__) == ENABLE))
|
||||
|
||||
#define IS_TSC_SSD(__VALUE__) (((__VALUE__) == 0UL) || (((__VALUE__) > 0UL) && ((__VALUE__) < 128UL)))
|
||||
|
||||
#define IS_TSC_SS_PRESC(__VALUE__) (((__VALUE__) == TSC_SS_PRESC_DIV1) || ((__VALUE__) == TSC_SS_PRESC_DIV2))
|
||||
|
||||
#define IS_TSC_PG_PRESC(__VALUE__) (((__VALUE__) == TSC_PG_PRESC_DIV1) || \
|
||||
((__VALUE__) == TSC_PG_PRESC_DIV2) || \
|
||||
((__VALUE__) == TSC_PG_PRESC_DIV4) || \
|
||||
((__VALUE__) == TSC_PG_PRESC_DIV8) || \
|
||||
((__VALUE__) == TSC_PG_PRESC_DIV16) || \
|
||||
((__VALUE__) == TSC_PG_PRESC_DIV32) || \
|
||||
((__VALUE__) == TSC_PG_PRESC_DIV64) || \
|
||||
((__VALUE__) == TSC_PG_PRESC_DIV128))
|
||||
|
||||
#define IS_TSC_MCV(__VALUE__) (((__VALUE__) == TSC_MCV_255) || \
|
||||
((__VALUE__) == TSC_MCV_511) || \
|
||||
((__VALUE__) == TSC_MCV_1023) || \
|
||||
((__VALUE__) == TSC_MCV_2047) || \
|
||||
((__VALUE__) == TSC_MCV_4095) || \
|
||||
((__VALUE__) == TSC_MCV_8191) || \
|
||||
((__VALUE__) == TSC_MCV_16383))
|
||||
|
||||
#define IS_TSC_IODEF(__VALUE__) (((__VALUE__) == TSC_IODEF_OUT_PP_LOW) || ((__VALUE__) == TSC_IODEF_IN_FLOAT))
|
||||
|
||||
#define IS_TSC_SYNC_POL(__VALUE__) (((__VALUE__) == TSC_SYNC_POLARITY_FALLING) || ((__VALUE__) == TSC_SYNC_POLARITY_RISING))
|
||||
|
||||
#define IS_TSC_ACQ_MODE(__VALUE__) (((__VALUE__) == TSC_ACQ_MODE_NORMAL) || ((__VALUE__) == TSC_ACQ_MODE_SYNCHRO))
|
||||
|
||||
#define IS_TSC_MCE_IT(__VALUE__) (((FunctionalState)(__VALUE__) == DISABLE) || ((FunctionalState)(__VALUE__) == ENABLE))
|
||||
|
||||
#define IS_TSC_GROUP_INDEX(__VALUE__) (((__VALUE__) == 0UL) || (((__VALUE__) > 0UL) && ((__VALUE__) < (uint32_t)TSC_NB_OF_GROUPS)))
|
||||
|
||||
|
||||
#define IS_TSC_GROUP(__VALUE__) ((((__VALUE__) & TSC_GROUPX_NOT_SUPPORTED) != TSC_GROUPX_NOT_SUPPORTED) && \
|
||||
((((__VALUE__) & TSC_GROUP1_IO1) == TSC_GROUP1_IO1) ||\
|
||||
(((__VALUE__) & TSC_GROUP1_IO2) == TSC_GROUP1_IO2) ||\
|
||||
(((__VALUE__) & TSC_GROUP1_IO3) == TSC_GROUP1_IO3) ||\
|
||||
(((__VALUE__) & TSC_GROUP1_IO4) == TSC_GROUP1_IO4) ||\
|
||||
(((__VALUE__) & TSC_GROUP2_IO1) == TSC_GROUP2_IO1) ||\
|
||||
(((__VALUE__) & TSC_GROUP2_IO2) == TSC_GROUP2_IO2) ||\
|
||||
(((__VALUE__) & TSC_GROUP2_IO3) == TSC_GROUP2_IO3) ||\
|
||||
(((__VALUE__) & TSC_GROUP2_IO4) == TSC_GROUP2_IO4) ||\
|
||||
(((__VALUE__) & TSC_GROUP3_IO1) == TSC_GROUP3_IO1) ||\
|
||||
(((__VALUE__) & TSC_GROUP3_IO2) == TSC_GROUP3_IO2) ||\
|
||||
(((__VALUE__) & TSC_GROUP3_IO3) == TSC_GROUP3_IO3) ||\
|
||||
(((__VALUE__) & TSC_GROUP3_IO4) == TSC_GROUP3_IO4) ||\
|
||||
(((__VALUE__) & TSC_GROUP4_IO1) == TSC_GROUP4_IO1) ||\
|
||||
(((__VALUE__) & TSC_GROUP4_IO2) == TSC_GROUP4_IO2) ||\
|
||||
(((__VALUE__) & TSC_GROUP4_IO3) == TSC_GROUP4_IO3) ||\
|
||||
(((__VALUE__) & TSC_GROUP4_IO4) == TSC_GROUP4_IO4) ||\
|
||||
(((__VALUE__) & TSC_GROUP5_IO1) == TSC_GROUP5_IO1) ||\
|
||||
(((__VALUE__) & TSC_GROUP5_IO2) == TSC_GROUP5_IO2) ||\
|
||||
(((__VALUE__) & TSC_GROUP5_IO3) == TSC_GROUP5_IO3) ||\
|
||||
(((__VALUE__) & TSC_GROUP5_IO4) == TSC_GROUP5_IO4) ||\
|
||||
(((__VALUE__) & TSC_GROUP6_IO1) == TSC_GROUP6_IO1) ||\
|
||||
(((__VALUE__) & TSC_GROUP6_IO2) == TSC_GROUP6_IO2) ||\
|
||||
(((__VALUE__) & TSC_GROUP6_IO3) == TSC_GROUP6_IO3) ||\
|
||||
(((__VALUE__) & TSC_GROUP6_IO4) == TSC_GROUP6_IO4) ||\
|
||||
(((__VALUE__) & TSC_GROUP7_IO1) == TSC_GROUP7_IO1) ||\
|
||||
(((__VALUE__) & TSC_GROUP7_IO2) == TSC_GROUP7_IO2) ||\
|
||||
(((__VALUE__) & TSC_GROUP7_IO3) == TSC_GROUP7_IO3) ||\
|
||||
(((__VALUE__) & TSC_GROUP7_IO4) == TSC_GROUP7_IO4) ||\
|
||||
(((__VALUE__) & TSC_GROUP8_IO1) == TSC_GROUP8_IO1) ||\
|
||||
(((__VALUE__) & TSC_GROUP8_IO2) == TSC_GROUP8_IO2) ||\
|
||||
(((__VALUE__) & TSC_GROUP8_IO3) == TSC_GROUP8_IO3) ||\
|
||||
(((__VALUE__) & TSC_GROUP8_IO4) == TSC_GROUP8_IO4)))
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Exported functions --------------------------------------------------------*/
|
||||
/** @addtogroup TSC_Exported_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup TSC_Exported_Functions_Group1 Initialization and de-initialization functions
|
||||
* @{
|
||||
*/
|
||||
/* Initialization and de-initialization functions *****************************/
|
||||
HAL_StatusTypeDef HAL_TSC_Init(TSC_HandleTypeDef *htsc);
|
||||
HAL_StatusTypeDef HAL_TSC_DeInit(TSC_HandleTypeDef *htsc);
|
||||
void HAL_TSC_MspInit(TSC_HandleTypeDef *htsc);
|
||||
void HAL_TSC_MspDeInit(TSC_HandleTypeDef *htsc);
|
||||
|
||||
/* Callbacks Register/UnRegister functions ***********************************/
|
||||
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
|
||||
HAL_StatusTypeDef HAL_TSC_RegisterCallback(TSC_HandleTypeDef *htsc, HAL_TSC_CallbackIDTypeDef CallbackID, pTSC_CallbackTypeDef pCallback);
|
||||
HAL_StatusTypeDef HAL_TSC_UnRegisterCallback(TSC_HandleTypeDef *htsc, HAL_TSC_CallbackIDTypeDef CallbackID);
|
||||
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup TSC_Exported_Functions_Group2 Input and Output operation functions
|
||||
* @{
|
||||
*/
|
||||
/* IO operation functions *****************************************************/
|
||||
HAL_StatusTypeDef HAL_TSC_Start(TSC_HandleTypeDef *htsc);
|
||||
HAL_StatusTypeDef HAL_TSC_Start_IT(TSC_HandleTypeDef *htsc);
|
||||
HAL_StatusTypeDef HAL_TSC_Stop(TSC_HandleTypeDef *htsc);
|
||||
HAL_StatusTypeDef HAL_TSC_Stop_IT(TSC_HandleTypeDef *htsc);
|
||||
HAL_StatusTypeDef HAL_TSC_PollForAcquisition(TSC_HandleTypeDef *htsc);
|
||||
TSC_GroupStatusTypeDef HAL_TSC_GroupGetStatus(TSC_HandleTypeDef *htsc, uint32_t gx_index);
|
||||
uint32_t HAL_TSC_GroupGetValue(TSC_HandleTypeDef *htsc, uint32_t gx_index);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup TSC_Exported_Functions_Group3 Peripheral Control functions
|
||||
* @{
|
||||
*/
|
||||
/* Peripheral Control functions ***********************************************/
|
||||
HAL_StatusTypeDef HAL_TSC_IOConfig(TSC_HandleTypeDef *htsc, TSC_IOConfigTypeDef *config);
|
||||
HAL_StatusTypeDef HAL_TSC_IODischarge(TSC_HandleTypeDef *htsc, uint32_t choice);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup TSC_Exported_Functions_Group4 Peripheral State and Errors functions
|
||||
* @{
|
||||
*/
|
||||
/* Peripheral State and Error functions ***************************************/
|
||||
HAL_TSC_StateTypeDef HAL_TSC_GetState(TSC_HandleTypeDef *htsc);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup TSC_IRQ_Handler_and_Callbacks IRQ Handler and Callbacks
|
||||
* @{
|
||||
*/
|
||||
/******* TSC IRQHandler and Callbacks used in Interrupt mode */
|
||||
void HAL_TSC_IRQHandler(TSC_HandleTypeDef *htsc);
|
||||
void HAL_TSC_ConvCpltCallback(TSC_HandleTypeDef *htsc);
|
||||
void HAL_TSC_ErrorCallback(TSC_HandleTypeDef *htsc);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STM32L4xx_HAL_TSC_H */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@ -342,6 +342,7 @@ static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
||||
uint8_t *pbuf = NULL;
|
||||
uint16_t status_info = 0U;
|
||||
USBD_StatusTypeDef ret = USBD_OK;
|
||||
req->wLength = req->wLength & 0x7f;
|
||||
|
||||
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
||||
{
|
||||
@ -386,6 +387,7 @@ static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
||||
break;
|
||||
|
||||
case USB_REQ_GET_DESCRIPTOR:
|
||||
req->wLength = req->wLength & 0x7f;
|
||||
if(req->wValue >> 8 == HID_REPORT_DESC)
|
||||
{
|
||||
len = MIN(HID_FIDO_REPORT_DESC_SIZE , req->wLength);
|
||||
|
@ -270,7 +270,7 @@ void ams_print_int1(uint8_t int0)
|
||||
#endif
|
||||
}
|
||||
|
||||
void ams_init()
|
||||
int ams_init()
|
||||
{
|
||||
LL_GPIO_SetPinMode(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN,LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN);
|
||||
@ -283,6 +283,13 @@ void ams_init()
|
||||
// delay(10);
|
||||
SELECT();
|
||||
delay(1);
|
||||
|
||||
uint8_t productType = ams_read_reg(AMS_REG_PRODUCT_TYPE);
|
||||
if (productType == 0x14)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ams_configure()
|
||||
|
@ -39,7 +39,7 @@ typedef union
|
||||
#define SELECT() LL_GPIO_ResetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
|
||||
#define UNSELECT() LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
|
||||
|
||||
void ams_init();
|
||||
int ams_init();
|
||||
void ams_configure();
|
||||
|
||||
void ams_read_buffer(uint8_t * data, int len);
|
||||
|
@ -23,6 +23,7 @@
|
||||
//#define USING_DEV_BOARD
|
||||
|
||||
#define ENABLE_U2F_EXTENSIONS
|
||||
// #define ENABLE_WALLET
|
||||
|
||||
#define ENABLE_U2F
|
||||
|
||||
@ -30,7 +31,7 @@
|
||||
// #define DISABLE_CTAPHID_WINK
|
||||
// #define DISABLE_CTAPHID_CBOR
|
||||
|
||||
#define ENABLE_SERIAL_PRINTING
|
||||
// #define ENABLE_SERIAL_PRINTING
|
||||
|
||||
#if defined(SOLO_HACKER)
|
||||
#define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION
|
||||
|
@ -157,6 +157,11 @@ void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||
key = master_secret;
|
||||
klen = sizeof(master_secret)/2;
|
||||
}
|
||||
else if (key == CRYPTO_TRANSPORT_KEY2)
|
||||
{
|
||||
key = transport_secret;
|
||||
klen = 32;
|
||||
}
|
||||
|
||||
|
||||
if(klen > 64)
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "usbd_cdc_if.h"
|
||||
#include "nfc.h"
|
||||
#include "init.h"
|
||||
#include "sense.h"
|
||||
|
||||
#define LOW_FREQUENCY 1
|
||||
#define HIGH_FREQUENCY 0
|
||||
@ -40,10 +41,26 @@ uint32_t __90_ms = 0;
|
||||
uint32_t __device_status = 0;
|
||||
uint32_t __last_update = 0;
|
||||
extern PCD_HandleTypeDef hpcd;
|
||||
static bool haveNFC = 0;
|
||||
static int _NFC_status = 0;
|
||||
static bool isLowFreq = 0;
|
||||
static bool _RequestComeFromNFC = false;
|
||||
|
||||
#define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
||||
// #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
||||
static int is_physical_button_pressed()
|
||||
{
|
||||
return (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN));
|
||||
}
|
||||
|
||||
static int is_touch_button_pressed()
|
||||
{
|
||||
return tsc_read_button(0) || tsc_read_button(1);
|
||||
}
|
||||
|
||||
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
|
||||
|
||||
void request_from_nfc(bool request_active) {
|
||||
_RequestComeFromNFC = request_active;
|
||||
}
|
||||
|
||||
// Timer6 overflow handler. happens every ~90ms.
|
||||
void TIM6_DAC_IRQHandler()
|
||||
@ -51,7 +68,7 @@ void TIM6_DAC_IRQHandler()
|
||||
// timer is only 16 bits, so roll it over here
|
||||
TIM6->SR = 0;
|
||||
__90_ms += 1;
|
||||
if ((millis() - __last_update) > 8)
|
||||
if ((millis() - __last_update) > 90)
|
||||
{
|
||||
if (__device_status != CTAPHID_STATUS_IDLE)
|
||||
{
|
||||
@ -60,7 +77,7 @@ void TIM6_DAC_IRQHandler()
|
||||
}
|
||||
#ifndef IS_BOOTLOADER
|
||||
// NFC sending WTX if needs
|
||||
if (device_is_nfc())
|
||||
if (device_is_nfc() == NFC_IS_ACTIVE)
|
||||
{
|
||||
WTX_timer_exec();
|
||||
}
|
||||
@ -93,6 +110,7 @@ void device_set_status(uint32_t status)
|
||||
|
||||
int device_is_button_pressed()
|
||||
{
|
||||
|
||||
return IS_BUTTON_PRESSED();
|
||||
}
|
||||
|
||||
@ -107,23 +125,41 @@ void device_reboot()
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void device_init()
|
||||
void device_init_button()
|
||||
{
|
||||
if (tsc_sensor_exists())
|
||||
{
|
||||
tsc_init();
|
||||
IS_BUTTON_PRESSED = is_touch_button_pressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
IS_BUTTON_PRESSED = is_physical_button_pressed;
|
||||
}
|
||||
}
|
||||
|
||||
void device_init(int argc, char *argv[])
|
||||
{
|
||||
|
||||
hw_init(LOW_FREQUENCY);
|
||||
isLowFreq = 0;
|
||||
|
||||
haveNFC = nfc_init();
|
||||
if (! tsc_sensor_exists())
|
||||
{
|
||||
_NFC_status = nfc_init();
|
||||
}
|
||||
|
||||
if (haveNFC)
|
||||
if (_NFC_status == NFC_IS_ACTIVE)
|
||||
{
|
||||
printf1(TAG_NFC, "Have NFC\r\n");
|
||||
isLowFreq = 1;
|
||||
IS_BUTTON_PRESSED = is_physical_button_pressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_NFC, "Have NO NFC\r\n");
|
||||
hw_init(HIGH_FREQUENCY);
|
||||
isLowFreq = 0;
|
||||
device_init_button();
|
||||
}
|
||||
|
||||
usbhid_init();
|
||||
@ -139,9 +175,9 @@ void device_init()
|
||||
|
||||
}
|
||||
|
||||
bool device_is_nfc()
|
||||
int device_is_nfc()
|
||||
{
|
||||
return haveNFC;
|
||||
return _NFC_status;
|
||||
}
|
||||
|
||||
void wait_for_usb_tether()
|
||||
@ -433,7 +469,7 @@ void device_manage()
|
||||
}
|
||||
#endif
|
||||
#ifndef IS_BOOTLOADER
|
||||
// if(device_is_nfc())
|
||||
if(device_is_nfc())
|
||||
nfc_loop();
|
||||
#endif
|
||||
}
|
||||
@ -457,9 +493,13 @@ static int handle_packets()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctap_user_presence_test()
|
||||
int ctap_user_presence_test(uint32_t up_delay)
|
||||
{
|
||||
int ret;
|
||||
if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#if SKIP_BUTTON_CHECK_WITH_DELAY
|
||||
int i=500;
|
||||
while(i--)
|
||||
@ -478,22 +518,26 @@ int ctap_user_presence_test()
|
||||
uint32_t t1 = millis();
|
||||
led_rgb(0xff3520);
|
||||
|
||||
while (IS_BUTTON_PRESSED())
|
||||
if (IS_BUTTON_PRESSED == is_touch_button_pressed)
|
||||
{
|
||||
if (t1 + 5000 < millis())
|
||||
// Wait for user to release touch button if it's already pressed
|
||||
while (IS_BUTTON_PRESSED())
|
||||
{
|
||||
printf1(TAG_GEN,"Button not pressed\n");
|
||||
goto fail;
|
||||
if (t1 + up_delay < millis())
|
||||
{
|
||||
printf1(TAG_GEN,"Button not pressed\n");
|
||||
goto fail;
|
||||
}
|
||||
ret = handle_packets();
|
||||
if (ret) return ret;
|
||||
}
|
||||
ret = handle_packets();
|
||||
if (ret) return ret;
|
||||
}
|
||||
|
||||
t1 = millis();
|
||||
|
||||
do
|
||||
{
|
||||
if (t1 + 5000 < millis())
|
||||
if (t1 + up_delay < millis())
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "usbd_cdc_if.h"
|
||||
#include "device.h"
|
||||
#include "init.h"
|
||||
#include "sense.h"
|
||||
#include APP_CONFIG
|
||||
|
||||
// KHz
|
||||
@ -94,8 +95,6 @@ void hw_init(int lowfreq)
|
||||
SystemClock_Config();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!lowfreq)
|
||||
{
|
||||
init_pwm();
|
||||
@ -108,6 +107,7 @@ void hw_init(int lowfreq)
|
||||
#endif
|
||||
|
||||
init_rng();
|
||||
|
||||
init_spi();
|
||||
|
||||
}
|
||||
|
@ -14,6 +14,16 @@
|
||||
|
||||
#define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN))
|
||||
|
||||
uint8_t p14443_block_offset(uint8_t pcb) {
|
||||
uint8_t offset = 1;
|
||||
// NAD following
|
||||
if (pcb & 0x04) offset++;
|
||||
// CID following
|
||||
if (pcb & 0x08) offset++;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
// Capability container
|
||||
const CAPABILITY_CONTAINER NFC_CC = {
|
||||
.cclen_hi = 0x00, .cclen_lo = 0x0f,
|
||||
@ -55,11 +65,12 @@ void nfc_state_init()
|
||||
NFC_STATE.block_num = 1;
|
||||
}
|
||||
|
||||
bool nfc_init()
|
||||
int nfc_init()
|
||||
{
|
||||
uint32_t t1;
|
||||
int init;
|
||||
nfc_state_init();
|
||||
ams_init();
|
||||
init = ams_init();
|
||||
|
||||
// Detect if we are powered by NFC field by listening for a message for
|
||||
// first 10 ms.
|
||||
@ -67,13 +78,18 @@ bool nfc_init()
|
||||
while ((millis() - t1) < 10)
|
||||
{
|
||||
if (nfc_loop() > 0)
|
||||
return 1;
|
||||
return NFC_IS_ACTIVE;
|
||||
}
|
||||
|
||||
// Under USB power. Configure AMS chip.
|
||||
ams_configure();
|
||||
|
||||
return 0;
|
||||
if (init)
|
||||
{
|
||||
return NFC_IS_AVAILABLE;
|
||||
}
|
||||
|
||||
return NFC_IS_NA;
|
||||
}
|
||||
|
||||
void process_int0(uint8_t int0)
|
||||
@ -106,6 +122,7 @@ bool ams_receive_with_timeout(uint32_t timeout_ms, uint8_t * data, int maxlen, i
|
||||
while (tstart + timeout_ms > millis())
|
||||
{
|
||||
uint8_t int0 = ams_read_reg(AMS_REG_INT0);
|
||||
if (int0) process_int0(int0);
|
||||
uint8_t buffer_status2 = ams_read_reg(AMS_REG_BUF2);
|
||||
|
||||
if (buffer_status2 && (int0 & AMS_INT_RXE))
|
||||
@ -155,14 +172,18 @@ bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t r
|
||||
if (len > 32 - 3)
|
||||
return false;
|
||||
|
||||
res[0] = NFC_CMD_IBLOCK | (req0 & 3);
|
||||
res[0] = NFC_CMD_IBLOCK | (req0 & 0x0f);
|
||||
res[1] = 0;
|
||||
res[2] = 0;
|
||||
|
||||
uint8_t block_offset = p14443_block_offset(req0);
|
||||
|
||||
if (len && data)
|
||||
memcpy(&res[1], data, len);
|
||||
memcpy(&res[block_offset], data, len);
|
||||
|
||||
res[len + 1] = resp >> 8;
|
||||
res[len + 2] = resp & 0xff;
|
||||
nfc_write_frame(res, 3 + len);
|
||||
res[len + block_offset + 0] = resp >> 8;
|
||||
res[len + block_offset + 1] = resp & 0xff;
|
||||
nfc_write_frame(res, block_offset + len + 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -176,21 +197,24 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
|
||||
{
|
||||
uint8_t res[32 + 2];
|
||||
int sendlen = 0;
|
||||
uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 3);
|
||||
uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 0x0f);
|
||||
uint8_t block_offset = p14443_block_offset(req0);
|
||||
|
||||
if (len <= 31)
|
||||
{
|
||||
uint8_t res[32] = {0};
|
||||
res[0] = iBlock;
|
||||
res[0] = iBlock;
|
||||
if (len && data)
|
||||
memcpy(&res[1], data, len);
|
||||
nfc_write_frame(res, len + 1);
|
||||
memcpy(&res[block_offset], data, len);
|
||||
nfc_write_frame(res, len + block_offset);
|
||||
} else {
|
||||
do {
|
||||
// transmit I block
|
||||
int vlen = MIN(31, len - sendlen);
|
||||
res[0] = iBlock;
|
||||
memcpy(&res[1], &data[sendlen], vlen);
|
||||
int vlen = MIN(32 - block_offset, len - sendlen);
|
||||
res[0] = iBlock;
|
||||
res[1] = 0;
|
||||
res[2] = 0;
|
||||
memcpy(&res[block_offset], &data[sendlen], vlen);
|
||||
|
||||
// if not a last block
|
||||
if (vlen + sendlen < len)
|
||||
@ -199,7 +223,7 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
|
||||
}
|
||||
|
||||
// send data
|
||||
nfc_write_frame(res, vlen + 1);
|
||||
nfc_write_frame(res, vlen + block_offset);
|
||||
sendlen += vlen;
|
||||
|
||||
// wait for transmit (32 bytes aprox 2,5ms)
|
||||
@ -220,9 +244,10 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
|
||||
break;
|
||||
}
|
||||
|
||||
if (reclen != 1)
|
||||
uint8_t rblock_offset = p14443_block_offset(recbuf[0]);
|
||||
if (reclen != rblock_offset)
|
||||
{
|
||||
printf1(TAG_NFC, "R block length error. len: %d. %d/%d \r\n", reclen,sendlen,len);
|
||||
printf1(TAG_NFC, "R block length error. len: %d. %d/%d \r\n", reclen, sendlen, len);
|
||||
dump_hex1(TAG_NFC, recbuf, reclen);
|
||||
break;
|
||||
}
|
||||
@ -365,39 +390,72 @@ int answer_rats(uint8_t parameter)
|
||||
|
||||
|
||||
nfc_write_frame(res, sizeof(res));
|
||||
ams_wait_for_tx(10);
|
||||
if (!ams_wait_for_tx(10))
|
||||
{
|
||||
printf1(TAG_NFC, "RATS TX timeout.\r\n");
|
||||
ams_write_command(AMS_CMD_DEFAULT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rblock_acknowledge()
|
||||
void rblock_acknowledge(uint8_t req0, bool ack)
|
||||
{
|
||||
uint8_t buf[32];
|
||||
uint8_t buf[32] = {0};
|
||||
|
||||
uint8_t block_offset = p14443_block_offset(req0);
|
||||
NFC_STATE.block_num = !NFC_STATE.block_num;
|
||||
buf[0] = NFC_CMD_RBLOCK | NFC_STATE.block_num;
|
||||
nfc_write_frame(buf,1);
|
||||
|
||||
buf[0] = NFC_CMD_RBLOCK | (req0 & 0x0f);
|
||||
if (ack)
|
||||
buf[0] |= NFC_CMD_RBLOCK_ACK;
|
||||
|
||||
nfc_write_frame(buf, block_offset);
|
||||
}
|
||||
|
||||
// international AID = RID:PIX
|
||||
// RID length == 5 bytes
|
||||
// usually aid length must be between 5 and 16 bytes
|
||||
int applet_cmp(uint8_t * aid, int len, uint8_t * const_aid, int const_len)
|
||||
{
|
||||
if (len > const_len)
|
||||
return 10;
|
||||
|
||||
// if international AID
|
||||
if ((const_aid[0] & 0xf0) == 0xa0)
|
||||
{
|
||||
if (len < 5)
|
||||
return 11;
|
||||
return memcmp(aid, const_aid, MIN(len, const_len));
|
||||
} else {
|
||||
if (len != const_len)
|
||||
return 11;
|
||||
|
||||
return memcmp(aid, const_aid, const_len);
|
||||
}
|
||||
}
|
||||
|
||||
// Selects application. Returns 1 if success, 0 otherwise
|
||||
int select_applet(uint8_t * aid, int len)
|
||||
{
|
||||
if (memcmp(aid,AID_FIDO,sizeof(AID_FIDO)) == 0)
|
||||
if (applet_cmp(aid, len, (uint8_t *)AID_FIDO, sizeof(AID_FIDO) - 1) == 0)
|
||||
{
|
||||
NFC_STATE.selected_applet = APP_FIDO;
|
||||
return APP_FIDO;
|
||||
}
|
||||
else if (memcmp(aid,AID_NDEF_TYPE_4,sizeof(AID_NDEF_TYPE_4)) == 0)
|
||||
else if (applet_cmp(aid, len, (uint8_t *)AID_NDEF_TYPE_4, sizeof(AID_NDEF_TYPE_4) - 1) == 0)
|
||||
{
|
||||
NFC_STATE.selected_applet = APP_NDEF_TYPE_4;
|
||||
return APP_NDEF_TYPE_4;
|
||||
}
|
||||
else if (memcmp(aid,AID_CAPABILITY_CONTAINER,sizeof(AID_CAPABILITY_CONTAINER)) == 0)
|
||||
else if (applet_cmp(aid, len, (uint8_t *)AID_CAPABILITY_CONTAINER, sizeof(AID_CAPABILITY_CONTAINER) - 1) == 0)
|
||||
{
|
||||
NFC_STATE.selected_applet = APP_CAPABILITY_CONTAINER;
|
||||
return APP_CAPABILITY_CONTAINER;
|
||||
}
|
||||
else if (memcmp(aid,AID_NDEF_TAG,sizeof(AID_NDEF_TAG)) == 0)
|
||||
else if (applet_cmp(aid, len, (uint8_t *)AID_NDEF_TAG, sizeof(AID_NDEF_TAG) - 1) == 0)
|
||||
{
|
||||
NFC_STATE.selected_applet = APP_NDEF_TAG;
|
||||
return APP_NDEF_TAG;
|
||||
@ -407,25 +465,36 @@ int select_applet(uint8_t * aid, int len)
|
||||
|
||||
void nfc_process_iblock(uint8_t * buf, int len)
|
||||
{
|
||||
APDU_HEADER * apdu = (APDU_HEADER *)(buf + 1);
|
||||
uint8_t * payload = buf + 1 + 5;
|
||||
uint8_t plen = apdu->lc;
|
||||
int selected;
|
||||
CTAP_RESPONSE ctap_resp;
|
||||
int status;
|
||||
|
||||
uint16_t reslen;
|
||||
|
||||
printf1(TAG_NFC,"Iblock: ");
|
||||
dump_hex1(TAG_NFC, buf, len);
|
||||
|
||||
uint8_t block_offset = p14443_block_offset(buf[0]);
|
||||
|
||||
APDU_STRUCT apdu;
|
||||
if (apdu_decode(buf + block_offset, len - block_offset, &apdu)) {
|
||||
printf1(TAG_NFC,"apdu decode error\r\n");
|
||||
nfc_write_response(buf[0], SW_COND_USE_NOT_SATISFIED);
|
||||
return;
|
||||
}
|
||||
printf1(TAG_NFC,"apdu ok. %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\r\n",
|
||||
apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le);
|
||||
|
||||
// check CLA
|
||||
if (apdu.cla != 0x00 && apdu.cla != 0x80) {
|
||||
printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu.cla);
|
||||
nfc_write_response(buf[0], SW_CLA_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO this needs to be organized better
|
||||
switch(apdu->ins)
|
||||
switch(apdu.ins)
|
||||
{
|
||||
case APDU_INS_SELECT:
|
||||
if (plen > len - 6)
|
||||
{
|
||||
printf1(TAG_ERR, "Truncating APDU length %d\r\n", apdu->lc);
|
||||
plen = len-6;
|
||||
}
|
||||
// if (apdu->p1 == 0 && apdu->p2 == 0x0c)
|
||||
// {
|
||||
// printf1(TAG_NFC,"Select NDEF\r\n");
|
||||
@ -440,14 +509,9 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
||||
// }
|
||||
// else
|
||||
{
|
||||
selected = select_applet(payload, plen);
|
||||
selected = select_applet(apdu.data, apdu.lc);
|
||||
if (selected == APP_FIDO)
|
||||
{
|
||||
// block = buf[0] & 1;
|
||||
// block = NFC_STATE.block_num;
|
||||
// block = !block;
|
||||
// NFC_STATE.block_num = block;
|
||||
// NFC_STATE.block_num = block;
|
||||
nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
|
||||
printf1(TAG_NFC, "FIDO applet selected.\r\n");
|
||||
}
|
||||
@ -459,7 +523,7 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
||||
else
|
||||
{
|
||||
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
|
||||
printf1(TAG_NFC, "NOT selected\r\n"); dump_hex1(TAG_NFC,payload, plen);
|
||||
printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu.data, apdu.lc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -472,7 +536,8 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
||||
|
||||
printf1(TAG_NFC, "U2F GetVersion command.\r\n");
|
||||
|
||||
nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
|
||||
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
||||
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||
break;
|
||||
|
||||
case APDU_FIDO_U2F_REGISTER:
|
||||
@ -483,9 +548,9 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
||||
|
||||
printf1(TAG_NFC, "U2F Register command.\r\n");
|
||||
|
||||
if (plen != 64)
|
||||
if (apdu.lc != 64)
|
||||
{
|
||||
printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", plen);
|
||||
printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu.lc);
|
||||
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
@ -496,20 +561,16 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
||||
// WTX_on(WTX_TIME_DEFAULT);
|
||||
// SystemClock_Config_LF32();
|
||||
// delay(300);
|
||||
device_set_clock_rate(DEVICE_LOW_POWER_FAST);;
|
||||
u2f_request_nfc(&buf[1], len, &ctap_resp);
|
||||
device_set_clock_rate(DEVICE_LOW_POWER_IDLE);;
|
||||
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
|
||||
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
||||
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
|
||||
// if (!WTX_off())
|
||||
// return;
|
||||
|
||||
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
||||
printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp());
|
||||
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||
|
||||
// printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
||||
|
||||
|
||||
|
||||
|
||||
printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp());
|
||||
break;
|
||||
|
||||
@ -521,17 +582,17 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
||||
|
||||
printf1(TAG_NFC, "U2F Authenticate command.\r\n");
|
||||
|
||||
if (plen != 64 + 1 + buf[6 + 64])
|
||||
if (apdu.lc != 64 + 1 + apdu.data[64])
|
||||
{
|
||||
delay(5);
|
||||
printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", plen, buf[6 + 64]);
|
||||
printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", apdu.lc, apdu.data[64]);
|
||||
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
timestamp();
|
||||
// WTX_on(WTX_TIME_DEFAULT);
|
||||
u2f_request_nfc(&buf[1], len, &ctap_resp);
|
||||
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
||||
// if (!WTX_off())
|
||||
// return;
|
||||
|
||||
@ -544,14 +605,16 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
||||
case APDU_FIDO_NFCCTAP_MSG:
|
||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
|
||||
|
||||
WTX_on(WTX_TIME_DEFAULT);
|
||||
request_from_nfc(true);
|
||||
ctap_response_init(&ctap_resp);
|
||||
status = ctap_request(payload, plen, &ctap_resp);
|
||||
status = ctap_request(apdu.data, apdu.lc, &ctap_resp);
|
||||
request_from_nfc(false);
|
||||
if (!WTX_off())
|
||||
return;
|
||||
|
||||
@ -574,44 +637,37 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
||||
break;
|
||||
|
||||
case APDU_INS_READ_BINARY:
|
||||
|
||||
|
||||
// response length
|
||||
reslen = apdu.le & 0xffff;
|
||||
switch(NFC_STATE.selected_applet)
|
||||
{
|
||||
case APP_CAPABILITY_CONTAINER:
|
||||
printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n");
|
||||
if (plen > 15)
|
||||
{
|
||||
printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc);
|
||||
plen = 15;
|
||||
}
|
||||
nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, plen, SW_SUCCESS);
|
||||
if (reslen == 0 || reslen > sizeof(NFC_CC))
|
||||
reslen = sizeof(NFC_CC);
|
||||
nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, reslen, SW_SUCCESS);
|
||||
ams_wait_for_tx(10);
|
||||
break;
|
||||
case APP_NDEF_TAG:
|
||||
printf1(TAG_NFC,"APP_NDEF_TAG\r\n");
|
||||
if (plen > (sizeof(NDEF_SAMPLE) - 1))
|
||||
{
|
||||
printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc);
|
||||
plen = sizeof(NDEF_SAMPLE) - 1;
|
||||
}
|
||||
nfc_write_response_ex(buf[0], NDEF_SAMPLE, plen, SW_SUCCESS);
|
||||
if (reslen == 0 || reslen > sizeof(NDEF_SAMPLE) - 1)
|
||||
reslen = sizeof(NDEF_SAMPLE) - 1;
|
||||
nfc_write_response_ex(buf[0], NDEF_SAMPLE, reslen, SW_SUCCESS);
|
||||
ams_wait_for_tx(10);
|
||||
break;
|
||||
default:
|
||||
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
|
||||
printf1(TAG_ERR, "No binary applet selected!\r\n");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins);
|
||||
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu.ins);
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static uint8_t ibuf[1024];
|
||||
@ -625,7 +681,7 @@ void clear_ibuf()
|
||||
|
||||
void nfc_process_block(uint8_t * buf, unsigned int len)
|
||||
{
|
||||
|
||||
printf1(TAG_NFC, "-----\r\n");
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
@ -635,6 +691,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
||||
}
|
||||
else if (IS_IBLOCK(buf[0]))
|
||||
{
|
||||
uint8_t block_offset = p14443_block_offset(buf[0]);
|
||||
if (buf[0] & 0x10)
|
||||
{
|
||||
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d\r\n", ibuflen, len);
|
||||
@ -648,27 +705,27 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
||||
printf1(TAG_NFC_APDU,"i> ");
|
||||
dump_hex1(TAG_NFC_APDU, buf, len);
|
||||
|
||||
if (len)
|
||||
if (len > block_offset)
|
||||
{
|
||||
memcpy(&ibuf[ibuflen], &buf[1], len - 1);
|
||||
ibuflen += len - 1;
|
||||
memcpy(&ibuf[ibuflen], &buf[block_offset], len - block_offset);
|
||||
ibuflen += len - block_offset;
|
||||
}
|
||||
|
||||
// send R block
|
||||
uint8_t rb = NFC_CMD_RBLOCK | NFC_CMD_RBLOCK_ACK | (buf[0] & 3);
|
||||
nfc_write_frame(&rb, 1);
|
||||
rblock_acknowledge(buf[0], true);
|
||||
} else {
|
||||
if (ibuflen)
|
||||
{
|
||||
if (len)
|
||||
if (len > block_offset)
|
||||
{
|
||||
memcpy(&ibuf[ibuflen], &buf[1], len - 1);
|
||||
ibuflen += len - 1;
|
||||
memcpy(&ibuf[ibuflen], &buf[block_offset], len - block_offset);
|
||||
ibuflen += len - block_offset;
|
||||
}
|
||||
|
||||
memmove(&ibuf[1], ibuf, ibuflen);
|
||||
ibuf[0] = buf[0];
|
||||
ibuflen++;
|
||||
// add last chaining to top of the block
|
||||
memmove(&ibuf[block_offset], ibuf, ibuflen);
|
||||
memmove(ibuf, buf, block_offset);
|
||||
ibuflen += block_offset;
|
||||
|
||||
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d\r\n", ibuflen, len);
|
||||
|
||||
@ -677,7 +734,6 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
||||
|
||||
nfc_process_iblock(ibuf, ibuflen);
|
||||
} else {
|
||||
// printf1(TAG_NFC, "NFC_CMD_IBLOCK\r\n");
|
||||
nfc_process_iblock(buf, len);
|
||||
}
|
||||
clear_ibuf();
|
||||
@ -685,7 +741,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
||||
}
|
||||
else if (IS_RBLOCK(buf[0]))
|
||||
{
|
||||
rblock_acknowledge();
|
||||
rblock_acknowledge(buf[0], false);
|
||||
printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n");
|
||||
}
|
||||
else if (IS_SBLOCK(buf[0]))
|
||||
@ -704,6 +760,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
||||
else
|
||||
{
|
||||
printf1(TAG_NFC, "NFC_CMD_SBLOCK, Unknown. len[%d]\r\n", len);
|
||||
nfc_write_response(buf[0], SW_COND_USE_NOT_SATISFIED);
|
||||
}
|
||||
dump_hex1(TAG_NFC, buf, len);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
// Return number of bytes read if any.
|
||||
int nfc_loop();
|
||||
|
||||
bool nfc_init();
|
||||
int nfc_init();
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -40,6 +40,8 @@ typedef struct
|
||||
#define NFC_CMD_SBLOCK 0xc0
|
||||
#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) )
|
||||
|
||||
extern uint8_t p14443_block_offset(uint8_t pcb);
|
||||
|
||||
#define NFC_SBLOCK_DESELECT 0x30
|
||||
#define NFC_SBLOCK_WTX 0x30
|
||||
|
||||
|
136
targets/stm32l432/src/sense.c
Normal file
136
targets/stm32l432/src/sense.c
Normal file
@ -0,0 +1,136 @@
|
||||
#include "sense.h"
|
||||
#include "device.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "stm32l4xx_ll_gpio.h"
|
||||
#include "stm32l4xx_hal_tsc.h"
|
||||
|
||||
#define ELECTRODE_0 TSC_GROUP2_IO1
|
||||
#define ELECTRODE_1 TSC_GROUP2_IO2
|
||||
|
||||
void tsc_init()
|
||||
{
|
||||
LL_GPIO_InitTypeDef GPIO_InitStruct;
|
||||
// Enable TSC clock
|
||||
RCC->AHB1ENR |= (1<<16);
|
||||
|
||||
/** TSC GPIO Configuration
|
||||
PA4 ------> Channel 1
|
||||
PA5 ------> Channel 2
|
||||
*/
|
||||
GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_4;
|
||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_9;
|
||||
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/** TSC GPIO Configuration
|
||||
PA6 ------> sampling cap
|
||||
*/
|
||||
GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
|
||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
|
||||
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
// Channel IOs
|
||||
uint32_t channel_ios = TSC_GROUP2_IO1 | TSC_GROUP2_IO2;
|
||||
|
||||
// enable
|
||||
TSC->CR = TSC_CR_TSCE;
|
||||
|
||||
TSC->CR |= (TSC_CTPH_8CYCLES |
|
||||
TSC_CTPL_10CYCLES |
|
||||
(uint32_t)(1 << TSC_CR_SSD_Pos) |
|
||||
TSC_SS_PRESC_DIV1 |
|
||||
TSC_PG_PRESC_DIV16 |
|
||||
TSC_MCV_16383 |
|
||||
TSC_SYNC_POLARITY_FALLING |
|
||||
TSC_ACQ_MODE_NORMAL);
|
||||
|
||||
// Spread spectrum
|
||||
if (0)
|
||||
{
|
||||
TSC->CR |= TSC_CR_SSE;
|
||||
}
|
||||
|
||||
// Schmitt trigger and hysteresis
|
||||
TSC->IOHCR = (uint32_t)(~(channel_ios | 0 | TSC_GROUP2_IO3));
|
||||
|
||||
// Sampling IOs
|
||||
TSC->IOSCR = TSC_GROUP2_IO3;
|
||||
|
||||
// Groups
|
||||
uint32_t grps = 0x02;
|
||||
TSC->IOGCSR = grps;
|
||||
|
||||
TSC->IER &= (uint32_t)(~(TSC_IT_EOA | TSC_IT_MCE));
|
||||
TSC->ICR = (TSC_FLAG_EOA | TSC_FLAG_MCE);
|
||||
|
||||
}
|
||||
|
||||
void tsc_set_electrode(uint32_t channel_ids)
|
||||
{
|
||||
TSC->IOCCR = (channel_ids);
|
||||
}
|
||||
|
||||
void tsc_start_acq()
|
||||
{
|
||||
TSC->CR &= ~(TSC_CR_START);
|
||||
|
||||
TSC->ICR = TSC_FLAG_EOA | TSC_FLAG_MCE;
|
||||
|
||||
// Set IO output to output push-pull low
|
||||
TSC->CR &= (~TSC_CR_IODEF);
|
||||
|
||||
TSC->CR |= TSC_CR_START;
|
||||
}
|
||||
|
||||
void tsc_wait_on_acq()
|
||||
{
|
||||
while ( ! (TSC->ISR & TSC_FLAG_EOA) )
|
||||
;
|
||||
if ( TSC->ISR & TSC_FLAG_MCE )
|
||||
{
|
||||
printf1(TAG_ERR,"Max count reached\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t tsc_read(uint32_t indx)
|
||||
{
|
||||
return TSC->IOGXCR[indx];
|
||||
}
|
||||
|
||||
uint32_t tsc_read_button(uint32_t index)
|
||||
{
|
||||
switch(index)
|
||||
{
|
||||
case 0:
|
||||
tsc_set_electrode(ELECTRODE_0);
|
||||
break;
|
||||
case 1:
|
||||
tsc_set_electrode(ELECTRODE_1);
|
||||
break;
|
||||
}
|
||||
tsc_start_acq();
|
||||
tsc_wait_on_acq();
|
||||
return tsc_read(1) < 45;
|
||||
}
|
||||
|
||||
int tsc_sensor_exists()
|
||||
{
|
||||
static uint8_t does = 0;
|
||||
if (does) return 1;
|
||||
|
||||
LL_GPIO_SetPinMode(GPIOB, (1 << 1), LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinPull(GPIOB, (1 << 1), LL_GPIO_PULL_UP);
|
||||
|
||||
// Short delay before reading pin
|
||||
asm("nop"); asm("nop"); asm("nop"); asm("nop");
|
||||
|
||||
does = (LL_GPIO_ReadInputPort(GPIOB) & (1 << 1)) == 0;
|
||||
|
||||
LL_GPIO_SetPinPull(GPIOB, 1, LL_GPIO_PULL_NO);
|
||||
|
||||
return does;
|
||||
}
|
14
targets/stm32l432/src/sense.h
Normal file
14
targets/stm32l432/src/sense.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _SENSE_H_
|
||||
#define _SENSE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void tsc_init();
|
||||
|
||||
int tsc_sensor_exists();
|
||||
|
||||
// Read button0 or button1
|
||||
// Returns 1 if pressed, 0 if not.
|
||||
uint32_t tsc_read_button(uint32_t index);
|
||||
|
||||
#endif
|
2
tinycbor
2
tinycbor
Submodule tinycbor updated: c9059d9e33...878eb01b96
65
tools/gadgetfs/Makefile
Normal file
65
tools/gadgetfs/Makefile
Normal file
@ -0,0 +1,65 @@
|
||||
TOP := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
KERNEL_FULL_VERSION := $(shell uname -r)
|
||||
KERNEL_VERSION := $(shell uname -r | grep -o "^[^-]*")
|
||||
KERNEL_MAJOR := $(shell uname -r | cut -d. -f1)
|
||||
KERNEL_MINOR := $(shell uname -r | cut -d. -f2)
|
||||
|
||||
MANUFACTURER = "Solo"
|
||||
SERIAL = "1234567890"
|
||||
IDVENDOR = "0x0483"
|
||||
IDPRODUCT = "0xa2ca"
|
||||
PRODUCT = "Solo Software Authenticator"
|
||||
CONFIGFS = /sys/kernel/config
|
||||
CONFIGFS_FIDO2 = $(CONFIGFS)/usb_gadget/fido2
|
||||
|
||||
obj-m := dummy_hcd.o
|
||||
KVERSION := $(shell uname -r)
|
||||
SHELL := /bin/bash
|
||||
|
||||
all: dummy_hcd.ko
|
||||
|
||||
install: dummy_hcd.ko
|
||||
modprobe libcomposite
|
||||
insmod dummy_hcd.ko
|
||||
mkdir -p $(CONFIGFS_FIDO2)
|
||||
mkdir -p $(CONFIGFS_FIDO2)/configs/c.1
|
||||
mkdir -p $(CONFIGFS_FIDO2)/functions/hid.usb0
|
||||
echo 0 > $(CONFIGFS_FIDO2)/functions/hid.usb0/protocol
|
||||
echo 0 > $(CONFIGFS_FIDO2)/functions/hid.usb0/subclass
|
||||
echo 64 > $(CONFIGFS_FIDO2)/functions/hid.usb0/report_length
|
||||
echo -ne "\x06\xd0\xf1\x09\x01\xa1\x01\x09\x20\x15\x00\x26\xff\x00\x75\x08\x95\x40\x81\x02\x09\x21\x15\x00\x26\xff\x00\x75\x08\x95\x40\x91\x02\xc0" > $(CONFIGFS_FIDO2)/functions/hid.usb0/report_desc
|
||||
mkdir $(CONFIGFS_FIDO2)/strings/0x409
|
||||
mkdir $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409
|
||||
echo $(IDPRODUCT) > $(CONFIGFS_FIDO2)/idProduct
|
||||
echo $(IDVENDOR) > $(CONFIGFS_FIDO2)/idVendor
|
||||
echo $(SERIAL) > $(CONFIGFS_FIDO2)/strings/0x409/serialnumber
|
||||
echo $(MANUFACTURER) > $(CONFIGFS_FIDO2)/strings/0x409/manufacturer
|
||||
echo $(PRODUCT) > $(CONFIGFS_FIDO2)/strings/0x409/product
|
||||
echo "Configuration 1" > $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409/configuration
|
||||
echo 120 > $(CONFIGFS_FIDO2)/configs/c.1/MaxPower
|
||||
ln -s $(CONFIGFS_FIDO2)/functions/hid.usb0 $(CONFIGFS_FIDO2)/configs/c.1
|
||||
echo "dummy_udc.0" > $(CONFIGFS_FIDO2)/UDC
|
||||
|
||||
uninstall:
|
||||
echo "" > $(CONFIGFS_FIDO2)/UDC
|
||||
rm $(CONFIGFS_FIDO2)/configs/c.1/hid.usb0
|
||||
rmdir $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409
|
||||
rmdir $(CONFIGFS_FIDO2)/configs/c.1
|
||||
rmdir $(CONFIGFS_FIDO2)/functions/hid.usb0
|
||||
rmdir $(CONFIGFS_FIDO2)/strings/0x409
|
||||
rmdir $(CONFIGFS_FIDO2)
|
||||
rmmod dummy_hcd.ko
|
||||
|
||||
dummy_hcd.ko: dummy_hcd.c
|
||||
$(MAKE) -C /lib/modules/$(KERNEL_FULL_VERSION)/build M=$(TOP) modules
|
||||
|
||||
dummy_hcd.c: /usr/src/linux-source-$(KERNEL_VERSION).tar.bz2
|
||||
tar -xvf $^ linux-source-$(KERNEL_VERSION)/drivers/usb/gadget/udc/dummy_hcd.c
|
||||
cp linux-source-$(KERNEL_VERSION)/drivers/usb/gadget/udc/dummy_hcd.c $@
|
||||
|
||||
clean:
|
||||
$(MAKE) -C /lib/modules/$(KERNEL_FULL_VERSION)/build M=$(TOP) clean
|
||||
rm -rf linux-source-$(KERNEL_VERSION)
|
||||
rm -f dummy_hcd.c
|
||||
|
||||
|
@ -19,7 +19,9 @@ from tests import Tester, FIDO2Tests, U2FTests, HIDTests, SoloTests
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: %s [sim] <[u2f]|[fido2]|[rk]|[hid]|[ping]>")
|
||||
print("Usage: %s [sim] [nfc] <[u2f]|[fido2]|[rk]|[hid]|[ping]>")
|
||||
print(" sim - test via UDP simulation backend only")
|
||||
print(" nfc - test via NFC interface only")
|
||||
sys.exit(0)
|
||||
|
||||
t = Tester()
|
||||
@ -31,7 +33,11 @@ if __name__ == "__main__":
|
||||
t.set_sim(True)
|
||||
t.set_user_count(10)
|
||||
|
||||
t.find_device()
|
||||
nfcOnly = False
|
||||
if "nfc" in sys.argv:
|
||||
nfcOnly = True
|
||||
|
||||
t.find_device(nfcOnly)
|
||||
|
||||
if "solo" in sys.argv:
|
||||
SoloTests(t).run()
|
||||
|
@ -78,7 +78,7 @@ def TestCborKeysSorted(cbor_obj):
|
||||
# https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#ctap2-canonical-cbor-encoding-form
|
||||
|
||||
if isinstance(cbor_obj, bytes):
|
||||
cbor_obj = cbor.loads(cbor_obj)[0]
|
||||
cbor_obj = cbor.decode_from(cbor_obj)[0]
|
||||
|
||||
if isinstance(cbor_obj, dict):
|
||||
l = [x for x in cbor_obj]
|
||||
@ -211,7 +211,7 @@ class FIDO2Tests(Tester):
|
||||
assert "hmac-secret" in reg.auth_data.extensions
|
||||
assert reg.auth_data.extensions["hmac-secret"] == True
|
||||
|
||||
reg = self.testMC(
|
||||
self.testMC(
|
||||
"Send MC with fake extension set to true, expect SUCCESS",
|
||||
cdh,
|
||||
rp,
|
||||
@ -222,9 +222,7 @@ class FIDO2Tests(Tester):
|
||||
)
|
||||
|
||||
with Test("Get shared secret"):
|
||||
key_agreement, shared_secret = (
|
||||
self.client.pin_protocol._init_shared_secret()
|
||||
)
|
||||
key_agreement, shared_secret = self.client.pin_protocol.get_shared_secret()
|
||||
cipher = Cipher(
|
||||
algorithms.AES(shared_secret),
|
||||
modes.CBC(b"\x00" * 16),
|
||||
@ -280,6 +278,10 @@ class FIDO2Tests(Tester):
|
||||
assert shannon_entropy(ext["hmac-secret"]) > 5.4
|
||||
assert shannon_entropy(key) > 5.4
|
||||
|
||||
with Test("Check that the assertion is valid"):
|
||||
credential_data = AttestedCredentialData(reg.auth_data.credential_data)
|
||||
auth.verify(cdh, credential_data.public_key)
|
||||
|
||||
salt_enc, salt_auth = get_salt_params((salt3,))
|
||||
|
||||
auth = self.testGA(
|
||||
@ -341,8 +343,8 @@ class FIDO2Tests(Tester):
|
||||
def test_get_info(self,):
|
||||
with Test("Get info"):
|
||||
info = self.ctap.get_info()
|
||||
print(bytes(info))
|
||||
print(cbor.loads(bytes(info)))
|
||||
print("data:", bytes(info))
|
||||
print("decoded:", cbor.decode_from(bytes(info)))
|
||||
|
||||
with Test("Check FIDO2 string is in VERSIONS field"):
|
||||
assert "FIDO_2_0" in info.versions
|
||||
@ -621,6 +623,20 @@ class FIDO2Tests(Tester):
|
||||
other={"exclude_list": [{"id": b"1234", "type": "rot13"}]},
|
||||
)
|
||||
|
||||
self.testMC(
|
||||
"Send MC request with excludeList item with bogus type, expect SUCCESS",
|
||||
cdh,
|
||||
rp,
|
||||
user,
|
||||
key_params,
|
||||
expectedError=CtapError.ERR.SUCCESS,
|
||||
other={
|
||||
"exclude_list": [
|
||||
{"id": b"1234", "type": "mangoPapayaCoconutNotAPublicKey"}
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
self.testMC(
|
||||
"Send MC request with excludeList with bad item, expect error",
|
||||
cdh,
|
||||
@ -731,6 +747,40 @@ class FIDO2Tests(Tester):
|
||||
expectedError=CtapError.ERR.SUCCESS,
|
||||
)
|
||||
|
||||
with Test("Check assertion is correct"):
|
||||
credential_data = AttestedCredentialData(prev_reg.auth_data.credential_data)
|
||||
prev_auth.verify(cdh, credential_data.public_key)
|
||||
assert (
|
||||
prev_auth.credential["id"]
|
||||
== prev_reg.auth_data.credential_data.credential_id
|
||||
)
|
||||
|
||||
self.reboot()
|
||||
|
||||
prev_auth = self.testGA(
|
||||
"Send GA request after reboot, expect success",
|
||||
rp["id"],
|
||||
cdh,
|
||||
allow_list,
|
||||
expectedError=CtapError.ERR.SUCCESS,
|
||||
)
|
||||
|
||||
with Test("Check assertion is correct"):
|
||||
credential_data = AttestedCredentialData(prev_reg.auth_data.credential_data)
|
||||
prev_auth.verify(cdh, credential_data.public_key)
|
||||
assert (
|
||||
prev_auth.credential["id"]
|
||||
== prev_reg.auth_data.credential_data.credential_id
|
||||
)
|
||||
|
||||
prev_auth = self.testGA(
|
||||
"Send GA request, expect success",
|
||||
rp["id"],
|
||||
cdh,
|
||||
allow_list,
|
||||
expectedError=CtapError.ERR.SUCCESS,
|
||||
)
|
||||
|
||||
with Test("Test auth_data is 37 bytes"):
|
||||
assert len(prev_auth.auth_data) == 37
|
||||
|
||||
@ -1009,8 +1059,8 @@ class FIDO2Tests(Tester):
|
||||
key = res[1]
|
||||
assert "Is public key" and key[1] == 2
|
||||
assert "Is P256" and key[-1] == 1
|
||||
if key[3] != -7:
|
||||
print("WARNING: algorithm returned is not for ES256 (-7): ", key[3])
|
||||
assert "Is ALG_ECDH_ES_HKDF_256" and key[3] == -25
|
||||
|
||||
assert "Right key" and len(key[-3]) == 32 and isinstance(key[-3], bytes)
|
||||
|
||||
with Test("Test setting a new pin"):
|
||||
@ -1069,9 +1119,45 @@ class FIDO2Tests(Tester):
|
||||
|
||||
self.testReset()
|
||||
|
||||
with Test("Test sending zero-length pin_auth, expect PIN_NOT_SET"):
|
||||
self.testMC(
|
||||
"Send MC request with new pin auth",
|
||||
cdh,
|
||||
rp,
|
||||
user,
|
||||
key_params,
|
||||
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
||||
expectedError=CtapError.ERR.PIN_NOT_SET,
|
||||
)
|
||||
self.testGA(
|
||||
"Send MC request with new pin auth",
|
||||
rp["id"],
|
||||
cdh,
|
||||
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
||||
expectedError=CtapError.ERR.PIN_NOT_SET,
|
||||
)
|
||||
|
||||
with Test("Setting pin code, expect SUCCESS"):
|
||||
self.client.pin_protocol.set_pin(pin1)
|
||||
|
||||
with Test("Test sending zero-length pin_auth, expect PIN_INVALID"):
|
||||
self.testMC(
|
||||
"Send MC request with new pin auth",
|
||||
cdh,
|
||||
rp,
|
||||
user,
|
||||
key_params,
|
||||
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
||||
expectedError=CtapError.ERR.PIN_INVALID,
|
||||
)
|
||||
self.testGA(
|
||||
"Send MC request with new pin auth",
|
||||
rp["id"],
|
||||
cdh,
|
||||
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
||||
expectedError=CtapError.ERR.PIN_INVALID,
|
||||
)
|
||||
|
||||
self.testReset()
|
||||
with Test("Setting pin code >63 bytes, expect POLICY_VIOLATION "):
|
||||
try:
|
||||
|
@ -1,6 +1,8 @@
|
||||
from solo.client import SoloClient
|
||||
from solo.commands import SoloExtension
|
||||
|
||||
from fido2.ctap1 import ApduError
|
||||
from fido2.utils import sha256
|
||||
|
||||
from .util import shannon_entropy
|
||||
from .tester import Tester, Test
|
||||
@ -44,6 +46,17 @@ class SoloTests(Tester):
|
||||
pass
|
||||
|
||||
sc.exchange = sc.exchange_fido2
|
||||
|
||||
req = SoloClient.format_request(SoloExtension.version, 0, b"A" * 16)
|
||||
a = sc.ctap2.get_assertion(
|
||||
sc.host, b"B" * 32, [{"id": req, "type": "public-key"}]
|
||||
)
|
||||
|
||||
with Test("Test custom command returned valid assertion"):
|
||||
assert a.auth_data.rp_id_hash == sha256(sc.host.encode("utf8"))
|
||||
assert a.credential["id"] == req
|
||||
assert (a.auth_data.flags & 0x5) == 0x5
|
||||
|
||||
with Test("Test Solo version and random commands with fido2 layer"):
|
||||
assert len(sc.solo_version()) == 3
|
||||
sc.get_rng()
|
||||
|
@ -2,6 +2,7 @@ import time, struct
|
||||
|
||||
from fido2.hid import CtapHidDevice
|
||||
from fido2.client import Fido2Client
|
||||
from fido2.attestation import Attestation
|
||||
from fido2.ctap1 import CTAP1
|
||||
from fido2.utils import Timeout
|
||||
|
||||
@ -51,6 +52,7 @@ class Tester:
|
||||
self.host = "examplo.org"
|
||||
self.user_count = 10
|
||||
self.is_sim = False
|
||||
self.nfc_interface_only = False
|
||||
if tester:
|
||||
self.initFromTester(tester)
|
||||
|
||||
@ -61,10 +63,23 @@ class Tester:
|
||||
self.ctap = tester.ctap
|
||||
self.ctap1 = tester.ctap1
|
||||
self.client = tester.client
|
||||
self.nfc_interface_only = tester.nfc_interface_only
|
||||
|
||||
def find_device(self, nfcInterfaceOnly=False):
|
||||
dev = None
|
||||
self.nfc_interface_only = nfcInterfaceOnly
|
||||
if not nfcInterfaceOnly:
|
||||
print("--- HID ---")
|
||||
print(list(CtapHidDevice.list_devices()))
|
||||
dev = next(CtapHidDevice.list_devices(), None)
|
||||
|
||||
if not dev:
|
||||
from fido2.pcsc import CtapPcscDevice
|
||||
|
||||
print("--- NFC ---")
|
||||
print(list(CtapPcscDevice.list_devices()))
|
||||
dev = next(CtapPcscDevice.list_devices(), None)
|
||||
|
||||
def find_device(self,):
|
||||
print(list(CtapHidDevice.list_devices()))
|
||||
dev = next(CtapHidDevice.list_devices(), None)
|
||||
if not dev:
|
||||
raise RuntimeError("No FIDO device found")
|
||||
self.dev = dev
|
||||
@ -89,7 +104,7 @@ class Tester:
|
||||
else:
|
||||
print("Please reboot authentictor and hit enter")
|
||||
input()
|
||||
self.find_device()
|
||||
self.find_device(self.nfc_interface_only)
|
||||
|
||||
def send_data(self, cmd, data):
|
||||
if not isinstance(data, bytes):
|
||||
@ -183,11 +198,22 @@ class Tester:
|
||||
print("You must power cycle authentictor. Hit enter when done.")
|
||||
input()
|
||||
time.sleep(0.2)
|
||||
self.find_device()
|
||||
self.find_device(self.nfc_interface_only)
|
||||
self.ctap.reset()
|
||||
|
||||
def testMC(self, test, *args, **kwargs):
|
||||
return self.testFunc(self.ctap.make_credential, test, *args, **kwargs)
|
||||
attestation_object = self.testFunc(
|
||||
self.ctap.make_credential, test, *args, **kwargs
|
||||
)
|
||||
if attestation_object:
|
||||
verifier = Attestation.for_type(attestation_object.fmt)
|
||||
client_data = args[0]
|
||||
verifier().verify(
|
||||
attestation_object.att_statement,
|
||||
attestation_object.auth_data,
|
||||
client_data,
|
||||
)
|
||||
return attestation_object
|
||||
|
||||
def testGA(self, test, *args, **kwargs):
|
||||
return self.testFunc(self.ctap.get_assertion, test, *args, **kwargs)
|
||||
|
@ -42,12 +42,14 @@ class U2FTests(Tester):
|
||||
with Test("Check bad INS"):
|
||||
try:
|
||||
self.ctap1.send_apdu(0, 0, 0, 0, b"")
|
||||
assert False
|
||||
except ApduError as e:
|
||||
assert e.code == 0x6D00
|
||||
|
||||
with Test("Check bad CLA"):
|
||||
try:
|
||||
self.ctap1.send_apdu(1, CTAP1.INS.VERSION, 0, 0, b"abc")
|
||||
assert False
|
||||
except ApduError as e:
|
||||
assert e.code == 0x6E00
|
||||
|
||||
@ -76,6 +78,16 @@ class U2FTests(Tester):
|
||||
auth = self.authenticate(chal, appid, regs[i].key_handle)
|
||||
auth.verify(appid, chal, regs[i].public_key)
|
||||
|
||||
self.reboot()
|
||||
|
||||
for i in range(0, self.user_count):
|
||||
with Test(
|
||||
"Post reboot, Checking previous registration %d/%d"
|
||||
% (i + 1, self.user_count)
|
||||
):
|
||||
auth = self.authenticate(chal, appid, regs[i].key_handle)
|
||||
auth.verify(appid, chal, regs[i].public_key)
|
||||
|
||||
print("Check that all previous credentials are registered...")
|
||||
for i in range(0, self.user_count):
|
||||
with Test("Check that previous credential %d is registered" % i):
|
||||
|
28
web/.key
28
web/.key
@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDxXjGjdpW8N2/3
|
||||
s1pYCe1LgVEJlnv0sz/iUaVsd2Z6hv5khaJPVc/LBl5uR5IzotLVw/fp9CU4r7wL
|
||||
xkwezpH+zyo7VjlulRxUZ2zaclYyiKuE1LpdYmuLetzkDI/e2CF26eCQv3vbqxPy
|
||||
dS9wplbgplBax6s8IlfjEhpvIxb4JW1+g7U+zyYGTYVakJYzvzTTl3IFqtO34BBE
|
||||
vSJFDtBuZViwfEctFsinjMHXBo6Nb7OoCQq0ih0gZJwKcojYTbpbm2YhNR2i8mHy
|
||||
6jpsv3bJTygJHIEDGILgu5T6uNY5nwMC4Js/w4YnI+kO4kmwAEEFzxZXa666UxZV
|
||||
VbkWMUezAgMBAAECggEBANr5yuzzC9uLLAC8ba1LrEYBF0Usil6xNLcdvYePN6DX
|
||||
0fnepyd0waT+rTM9qW1BPigDt2pAPniULnU8PRkB7cAPsM/OZSJnEyGcB0yTyJHm
|
||||
Hj3PRRitzsXm/HnEz82rpYidnEeWAUeEiP9Bw31e25jKKkKBvV88BSIT7XmAizkp
|
||||
8H/ya+qm3R8Kxsr/t19UbkrBJ0V9OIM6GXsCZHul2EsRoY7d4om90IvKCHW5MIuT
|
||||
MPkIR2msntgNIhYh+mxDrcZ2qq/AZO/GGf3GpxiDN4imuNvgd6HVg0qwxIpblhjK
|
||||
qX1AeiLQ+ljlz3ktY4TVpt2vgPToekKbme6neCFD3FkCgYEA+4E5UegMTcLce6jR
|
||||
6JMxA5PeING7zRLLKwNsgZvwdpEXh5OBMxWu674tg+OTWG3fPNaIdz+PN+DJFtoV
|
||||
/dDNkOG5TCwBQJPipN2Y5bSmjbBDI4jb/rDLeUvFFF/Hp81bMDYe+o1DNomzkC+A
|
||||
5/uGeNXET90D5NpgRU8Jk0gKlNcCgYEA9a6WmBHWZctXNqD9Sx9pw5i5RQyy2s/D
|
||||
2PmZ01VcE6uMZGghHw4gJIzpD1bY2nP9g8yD5v/VD0bz+GTBp3eKlw/9E1aYfMwN
|
||||
gUdP2sqgnYI7gareI/DTONBVQEmDcRTCH6fewgnwg9wuCwoqgxGAoi9IX4vBWFJt
|
||||
YNlOYQErLIUCgYAVtJlV0Ej/jQmqQm+bOtjIDkLlYjRrBmwyUiFTLjoagXseYESO
|
||||
PBjUj50t/L4Cq7jQb1NntzyM/gFcz4WGWjbjgheT01hoUlsFD3ramDSnlca1kmIq
|
||||
IOful/NyRrHccYSlLIaP6REb69ZrYy4k1zhLxWcj3VcwsQgN8zxIUbdYEQKBgQCL
|
||||
APUDpVQA1EPMDNpDHsrgeBCbGMw5MURGBzMZdzpZhr4wMRpMT9mv1Goo26JmNypA
|
||||
3/3hPO53blWrPJa1AdXQEqPFxUERmwIpGwf7apnlhEHW4647944KnxUdAnr0CCKt
|
||||
dnV6o9UJRhJm/KGA9u4o1UfFh3UlW723BjxqdhbPYQKBgF4KQtcw/Y2kF2BIerD6
|
||||
LyO/tbS90VMQiZYZjGmuLG0K351RqW/l5U9RaEK2hpb10Qu7x/inmSM7sBY7NWE8
|
||||
YOJLH/ArubTCLwiFzkQp24NFZt19xj2qlAunydhgus+q+r5mCp18QyjhTdMYVFqk
|
||||
3biBiaWbI3HoS3qyCf7ezWvw
|
||||
-----END PRIVATE KEY-----
|
@ -1,23 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<h1>U2F Bridge Demo</h1>
|
||||
<h3 id="progress"></h3>
|
||||
<h3 id="errors" style="color:red;"></h3>
|
||||
|
||||
<p>To update firmware, upload JSON file here.</p>
|
||||
<input type="file" id="input" onchange="handleFirmware(this.files)">
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<button onclick="run_tests()">Run tests</button>
|
||||
|
||||
</body>
|
||||
<script src="js/u2f-api.js"></script>
|
||||
<script src="js/elliptic.js"></script>
|
||||
<script src="js/sha256.min.js"></script>
|
||||
<script src="js/aes.js"></script>
|
||||
<script src="js/intel-hex.js"></script>
|
||||
<script src="js/wallet.js"></script>
|
||||
</html>
|
803
web/js/aes.js
803
web/js/aes.js
@ -1,803 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
(function(root) {
|
||||
|
||||
function checkInt(value) {
|
||||
return (parseInt(value) === value);
|
||||
}
|
||||
|
||||
function checkInts(arrayish) {
|
||||
if (!checkInt(arrayish.length)) { return false; }
|
||||
|
||||
for (var i = 0; i < arrayish.length; i++) {
|
||||
if (!checkInt(arrayish[i]) || arrayish[i] < 0 || arrayish[i] > 255) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function coerceArray(arg, copy) {
|
||||
|
||||
// ArrayBuffer view
|
||||
if (arg.buffer && ArrayBuffer.isView(arg) && arg.name === 'Uint8Array') {
|
||||
|
||||
if (copy) {
|
||||
if (arg.slice) {
|
||||
arg = arg.slice();
|
||||
} else {
|
||||
arg = Array.prototype.slice.call(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
// It's an array; check it is a valid representation of a byte
|
||||
if (Array.isArray(arg)) {
|
||||
if (!checkInts(arg)) {
|
||||
throw new Error('Array contains invalid value: ' + arg);
|
||||
}
|
||||
|
||||
return new Uint8Array(arg);
|
||||
}
|
||||
|
||||
// Something else, but behaves like an array (maybe a Buffer? Arguments?)
|
||||
if (checkInt(arg.length) && checkInts(arg)) {
|
||||
return new Uint8Array(arg);
|
||||
}
|
||||
|
||||
throw new Error('unsupported array-like object');
|
||||
}
|
||||
|
||||
function createArray(length) {
|
||||
return new Uint8Array(length);
|
||||
}
|
||||
|
||||
function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
|
||||
if (sourceStart != null || sourceEnd != null) {
|
||||
if (sourceArray.slice) {
|
||||
sourceArray = sourceArray.slice(sourceStart, sourceEnd);
|
||||
} else {
|
||||
sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
|
||||
}
|
||||
}
|
||||
targetArray.set(sourceArray, targetStart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
var convertUtf8 = (function() {
|
||||
function toBytes(text) {
|
||||
var result = [], i = 0;
|
||||
text = encodeURI(text);
|
||||
while (i < text.length) {
|
||||
var c = text.charCodeAt(i++);
|
||||
|
||||
// if it is a % sign, encode the following 2 bytes as a hex value
|
||||
if (c === 37) {
|
||||
result.push(parseInt(text.substr(i, 2), 16))
|
||||
i += 2;
|
||||
|
||||
// otherwise, just the actual byte
|
||||
} else {
|
||||
result.push(c)
|
||||
}
|
||||
}
|
||||
|
||||
return coerceArray(result);
|
||||
}
|
||||
|
||||
function fromBytes(bytes) {
|
||||
var result = [], i = 0;
|
||||
|
||||
while (i < bytes.length) {
|
||||
var c = bytes[i];
|
||||
|
||||
if (c < 128) {
|
||||
result.push(String.fromCharCode(c));
|
||||
i++;
|
||||
} else if (c > 191 && c < 224) {
|
||||
result.push(String.fromCharCode(((c & 0x1f) << 6) | (bytes[i + 1] & 0x3f)));
|
||||
i += 2;
|
||||
} else {
|
||||
result.push(String.fromCharCode(((c & 0x0f) << 12) | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f)));
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
|
||||
return result.join('');
|
||||
}
|
||||
|
||||
return {
|
||||
toBytes: toBytes,
|
||||
fromBytes: fromBytes,
|
||||
}
|
||||
})();
|
||||
|
||||
var convertHex = (function() {
|
||||
function toBytes(text) {
|
||||
var result = [];
|
||||
for (var i = 0; i < text.length; i += 2) {
|
||||
result.push(parseInt(text.substr(i, 2), 16));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// http://ixti.net/development/javascript/2011/11/11/base64-encodedecode-of-utf8-in-browser-with-js.html
|
||||
var Hex = '0123456789abcdef';
|
||||
|
||||
function fromBytes(bytes) {
|
||||
var result = [];
|
||||
for (var i = 0; i < bytes.length; i++) {
|
||||
var v = bytes[i];
|
||||
result.push(Hex[(v & 0xf0) >> 4] + Hex[v & 0x0f]);
|
||||
}
|
||||
return result.join('');
|
||||
}
|
||||
|
||||
return {
|
||||
toBytes: toBytes,
|
||||
fromBytes: fromBytes,
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
// Number of rounds by keysize
|
||||
var numberOfRounds = {16: 10, 24: 12, 32: 14}
|
||||
|
||||
// Round constant words
|
||||
var rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91];
|
||||
|
||||
// S-box and Inverse S-box (S is for Substitution)
|
||||
var S = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16];
|
||||
var Si =[0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d];
|
||||
|
||||
// Transformations for encryption
|
||||
var T1 = [0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a];
|
||||
var T2 = [0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616];
|
||||
var T3 = [0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16];
|
||||
var T4 = [0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c];
|
||||
|
||||
// Transformations for decryption
|
||||
var T5 = [0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742];
|
||||
var T6 = [0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857];
|
||||
var T7 = [0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8];
|
||||
var T8 = [0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0];
|
||||
|
||||
// Transformations for decryption key expansion
|
||||
var U1 = [0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3];
|
||||
var U2 = [0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697];
|
||||
var U3 = [0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46];
|
||||
var U4 = [0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d];
|
||||
|
||||
function convertToInt32(bytes) {
|
||||
var result = [];
|
||||
for (var i = 0; i < bytes.length; i += 4) {
|
||||
result.push(
|
||||
(bytes[i ] << 24) |
|
||||
(bytes[i + 1] << 16) |
|
||||
(bytes[i + 2] << 8) |
|
||||
bytes[i + 3]
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var AES = function(key) {
|
||||
if (!(this instanceof AES)) {
|
||||
throw Error('AES must be instanitated with `new`');
|
||||
}
|
||||
|
||||
Object.defineProperty(this, 'key', {
|
||||
value: coerceArray(key, true)
|
||||
});
|
||||
|
||||
this._prepare();
|
||||
}
|
||||
|
||||
|
||||
AES.prototype._prepare = function() {
|
||||
|
||||
var rounds = numberOfRounds[this.key.length];
|
||||
if (rounds == null) {
|
||||
throw new Error('invalid key size (must be 16, 24 or 32 bytes)');
|
||||
}
|
||||
|
||||
// encryption round keys
|
||||
this._Ke = [];
|
||||
|
||||
// decryption round keys
|
||||
this._Kd = [];
|
||||
|
||||
for (var i = 0; i <= rounds; i++) {
|
||||
this._Ke.push([0, 0, 0, 0]);
|
||||
this._Kd.push([0, 0, 0, 0]);
|
||||
}
|
||||
|
||||
var roundKeyCount = (rounds + 1) * 4;
|
||||
var KC = this.key.length / 4;
|
||||
|
||||
// convert the key into ints
|
||||
var tk = convertToInt32(this.key);
|
||||
|
||||
// copy values into round key arrays
|
||||
var index;
|
||||
for (var i = 0; i < KC; i++) {
|
||||
index = i >> 2;
|
||||
this._Ke[index][i % 4] = tk[i];
|
||||
this._Kd[rounds - index][i % 4] = tk[i];
|
||||
}
|
||||
|
||||
// key expansion (fips-197 section 5.2)
|
||||
var rconpointer = 0;
|
||||
var t = KC, tt;
|
||||
while (t < roundKeyCount) {
|
||||
tt = tk[KC - 1];
|
||||
tk[0] ^= ((S[(tt >> 16) & 0xFF] << 24) ^
|
||||
(S[(tt >> 8) & 0xFF] << 16) ^
|
||||
(S[ tt & 0xFF] << 8) ^
|
||||
S[(tt >> 24) & 0xFF] ^
|
||||
(rcon[rconpointer] << 24));
|
||||
rconpointer += 1;
|
||||
|
||||
// key expansion (for non-256 bit)
|
||||
if (KC != 8) {
|
||||
for (var i = 1; i < KC; i++) {
|
||||
tk[i] ^= tk[i - 1];
|
||||
}
|
||||
|
||||
// key expansion for 256-bit keys is "slightly different" (fips-197)
|
||||
} else {
|
||||
for (var i = 1; i < (KC / 2); i++) {
|
||||
tk[i] ^= tk[i - 1];
|
||||
}
|
||||
tt = tk[(KC / 2) - 1];
|
||||
|
||||
tk[KC / 2] ^= (S[ tt & 0xFF] ^
|
||||
(S[(tt >> 8) & 0xFF] << 8) ^
|
||||
(S[(tt >> 16) & 0xFF] << 16) ^
|
||||
(S[(tt >> 24) & 0xFF] << 24));
|
||||
|
||||
for (var i = (KC / 2) + 1; i < KC; i++) {
|
||||
tk[i] ^= tk[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// copy values into round key arrays
|
||||
var i = 0, r, c;
|
||||
while (i < KC && t < roundKeyCount) {
|
||||
r = t >> 2;
|
||||
c = t % 4;
|
||||
this._Ke[r][c] = tk[i];
|
||||
this._Kd[rounds - r][c] = tk[i++];
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
// inverse-cipher-ify the decryption round key (fips-197 section 5.3)
|
||||
for (var r = 1; r < rounds; r++) {
|
||||
for (var c = 0; c < 4; c++) {
|
||||
tt = this._Kd[r][c];
|
||||
this._Kd[r][c] = (U1[(tt >> 24) & 0xFF] ^
|
||||
U2[(tt >> 16) & 0xFF] ^
|
||||
U3[(tt >> 8) & 0xFF] ^
|
||||
U4[ tt & 0xFF]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AES.prototype.encrypt = function(plaintext) {
|
||||
if (plaintext.length != 16) {
|
||||
throw new Error('invalid plaintext size (must be 16 bytes)');
|
||||
}
|
||||
|
||||
var rounds = this._Ke.length - 1;
|
||||
var a = [0, 0, 0, 0];
|
||||
|
||||
// convert plaintext to (ints ^ key)
|
||||
var t = convertToInt32(plaintext);
|
||||
for (var i = 0; i < 4; i++) {
|
||||
t[i] ^= this._Ke[0][i];
|
||||
}
|
||||
|
||||
// apply round transforms
|
||||
for (var r = 1; r < rounds; r++) {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
a[i] = (T1[(t[ i ] >> 24) & 0xff] ^
|
||||
T2[(t[(i + 1) % 4] >> 16) & 0xff] ^
|
||||
T3[(t[(i + 2) % 4] >> 8) & 0xff] ^
|
||||
T4[ t[(i + 3) % 4] & 0xff] ^
|
||||
this._Ke[r][i]);
|
||||
}
|
||||
t = a.slice();
|
||||
}
|
||||
|
||||
// the last round is special
|
||||
var result = createArray(16), tt;
|
||||
for (var i = 0; i < 4; i++) {
|
||||
tt = this._Ke[rounds][i];
|
||||
result[4 * i ] = (S[(t[ i ] >> 24) & 0xff] ^ (tt >> 24)) & 0xff;
|
||||
result[4 * i + 1] = (S[(t[(i + 1) % 4] >> 16) & 0xff] ^ (tt >> 16)) & 0xff;
|
||||
result[4 * i + 2] = (S[(t[(i + 2) % 4] >> 8) & 0xff] ^ (tt >> 8)) & 0xff;
|
||||
result[4 * i + 3] = (S[ t[(i + 3) % 4] & 0xff] ^ tt ) & 0xff;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
AES.prototype.decrypt = function(ciphertext) {
|
||||
if (ciphertext.length != 16) {
|
||||
throw new Error('invalid ciphertext size (must be 16 bytes)');
|
||||
}
|
||||
|
||||
var rounds = this._Kd.length - 1;
|
||||
var a = [0, 0, 0, 0];
|
||||
|
||||
// convert plaintext to (ints ^ key)
|
||||
var t = convertToInt32(ciphertext);
|
||||
for (var i = 0; i < 4; i++) {
|
||||
t[i] ^= this._Kd[0][i];
|
||||
}
|
||||
|
||||
// apply round transforms
|
||||
for (var r = 1; r < rounds; r++) {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
a[i] = (T5[(t[ i ] >> 24) & 0xff] ^
|
||||
T6[(t[(i + 3) % 4] >> 16) & 0xff] ^
|
||||
T7[(t[(i + 2) % 4] >> 8) & 0xff] ^
|
||||
T8[ t[(i + 1) % 4] & 0xff] ^
|
||||
this._Kd[r][i]);
|
||||
}
|
||||
t = a.slice();
|
||||
}
|
||||
|
||||
// the last round is special
|
||||
var result = createArray(16), tt;
|
||||
for (var i = 0; i < 4; i++) {
|
||||
tt = this._Kd[rounds][i];
|
||||
result[4 * i ] = (Si[(t[ i ] >> 24) & 0xff] ^ (tt >> 24)) & 0xff;
|
||||
result[4 * i + 1] = (Si[(t[(i + 3) % 4] >> 16) & 0xff] ^ (tt >> 16)) & 0xff;
|
||||
result[4 * i + 2] = (Si[(t[(i + 2) % 4] >> 8) & 0xff] ^ (tt >> 8)) & 0xff;
|
||||
result[4 * i + 3] = (Si[ t[(i + 1) % 4] & 0xff] ^ tt ) & 0xff;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mode Of Operation - Electonic Codebook (ECB)
|
||||
*/
|
||||
var ModeOfOperationECB = function(key) {
|
||||
if (!(this instanceof ModeOfOperationECB)) {
|
||||
throw Error('AES must be instanitated with `new`');
|
||||
}
|
||||
|
||||
this.description = "Electronic Code Block";
|
||||
this.name = "ecb";
|
||||
|
||||
this._aes = new AES(key);
|
||||
}
|
||||
|
||||
ModeOfOperationECB.prototype.encrypt = function(plaintext) {
|
||||
plaintext = coerceArray(plaintext);
|
||||
|
||||
if ((plaintext.length % 16) !== 0) {
|
||||
throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
|
||||
}
|
||||
|
||||
var ciphertext = createArray(plaintext.length);
|
||||
var block = createArray(16);
|
||||
|
||||
for (var i = 0; i < plaintext.length; i += 16) {
|
||||
copyArray(plaintext, block, 0, i, i + 16);
|
||||
block = this._aes.encrypt(block);
|
||||
copyArray(block, ciphertext, i);
|
||||
}
|
||||
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
ModeOfOperationECB.prototype.decrypt = function(ciphertext) {
|
||||
ciphertext = coerceArray(ciphertext);
|
||||
|
||||
if ((ciphertext.length % 16) !== 0) {
|
||||
throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
|
||||
}
|
||||
|
||||
var plaintext = createArray(ciphertext.length);
|
||||
var block = createArray(16);
|
||||
|
||||
for (var i = 0; i < ciphertext.length; i += 16) {
|
||||
copyArray(ciphertext, block, 0, i, i + 16);
|
||||
block = this._aes.decrypt(block);
|
||||
copyArray(block, plaintext, i);
|
||||
}
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mode Of Operation - Cipher Block Chaining (CBC)
|
||||
*/
|
||||
var ModeOfOperationCBC = function(key, iv) {
|
||||
if (!(this instanceof ModeOfOperationCBC)) {
|
||||
throw Error('AES must be instanitated with `new`');
|
||||
}
|
||||
|
||||
this.description = "Cipher Block Chaining";
|
||||
this.name = "cbc";
|
||||
|
||||
if (!iv) {
|
||||
iv = createArray(16);
|
||||
|
||||
} else if (iv.length != 16) {
|
||||
throw new Error('invalid initialation vector size (must be 16 bytes)');
|
||||
}
|
||||
|
||||
this._lastCipherblock = coerceArray(iv, true);
|
||||
|
||||
this._aes = new AES(key);
|
||||
}
|
||||
|
||||
ModeOfOperationCBC.prototype.encrypt = function(plaintext) {
|
||||
plaintext = coerceArray(plaintext);
|
||||
|
||||
if ((plaintext.length % 16) !== 0) {
|
||||
throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
|
||||
}
|
||||
|
||||
var ciphertext = createArray(plaintext.length);
|
||||
var block = createArray(16);
|
||||
|
||||
for (var i = 0; i < plaintext.length; i += 16) {
|
||||
copyArray(plaintext, block, 0, i, i + 16);
|
||||
|
||||
for (var j = 0; j < 16; j++) {
|
||||
block[j] ^= this._lastCipherblock[j];
|
||||
}
|
||||
|
||||
this._lastCipherblock = this._aes.encrypt(block);
|
||||
copyArray(this._lastCipherblock, ciphertext, i);
|
||||
}
|
||||
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
ModeOfOperationCBC.prototype.decrypt = function(ciphertext) {
|
||||
ciphertext = coerceArray(ciphertext);
|
||||
|
||||
if ((ciphertext.length % 16) !== 0) {
|
||||
throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
|
||||
}
|
||||
|
||||
var plaintext = createArray(ciphertext.length);
|
||||
var block = createArray(16);
|
||||
|
||||
for (var i = 0; i < ciphertext.length; i += 16) {
|
||||
copyArray(ciphertext, block, 0, i, i + 16);
|
||||
block = this._aes.decrypt(block);
|
||||
|
||||
for (var j = 0; j < 16; j++) {
|
||||
plaintext[i + j] = block[j] ^ this._lastCipherblock[j];
|
||||
}
|
||||
|
||||
copyArray(ciphertext, this._lastCipherblock, 0, i, i + 16);
|
||||
}
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mode Of Operation - Cipher Feedback (CFB)
|
||||
*/
|
||||
var ModeOfOperationCFB = function(key, iv, segmentSize) {
|
||||
if (!(this instanceof ModeOfOperationCFB)) {
|
||||
throw Error('AES must be instanitated with `new`');
|
||||
}
|
||||
|
||||
this.description = "Cipher Feedback";
|
||||
this.name = "cfb";
|
||||
|
||||
if (!iv) {
|
||||
iv = createArray(16);
|
||||
|
||||
} else if (iv.length != 16) {
|
||||
throw new Error('invalid initialation vector size (must be 16 size)');
|
||||
}
|
||||
|
||||
if (!segmentSize) { segmentSize = 1; }
|
||||
|
||||
this.segmentSize = segmentSize;
|
||||
|
||||
this._shiftRegister = coerceArray(iv, true);
|
||||
|
||||
this._aes = new AES(key);
|
||||
}
|
||||
|
||||
ModeOfOperationCFB.prototype.encrypt = function(plaintext) {
|
||||
if ((plaintext.length % this.segmentSize) != 0) {
|
||||
throw new Error('invalid plaintext size (must be segmentSize bytes)');
|
||||
}
|
||||
|
||||
var encrypted = coerceArray(plaintext, true);
|
||||
|
||||
var xorSegment;
|
||||
for (var i = 0; i < encrypted.length; i += this.segmentSize) {
|
||||
xorSegment = this._aes.encrypt(this._shiftRegister);
|
||||
for (var j = 0; j < this.segmentSize; j++) {
|
||||
encrypted[i + j] ^= xorSegment[j];
|
||||
}
|
||||
|
||||
// Shift the register
|
||||
copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
|
||||
copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
|
||||
}
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
ModeOfOperationCFB.prototype.decrypt = function(ciphertext) {
|
||||
if ((ciphertext.length % this.segmentSize) != 0) {
|
||||
throw new Error('invalid ciphertext size (must be segmentSize bytes)');
|
||||
}
|
||||
|
||||
var plaintext = coerceArray(ciphertext, true);
|
||||
|
||||
var xorSegment;
|
||||
for (var i = 0; i < plaintext.length; i += this.segmentSize) {
|
||||
xorSegment = this._aes.encrypt(this._shiftRegister);
|
||||
|
||||
for (var j = 0; j < this.segmentSize; j++) {
|
||||
plaintext[i + j] ^= xorSegment[j];
|
||||
}
|
||||
|
||||
// Shift the register
|
||||
copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
|
||||
copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
|
||||
}
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mode Of Operation - Output Feedback (OFB)
|
||||
*/
|
||||
var ModeOfOperationOFB = function(key, iv) {
|
||||
if (!(this instanceof ModeOfOperationOFB)) {
|
||||
throw Error('AES must be instanitated with `new`');
|
||||
}
|
||||
|
||||
this.description = "Output Feedback";
|
||||
this.name = "ofb";
|
||||
|
||||
if (!iv) {
|
||||
iv = createArray(16);
|
||||
|
||||
} else if (iv.length != 16) {
|
||||
throw new Error('invalid initialation vector size (must be 16 bytes)');
|
||||
}
|
||||
|
||||
this._lastPrecipher = coerceArray(iv, true);
|
||||
this._lastPrecipherIndex = 16;
|
||||
|
||||
this._aes = new AES(key);
|
||||
}
|
||||
|
||||
ModeOfOperationOFB.prototype.encrypt = function(plaintext) {
|
||||
var encrypted = coerceArray(plaintext, true);
|
||||
|
||||
for (var i = 0; i < encrypted.length; i++) {
|
||||
if (this._lastPrecipherIndex === 16) {
|
||||
this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
|
||||
this._lastPrecipherIndex = 0;
|
||||
}
|
||||
encrypted[i] ^= this._lastPrecipher[this._lastPrecipherIndex++];
|
||||
}
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
// Decryption is symetric
|
||||
ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
|
||||
|
||||
|
||||
/**
|
||||
* Counter object for CTR common mode of operation
|
||||
*/
|
||||
var Counter = function(initialValue) {
|
||||
if (!(this instanceof Counter)) {
|
||||
throw Error('Counter must be instanitated with `new`');
|
||||
}
|
||||
|
||||
// We allow 0, but anything false-ish uses the default 1
|
||||
if (initialValue !== 0 && !initialValue) { initialValue = 1; }
|
||||
|
||||
if (typeof(initialValue) === 'number') {
|
||||
this._counter = createArray(16);
|
||||
this.setValue(initialValue);
|
||||
|
||||
} else {
|
||||
this.setBytes(initialValue);
|
||||
}
|
||||
}
|
||||
|
||||
Counter.prototype.setValue = function(value) {
|
||||
if (typeof(value) !== 'number' || parseInt(value) != value) {
|
||||
throw new Error('invalid counter value (must be an integer)');
|
||||
}
|
||||
|
||||
// We cannot safely handle numbers beyond the safe range for integers
|
||||
if (value > Number.MAX_SAFE_INTEGER) {
|
||||
throw new Error('integer value out of safe range');
|
||||
}
|
||||
|
||||
for (var index = 15; index >= 0; --index) {
|
||||
this._counter[index] = value % 256;
|
||||
value = parseInt(value / 256);
|
||||
}
|
||||
}
|
||||
|
||||
Counter.prototype.setBytes = function(bytes) {
|
||||
bytes = coerceArray(bytes, true);
|
||||
|
||||
if (bytes.length != 16) {
|
||||
throw new Error('invalid counter bytes size (must be 16 bytes)');
|
||||
}
|
||||
|
||||
this._counter = bytes;
|
||||
};
|
||||
|
||||
Counter.prototype.increment = function() {
|
||||
for (var i = 15; i >= 0; i--) {
|
||||
if (this._counter[i] === 255) {
|
||||
this._counter[i] = 0;
|
||||
} else {
|
||||
this._counter[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mode Of Operation - Counter (CTR)
|
||||
*/
|
||||
var ModeOfOperationCTR = function(key, counter) {
|
||||
if (!(this instanceof ModeOfOperationCTR)) {
|
||||
throw Error('AES must be instanitated with `new`');
|
||||
}
|
||||
|
||||
this.description = "Counter";
|
||||
this.name = "ctr";
|
||||
|
||||
if (!(counter instanceof Counter)) {
|
||||
counter = new Counter(counter)
|
||||
}
|
||||
|
||||
this._counter = counter;
|
||||
|
||||
this._remainingCounter = null;
|
||||
this._remainingCounterIndex = 16;
|
||||
|
||||
this._aes = new AES(key);
|
||||
}
|
||||
|
||||
ModeOfOperationCTR.prototype.encrypt = function(plaintext) {
|
||||
var encrypted = coerceArray(plaintext, true);
|
||||
|
||||
for (var i = 0; i < encrypted.length; i++) {
|
||||
if (this._remainingCounterIndex === 16) {
|
||||
this._remainingCounter = this._aes.encrypt(this._counter._counter);
|
||||
this._remainingCounterIndex = 0;
|
||||
this._counter.increment();
|
||||
}
|
||||
encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
|
||||
}
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
// Decryption is symetric
|
||||
ModeOfOperationCTR.prototype.decrypt = ModeOfOperationCTR.prototype.encrypt;
|
||||
|
||||
|
||||
///////////////////////
|
||||
// Padding
|
||||
|
||||
// See:https://tools.ietf.org/html/rfc2315
|
||||
function pkcs7pad(data) {
|
||||
data = coerceArray(data, true);
|
||||
var padder = 16 - (data.length % 16);
|
||||
var result = createArray(data.length + padder);
|
||||
copyArray(data, result);
|
||||
for (var i = data.length; i < result.length; i++) {
|
||||
result[i] = padder;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function pkcs7strip(data) {
|
||||
data = coerceArray(data, true);
|
||||
if (data.length < 16) { throw new Error('PKCS#7 invalid length'); }
|
||||
|
||||
var padder = data[data.length - 1];
|
||||
if (padder > 16) { throw new Error('PKCS#7 padding byte out of range'); }
|
||||
|
||||
var length = data.length - padder;
|
||||
for (var i = 0; i < padder; i++) {
|
||||
if (data[length + i] !== padder) {
|
||||
throw new Error('PKCS#7 invalid padding byte');
|
||||
}
|
||||
}
|
||||
|
||||
var result = createArray(length);
|
||||
copyArray(data, result, 0, 0, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// Exporting
|
||||
|
||||
|
||||
// The block cipher
|
||||
var aesjs = {
|
||||
AES: AES,
|
||||
Counter: Counter,
|
||||
|
||||
ModeOfOperation: {
|
||||
ecb: ModeOfOperationECB,
|
||||
cbc: ModeOfOperationCBC,
|
||||
cfb: ModeOfOperationCFB,
|
||||
ofb: ModeOfOperationOFB,
|
||||
ctr: ModeOfOperationCTR
|
||||
},
|
||||
|
||||
utils: {
|
||||
hex: convertHex,
|
||||
utf8: convertUtf8
|
||||
},
|
||||
|
||||
padding: {
|
||||
pkcs7: {
|
||||
pad: pkcs7pad,
|
||||
strip: pkcs7strip
|
||||
}
|
||||
},
|
||||
|
||||
_arrayTest: {
|
||||
coerceArray: coerceArray,
|
||||
createArray: createArray,
|
||||
copyArray: copyArray,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// node.js
|
||||
if (typeof exports !== 'undefined') {
|
||||
module.exports = aesjs
|
||||
|
||||
// RequireJS/AMD
|
||||
// http://www.requirejs.org/docs/api.html
|
||||
// https://github.com/amdjs/amdjs-api/wiki/AMD
|
||||
} else if (typeof(define) === 'function' && define.amd) {
|
||||
define(aesjs);
|
||||
|
||||
// Web Browsers
|
||||
} else {
|
||||
|
||||
// If there was an existing library at "aesjs" make sure it's still available
|
||||
if (root.aesjs) {
|
||||
aesjs._aesjs = root.aesjs;
|
||||
}
|
||||
|
||||
root.aesjs = aesjs;
|
||||
}
|
||||
|
||||
|
||||
})(this);
|
8812
web/js/elliptic.js
8812
web/js/elliptic.js
File diff suppressed because it is too large
Load Diff
@ -1,977 +0,0 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global.MemoryMap = factory());
|
||||
}(this, (function () { 'use strict';
|
||||
|
||||
/**
|
||||
* Parser/writer for the "Intel hex" format.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A regexp that matches lines in a .hex file.
|
||||
*
|
||||
* One hexadecimal character is matched by "[0-9A-Fa-f]".
|
||||
* Two hex characters are matched by "[0-9A-Fa-f]{2}"
|
||||
* Eight or more hex characters are matched by "[0-9A-Fa-f]{8,}"
|
||||
* A capture group of two hex characters is "([0-9A-Fa-f]{2})"
|
||||
*
|
||||
* Record mark :
|
||||
* 8 or more hex chars ([0-9A-Fa-f]{8,})
|
||||
* Checksum ([0-9A-Fa-f]{2})
|
||||
* Optional newline (?:\r\n|\r|\n|)
|
||||
*/
|
||||
var hexLineRegexp = /:([0-9A-Fa-f]{8,})([0-9A-Fa-f]{2})(?:\r\n|\r|\n|)/g;
|
||||
|
||||
|
||||
// Takes a Uint8Array as input,
|
||||
// Returns an integer in the 0-255 range.
|
||||
function checksum(bytes) {
|
||||
return (-bytes.reduce(function (sum, v){ return sum + v; }, 0)) & 0xFF;
|
||||
}
|
||||
|
||||
// Takes two Uint8Arrays as input,
|
||||
// Returns an integer in the 0-255 range.
|
||||
function checksumTwo(array1, array2) {
|
||||
var partial1 = array1.reduce(function (sum, v){ return sum + v; }, 0);
|
||||
var partial2 = array2.reduce(function (sum, v){ return sum + v; }, 0);
|
||||
return -( partial1 + partial2 ) & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
// Trivial utility. Converts a number to hex and pads with zeroes up to 2 characters.
|
||||
function hexpad(number) {
|
||||
return number.toString(16).toUpperCase().padStart(2, '0');
|
||||
}
|
||||
|
||||
|
||||
// Polyfill as per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
|
||||
Number.isInteger = Number.isInteger || function(value) {
|
||||
return typeof value === 'number' &&
|
||||
isFinite(value) &&
|
||||
Math.floor(value) === value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @class MemoryMap
|
||||
*
|
||||
* Represents the contents of a memory layout, with main focus into (possibly sparse) blocks of data.
|
||||
*<br/>
|
||||
* A {@linkcode MemoryMap} acts as a subclass of
|
||||
* {@linkcode https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map|Map}.
|
||||
* In every entry of it, the key is the starting address of a data block (an integer number),
|
||||
* and the value is the <tt>Uint8Array</tt> with the data for that block.
|
||||
*<br/>
|
||||
* The main rationale for this is that a .hex file can contain a single block of contiguous
|
||||
* data starting at memory address 0 (and it's the common case for simple .hex files),
|
||||
* but complex files with several non-contiguous data blocks are also possible, thus
|
||||
* the need for a data structure on top of the <tt>Uint8Array</tt>s.
|
||||
*<br/>
|
||||
* In order to parse <tt>.hex</tt> files, use the {@linkcode MemoryMap.fromHex} <em>static</em> factory
|
||||
* method. In order to write <tt>.hex</tt> files, create a new {@linkcode MemoryMap} and call
|
||||
* its {@linkcode MemoryMap.asHexString} method.
|
||||
*
|
||||
* @extends Map
|
||||
* @example
|
||||
* import MemoryMap from 'nrf-intel-hex';
|
||||
*
|
||||
* let memMap1 = new MemoryMap();
|
||||
* let memMap2 = new MemoryMap([[0, new Uint8Array(1,2,3,4)]]);
|
||||
* let memMap3 = new MemoryMap({0: new Uint8Array(1,2,3,4)});
|
||||
* let memMap4 = new MemoryMap({0xCF0: new Uint8Array(1,2,3,4)});
|
||||
*/
|
||||
var MemoryMap = function MemoryMap(blocks) {
|
||||
var this$1 = this;
|
||||
|
||||
this._blocks = new Map();
|
||||
|
||||
if (blocks && typeof blocks[Symbol.iterator] === 'function') {
|
||||
for (var tuple of blocks) {
|
||||
if (!(tuple instanceof Array) || tuple.length !== 2) {
|
||||
throw new Error('First parameter to MemoryMap constructor must be an iterable of [addr, bytes] or undefined');
|
||||
}
|
||||
this$1.set(tuple[0], tuple[1]);
|
||||
}
|
||||
} else if (typeof blocks === 'object') {
|
||||
// Try iterating through the object's keys
|
||||
var addrs = Object.keys(blocks);
|
||||
for (var addr of addrs) {
|
||||
this$1.set(parseInt(addr), blocks[addr]);
|
||||
}
|
||||
|
||||
} else if (blocks !== undefined && blocks !== null) {
|
||||
throw new Error('First parameter to MemoryMap constructor must be an iterable of [addr, bytes] or undefined');
|
||||
}
|
||||
};
|
||||
|
||||
var prototypeAccessors = { size: { configurable: true } };
|
||||
|
||||
MemoryMap.prototype.set = function set (addr, value) {
|
||||
if (!Number.isInteger(addr)) {
|
||||
throw new Error('Address passed to MemoryMap is not an integer');
|
||||
}
|
||||
if (addr < 0) {
|
||||
throw new Error('Address passed to MemoryMap is negative');
|
||||
}
|
||||
if (!(value instanceof Uint8Array)) {
|
||||
throw new Error('Bytes passed to MemoryMap are not an Uint8Array');
|
||||
}
|
||||
return this._blocks.set(addr, value);
|
||||
};
|
||||
// Delegate the following to the 'this._blocks' Map:
|
||||
MemoryMap.prototype.get = function get (addr){ return this._blocks.get(addr);};
|
||||
MemoryMap.prototype.clear = function clear () { return this._blocks.clear(); };
|
||||
MemoryMap.prototype.delete = function delete$1 (addr) { return this._blocks.delete(addr); };
|
||||
MemoryMap.prototype.entries = function entries (){ return this._blocks.entries();};
|
||||
MemoryMap.prototype.forEach = function forEach (callback, that) { return this._blocks.forEach(callback, that); };
|
||||
MemoryMap.prototype.has = function has (addr){ return this._blocks.has(addr);};
|
||||
MemoryMap.prototype.keys = function keys () { return this._blocks.keys(); };
|
||||
MemoryMap.prototype.values = function values () { return this._blocks.values(); };
|
||||
prototypeAccessors.size.get = function () { return this._blocks.size; };
|
||||
MemoryMap.prototype[Symbol.iterator] = function () { return this._blocks[Symbol.iterator](); };
|
||||
|
||||
|
||||
/**
|
||||
* Parses a string containing data formatted in "Intel HEX" format, and
|
||||
* returns an instance of {@linkcode MemoryMap}.
|
||||
*<br/>
|
||||
* The insertion order of keys in the {@linkcode MemoryMap} is guaranteed to be strictly
|
||||
* ascending. In other words, when iterating through the {@linkcode MemoryMap}, the addresses
|
||||
* will be ordered in ascending order.
|
||||
*<br/>
|
||||
* The parser has an opinionated behaviour, and will throw a descriptive error if it
|
||||
* encounters some malformed input. Check the project's
|
||||
* {@link https://github.com/NordicSemiconductor/nrf-intel-hex#Features|README file} for details.
|
||||
*<br/>
|
||||
* If <tt>maxBlockSize</tt> is given, any contiguous data block larger than that will
|
||||
* be split in several blocks.
|
||||
*
|
||||
* @param {String} hexText The contents of a .hex file.
|
||||
* @param {Number} [maxBlockSize=Infinity] Maximum size of the returned <tt>Uint8Array</tt>s.
|
||||
*
|
||||
* @return {MemoryMap}
|
||||
*
|
||||
* @example
|
||||
* import MemoryMap from 'nrf-intel-hex';
|
||||
*
|
||||
* let intelHexString =
|
||||
* ":100000000102030405060708090A0B0C0D0E0F1068\n" +
|
||||
* ":00000001FF";
|
||||
*
|
||||
* let memMap = MemoryMap.fromHex(intelHexString);
|
||||
*
|
||||
* for (let [address, dataBlock] of memMap) {
|
||||
* console.log('Data block at ', address, ', bytes: ', dataBlock);
|
||||
* }
|
||||
*/
|
||||
MemoryMap.fromHex = function fromHex (hexText, maxBlockSize) {
|
||||
if ( maxBlockSize === void 0 ) maxBlockSize = Infinity;
|
||||
|
||||
var blocks = new MemoryMap();
|
||||
|
||||
var lastCharacterParsed = 0;
|
||||
var matchResult;
|
||||
var recordCount = 0;
|
||||
|
||||
// Upper Linear Base Address, the 16 most significant bits (2 bytes) of
|
||||
// the current 32-bit (4-byte) address
|
||||
// In practice this is a offset that is summed to the "load offset" of the
|
||||
// data records
|
||||
var ulba = 0;
|
||||
|
||||
hexLineRegexp.lastIndex = 0; // Reset the regexp, if not it would skip content when called twice
|
||||
|
||||
while ((matchResult = hexLineRegexp.exec(hexText)) !== null) {
|
||||
recordCount++;
|
||||
|
||||
// By default, a regexp loop ignores gaps between matches, but
|
||||
// we want to be aware of them.
|
||||
if (lastCharacterParsed !== matchResult.index) {
|
||||
throw new Error(
|
||||
'Malformed hex file: Could not parse between characters ' +
|
||||
lastCharacterParsed +
|
||||
' and ' +
|
||||
matchResult.index +
|
||||
' ("' +
|
||||
hexText.substring(lastCharacterParsed, Math.min(matchResult.index, lastCharacterParsed + 16)).trim() +
|
||||
'")');
|
||||
}
|
||||
lastCharacterParsed = hexLineRegexp.lastIndex;
|
||||
|
||||
// Give pretty names to the match's capture groups
|
||||
var recordStr = matchResult[1];
|
||||
var recordChecksum = matchResult[2];
|
||||
|
||||
// String to Uint8Array - https://stackoverflow.com/questions/43131242/how-to-convert-a-hexademical-string-of-data-to-an-arraybuffer-in-javascript
|
||||
var recordBytes = new Uint8Array(recordStr.match(/[\da-f]{2}/gi).map(function (h){ return parseInt(h, 16); }));
|
||||
|
||||
var recordLength = recordBytes[0];
|
||||
if (recordLength + 4 !== recordBytes.length) {
|
||||
throw new Error('Mismatched record length at record ' + recordCount + ' (' + matchResult[0].trim() + '), expected ' + (recordLength) + ' data bytes but actual length is ' + (recordBytes.length - 4));
|
||||
}
|
||||
|
||||
var cs = checksum(recordBytes);
|
||||
if (parseInt(recordChecksum, 16) !== cs) {
|
||||
throw new Error('Checksum failed at record ' + recordCount + ' (' + matchResult[0].trim() + '), should be ' + cs.toString(16) );
|
||||
}
|
||||
|
||||
var offset = (recordBytes[1] << 8) + recordBytes[2];
|
||||
var recordType = recordBytes[3];
|
||||
var data = recordBytes.subarray(4);
|
||||
|
||||
if (recordType === 0) {
|
||||
// Data record, contains data
|
||||
// Create a new block, at (upper linear base address + offset)
|
||||
if (blocks.has(ulba + offset)) {
|
||||
throw new Error('Duplicated data at record ' + recordCount + ' (' + matchResult[0].trim() + ')');
|
||||
}
|
||||
if (offset + data.length > 0x10000) {
|
||||
throw new Error(
|
||||
'Data at record ' +
|
||||
recordCount +
|
||||
' (' +
|
||||
matchResult[0].trim() +
|
||||
') wraps over 0xFFFF. This would trigger ambiguous behaviour. Please restructure your data so that for every record the data offset plus the data length do not exceed 0xFFFF.');
|
||||
}
|
||||
|
||||
blocks.set( ulba + offset, data );
|
||||
|
||||
} else {
|
||||
|
||||
// All non-data records must have a data offset of zero
|
||||
if (offset !== 0) {
|
||||
throw new Error('Record ' + recordCount + ' (' + matchResult[0].trim() + ') must have 0000 as data offset.');
|
||||
}
|
||||
|
||||
switch (recordType) {
|
||||
case 1: // EOF
|
||||
if (lastCharacterParsed !== hexText.length) {
|
||||
// This record should be at the very end of the string
|
||||
throw new Error('There is data after an EOF record at record ' + recordCount);
|
||||
}
|
||||
|
||||
return blocks.join(maxBlockSize);
|
||||
|
||||
case 2: // Extended Segment Address Record
|
||||
// Sets the 16 most significant bits of the 20-bit Segment Base
|
||||
// Address for the subsequent data.
|
||||
ulba = ((data[0] << 8) + data[1]) << 4;
|
||||
break;
|
||||
|
||||
case 3: // Start Segment Address Record
|
||||
// Do nothing. Record type 3 only applies to 16-bit Intel CPUs,
|
||||
// where it should reset the program counter (CS+IP CPU registers)
|
||||
break;
|
||||
|
||||
case 4: // Extended Linear Address Record
|
||||
// Sets the 16 most significant (upper) bits of the 32-bit Linear Address
|
||||
// for the subsequent data
|
||||
ulba = ((data[0] << 8) + data[1]) << 16;
|
||||
break;
|
||||
|
||||
case 5: // Start Linear Address Record
|
||||
// Do nothing. Record type 5 only applies to 32-bit Intel CPUs,
|
||||
// where it should reset the program counter (EIP CPU register)
|
||||
// It might have meaning for other CPU architectures
|
||||
// (see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka9903.html )
|
||||
// but will be ignored nonetheless.
|
||||
break;
|
||||
default:
|
||||
throw new Error('Invalid record type 0x' + hexpad(recordType) + ' at record ' + recordCount + ' (should be between 0x00 and 0x05)');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (recordCount) {
|
||||
throw new Error('No EOF record at end of file');
|
||||
} else {
|
||||
throw new Error('Malformed .hex file, could not parse any registers');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a <strong>new</strong> instance of {@linkcode MemoryMap}, containing
|
||||
* the same data, but concatenating together those memory blocks that are adjacent.
|
||||
*<br/>
|
||||
* The insertion order of keys in the {@linkcode MemoryMap} is guaranteed to be strictly
|
||||
* ascending. In other words, when iterating through the {@linkcode MemoryMap}, the addresses
|
||||
* will be ordered in ascending order.
|
||||
*<br/>
|
||||
* If <tt>maxBlockSize</tt> is given, blocks will be concatenated together only
|
||||
* until the joined block reaches this size in bytes. This means that the output
|
||||
* {@linkcode MemoryMap} might have more entries than the input one.
|
||||
*<br/>
|
||||
* If there is any overlap between blocks, an error will be thrown.
|
||||
*<br/>
|
||||
* The returned {@linkcode MemoryMap} will use newly allocated memory.
|
||||
*
|
||||
* @param {Number} [maxBlockSize=Infinity] Maximum size of the <tt>Uint8Array</tt>s in the
|
||||
* returned {@linkcode MemoryMap}.
|
||||
*
|
||||
* @return {MemoryMap}
|
||||
*/
|
||||
MemoryMap.prototype.join = function join (maxBlockSize) {
|
||||
var this$1 = this;
|
||||
if ( maxBlockSize === void 0 ) maxBlockSize = Infinity;
|
||||
|
||||
|
||||
// First pass, create a Map of address→length of contiguous blocks
|
||||
var sortedKeys = Array.from(this.keys()).sort(function (a,b){ return a-b; });
|
||||
var blockSizes = new Map();
|
||||
var lastBlockAddr = -1;
|
||||
var lastBlockEndAddr = -1;
|
||||
|
||||
for (var i=0,l=sortedKeys.length; i<l; i++) {
|
||||
var blockAddr = sortedKeys[i];
|
||||
var blockLength = this$1.get(sortedKeys[i]).length;
|
||||
|
||||
if (lastBlockEndAddr === blockAddr && (lastBlockEndAddr - lastBlockAddr) < maxBlockSize) {
|
||||
// Grow when the previous end address equals the current,
|
||||
// and we don't go over the maximum block size.
|
||||
blockSizes.set(lastBlockAddr, blockSizes.get(lastBlockAddr) + blockLength);
|
||||
lastBlockEndAddr += blockLength;
|
||||
} else if (lastBlockEndAddr <= blockAddr) {
|
||||
// Else mark a new block.
|
||||
blockSizes.set(blockAddr, blockLength);
|
||||
lastBlockAddr = blockAddr;
|
||||
lastBlockEndAddr = blockAddr + blockLength;
|
||||
} else {
|
||||
throw new Error('Overlapping data around address 0x' + blockAddr.toString(16));
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: allocate memory for the contiguous blocks and copy data around.
|
||||
var mergedBlocks = new MemoryMap();
|
||||
var mergingBlock;
|
||||
var mergingBlockAddr = -1;
|
||||
for (var i$1=0,l$1=sortedKeys.length; i$1<l$1; i$1++) {
|
||||
var blockAddr$1 = sortedKeys[i$1];
|
||||
if (blockSizes.has(blockAddr$1)) {
|
||||
mergingBlock = new Uint8Array(blockSizes.get(blockAddr$1));
|
||||
mergedBlocks.set(blockAddr$1, mergingBlock);
|
||||
mergingBlockAddr = blockAddr$1;
|
||||
}
|
||||
mergingBlock.set(this$1.get(blockAddr$1), blockAddr$1 - mergingBlockAddr);
|
||||
}
|
||||
|
||||
return mergedBlocks;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map|<tt>Map</tt>}
|
||||
* of {@linkcode MemoryMap}s, indexed by a alphanumeric ID,
|
||||
* returns a <tt>Map</tt> of address to tuples (<tt>Arrays</tt>s of length 2) of the form
|
||||
* <tt>(id, Uint8Array)</tt>s.
|
||||
*<br/>
|
||||
* The scenario for using this is having several {@linkcode MemoryMap}s, from several calls to
|
||||
* {@link module:nrf-intel-hex~hexToArrays|hexToArrays}, each having a different identifier.
|
||||
* This function locates where those memory block sets overlap, and returns a <tt>Map</tt>
|
||||
* containing addresses as keys, and arrays as values. Each array will contain 1 or more
|
||||
* <tt>(id, Uint8Array)</tt> tuples: the identifier of the memory block set that has
|
||||
* data in that region, and the data itself. When memory block sets overlap, there will
|
||||
* be more than one tuple.
|
||||
*<br/>
|
||||
* The <tt>Uint8Array</tt>s in the output are
|
||||
* {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray|subarrays}
|
||||
* of the input data; new memory is <strong>not</strong> allocated for them.
|
||||
*<br/>
|
||||
* The insertion order of keys in the output <tt>Map</tt> is guaranteed to be strictly
|
||||
* ascending. In other words, when iterating through the <tt>Map</tt>, the addresses
|
||||
* will be ordered in ascending order.
|
||||
*<br/>
|
||||
* When two blocks overlap, the corresponding array of tuples will have the tuples ordered
|
||||
* in the insertion order of the input <tt>Map</tt> of block sets.
|
||||
*<br/>
|
||||
*
|
||||
* @param {Map.MemoryMap} memoryMaps The input memory block sets
|
||||
*
|
||||
* @example
|
||||
* import MemoryMap from 'nrf-intel-hex';
|
||||
*
|
||||
* let memMap1 = MemoryMap.fromHex( hexdata1 );
|
||||
* let memMap2 = MemoryMap.fromHex( hexdata2 );
|
||||
* let memMap3 = MemoryMap.fromHex( hexdata3 );
|
||||
*
|
||||
* let maps = new Map([
|
||||
* ['file A', blocks1],
|
||||
* ['file B', blocks2],
|
||||
* ['file C', blocks3]
|
||||
* ]);
|
||||
*
|
||||
* let overlappings = MemoryMap.overlapMemoryMaps(maps);
|
||||
*
|
||||
* for (let [address, tuples] of overlappings) {
|
||||
* // if 'tuples' has length > 1, there is an overlap starting at 'address'
|
||||
*
|
||||
* for (let [address, tuples] of overlappings) {
|
||||
* let [id, bytes] = tuple;
|
||||
* // 'id' in this example is either 'file A', 'file B' or 'file C'
|
||||
* }
|
||||
* }
|
||||
* @return {Map.Array<mixed,Uint8Array>} The map of possibly overlapping memory blocks
|
||||
*/
|
||||
MemoryMap.overlapMemoryMaps = function overlapMemoryMaps (memoryMaps) {
|
||||
// First pass: create a list of addresses where any block starts or ends.
|
||||
var cuts = new Set();
|
||||
for (var [, blocks] of memoryMaps) {
|
||||
for (var [address, block] of blocks) {
|
||||
cuts.add(address);
|
||||
cuts.add(address + block.length);
|
||||
}
|
||||
}
|
||||
|
||||
var orderedCuts = Array.from(cuts.values()).sort(function (a,b){ return a-b; });
|
||||
var overlaps = new Map();
|
||||
|
||||
// Second pass: iterate through the cuts, get slices of every intersecting blockset
|
||||
var loop = function ( i, l ) {
|
||||
var cut = orderedCuts[i];
|
||||
var nextCut = orderedCuts[i+1];
|
||||
var tuples = [];
|
||||
|
||||
for (var [setId, blocks$1] of memoryMaps) {
|
||||
// Find the block with the highest address that is equal or lower to
|
||||
// the current cut (if any)
|
||||
var blockAddr = Array.from(blocks$1.keys()).reduce(function (acc, val){
|
||||
if (val > cut) {
|
||||
return acc;
|
||||
}
|
||||
return Math.max( acc, val );
|
||||
}, -1);
|
||||
|
||||
if (blockAddr !== -1) {
|
||||
var block$1 = blocks$1.get(blockAddr);
|
||||
var subBlockStart = cut - blockAddr;
|
||||
var subBlockEnd = nextCut - blockAddr;
|
||||
|
||||
if (subBlockStart < block$1.length) {
|
||||
tuples.push([ setId, block$1.subarray(subBlockStart, subBlockEnd) ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tuples.length) {
|
||||
overlaps.set(cut, tuples);
|
||||
}
|
||||
};
|
||||
|
||||
for (var i=0, l=orderedCuts.length-1; i<l; i++) loop( i, l );
|
||||
|
||||
return overlaps;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given the output of the {@linkcode MemoryMap.overlapMemoryMaps|overlapMemoryMaps}
|
||||
* (a <tt>Map</tt> of address to an <tt>Array</tt> of <tt>(id, Uint8Array)</tt> tuples),
|
||||
* returns a {@linkcode MemoryMap}. This discards the IDs in the process.
|
||||
*<br/>
|
||||
* The output <tt>Map</tt> contains as many entries as the input one (using the same addresses
|
||||
* as keys), but the value for each entry will be the <tt>Uint8Array</tt> of the <b>last</b>
|
||||
* tuple for each address in the input data.
|
||||
*<br/>
|
||||
* The scenario is wanting to join together several parsed .hex files, not worrying about
|
||||
* their overlaps.
|
||||
*<br/>
|
||||
*
|
||||
* @param {Map.Array<mixed,Uint8Array>} overlaps The (possibly overlapping) input memory blocks
|
||||
* @return {MemoryMap} The flattened memory blocks
|
||||
*/
|
||||
MemoryMap.flattenOverlaps = function flattenOverlaps (overlaps) {
|
||||
return new MemoryMap(
|
||||
Array.from(overlaps.entries()).map(function (ref) {
|
||||
var address = ref[0];
|
||||
var tuples = ref[1];
|
||||
|
||||
return [address, tuples[tuples.length - 1][1] ];
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@linkcode MemoryMap}, where:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Each key (the start address of each <tt>Uint8Array</tt>) is a multiple of
|
||||
*<tt>pageSize</tt></li>
|
||||
* <li>The size of each <tt>Uint8Array</tt> is exactly <tt>pageSize</tt></li>
|
||||
* <li>Bytes from the input map to bytes in the output</li>
|
||||
* <li>Bytes not in the input are replaced by a padding value</li>
|
||||
* </ul>
|
||||
*<br/>
|
||||
* The scenario is wanting to prepare pages of bytes for a write operation, where the write
|
||||
* operation affects a whole page/sector at once.
|
||||
*<br/>
|
||||
* The insertion order of keys in the output {@linkcode MemoryMap} is guaranteed
|
||||
* to be strictly ascending. In other words, when iterating through the
|
||||
* {@linkcode MemoryMap}, the addresses will be ordered in ascending order.
|
||||
*<br/>
|
||||
* The <tt>Uint8Array</tt>s in the output will be newly allocated.
|
||||
*<br/>
|
||||
*
|
||||
* @param {Number} [pageSize=1024] The size of the output pages, in bytes
|
||||
* @param {Number} [pad=0xFF] The byte value to use for padding
|
||||
* @return {MemoryMap}
|
||||
*/
|
||||
MemoryMap.prototype.paginate = function paginate ( pageSize, pad) {
|
||||
var this$1 = this;
|
||||
if ( pageSize === void 0 ) pageSize=1024;
|
||||
if ( pad === void 0 ) pad=0xFF;
|
||||
|
||||
if (pageSize <= 0) {
|
||||
throw new Error('Page size must be greater than zero');
|
||||
}
|
||||
var outPages = new MemoryMap();
|
||||
var page;
|
||||
|
||||
var sortedKeys = Array.from(this.keys()).sort(function (a,b){ return a-b; });
|
||||
|
||||
for (var i=0,l=sortedKeys.length; i<l; i++) {
|
||||
var blockAddr = sortedKeys[i];
|
||||
var block = this$1.get(blockAddr);
|
||||
var blockLength = block.length;
|
||||
var blockEnd = blockAddr + blockLength;
|
||||
|
||||
for (var pageAddr = blockAddr - (blockAddr % pageSize); pageAddr < blockEnd; pageAddr += pageSize) {
|
||||
page = outPages.get(pageAddr);
|
||||
if (!page) {
|
||||
page = new Uint8Array(pageSize);
|
||||
page.fill(pad);
|
||||
outPages.set(pageAddr, page);
|
||||
}
|
||||
|
||||
var offset = pageAddr - blockAddr;
|
||||
var subBlock = (void 0);
|
||||
if (offset <= 0) {
|
||||
// First page which intersects the block
|
||||
subBlock = block.subarray(0, Math.min(pageSize + offset, blockLength));
|
||||
page.set(subBlock, -offset);
|
||||
} else {
|
||||
// Any other page which intersects the block
|
||||
subBlock = block.subarray(offset, offset + Math.min(pageSize, blockLength - offset));
|
||||
page.set(subBlock, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outPages;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Locates the <tt>Uint8Array</tt> which contains the given offset,
|
||||
* and returns the four bytes held at that offset, as a 32-bit unsigned integer.
|
||||
*
|
||||
*<br/>
|
||||
* Behaviour is similar to {@linkcode https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getUint32|DataView.prototype.getUint32},
|
||||
* except that this operates over a {@linkcode MemoryMap} instead of
|
||||
* over an <tt>ArrayBuffer</tt>, and that this may return <tt>undefined</tt> if
|
||||
* the address is not <em>entirely</em> contained within one of the <tt>Uint8Array</tt>s.
|
||||
*<br/>
|
||||
*
|
||||
* @param {Number} offset The memory offset to read the data
|
||||
* @param {Boolean} [littleEndian=false] Whether to fetch the 4 bytes as a little- or big-endian integer
|
||||
* @return {Number|undefined} An unsigned 32-bit integer number
|
||||
*/
|
||||
MemoryMap.prototype.getUint32 = function getUint32 (offset, littleEndian) {
|
||||
var this$1 = this;
|
||||
|
||||
var keys = Array.from(this.keys());
|
||||
|
||||
for (var i=0,l=keys.length; i<l; i++) {
|
||||
var blockAddr = keys[i];
|
||||
var block = this$1.get(blockAddr);
|
||||
var blockLength = block.length;
|
||||
var blockEnd = blockAddr + blockLength;
|
||||
|
||||
if (blockAddr <= offset && (offset+4) <= blockEnd) {
|
||||
return (new DataView(block.buffer, offset - blockAddr, 4)).getUint32(0, littleEndian);
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a <tt>String</tt> of text representing a .hex file.
|
||||
* <br/>
|
||||
* The writer has an opinionated behaviour. Check the project's
|
||||
* {@link https://github.com/NordicSemiconductor/nrf-intel-hex#Features|README file} for details.
|
||||
*
|
||||
* @param {Number} [lineSize=16] Maximum number of bytes to be encoded in each data record.
|
||||
* Must have a value between 1 and 255, as per the specification.
|
||||
*
|
||||
* @return {String} String of text with the .hex representation of the input binary data
|
||||
*
|
||||
* @example
|
||||
* import MemoryMap from 'nrf-intel-hex';
|
||||
*
|
||||
* let memMap = new MemoryMap();
|
||||
* let bytes = new Uint8Array(....);
|
||||
* memMap.set(0x0FF80000, bytes); // The block with 'bytes' will start at offset 0x0FF80000
|
||||
*
|
||||
* let string = memMap.asHexString();
|
||||
*/
|
||||
MemoryMap.prototype.asHexString = function asHexString (lineSize) {
|
||||
var this$1 = this;
|
||||
if ( lineSize === void 0 ) lineSize = 16;
|
||||
|
||||
var lowAddress = 0;// 16 least significant bits of the current addr
|
||||
var highAddress = -1 << 16; // 16 most significant bits of the current addr
|
||||
var records = [];
|
||||
if (lineSize <=0) {
|
||||
throw new Error('Size of record must be greater than zero');
|
||||
} else if (lineSize > 255) {
|
||||
throw new Error('Size of record must be less than 256');
|
||||
}
|
||||
|
||||
// Placeholders
|
||||
var offsetRecord = new Uint8Array(6);
|
||||
var recordHeader = new Uint8Array(4);
|
||||
|
||||
var sortedKeys = Array.from(this.keys()).sort(function (a,b){ return a-b; });
|
||||
for (var i=0,l=sortedKeys.length; i<l; i++) {
|
||||
var blockAddr = sortedKeys[i];
|
||||
var block = this$1.get(blockAddr);
|
||||
|
||||
// Sanity checks
|
||||
if (!(block instanceof Uint8Array)) {
|
||||
throw new Error('Block at offset ' + blockAddr + ' is not an Uint8Array');
|
||||
}
|
||||
if (blockAddr < 0) {
|
||||
throw new Error('Block at offset ' + blockAddr + ' has a negative thus invalid address');
|
||||
}
|
||||
var blockSize = block.length;
|
||||
if (!blockSize) { continue; } // Skip zero-length blocks
|
||||
|
||||
|
||||
if (blockAddr > (highAddress + 0xFFFF)) {
|
||||
// Insert a new 0x04 record to jump to a new 64KiB block
|
||||
|
||||
// Round up the least significant 16 bits - no bitmasks because they trigger
|
||||
// base-2 negative numbers, whereas subtracting the modulo maintains precision
|
||||
highAddress = blockAddr - blockAddr % 0x10000;
|
||||
lowAddress = 0;
|
||||
|
||||
offsetRecord[0] = 2;// Length
|
||||
offsetRecord[1] = 0;// Load offset, high byte
|
||||
offsetRecord[2] = 0;// Load offset, low byte
|
||||
offsetRecord[3] = 4;// Record type
|
||||
offsetRecord[4] = highAddress >> 24;// new address offset, high byte
|
||||
offsetRecord[5] = highAddress >> 16;// new address offset, low byte
|
||||
|
||||
records.push(
|
||||
':' +
|
||||
Array.prototype.map.call(offsetRecord, hexpad).join('') +
|
||||
hexpad(checksum(offsetRecord))
|
||||
);
|
||||
}
|
||||
|
||||
if (blockAddr < (highAddress + lowAddress)) {
|
||||
throw new Error(
|
||||
'Block starting at 0x' +
|
||||
blockAddr.toString(16) +
|
||||
' overlaps with a previous block.');
|
||||
}
|
||||
|
||||
lowAddress = blockAddr % 0x10000;
|
||||
var blockOffset = 0;
|
||||
var blockEnd = blockAddr + blockSize;
|
||||
if (blockEnd > 0xFFFFFFFF) {
|
||||
throw new Error('Data cannot be over 0xFFFFFFFF');
|
||||
}
|
||||
|
||||
// Loop for every 64KiB memory segment that spans this block
|
||||
while (highAddress + lowAddress < blockEnd) {
|
||||
|
||||
if (lowAddress > 0xFFFF) {
|
||||
// Insert a new 0x04 record to jump to a new 64KiB block
|
||||
highAddress += 1 << 16; // Increase by one
|
||||
lowAddress = 0;
|
||||
|
||||
offsetRecord[0] = 2;// Length
|
||||
offsetRecord[1] = 0;// Load offset, high byte
|
||||
offsetRecord[2] = 0;// Load offset, low byte
|
||||
offsetRecord[3] = 4;// Record type
|
||||
offsetRecord[4] = highAddress >> 24;// new address offset, high byte
|
||||
offsetRecord[5] = highAddress >> 16;// new address offset, low byte
|
||||
|
||||
records.push(
|
||||
':' +
|
||||
Array.prototype.map.call(offsetRecord, hexpad).join('') +
|
||||
hexpad(checksum(offsetRecord))
|
||||
);
|
||||
}
|
||||
|
||||
var recordSize = -1;
|
||||
// Loop for every record for that spans the current 64KiB memory segment
|
||||
while (lowAddress < 0x10000 && recordSize) {
|
||||
recordSize = Math.min(
|
||||
lineSize, // Normal case
|
||||
blockEnd - highAddress - lowAddress, // End of block
|
||||
0x10000 - lowAddress // End of low addresses
|
||||
);
|
||||
|
||||
if (recordSize) {
|
||||
|
||||
recordHeader[0] = recordSize; // Length
|
||||
recordHeader[1] = lowAddress >> 8;// Load offset, high byte
|
||||
recordHeader[2] = lowAddress;// Load offset, low byte
|
||||
recordHeader[3] = 0;// Record type
|
||||
|
||||
var subBlock = block.subarray(blockOffset, blockOffset + recordSize); // Data bytes for this record
|
||||
|
||||
records.push(
|
||||
':' +
|
||||
Array.prototype.map.call(recordHeader, hexpad).join('') +
|
||||
Array.prototype.map.call(subBlock, hexpad).join('') +
|
||||
hexpad(checksumTwo(recordHeader, subBlock))
|
||||
);
|
||||
|
||||
blockOffset += recordSize;
|
||||
lowAddress += recordSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
records.push(':00000001FF');// EOF record
|
||||
|
||||
return records.join('\n');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs a deep copy of the current {@linkcode MemoryMap}, returning a new one
|
||||
* with exactly the same contents, but allocating new memory for each of its
|
||||
* <tt>Uint8Array</tt>s.
|
||||
*
|
||||
* @return {MemoryMap}
|
||||
*/
|
||||
MemoryMap.prototype.clone = function clone () {
|
||||
var this$1 = this;
|
||||
|
||||
var cloned = new MemoryMap();
|
||||
|
||||
for (var [addr, value] of this$1) {
|
||||
cloned.set(addr, new Uint8Array(value));
|
||||
}
|
||||
|
||||
return cloned;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given one <tt>Uint8Array</tt>, looks through its contents and returns a new
|
||||
* {@linkcode MemoryMap}, stripping away those regions where there are only
|
||||
* padding bytes.
|
||||
* <br/>
|
||||
* The start of the input <tt>Uint8Array</tt> is assumed to be offset zero for the output.
|
||||
* <br/>
|
||||
* The use case here is dumping memory from a working device and try to see the
|
||||
* "interesting" memory regions it has. This assumes that there is a constant,
|
||||
* predefined padding byte value being used in the "non-interesting" regions.
|
||||
* In other words: this will work as long as the dump comes from a flash memory
|
||||
* which has been previously erased (thus <tt>0xFF</tt>s for padding), or from a
|
||||
* previously blanked HDD (thus <tt>0x00</tt>s for padding).
|
||||
* <br/>
|
||||
* This method uses <tt>subarray</tt> on the input data, and thus does not allocate memory
|
||||
* for the <tt>Uint8Array</tt>s.
|
||||
*
|
||||
* @param {Uint8Array} bytes The input data
|
||||
* @param {Number} [padByte=0xFF] The value of the byte assumed to be used as padding
|
||||
* @param {Number} [minPadLength=64] The minimum number of consecutive pad bytes to
|
||||
* be considered actual padding
|
||||
*
|
||||
* @return {MemoryMap}
|
||||
*/
|
||||
MemoryMap.fromPaddedUint8Array = function fromPaddedUint8Array (bytes, padByte, minPadLength) {
|
||||
if ( padByte === void 0 ) padByte=0xFF;
|
||||
if ( minPadLength === void 0 ) minPadLength=64;
|
||||
|
||||
|
||||
if (!(bytes instanceof Uint8Array)) {
|
||||
throw new Error('Bytes passed to fromPaddedUint8Array are not an Uint8Array');
|
||||
}
|
||||
|
||||
// The algorithm used is naïve and checks every byte.
|
||||
// An obvious optimization would be to implement Boyer-Moore
|
||||
// (see https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm )
|
||||
// or otherwise start skipping up to minPadLength bytes when going through a non-pad
|
||||
// byte.
|
||||
// Anyway, we could expect a lot of cases where there is a majority of pad bytes,
|
||||
// and the algorithm should check most of them anyway, so the perf gain is questionable.
|
||||
|
||||
var memMap = new MemoryMap();
|
||||
var consecutivePads = 0;
|
||||
var lastNonPad = -1;
|
||||
var firstNonPad = 0;
|
||||
var skippingBytes = false;
|
||||
var l = bytes.length;
|
||||
|
||||
for (var addr = 0; addr < l; addr++) {
|
||||
var byte = bytes[addr];
|
||||
|
||||
if (byte === padByte) {
|
||||
consecutivePads++;
|
||||
if (consecutivePads >= minPadLength) {
|
||||
// Edge case: ignore writing a zero-length block when skipping
|
||||
// bytes at the beginning of the input
|
||||
if (lastNonPad !== -1) {
|
||||
/// Add the previous block to the result memMap
|
||||
memMap.set(firstNonPad, bytes.subarray(firstNonPad, lastNonPad+1));
|
||||
}
|
||||
|
||||
skippingBytes = true;
|
||||
}
|
||||
} else {
|
||||
if (skippingBytes) {
|
||||
skippingBytes = false;
|
||||
firstNonPad = addr;
|
||||
}
|
||||
lastNonPad = addr;
|
||||
consecutivePads = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// At EOF, add the last block if not skipping bytes already (and input not empty)
|
||||
if (!skippingBytes && lastNonPad !== -1) {
|
||||
memMap.set(firstNonPad, bytes.subarray(firstNonPad, l));
|
||||
}
|
||||
|
||||
return memMap;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@linkcode MemoryMap}, containing only data between
|
||||
* the addresses <tt>address</tt> and <tt>address + length</tt>.
|
||||
* Behaviour is similar to {@linkcode https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/slice|Array.prototype.slice},
|
||||
* in that the return value is a portion of the current {@linkcode MemoryMap}.
|
||||
*
|
||||
* <br/>
|
||||
* The returned {@linkcode MemoryMap} might be empty.
|
||||
*
|
||||
* <br/>
|
||||
* Internally, this uses <tt>subarray</tt>, so new memory is not allocated.
|
||||
*
|
||||
* @param {Number} address The start address of the slice
|
||||
* @param {Number} length The length of memory map to slice out
|
||||
* @return {MemoryMap}
|
||||
*/
|
||||
MemoryMap.prototype.slice = function slice (address, length){
|
||||
var this$1 = this;
|
||||
if ( length === void 0 ) length = Infinity;
|
||||
|
||||
if (length < 0) {
|
||||
throw new Error('Length of the slice cannot be negative');
|
||||
}
|
||||
|
||||
var sliced = new MemoryMap();
|
||||
|
||||
for (var [blockAddr, block] of this$1) {
|
||||
var blockLength = block.length;
|
||||
|
||||
if ((blockAddr + blockLength) >= address && blockAddr < (address + length)) {
|
||||
var sliceStart = Math.max(address, blockAddr);
|
||||
var sliceEnd = Math.min(address + length, blockAddr + blockLength);
|
||||
var sliceLength = sliceEnd - sliceStart;
|
||||
var relativeSliceStart = sliceStart - blockAddr;
|
||||
|
||||
if (sliceLength > 0) {
|
||||
sliced.set(sliceStart, block.subarray(relativeSliceStart, relativeSliceStart + sliceLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
return sliced;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@linkcode https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getUint32|Uint8Array}, containing only data between
|
||||
* the addresses <tt>address</tt> and <tt>address + length</tt>. Any byte without a value
|
||||
* in the input {@linkcode MemoryMap} will have a value of <tt>padByte</tt>.
|
||||
*
|
||||
* <br/>
|
||||
* This method allocates new memory.
|
||||
*
|
||||
* @param {Number} address The start address of the slice
|
||||
* @param {Number} length The length of memory map to slice out
|
||||
* @param {Number} [padByte=0xFF] The value of the byte assumed to be used as padding
|
||||
* @return {MemoryMap}
|
||||
*/
|
||||
MemoryMap.prototype.slicePad = function slicePad (address, length, padByte){
|
||||
var this$1 = this;
|
||||
if ( padByte === void 0 ) padByte=0xFF;
|
||||
|
||||
if (length < 0) {
|
||||
throw new Error('Length of the slice cannot be negative');
|
||||
}
|
||||
|
||||
var out = (new Uint8Array(length)).fill(padByte);
|
||||
|
||||
for (var [blockAddr, block] of this$1) {
|
||||
var blockLength = block.length;
|
||||
|
||||
if ((blockAddr + blockLength) >= address && blockAddr < (address + length)) {
|
||||
var sliceStart = Math.max(address, blockAddr);
|
||||
var sliceEnd = Math.min(address + length, blockAddr + blockLength);
|
||||
var sliceLength = sliceEnd - sliceStart;
|
||||
var relativeSliceStart = sliceStart - blockAddr;
|
||||
|
||||
if (sliceLength > 0) {
|
||||
out.set(block.subarray(relativeSliceStart, relativeSliceStart + sliceLength), sliceStart - address);
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the current memory map contains the one given as a parameter.
|
||||
*
|
||||
* <br/>
|
||||
* "Contains" means that all the offsets that have a byte value in the given
|
||||
* memory map have a value in the current memory map, and that the byte values
|
||||
* are the same.
|
||||
*
|
||||
* <br/>
|
||||
* An empty memory map is always contained in any other memory map.
|
||||
*
|
||||
* <br/>
|
||||
* Returns boolean <tt>true</tt> if the memory map is contained, <tt>false</tt>
|
||||
* otherwise.
|
||||
*
|
||||
* @param {MemoryMap} memMap The memory map to check
|
||||
* @return {Boolean}
|
||||
*/
|
||||
MemoryMap.prototype.contains = function contains (memMap) {
|
||||
var this$1 = this;
|
||||
|
||||
for (var [blockAddr, block] of memMap) {
|
||||
|
||||
var blockLength = block.length;
|
||||
|
||||
var slice = this$1.slice(blockAddr, blockLength).join().get(blockAddr);
|
||||
|
||||
if ((!slice) || slice.length !== blockLength ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i in block) {
|
||||
if (block[i] !== slice[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Object.defineProperties( MemoryMap.prototype, prototypeAccessors );
|
||||
|
||||
return MemoryMap;
|
||||
|
||||
})));
|
||||
//# sourceMappingURL=intel-hex.browser.js.map
|
9
web/js/sha256.min.js
vendored
9
web/js/sha256.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,753 +0,0 @@
|
||||
//Copyright 2014-2015 Google Inc. All rights reserved.
|
||||
|
||||
//Use of this source code is governed by a BSD-style
|
||||
//license that can be found in the LICENSE file or at
|
||||
//https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
/**
|
||||
* @fileoverview The U2F api.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
||||
/**
|
||||
* Namespace for the U2F api.
|
||||
* @type {Object}
|
||||
*/
|
||||
var u2f = u2f || {};
|
||||
|
||||
/**
|
||||
* FIDO U2F Javascript API Version
|
||||
* @number
|
||||
*/
|
||||
var js_api_version;
|
||||
|
||||
/**
|
||||
* The U2F extension id
|
||||
* @const {string}
|
||||
*/
|
||||
// The Chrome packaged app extension ID.
|
||||
// Uncomment this if you want to deploy a server instance that uses
|
||||
// the package Chrome app and does not require installing the U2F Chrome extension.
|
||||
u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
|
||||
// The U2F Chrome extension ID.
|
||||
// Uncomment this if you want to deploy a server instance that uses
|
||||
// the U2F Chrome extension to authenticate.
|
||||
// u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
|
||||
|
||||
|
||||
/**
|
||||
* Message types for messsages to/from the extension
|
||||
* @const
|
||||
* @enum {string}
|
||||
*/
|
||||
u2f.MessageTypes = {
|
||||
'U2F_REGISTER_REQUEST': 'u2f_register_request',
|
||||
'U2F_REGISTER_RESPONSE': 'u2f_register_response',
|
||||
'U2F_SIGN_REQUEST': 'u2f_sign_request',
|
||||
'U2F_SIGN_RESPONSE': 'u2f_sign_response',
|
||||
'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request',
|
||||
'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Response status codes
|
||||
* @const
|
||||
* @enum {number}
|
||||
*/
|
||||
u2f.ErrorCodes = {
|
||||
'OK': 0,
|
||||
'OTHER_ERROR': 1,
|
||||
'BAD_REQUEST': 2,
|
||||
'CONFIGURATION_UNSUPPORTED': 3,
|
||||
'DEVICE_INELIGIBLE': 4,
|
||||
'TIMEOUT': 5
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A message for registration requests
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* appId: ?string,
|
||||
* timeoutSeconds: ?number,
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.U2fRequest;
|
||||
|
||||
|
||||
/**
|
||||
* A message for registration responses
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.U2fResponse;
|
||||
|
||||
|
||||
/**
|
||||
* An error object for responses
|
||||
* @typedef {{
|
||||
* errorCode: u2f.ErrorCodes,
|
||||
* errorMessage: ?string
|
||||
* }}
|
||||
*/
|
||||
u2f.Error;
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC}}
|
||||
*/
|
||||
u2f.Transport;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {Array<u2f.Transport>}
|
||||
*/
|
||||
u2f.Transports;
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string,
|
||||
* keyHandle: string,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a sign response.
|
||||
* @typedef {{
|
||||
* keyHandle: string,
|
||||
* signatureData: string,
|
||||
* clientData: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registration request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registration response.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* keyHandle: string,
|
||||
* transports: Transports,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registered key.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* keyHandle: string,
|
||||
* transports: ?Transports,
|
||||
* appId: ?string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisteredKey;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a get API register response.
|
||||
* @typedef {{
|
||||
* js_api_version: number
|
||||
* }}
|
||||
*/
|
||||
u2f.GetJsApiVersionResponse;
|
||||
|
||||
|
||||
//Low level MessagePort API support
|
||||
|
||||
/**
|
||||
* Sets up a MessagePort to the U2F extension using the
|
||||
* available mechanisms.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
*/
|
||||
u2f.getMessagePort = function(callback) {
|
||||
if (typeof chrome != 'undefined' && chrome.runtime) {
|
||||
// The actual message here does not matter, but we need to get a reply
|
||||
// for the callback to run. Thus, send an empty signature request
|
||||
// in order to get a failure response.
|
||||
var msg = {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: []
|
||||
};
|
||||
chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
// We are on a whitelisted origin and can talk directly
|
||||
// with the extension.
|
||||
u2f.getChromeRuntimePort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was available, but we couldn't message
|
||||
// the extension directly, use iframe
|
||||
u2f.getIframePort_(callback);
|
||||
|
||||
}
|
||||
});
|
||||
} else if (u2f.isAndroidChrome_()) {
|
||||
u2f.getAuthenticatorPort_(callback);
|
||||
} else if (u2f.isIosChrome_()) {
|
||||
u2f.getIosPort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was not available at all, which is normal
|
||||
// when this origin doesn't have access to any extensions.
|
||||
u2f.getIframePort_(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect chrome running on android based on the browser's useragent.
|
||||
* @private
|
||||
*/
|
||||
u2f.isAndroidChrome_ = function() {
|
||||
var userAgent = navigator.userAgent;
|
||||
return userAgent.indexOf('Chrome') != -1 &&
|
||||
userAgent.indexOf('Android') != -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect chrome running on iOS based on the browser's platform.
|
||||
* @private
|
||||
*/
|
||||
u2f.isIosChrome_ = function() {
|
||||
return ["iPhone", "iPad", "iPod"].indexOf(navigator.platform) > -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects directly to the extension via chrome.runtime.connect.
|
||||
* @param {function(u2f.WrappedChromeRuntimePort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getChromeRuntimePort_ = function(callback) {
|
||||
var port = chrome.runtime.connect(u2f.EXTENSION_ID,
|
||||
{'includeTlsChannelId': true});
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedChromeRuntimePort_(port));
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a 'port' abstraction to the Authenticator app.
|
||||
* @param {function(u2f.WrappedAuthenticatorPort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getAuthenticatorPort_ = function(callback) {
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedAuthenticatorPort_());
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a 'port' abstraction to the iOS client app.
|
||||
* @param {function(u2f.WrappedIosPort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getIosPort_ = function(callback) {
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedIosPort_());
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper for chrome.runtime.Port that is compatible with MessagePort.
|
||||
* @param {Port} port
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_ = function(port) {
|
||||
this.port_ = port;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format and return a sign request compliant with the JS API version supported by the extension.
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.formatSignRequest_ =
|
||||
function(appId, challenge, registeredKeys, timeoutSeconds, reqId) {
|
||||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||||
// Adapt request to the 1.0 JS API
|
||||
var signRequests = [];
|
||||
for (var i = 0; i < registeredKeys.length; i++) {
|
||||
signRequests[i] = {
|
||||
version: registeredKeys[i].version,
|
||||
challenge: challenge,
|
||||
keyHandle: registeredKeys[i].keyHandle,
|
||||
appId: appId
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: signRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
}
|
||||
// JS 1.1 API
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
appId: appId,
|
||||
challenge: challenge,
|
||||
registeredKeys: registeredKeys,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Format and return a register request compliant with the JS API version supported by the extension..
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {Array<u2f.RegisterRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.formatRegisterRequest_ =
|
||||
function(appId, registeredKeys, registerRequests, timeoutSeconds, reqId) {
|
||||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||||
// Adapt request to the 1.0 JS API
|
||||
for (var i = 0; i < registerRequests.length; i++) {
|
||||
registerRequests[i].appId = appId;
|
||||
}
|
||||
var signRequests = [];
|
||||
for (var i = 0; i < registeredKeys.length; i++) {
|
||||
signRequests[i] = {
|
||||
version: registeredKeys[i].version,
|
||||
challenge: registerRequests[0],
|
||||
keyHandle: registeredKeys[i].keyHandle,
|
||||
appId: appId
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
signRequests: signRequests,
|
||||
registerRequests: registerRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
}
|
||||
// JS 1.1 API
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
appId: appId,
|
||||
registerRequests: registerRequests,
|
||||
registeredKeys: registeredKeys,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Posts a message on the underlying channel.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) {
|
||||
this.port_.postMessage(message);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface. Works only for the
|
||||
* onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
|
||||
function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message' || name == 'onmessage') {
|
||||
this.port_.onMessage.addListener(function(message) {
|
||||
// Emulate a minimal MessageEvent object
|
||||
handler({'data': message});
|
||||
});
|
||||
} else {
|
||||
console.error('WrappedChromeRuntimePort only supports onMessage');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap the Authenticator app with a MessagePort interface.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_ = function() {
|
||||
this.requestId_ = -1;
|
||||
this.requestObject_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the Authenticator intent.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.postMessage = function(message) {
|
||||
var intentUrl =
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
|
||||
';S.request=' + encodeURIComponent(JSON.stringify(message)) +
|
||||
';end';
|
||||
document.location = intentUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells what type of port this is.
|
||||
* @return {String} port type
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.getPortType = function() {
|
||||
return "WrappedAuthenticatorPort_";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message') {
|
||||
var self = this;
|
||||
/* Register a callback to that executes when
|
||||
* chrome injects the response. */
|
||||
window.addEventListener(
|
||||
'message', self.onRequestUpdate_.bind(self, handler), false);
|
||||
} else {
|
||||
console.error('WrappedAuthenticatorPort only supports message');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback invoked when a response is received from the Authenticator.
|
||||
* @param function({data: Object}) callback
|
||||
* @param {Object} message message Object
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
|
||||
function(callback, message) {
|
||||
var messageObject = JSON.parse(message.data);
|
||||
var intentUrl = messageObject['intentURL'];
|
||||
|
||||
var errorCode = messageObject['errorCode'];
|
||||
var responseObject = null;
|
||||
if (messageObject.hasOwnProperty('data')) {
|
||||
responseObject = /** @type {Object} */ (
|
||||
JSON.parse(messageObject['data']));
|
||||
}
|
||||
|
||||
callback({'data': responseObject});
|
||||
};
|
||||
|
||||
/**
|
||||
* Base URL for intents to Authenticator.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
|
||||
'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
|
||||
|
||||
/**
|
||||
* Wrap the iOS client app with a MessagePort interface.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedIosPort_ = function() {};
|
||||
|
||||
/**
|
||||
* Launch the iOS client app request
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.postMessage = function(message) {
|
||||
var str = JSON.stringify(message);
|
||||
var url = "u2f://auth?" + encodeURI(str);
|
||||
location.replace(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells what type of port this is.
|
||||
* @return {String} port type
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.getPortType = function() {
|
||||
return "WrappedIosPort_";
|
||||
};
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.addEventListener = function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name !== 'message') {
|
||||
console.error('WrappedIosPort only supports message');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets up an embedded trampoline iframe, sourced from the extension.
|
||||
* @param {function(MessagePort)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getIframePort_ = function(callback) {
|
||||
// Create the iframe
|
||||
var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = iframeOrigin + '/u2f-comms.html';
|
||||
iframe.setAttribute('style', 'display:none');
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
var channel = new MessageChannel();
|
||||
var ready = function(message) {
|
||||
if (message.data == 'ready') {
|
||||
channel.port1.removeEventListener('message', ready);
|
||||
callback(channel.port1);
|
||||
} else {
|
||||
console.error('First event on iframe port was not "ready"');
|
||||
}
|
||||
};
|
||||
channel.port1.addEventListener('message', ready);
|
||||
channel.port1.start();
|
||||
|
||||
iframe.addEventListener('load', function() {
|
||||
|
||||
// Deliver the port to the iframe and initialize
|
||||
//
|
||||
setTimeout(function(){
|
||||
iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
|
||||
|
||||
},1000);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//High-level JS API
|
||||
|
||||
/**
|
||||
* Default extension response timeout in seconds.
|
||||
* @const
|
||||
*/
|
||||
u2f.EXTENSION_TIMEOUT_SEC = 30;
|
||||
|
||||
/**
|
||||
* A singleton instance for a MessagePort to the extension.
|
||||
* @type {MessagePort|u2f.WrappedChromeRuntimePort_}
|
||||
* @private
|
||||
*/
|
||||
u2f.port_ = null;
|
||||
|
||||
/**
|
||||
* Callbacks waiting for a port
|
||||
* @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.waitingForPort_ = [];
|
||||
|
||||
/**
|
||||
* A counter for requestIds.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
u2f.reqCounter_ = 0;
|
||||
|
||||
/**
|
||||
* A map from requestIds to client callbacks
|
||||
* @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
|
||||
* |function((u2f.Error|u2f.SignResponse)))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.callbackMap_ = {};
|
||||
|
||||
/**
|
||||
* Creates or retrieves the MessagePort singleton to use.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getPortSingleton_ = function(callback) {
|
||||
if (u2f.port_) {
|
||||
callback(u2f.port_);
|
||||
} else {
|
||||
if (u2f.waitingForPort_.length == 0) {
|
||||
u2f.getMessagePort(function(port) {
|
||||
u2f.port_ = port;
|
||||
u2f.port_.addEventListener('message',
|
||||
/** @type {function(Event)} */ (u2f.responseHandler_));
|
||||
|
||||
// Careful, here be async callbacks. Maybe.
|
||||
while (u2f.waitingForPort_.length)
|
||||
u2f.waitingForPort_.shift()(u2f.port_);
|
||||
});
|
||||
}
|
||||
u2f.waitingForPort_.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles response messages from the extension.
|
||||
* @param {MessageEvent.<u2f.Response>} message
|
||||
* @private
|
||||
*/
|
||||
u2f.responseHandler_ = function(message) {
|
||||
var response = message.data;
|
||||
var reqId = response['requestId'];
|
||||
if (!reqId || !u2f.callbackMap_[reqId]) {
|
||||
console.error('Unknown or missing requestId in response.');
|
||||
return;
|
||||
}
|
||||
var cb = u2f.callbackMap_[reqId];
|
||||
delete u2f.callbackMap_[reqId];
|
||||
cb(response['responseData']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches an array of sign requests to available U2F tokens.
|
||||
* If the JS API version supported by the extension is unknown, it first sends a
|
||||
* message to the extension to find out the supported API version and then it sends
|
||||
* the sign request.
|
||||
* @param {string=} appId
|
||||
* @param {string=} challenge
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sign = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
if (js_api_version === undefined) {
|
||||
// Send a message to get the extension to JS API version, then send the actual sign request.
|
||||
u2f.getApiVersion(
|
||||
function (response) {
|
||||
js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
|
||||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||||
});
|
||||
} else {
|
||||
// We know the JS API version. Send the actual sign request in the supported API version.
|
||||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches an array of sign requests to available U2F tokens.
|
||||
* @param {string=} appId
|
||||
* @param {string=} challenge
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sendSignRequest = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches register requests to available U2F tokens. An array of sign
|
||||
* requests identifies already registered tokens.
|
||||
* If the JS API version supported by the extension is unknown, it first sends a
|
||||
* message to the extension to find out the supported API version and then it sends
|
||||
* the register request.
|
||||
* @param {string=} appId
|
||||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.register = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
if (js_api_version === undefined) {
|
||||
// Send a message to get the extension to JS API version, then send the actual register request.
|
||||
u2f.getApiVersion(
|
||||
function (response) {
|
||||
js_api_version = response['js_api_version'] === undefined ? 0: response['js_api_version'];
|
||||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||||
callback, opt_timeoutSeconds);
|
||||
});
|
||||
} else {
|
||||
// We know the JS API version. Send the actual register request in the supported API version.
|
||||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||||
callback, opt_timeoutSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches register requests to available U2F tokens. An array of sign
|
||||
* requests identifies already registered tokens.
|
||||
* @param {string=} appId
|
||||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sendRegisterRequest = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = u2f.formatRegisterRequest_(
|
||||
appId, registeredKeys, registerRequests, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches a message to the extension to find out the supported
|
||||
* JS API version.
|
||||
* If the user is on a mobile phone and is thus using Google Authenticator instead
|
||||
* of the Chrome extension, don't send the request and simply return 0.
|
||||
* @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.getApiVersion = function(callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
// If we are using Android Google Authenticator or iOS client app,
|
||||
// do not fire an intent to ask which JS API version to use.
|
||||
if (port.getPortType) {
|
||||
var apiVersion;
|
||||
switch (port.getPortType()) {
|
||||
case 'WrappedIosPort_':
|
||||
case 'WrappedAuthenticatorPort_':
|
||||
apiVersion = 1.1;
|
||||
break;
|
||||
|
||||
default:
|
||||
apiVersion = 0;
|
||||
break;
|
||||
}
|
||||
callback({ 'js_api_version': apiVersion });
|
||||
return;
|
||||
}
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var req = {
|
||||
type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
|
||||
timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC),
|
||||
requestId: reqId
|
||||
};
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
1467
web/js/wallet.js
1467
web/js/wallet.js
File diff suppressed because it is too large
Load Diff
@ -1,18 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC5TCCAc2gAwIBAgIJAPAHlj0PtV3iMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
|
||||
BAMMCWxvY2FsaG9zdDAeFw0xODA3MDgwMTUzMTlaFw0xODA4MDcwMTUzMTlaMBQx
|
||||
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAM9uac6J8FOOaVFtQIWmjZKQbUs1k2SBHHYASE5hOqCw9sBjlGix2VC/yuk7
|
||||
1Nn+N+QM59CkZxR33v2kEK1PTA5Ock/nOHljmnEQrDsKumpp6Jh/L3lB0uwHbTra
|
||||
RTl7giJ4CRPdMc7EYZnK+TecKMaq5O7X8RG55UJoHZFxVIkc2LoTupW13NfAs09G
|
||||
JdDSfMvLVy2ZqELlKQ4qR3kLE7RpDss7WKN0bqG3NebI5liG2cDdObP4yd4gBpKk
|
||||
Dg8nwB4hrDaJaf4MzvrTefnd06Fkx2Fl/H0rZx7HOFMHEX+08fXcby7LMO3VbwEx
|
||||
ChOlDvHiBUHJDLow67JzNq5lv+8CAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo
|
||||
b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B
|
||||
AQsFAAOCAQEAa5rPgtqb8PJ/ZEE62T6kKaSZeT+ebFqdRvv24WYulbLbZGwryfhq
|
||||
utzS2peNBq57LlwvI+bOFmPUdIJjHBX2EM9NV3B9nJliM22ri6HuiXFpNcD2ehJV
|
||||
W2wMCNXZRyHySgM+7JIz/0TYEpJi3gq9P+IHtz4aXBZ5T2M+HsCBdnBci1n9EqTF
|
||||
9rmt/2RPQxNDIWeAGMlq19cQmmGwVfjxtKIPBGJd7RxkgT3itSjVxb1wyQTlDsZc
|
||||
0dJaMNGJDtGgpRtOlpC6Xv0SZ66GfsFwa8x5d/mty4m1kKYPu+77A6g9lBhjo8r6
|
||||
5MFFjFoq0XZuW5bBLbxQUC6qR8+mRI7gNg==
|
||||
-----END CERTIFICATE-----
|
@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDPbmnOifBTjmlR
|
||||
bUCFpo2SkG1LNZNkgRx2AEhOYTqgsPbAY5RosdlQv8rpO9TZ/jfkDOfQpGcUd979
|
||||
pBCtT0wOTnJP5zh5Y5pxEKw7CrpqaeiYfy95QdLsB2062kU5e4IieAkT3THOxGGZ
|
||||
yvk3nCjGquTu1/ERueVCaB2RcVSJHNi6E7qVtdzXwLNPRiXQ0nzLy1ctmahC5SkO
|
||||
Kkd5CxO0aQ7LO1ijdG6htzXmyOZYhtnA3Tmz+MneIAaSpA4PJ8AeIaw2iWn+DM76
|
||||
03n53dOhZMdhZfx9K2cexzhTBxF/tPH13G8uyzDt1W8BMQoTpQ7x4gVByQy6MOuy
|
||||
czauZb/vAgMBAAECggEBAJpxv14E3meYNVpnWg8o/2gNGRNShLfkWeiSNUQGqLxU
|
||||
hqSggDOjmAbDhrU50zWsTrkB0uhKQGXBCssXiUNBM4PDbOGJa0cWnjtpCpO7XSk2
|
||||
SfShXhuOoxkSPoX/VmOCTlaTwU6E9zzYg0MbGYwKPWIOg/5B0kA8hTJ4iutr0mFz
|
||||
Pc8xu4CkEnyNirDpkCuFvC5sVe9xaLgN6AvhvmKteDYxA/deJhpTx21IwOVyoCt1
|
||||
axhfqUf8RnQJAShxuGyM0k9f1eErvFipU9DOYlyBWI1F44esfT8EoC2Muo/P8fWH
|
||||
qgz7UU4SMHgGRj78nq2d+Xh4J+5o+UCLxWFmikzgA+ECgYEA6Jp3xVS868PDkh2U
|
||||
q14sRo3x+m8QPqFjRV7fYnYKFkikQLZ8NwVXCPAaUeK4+clw1CDawaE/J0exp88z
|
||||
r7ETKiQWQFhVBXPI4xHVu5GvZ5Cl3Bl5nog6nXA8XFRf2dwQmQWYsx3RLFl/WR1G
|
||||
v4rqth/Al5fZep0MI8oJ2SesCYMCgYEA5EvDxiZ4XoNmVUROUSSdpsObWUhp7wxE
|
||||
VsJGXu8sahWzlfF669nJh9oykU0X+VP7pqgzUG8IC2L/urFK4l/QzyklOgslkbLM
|
||||
2Si2SwkTzqQHa03iDvMa43t6+Q575PMFXWJQCoCO6pvlx/cUrDrj0Zl7jul+4Z6I
|
||||
qTM+5IHIICUCgYEAhORz128hfMXc/6cc4IeuXiUNAhrgOhg0wlaA5B0yiCa6iSp5
|
||||
b2oCnt2m+++/5R5c8yVONmBs14FTk9+C1TcjDumNOPf+o13SgUEYTtDeWRpAWK7J
|
||||
WHTWoEqWgd3G4Y6kgPi8lGFNt7vuUTizyg2RKbqcaz/bhf0iCXSOCd5roQcCgYEA
|
||||
l5uA/Zwan5lfYgykfdp1H4QTLG2ce/WHhJ4roWvv8NtMkaz11p6g6SkMH9Y0r40I
|
||||
N5rHyQiTLQyni1Gly0OaJZjLcgpo/qLgyu3wcVAr6TShAK+OCiODncIo3jCyMk75
|
||||
JxTc1rydLEwvgmYhQmcxV8Y3eaaybh6b3tF7WMCfKEkCgYAqySNWMDbmAkPyCFAV
|
||||
1EsbYB9Hh8zLJEDfQCwAbCH4BLzRwFx5SpvEQsNML/kf0i/iBPfPoC4cvnMTVzk7
|
||||
1LY247FCFrtEV5TxObWQJPN45SjOiQeqhpHzBcCu+kh1fz99+VcqZRbmrGV4E4NY
|
||||
reVBSr7HxTaQzJqfg0Ss/y5J0A==
|
||||
-----END PRIVATE KEY-----
|
@ -1,4 +0,0 @@
|
||||
# Run this to make cert you can import in chrome, then run localhost with HTTPS
|
||||
|
||||
openssl req -x509 -out localhost.crt -keyout localhost.key -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' -extensions EXT -config <( \
|
||||
printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
|
@ -1,15 +0,0 @@
|
||||
# https://blog.anvileight.com/posts/simple-python-http-server/#python-3-x
|
||||
|
||||
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||
import ssl
|
||||
|
||||
|
||||
host =('localhost', 4443)
|
||||
httpd = HTTPServer(('localhost', 4443), SimpleHTTPRequestHandler)
|
||||
|
||||
httpd.socket = ssl.wrap_socket (httpd.socket,
|
||||
keyfile="localhost.key",
|
||||
certfile='localhost.crt', server_side=True)
|
||||
|
||||
print('serving on ', host)
|
||||
httpd.serve_forever()
|
Reference in New Issue
Block a user