Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ad4c171054 | |||
| 048fcc39e4 | |||
| f5c211041b | |||
| 589a2e36f2 | |||
| 161e26f2dc | |||
| bf9ca01621 | |||
| 86f5aae002 | |||
| 46f3a5c993 | |||
| 52015fb289 | |||
| 23ba62cd69 | |||
| cd1e9d6945 | |||
| c49b843096 | |||
| 0c35337bb7 | |||
| e419b9865a | |||
| a89cb55529 | |||
| efa653c7cf | |||
| 07957617e5 | |||
| 903104239b | |||
| 291c5320bb | |||
| edbc2f291e | |||
| c32ee61a4f | |||
| 0995609391 | |||
| 29fef56be1 | |||
| 6a348dd304 | |||
| 32a96e580d | |||
| 54f03a39c2 | |||
| a55189e2a4 | |||
| 14d10c0794 | |||
| 27818ccb1f | |||
| 0ebf26eff4 | |||
| ac620e2b0e | |||
| 46115cdf6c | |||
| f465c6edbb | |||
| ad795ae7ef | |||
| efff8d2f2e | |||
| c9c9c74117 |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -81,4 +81,12 @@ node_modules/
|
||||
|
||||
#companion app
|
||||
/companion
|
||||
/Flipper-Android-App
|
||||
/Flipper-Android-App
|
||||
|
||||
#WIP not ready to push protocols
|
||||
|
||||
lib/subghz/protocols/subghz_protocol_honda_pandora.c
|
||||
lib/subghz/protocols/honda_rolling.c
|
||||
lib/subghz/protocols/honda_rolling.h
|
||||
lib/subghz/protocols/honda_pandora.c
|
||||
lib/subghz/protocols/honda_pandora.h
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
---
|
||||
|
||||
### Added
|
||||
- Protocol name allowlist filter: in Receiver Config, a new "Proto Filter"
|
||||
field accepts a comma-separated list of protocol names (e.g. "Ford V2,VAG").
|
||||
When set, the receiver ignores all decoded signals that are not in the list,
|
||||
reducing RAM usage and increasing the chance of capturing the target protocol.
|
||||
Leave empty to disable (default behavior, all protocols accepted).
|
||||
Setting is persisted in last_subghz.settings under the ProtocolFilter key.
|
||||
|
||||
### Changed
|
||||
- Protocol Filter: replaced free-text input with a dedicated protocol list
|
||||
scene (Proto Filter in Receiver Config). All registered protocols are shown
|
||||
as toggleable items (--- / ONLY). Selecting one or more protocols restricts
|
||||
the receiver to only show those; leaving all as --- disables the filter.
|
||||
The active count is shown inline in Receiver Config ("N set" or "All").
|
||||
Filter is persisted across sessions and cleared by Reset to default.
|
||||
@@ -22,6 +22,7 @@ This project may incorporate, adapt, or build upon **other open-source projects*
|
||||
- [Contribution Policy](#contribution-policy)
|
||||
- [Citations & References](#citations--references)
|
||||
- [Disclaimer](#disclaimer)
|
||||
- [Special Thanks](#special-thanks-to-everyone-who-contributes-to-this-project)
|
||||
|
||||
---
|
||||
|
||||
@@ -35,6 +36,8 @@ This project may incorporate, adapt, or build upon **other open-source projects*
|
||||
| Keeloq Key Manager | Mod Hopping Config |
|
||||
|  |  |
|
||||
| PSA XTEA Decrypt | Counter BruteForce |
|
||||
|  |  |
|
||||
| Custom Emulation Settings | Custom Emulation Scene |
|
||||
|
||||
---
|
||||
|
||||
@@ -48,6 +51,7 @@ This project may incorporate, adapt, or build upon **other open-source projects*
|
||||
| Porsche | Porsche AG | 433/868 MHz | AM | Yes | Yes | No |
|
||||
| PSA (Peugeot/Citroën/DS) | PSA GROUP | 433 MHz | AM/FM | Yes | Yes | Yes |
|
||||
| Ford | Ford V0 | 315/433 MHz | AM | Yes | Yes | Yes |
|
||||
| Ford | Ford V1 | 315/433 MHz | FM | Yes | Yes | Yes |
|
||||
| Fiat | Fiat SpA | 433 MHz | AM | Yes | Yes | Yes |
|
||||
| Fiat | Marelli/Delphi | 433 MHz | AM | No | Yes | Yes |
|
||||
| Renault (old models) | Marelli | 433 MHz | AM | No | Yes | No|
|
||||
@@ -58,13 +62,17 @@ This project may incorporate, adapt, or build upon **other open-source projects*
|
||||
| Kia/Hyundai | KIA/HYU V3/V4 | 315/433 MHz | AM/FM | Yes | Yes | Yes |
|
||||
| Kia/Hyundai | KIA/HYU V5 | 433 MHz | FM | Yes | Yes | Yes |
|
||||
| Kia/Hyundai | KIA/HYU V6 | 433 MHz | FM | Yes | Yes | Yes |
|
||||
| Kia/Hyundai | KIA V7 | 433 MHz | FM | Yes | Yes | Yes |
|
||||
| Subaru | Subaru | 433 MHz | AM | Yes | Yes | No |
|
||||
| Suzuki | Suzuki | 433 MHz | FM | Yes | Yes | Yes |
|
||||
| Mitsubishi | Mitsubishi V0 | 868 MHz | FM | Yes | Yes | No |
|
||||
| Honda | Honda Type A/B | 433 MHz | FM (custom) | Yes | Yes | No |
|
||||
| Starline | Star Line | 433 MHz | AM | Yes | Yes | No |
|
||||
| Scher-Khan | Scher-Khan | 433 MHz | FM | Yes | Yes | No |
|
||||
| Scher-Khan | Magic Code PRO1/PRO2 | 433 MHz | FM | Yes | Yes | Yes |
|
||||
| Sheriff | Sheriff CFM (ZX-750/930) | 433 MHz | AM | Yes | Yes | No |
|
||||
| Chrysler/Dodge/Jeep | FOBIK GQ43VT | 315/433 MHz | AM | Yes | Yes | No |
|
||||
| Honda | Honda Static | 433 MHz | AM | Yes | Yes | No |
|
||||
|
||||
### Gate / Access Protocols
|
||||
|
||||
@@ -343,3 +351,36 @@ THIS SOFTWARE IS PROVIDED **"AS IS,"** WITHOUT ANY WARRANTIES OF ANY KIND, EXPRE
|
||||
IN NO EVENT SHALL THE AUTHORS, COPYRIGHT HOLDERS, OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR ITS USE.
|
||||
|
||||
**ALL RISKS FROM THE USE OR PERFORMANCE OF THIS SOFTWARE REMAIN WITH THE USER.**
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Special thanks to everyone who contributes to this project:
|
||||
|
||||
## Contributors (GitHub)
|
||||
|
||||
<a href="https://github.com/d4c1-labs/Flipper-ARF/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=d4c1-labs/Flipper-ARF"/>
|
||||
</a>
|
||||
|
||||
## Special Thanks
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/whatthefxck">
|
||||
<img src="https://avatars.githubusercontent.com/whatthefxck?s=80" width="80" height="80" alt="whatthefxck"/>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/zero-mega">
|
||||
<img src="https://avatars.githubusercontent.com/zero-mega?s=80" width="80" height="80" alt="zero-mega"/>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p align="center">
|
||||
Special thanks to everyone who contributed code, testing, reversing,
|
||||
research, ideas, captures and documentation.
|
||||
</p>
|
||||
|
||||
@@ -64,6 +64,10 @@ typedef enum {
|
||||
SubGhzCustomEventViewFreqAnalOkLong,
|
||||
|
||||
SubGhzCustomEventByteInputDone,
|
||||
SubGhzCustomEventCarEmulateTransmit,
|
||||
SubGhzCustomEventCarEmulateStop,
|
||||
SubGhzCustomEventCarEmulateExit,
|
||||
|
||||
} SubGhzCustomEvent;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -94,6 +94,7 @@ typedef enum {
|
||||
SubGhzViewIdReadRAW,
|
||||
SubGhzViewIdPsaDecrypt,
|
||||
SubGhzViewIdKeeloqDecrypt,
|
||||
SubGhzViewIdCarEmulate,
|
||||
|
||||
} SubGhzViewId;
|
||||
|
||||
|
||||
@@ -119,3 +119,13 @@ Custom_preset_data: 02 0D 07 04 08 32 0B 06 10 67 11 83 12 04 13 02 15 24 18 18
|
||||
Custom_preset_name: FM15k
|
||||
Custom_preset_module: CC1101
|
||||
Custom_preset_data: 02 0D 03 47 08 32 0B 06 10 A7 11 32 12 00 13 00 14 00 15 32 18 18 19 1D 1B 04 1C 00 1D 92 20 FB 21 B6 22 17 00 00 00 12 0E 34 60 C5 C1 C0
|
||||
|
||||
Custom_preset_name: Honda1
|
||||
Custom_preset_module: CC1101
|
||||
# G2 G3 G4 D L0 L1 L2
|
||||
Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00
|
||||
|
||||
Custom_preset_name: Honda2
|
||||
Custom_preset_module: CC1101
|
||||
# G2 G3 G4 D L0 L1 L2
|
||||
Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00
|
||||
|
||||
@@ -0,0 +1,499 @@
|
||||
/**
|
||||
* Scene: CarEmulate
|
||||
* Custom automotive-key emulation GUI ported from ProtoPirate.
|
||||
* Activated when SubGhzLastSettings::custom_car_emulate == true and the
|
||||
* user presses "Emulate" on a saved dynamic protocol.
|
||||
*
|
||||
* Flow:
|
||||
* SavedMenu → Emulate → (custom_car_emulate?) CarEmulate : Transmitter
|
||||
*/
|
||||
#include "../subghz_i.h"
|
||||
#include "../views/subghz_car_emulate.h"
|
||||
#include "../helpers/subghz_custom_event.h"
|
||||
#include <lib/subghz/blocks/generic.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include "../helpers/subghz_txrx_i.h"
|
||||
#include <lib/subghz/blocks/custom_btn_i.h>
|
||||
|
||||
#define TAG "SubGhzSceneCarEmulate"
|
||||
#define MIN_TX_TICKS 66U /* ~666 ms at 100 ms tick */
|
||||
|
||||
/* ── Per-session state (heap, freed on exit) ─────────────────────────────── */
|
||||
typedef struct {
|
||||
/* Signal metadata read from fff_data */
|
||||
char protocol_name[48];
|
||||
uint32_t serial;
|
||||
uint8_t original_button;
|
||||
uint32_t original_counter;
|
||||
uint32_t current_counter;
|
||||
uint32_t freq;
|
||||
char preset_short[12]; /* "AM650", "FM476", … */
|
||||
|
||||
/* TX state */
|
||||
bool is_transmitting;
|
||||
bool stop_pending; /* stop requested before MIN_TX_TICKS elapsed */
|
||||
uint32_t tx_start_tick;
|
||||
|
||||
/* Pending button key (InputKey) decoded from the packed custom event */
|
||||
uint8_t pending_button;
|
||||
} CarEmulateState;
|
||||
|
||||
static CarEmulateState* s_state = NULL;
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
* Button mapping (protocol-name → InputKey → button byte)
|
||||
* Ported verbatim from protopirate_scene_emulate.c
|
||||
* ═════════════════════════════════════════════════════════════════════════*/
|
||||
//static uint8_t car_emulate_map_button(
|
||||
// const char* protocol,
|
||||
// InputKey key,
|
||||
// uint8_t original) {
|
||||
|
||||
/* Land Rover V0 */
|
||||
// if(strstr(protocol, "Land Rover")) {
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x02; /* Lock */
|
||||
// case InputKeyOk: return 0x04; /* Unlock */
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
/* Mazda */
|
||||
// if(strstr(protocol, "Mazda")) {
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x01;
|
||||
// case InputKeyOk: return 0x02;
|
||||
// case InputKeyDown: return 0x04;
|
||||
// case InputKeyRight: return 0x08;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
/* PSA */
|
||||
// if(strstr(protocol, "PSA")) {
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x1;
|
||||
// case InputKeyOk: return 0x2;
|
||||
// case InputKeyDown: return 0x4;
|
||||
// case InputKeyLeft: return 0x8;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
/* VAG */
|
||||
// if(strstr(protocol, "VAG")) {
|
||||
// if(original == 0x10 || original == 0x20 || original == 0x40) {
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x20;
|
||||
// case InputKeyOk: return 0x10;
|
||||
// case InputKeyDown: return 0x40;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x2;
|
||||
// case InputKeyOk: return 0x1;
|
||||
// case InputKeyDown: return 0x4;
|
||||
// case InputKeyLeft: return 0x8;
|
||||
// case InputKeyRight: return 0x3;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
/* Honda Static */
|
||||
// if(strstr(protocol, "Honda Static")) {
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x1;
|
||||
// case InputKeyOk: return 0x2;
|
||||
// case InputKeyDown: return 0x4;
|
||||
// case InputKeyRight: return 0x5;
|
||||
// case InputKeyLeft: return 0x8;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
/* Ford */
|
||||
// if(strstr(protocol, "Ford")) {
|
||||
// switch(key) {
|
||||
// case InputKeyLeft: return 0x1;
|
||||
// case InputKeyUp: return 0x2;
|
||||
// case InputKeyOk: return 0x4;
|
||||
// case InputKeyDown: return 0x8;
|
||||
// case InputKeyRight: return 0x10;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
/* Chrysler */
|
||||
// if(strstr(protocol, "Chrysler")) {
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x1;
|
||||
// case InputKeyOk: return 0x2;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
/* Subaru */
|
||||
// if(strstr(protocol, "Subaru")) {
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x1;
|
||||
// case InputKeyOk: return 0x2;
|
||||
// case InputKeyDown: return 0x3;
|
||||
// case InputKeyLeft: return 0x4;
|
||||
// case InputKeyRight: return 0x8;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
/* Fiat V1 */
|
||||
// if(strstr(protocol, "Fiat V1")) {
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x8;
|
||||
// case InputKeyOk: return 0x0;
|
||||
// case InputKeyDown: return 0xD;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
/* Generic KeeLoq / KIA etc. – simple 4-button layout */
|
||||
// if(strstr(protocol, "Kia") || strstr(protocol, "KIA") ||
|
||||
// strstr(protocol, "KeeLoq") || strstr(protocol, "Keeloq")) {
|
||||
// switch(key) {
|
||||
// case InputKeyUp: return 0x1;
|
||||
// case InputKeyOk: return 0x2;
|
||||
// case InputKeyDown: return 0x3;
|
||||
// case InputKeyLeft: return 0x4;
|
||||
// case InputKeyRight: return 0x8;
|
||||
// default: return original;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return original;
|
||||
//}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
* TX helpers
|
||||
* ═════════════════════════════════════════════════════════════════════════*/
|
||||
|
||||
/**
|
||||
* Read frequency and short preset name from fff_data.
|
||||
* Falls back to 433.92 MHz / "AM650" on failure.
|
||||
*/
|
||||
static void car_emulate_read_freq_preset(SubGhz* subghz, CarEmulateState* st) {
|
||||
FlipperFormat* fff = subghz_txrx_get_fff_data(subghz->txrx);
|
||||
|
||||
st->freq = 433920000UL;
|
||||
strncpy(st->preset_short, "AM650", sizeof(st->preset_short) - 1);
|
||||
|
||||
if(!fff) return;
|
||||
|
||||
uint32_t freq = 0;
|
||||
flipper_format_rewind(fff);
|
||||
if(flipper_format_read_uint32(fff, "Frequency", &freq, 1) && freq > 0) {
|
||||
st->freq = freq;
|
||||
}
|
||||
|
||||
FuriString* preset_str = furi_string_alloc();
|
||||
flipper_format_rewind(fff);
|
||||
if(flipper_format_read_string(fff, "Preset", preset_str)) {
|
||||
/* Convert long FuriHal name → short token used by the setting */
|
||||
const char* raw = furi_string_get_cstr(preset_str);
|
||||
const char* short_name = "AM650";
|
||||
if(strstr(raw, "Ook270")) short_name = "AM270";
|
||||
else if(strstr(raw, "Ook650")) short_name = "AM650";
|
||||
else if(strstr(raw, "238")) short_name = "FM238";
|
||||
else if(strstr(raw, "12K")) short_name = "FM12K";
|
||||
else if(strstr(raw, "476")) short_name = "FM476";
|
||||
else if(strstr(raw, "Custom")) short_name = "CUST";
|
||||
strncpy(st->preset_short, short_name, sizeof(st->preset_short) - 1);
|
||||
}
|
||||
furi_string_free(preset_str);
|
||||
}
|
||||
|
||||
/** Update Btn and Cnt fields in fff_data so the transmitter re-serialises them. */
|
||||
static void car_emulate_apply_button(SubGhz* subghz, InputKey key) {
|
||||
UNUSED(subghz);
|
||||
|
||||
uint8_t custom_btn_id;
|
||||
switch(key) {
|
||||
case InputKeyUp: custom_btn_id = SUBGHZ_CUSTOM_BTN_UP; break;
|
||||
case InputKeyDown: custom_btn_id = SUBGHZ_CUSTOM_BTN_DOWN; break;
|
||||
case InputKeyLeft: custom_btn_id = SUBGHZ_CUSTOM_BTN_LEFT; break;
|
||||
case InputKeyRight: custom_btn_id = SUBGHZ_CUSTOM_BTN_RIGHT; break;
|
||||
case InputKeyOk:
|
||||
default: custom_btn_id = SUBGHZ_CUSTOM_BTN_OK; break;
|
||||
}
|
||||
|
||||
subghz_custom_btn_set(custom_btn_id);
|
||||
}
|
||||
|
||||
|
||||
/** Update Cnt in fff_data (Btn is handled by the protocol via custom_btn). */
|
||||
static void car_emulate_update_fff(SubGhz* subghz, uint32_t counter) {
|
||||
FlipperFormat* fff = subghz_txrx_get_fff_data(subghz->txrx);
|
||||
if(!fff) return;
|
||||
flipper_format_rewind(fff);
|
||||
flipper_format_insert_or_update_uint32(fff, "Cnt", &counter, 1);
|
||||
}
|
||||
|
||||
|
||||
/** Apply tx_power to the current preset and start a single transmission burst. */
|
||||
static bool car_emulate_start_tx(SubGhz* subghz, uint8_t custom_btn_id) {
|
||||
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||
if(preset.data && preset.data_size > 0 && subghz->tx_power > 0) {
|
||||
subghz_txrx_set_tx_power(preset.data, preset.data_size, subghz->tx_power);
|
||||
FURI_LOG_I(TAG, "TX power index applied: %u", subghz->tx_power);
|
||||
}
|
||||
|
||||
subghz_custom_btn_set(custom_btn_id);
|
||||
|
||||
bool ok = subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||
if(ok) {
|
||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||
notification_message(subghz->notifications, &sequence_blink_magenta_10);
|
||||
FURI_LOG_I(TAG, "TX started");
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "subghz_tx_start failed");
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
/** Stop an active transmission. */
|
||||
static void car_emulate_stop_tx(SubGhz* subghz) {
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
notification_message(subghz->notifications, &sequence_blink_stop);
|
||||
FURI_LOG_I(TAG, "TX stopped");
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
* View callback (fired from the View's input handler)
|
||||
* ═════════════════════════════════════════════════════════════════════════*/
|
||||
static void subghz_scene_car_emulate_view_callback(uint32_t event, void* context) {
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
* Helpers to keep the view in sync
|
||||
* ═════════════════════════════════════════════════════════════════════════*/
|
||||
static void car_emulate_refresh_view(SubGhz* subghz) {
|
||||
furi_assert(s_state);
|
||||
subghz_car_emulate_view_set_data(
|
||||
subghz->car_emulate_view,
|
||||
s_state->protocol_name,
|
||||
s_state->serial,
|
||||
s_state->current_counter,
|
||||
s_state->original_counter,
|
||||
s_state->freq,
|
||||
s_state->preset_short,
|
||||
s_state->is_transmitting);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
* Scene on_enter
|
||||
* ═════════════════════════════════════════════════════════════════════════*/
|
||||
void subghz_scene_car_emulate_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
furi_assert(subghz);
|
||||
|
||||
/* Allocate per-session state */
|
||||
s_state = malloc(sizeof(CarEmulateState));
|
||||
furi_check(s_state);
|
||||
memset(s_state, 0, sizeof(CarEmulateState));
|
||||
|
||||
/* ── Read metadata from the loaded fff_data ── */
|
||||
FlipperFormat* fff = subghz_txrx_get_fff_data(subghz->txrx);
|
||||
if(fff) {
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
flipper_format_rewind(fff);
|
||||
if(flipper_format_read_string(fff, "Protocol", tmp)) {
|
||||
strncpy(
|
||||
s_state->protocol_name,
|
||||
furi_string_get_cstr(tmp),
|
||||
sizeof(s_state->protocol_name) - 1);
|
||||
}
|
||||
|
||||
flipper_format_rewind(fff);
|
||||
flipper_format_read_uint32(fff, "Serial", &s_state->serial, 1);
|
||||
|
||||
flipper_format_rewind(fff);
|
||||
uint32_t btn_tmp = 0;
|
||||
if(flipper_format_read_uint32(fff, "Btn", &btn_tmp, 1)) {
|
||||
s_state->original_button = (uint8_t)btn_tmp;
|
||||
}
|
||||
|
||||
flipper_format_rewind(fff);
|
||||
flipper_format_read_uint32(fff, "Cnt", &s_state->original_counter, 1);
|
||||
s_state->current_counter = s_state->original_counter;
|
||||
|
||||
furi_string_free(tmp);
|
||||
}
|
||||
|
||||
/* ── Initialize the custom_btn system ──────────────────────────────────
|
||||
* Reset first so any leftover state from a previous session is cleared.
|
||||
* Then deserialize the decoder once: this causes the protocol's own
|
||||
* deserialize() to call subghz_custom_btn_set_original() and
|
||||
* subghz_custom_btn_set_max(), which is exactly what the standard
|
||||
* Transmitter scene does via subghz_scene_transmitter_update_data_show().
|
||||
* After this call:
|
||||
* - subghz_custom_btn_get_original() → the button that was in the file
|
||||
* - subghz_custom_btn_is_allowed() → true if protocol supports it
|
||||
* - subghz_custom_btn_get_max() → number of buttons available */
|
||||
subghz_custom_btns_reset();
|
||||
|
||||
SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx);
|
||||
if(decoder && fff) {
|
||||
flipper_format_rewind(fff);
|
||||
subghz_protocol_decoder_base_deserialize(decoder, fff);
|
||||
/* Rewind again so subsequent reads in car_emulate_read_freq_preset()
|
||||
* start from the beginning of the file. */
|
||||
flipper_format_rewind(fff);
|
||||
}
|
||||
|
||||
subghz_car_emulate_view_set_labels(
|
||||
subghz->car_emulate_view,
|
||||
"UNLOCK", /* OK */
|
||||
"LOCK", /* Up */
|
||||
"TRUNK", /* Down */
|
||||
"PANIC", /* Left */
|
||||
"START" /* Right */
|
||||
);
|
||||
|
||||
car_emulate_read_freq_preset(subghz, s_state);
|
||||
|
||||
/* ── Configure the view ── */
|
||||
subghz_car_emulate_view_set_callback(
|
||||
subghz->car_emulate_view, subghz_scene_car_emulate_view_callback, subghz);
|
||||
|
||||
car_emulate_refresh_view(subghz);
|
||||
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdCarEmulate);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
* Scene on_event
|
||||
* ═════════════════════════════════════════════════════════════════════════*/
|
||||
bool subghz_scene_car_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
furi_assert(s_state);
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
|
||||
/* ── Transmit ── */
|
||||
if((event.event & 0xFFFFU) == SubGhzCustomEventCarEmulateTransmit) {
|
||||
InputKey key = (InputKey)((event.event >> 16) & 0xFFU);
|
||||
|
||||
/* Stop any ongoing TX first */
|
||||
if(subghz->state_notifications == SubGhzNotificationStateTx) {
|
||||
car_emulate_stop_tx(subghz);
|
||||
}
|
||||
|
||||
/* Bump counter */
|
||||
s_state->current_counter++;
|
||||
|
||||
/* Set the custom button BEFORE deserialize() is called inside
|
||||
* subghz_tx_start() → subghz_txrx_tx_start().
|
||||
* The protocol's deserialize() will call subghz_custom_btn_get()
|
||||
* to pick the right button code. */
|
||||
car_emulate_apply_button(subghz, key);
|
||||
|
||||
/* Only update the counter in fff_data; the protocol handles Btn. */
|
||||
car_emulate_update_fff(subghz, s_state->current_counter);
|
||||
|
||||
s_state->is_transmitting = true;
|
||||
s_state->stop_pending = false;
|
||||
s_state->tx_start_tick = (uint32_t)furi_get_tick();
|
||||
|
||||
uint8_t cur_btn = subghz_custom_btn_get();
|
||||
if(!car_emulate_start_tx(subghz, cur_btn)) {
|
||||
s_state->is_transmitting = false;
|
||||
notification_message(subghz->notifications, &sequence_error);
|
||||
}
|
||||
|
||||
car_emulate_refresh_view(subghz);
|
||||
consumed = true;
|
||||
|
||||
/* ── Stop ── */
|
||||
} else if(event.event == SubGhzCustomEventCarEmulateStop) {
|
||||
if(s_state->is_transmitting &&
|
||||
subghz->state_notifications == SubGhzNotificationStateTx) {
|
||||
|
||||
uint32_t elapsed = (uint32_t)furi_get_tick() - s_state->tx_start_tick;
|
||||
if(elapsed >= MIN_TX_TICKS) {
|
||||
car_emulate_stop_tx(subghz);
|
||||
s_state->is_transmitting = false;
|
||||
s_state->stop_pending = false;
|
||||
} else {
|
||||
s_state->stop_pending = true;
|
||||
}
|
||||
}
|
||||
car_emulate_refresh_view(subghz);
|
||||
consumed = true;
|
||||
|
||||
/* ── Exit ── */
|
||||
} else if(event.event == SubGhzCustomEventCarEmulateExit) {
|
||||
if(subghz->state_notifications == SubGhzNotificationStateTx) {
|
||||
car_emulate_stop_tx(subghz);
|
||||
}
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneSavedMenu);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
|
||||
if(s_state->is_transmitting &&
|
||||
subghz->state_notifications == SubGhzNotificationStateTx) {
|
||||
|
||||
/* Check if hardware is done */
|
||||
if(subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) {
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
|
||||
if(s_state->stop_pending) {
|
||||
s_state->is_transmitting = false;
|
||||
s_state->stop_pending = false;
|
||||
notification_message(subghz->notifications, &sequence_blink_stop);
|
||||
}
|
||||
} else {
|
||||
/* Still transmitting – blink LED */
|
||||
notification_message(subghz->notifications, &sequence_blink_magenta_10);
|
||||
}
|
||||
|
||||
/* Enforce MIN_TX_TICKS stop gate */
|
||||
if(s_state->stop_pending) {
|
||||
uint32_t elapsed = (uint32_t)furi_get_tick() - s_state->tx_start_tick;
|
||||
if(elapsed >= MIN_TX_TICKS) {
|
||||
car_emulate_stop_tx(subghz);
|
||||
s_state->is_transmitting = false;
|
||||
s_state->stop_pending = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Refresh view every tick for animation */
|
||||
car_emulate_refresh_view(subghz);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
* Scene on_exit
|
||||
* ═════════════════════════════════════════════════════════════════════════*/
|
||||
void subghz_scene_car_emulate_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
if(subghz->state_notifications == SubGhzNotificationStateTx) {
|
||||
car_emulate_stop_tx(subghz);
|
||||
}
|
||||
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
notification_message(subghz->notifications, &sequence_blink_stop);
|
||||
|
||||
/* Clear view callbacks */
|
||||
subghz_car_emulate_view_set_callback(subghz->car_emulate_view, NULL, NULL);
|
||||
|
||||
/* Free per-session state */
|
||||
if(s_state) {
|
||||
free(s_state);
|
||||
s_state = NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Scene: CarEmulateSettings
|
||||
* Toggle: Custom Emulate Off / On
|
||||
* Selector: TX Power (reuses the same table as Radio Settings)
|
||||
* Both settings are persisted in SubGhzLastSettings.
|
||||
*/
|
||||
#include "../subghz_i.h"
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
#define TAG "SubGhzCarEmulateSettings"
|
||||
|
||||
/* ── Toggle ──────────────────────────────────────────────────────────────── */
|
||||
static const char* const toggle_text[] = {"Off", "On"};
|
||||
|
||||
static void subghz_scene_car_emulate_settings_toggle_changed(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
furi_assert(subghz);
|
||||
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, toggle_text[index]);
|
||||
|
||||
subghz->last_settings->custom_car_emulate = (index == 1);
|
||||
subghz_last_settings_save(subghz->last_settings);
|
||||
}
|
||||
|
||||
/* ── TX Power ────────────────────────────────────────────────────────────── */
|
||||
/* Must match the table in subghz_scene_radio_settings.c exactly */
|
||||
#define CE_TX_POWER_COUNT 9
|
||||
static const char* const ce_tx_power_text[CE_TX_POWER_COUNT] = {
|
||||
"Preset", /* index 0 → use whatever the preset has baked in */
|
||||
"10dBm +",
|
||||
"7dBm",
|
||||
"5dBm",
|
||||
"0dBm",
|
||||
"-10dBm",
|
||||
"-15dBm",
|
||||
"-20dBm",
|
||||
"-30dBm",
|
||||
};
|
||||
|
||||
static void subghz_scene_car_emulate_settings_power_changed(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
furi_assert(subghz);
|
||||
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, ce_tx_power_text[index]);
|
||||
|
||||
/* Mirror the same fields that Radio Settings touches so the value is
|
||||
* visible everywhere and survives app restart. */
|
||||
subghz->tx_power = index;
|
||||
subghz->last_settings->tx_power = index;
|
||||
subghz_last_settings_save(subghz->last_settings);
|
||||
|
||||
/* Patch the live preset buffer immediately so any subsequent TX in this
|
||||
* session uses the new power without needing a restart. */
|
||||
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
|
||||
if(preset.data && preset.data_size > 0) {
|
||||
subghz_txrx_set_tx_power(preset.data, preset.data_size, index);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Scene callbacks ─────────────────────────────────────────────────────── */
|
||||
void subghz_scene_car_emulate_settings_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
furi_assert(subghz);
|
||||
|
||||
VariableItemList* list = subghz->variable_item_list;
|
||||
variable_item_list_reset(list);
|
||||
|
||||
/* ── Row 1: Custom Emulate toggle ── */
|
||||
VariableItem* item = variable_item_list_add(
|
||||
list,
|
||||
"Custom Emulate",
|
||||
2,
|
||||
subghz_scene_car_emulate_settings_toggle_changed,
|
||||
subghz);
|
||||
|
||||
uint8_t toggle_idx = subghz->last_settings->custom_car_emulate ? 1 : 0;
|
||||
variable_item_set_current_value_index(item, toggle_idx);
|
||||
variable_item_set_current_value_text(item, toggle_text[toggle_idx]);
|
||||
|
||||
/* ── Row 2: TX Power ── */
|
||||
item = variable_item_list_add(
|
||||
list,
|
||||
"TX Power",
|
||||
CE_TX_POWER_COUNT,
|
||||
subghz_scene_car_emulate_settings_power_changed,
|
||||
subghz);
|
||||
|
||||
/* Clamp stored value to valid range in case settings file is corrupt */
|
||||
uint8_t power_idx = subghz->tx_power;
|
||||
if(power_idx >= CE_TX_POWER_COUNT) power_idx = 0;
|
||||
|
||||
variable_item_set_current_value_index(item, power_idx);
|
||||
variable_item_set_current_value_text(item, ce_tx_power_text[power_idx]);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
|
||||
}
|
||||
|
||||
bool subghz_scene_car_emulate_settings_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void subghz_scene_car_emulate_settings_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
variable_item_list_reset(subghz->variable_item_list);
|
||||
}
|
||||
@@ -34,3 +34,5 @@ ADD_SCENE(subghz, keeloq_decrypt, KeeloqDecrypt)
|
||||
ADD_SCENE(subghz, keeloq_bf2, KeeloqBf2)
|
||||
ADD_SCENE(subghz, kl_bf_cleanup, KlBfCleanup)
|
||||
ADD_SCENE(subghz, counter_bf, CounterBf)
|
||||
ADD_SCENE(subghz, car_emulate, CarEmulate)
|
||||
ADD_SCENE(subghz, car_emulate_settings, CarEmulateSettings)
|
||||
|
||||
@@ -1,53 +1,135 @@
|
||||
#include "../subghz_i.h"
|
||||
#include <lib/subghz/subghz_protocol_registry.h>
|
||||
|
||||
void subghz_scene_protocol_list_submenu_callback(void* context, uint32_t index) {
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, index);
|
||||
}
|
||||
#define TAG "SubGhzSceneProtocolList"
|
||||
|
||||
void subghz_scene_protocol_list_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
/* ── helpers ──────────────────────────────────────────────────────────────── */
|
||||
|
||||
submenu_reset(subghz->submenu);
|
||||
|
||||
size_t protocol_count = subghz_protocol_registry_count(&subghz_protocol_registry);
|
||||
|
||||
char header_str[32];
|
||||
snprintf(header_str, sizeof(header_str), "Protocols: %zu", protocol_count);
|
||||
submenu_set_header(subghz->submenu, header_str);
|
||||
|
||||
for(size_t i = 0; i < protocol_count; i++) {
|
||||
const SubGhzProtocol* protocol =
|
||||
subghz_protocol_registry_get_by_index(&subghz_protocol_registry, i);
|
||||
if(protocol) {
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
protocol->name,
|
||||
i,
|
||||
subghz_scene_protocol_list_submenu_callback,
|
||||
subghz);
|
||||
}
|
||||
}
|
||||
|
||||
submenu_set_selected_item(
|
||||
subghz->submenu,
|
||||
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneProtocolList));
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu);
|
||||
}
|
||||
|
||||
bool subghz_scene_protocol_list_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneProtocolList, event.event);
|
||||
return true;
|
||||
static bool proto_filter_contains(const char* filter, const char* name) {
|
||||
const char* p = filter;
|
||||
while(*p) {
|
||||
const char* comma = strchr(p, ',');
|
||||
size_t len = comma ? (size_t)(comma - p) : strlen(p);
|
||||
if(len == strlen(name) && strncmp(p, name, len) == 0) return true;
|
||||
if(!comma) break;
|
||||
p = comma + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void proto_filter_toggle(char* filter, size_t filter_size, const char* name) {
|
||||
if(proto_filter_contains(filter, name)) {
|
||||
/* remove it */
|
||||
char tmp[256] = {0};
|
||||
const char* p = filter;
|
||||
bool first = true;
|
||||
while(*p) {
|
||||
const char* comma = strchr(p, ',');
|
||||
size_t len = comma ? (size_t)(comma - p) : strlen(p);
|
||||
if(!(len == strlen(name) && strncmp(p, name, len) == 0)) {
|
||||
if(!first) strncat(tmp, ",", sizeof(tmp) - strlen(tmp) - 1);
|
||||
strncat(tmp, p, len < sizeof(tmp) - strlen(tmp) - 1 ? len : 0);
|
||||
first = false;
|
||||
}
|
||||
if(!comma) break;
|
||||
p = comma + 1;
|
||||
}
|
||||
strncpy(filter, tmp, filter_size - 1);
|
||||
filter[filter_size - 1] = '\0';
|
||||
} else {
|
||||
/* add it */
|
||||
if(filter[0] != '\0') strncat(filter, ",", filter_size - strlen(filter) - 1);
|
||||
strncat(filter, name, filter_size - strlen(filter) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── callbacks ────────────────────────────────────────────────────────────── */
|
||||
|
||||
static void subghz_scene_protocol_list_item_changed(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t value_index = variable_item_get_current_value_index(item);
|
||||
|
||||
uint32_t proto_idx =
|
||||
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneProtocolList);
|
||||
size_t selected =
|
||||
variable_item_list_get_selected_item_index(subghz->variable_item_list);
|
||||
UNUSED(proto_idx);
|
||||
|
||||
const SubGhzProtocol* protocol =
|
||||
subghz_protocol_registry_get_by_index(&subghz_protocol_registry, selected);
|
||||
if(!protocol) return;
|
||||
|
||||
const char* name = protocol->name;
|
||||
|
||||
bool currently_in =
|
||||
proto_filter_contains(subghz->last_settings->protocol_filter, name);
|
||||
|
||||
if((value_index == 1) != currently_in) {
|
||||
proto_filter_toggle(
|
||||
subghz->last_settings->protocol_filter,
|
||||
sizeof(subghz->last_settings->protocol_filter),
|
||||
name);
|
||||
}
|
||||
|
||||
variable_item_set_current_value_text(item, value_index ? "ONLY" : "---");
|
||||
subghz_last_settings_save(subghz->last_settings);
|
||||
}
|
||||
|
||||
/* ── scene callbacks ──────────────────────────────────────────────────────── */
|
||||
|
||||
void subghz_scene_protocol_list_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
VariableItemList* list = subghz->variable_item_list;
|
||||
variable_item_list_reset(list);
|
||||
|
||||
size_t protocol_count = subghz_protocol_registry_count(&subghz_protocol_registry);
|
||||
|
||||
for(size_t i = 0; i < protocol_count; i++) {
|
||||
const SubGhzProtocol* protocol =
|
||||
subghz_protocol_registry_get_by_index(&subghz_protocol_registry, i);
|
||||
if(!protocol) continue;
|
||||
|
||||
VariableItem* item = variable_item_list_add(
|
||||
list,
|
||||
protocol->name,
|
||||
2,
|
||||
subghz_scene_protocol_list_item_changed,
|
||||
subghz);
|
||||
|
||||
bool enabled = proto_filter_contains(
|
||||
subghz->last_settings->protocol_filter, protocol->name);
|
||||
variable_item_set_current_value_index(item, enabled ? 1 : 0);
|
||||
variable_item_set_current_value_text(item, enabled ? "ONLY" : "---");
|
||||
}
|
||||
|
||||
variable_item_list_set_selected_item(
|
||||
list,
|
||||
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneProtocolList));
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
|
||||
}
|
||||
|
||||
bool subghz_scene_protocol_list_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneProtocolList, event.event);
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_previous_scene(subghz->scene_manager);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subghz_scene_protocol_list_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
submenu_reset(subghz->submenu);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager,
|
||||
SubGhzSceneProtocolList,
|
||||
variable_item_list_get_selected_item_index(subghz->variable_item_list));
|
||||
variable_item_list_reset(subghz->variable_item_list);
|
||||
}
|
||||
|
||||
@@ -105,6 +105,29 @@ static void subghz_scene_add_to_history_callback(
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// The check can be moved to /lib/subghz/receiver.c, but may result in false positives
|
||||
/* Protocol name allowlist filter — if non-empty, drop anything not in the list */
|
||||
if(subghz->last_settings->protocol_filter[0] != '\0') {
|
||||
const char* proto_name = decoder_base->protocol->name;
|
||||
const char* filter = subghz->last_settings->protocol_filter;
|
||||
bool allowed = false;
|
||||
/* Walk the comma-separated list */
|
||||
const char* p = filter;
|
||||
while(*p) {
|
||||
const char* comma = strchr(p, ',');
|
||||
size_t len = comma ? (size_t)(comma - p) : strlen(p);
|
||||
if(len == strlen(proto_name) && strncmp(p, proto_name, len) == 0) {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
if(!comma) break;
|
||||
p = comma + 1;
|
||||
}
|
||||
if(!allowed) {
|
||||
FURI_LOG_D(TAG, "%s filtered by allowlist", proto_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if((decoder_base->protocol->flag & subghz->ignore_filter) == 0) {
|
||||
SubGhzHistory* history = subghz->history;
|
||||
FuriString* item_name = furi_string_alloc();
|
||||
|
||||
@@ -17,6 +17,7 @@ enum SubGhzSettingIndex {
|
||||
SubGhzSettingIndexIgnoreNiceFlorS,
|
||||
SubGhzSettingIndexDeleteOldSignals,
|
||||
SubGhzSettingIndexSound,
|
||||
SubGhzSettingIndexProtoFilter,
|
||||
SubGhzSettingIndexResetToDefault,
|
||||
SubGhzSettingIndexLock,
|
||||
SubGhzSettingIndexRAWThresholdRSSI,
|
||||
@@ -445,7 +446,9 @@ static void subghz_scene_receiver_config_set_delete_old_signals(VariableItem* it
|
||||
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
if(index == SubGhzSettingIndexLock) {
|
||||
if(index == SubGhzSettingIndexProtoFilter) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneProtocolList);
|
||||
} else if(index == SubGhzSettingIndexLock) {
|
||||
view_dispatcher_send_custom_event(
|
||||
subghz->view_dispatcher, SubGhzCustomEventSceneSettingLock);
|
||||
} else if(index == SubGhzSettingIndexResetToDefault) {
|
||||
@@ -473,6 +476,7 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context,
|
||||
subghz->last_settings->filter = subghz->filter;
|
||||
subghz->last_settings->delete_old_signals = false;
|
||||
subghz->last_settings->tx_power = subghz->tx_power = 0;
|
||||
subghz->last_settings->protocol_filter[0] = '\0';
|
||||
subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[default_index]);
|
||||
|
||||
subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[default_index]);
|
||||
@@ -668,6 +672,25 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
SubGhzCustomEventManagerSet) {
|
||||
/* Protocol filter */
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Proto Filter",
|
||||
1,
|
||||
NULL,
|
||||
subghz);
|
||||
if(subghz->last_settings->protocol_filter[0] == '\0') {
|
||||
variable_item_set_current_value_text(item, "All");
|
||||
} else {
|
||||
uint8_t count = 1;
|
||||
for(const char* p = subghz->last_settings->protocol_filter; *p; p++) {
|
||||
if(*p == ',') count++;
|
||||
}
|
||||
static char filter_count_str[8];
|
||||
snprintf(filter_count_str, sizeof(filter_count_str), "%u set", count);
|
||||
variable_item_set_current_value_text(item, filter_count_str);
|
||||
}
|
||||
|
||||
// Reset to default
|
||||
variable_item_list_add(subghz->variable_item_list, "Reset to default", 1, NULL, NULL);
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ enum SubmenuIndex {
|
||||
SubmenuIndexEdit,
|
||||
SubmenuIndexDelete,
|
||||
SubmenuIndexSignalSettings,
|
||||
SubmenuIndexCounterBf
|
||||
SubmenuIndexCounterBf, /* <-- comma was missing here */
|
||||
SubmenuIndexCarEmulateSettings,
|
||||
};
|
||||
|
||||
void subghz_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
|
||||
@@ -77,6 +78,13 @@ void subghz_scene_saved_menu_on_enter(void* context) {
|
||||
subghz_scene_saved_menu_submenu_callback,
|
||||
subghz);
|
||||
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Custom Emulate Settings",
|
||||
SubmenuIndexCarEmulateSettings,
|
||||
subghz_scene_saved_menu_submenu_callback,
|
||||
subghz);
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
@@ -109,7 +117,22 @@ bool subghz_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.event == SubmenuIndexEmulate) {
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneSavedMenu, SubmenuIndexEmulate);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter);
|
||||
|
||||
bool use_custom = subghz->last_settings->custom_car_emulate;
|
||||
if(use_custom) {
|
||||
FlipperFormat* fff = subghz_txrx_get_fff_data(subghz->txrx);
|
||||
uint32_t cnt_tmp = 0;
|
||||
flipper_format_rewind(fff);
|
||||
if(!flipper_format_read_uint32(fff, "Cnt", &cnt_tmp, 1)) {
|
||||
use_custom = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(use_custom) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneCarEmulate);
|
||||
} else {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter);
|
||||
}
|
||||
return true;
|
||||
} else if(event.event == SubmenuIndexPsaDecrypt) {
|
||||
scene_manager_set_scene_state(
|
||||
@@ -136,6 +159,14 @@ bool subghz_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->scene_manager, SubGhzSceneSavedMenu, SubmenuIndexCounterBf);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneCounterBf);
|
||||
return true;
|
||||
} else if(event.event == SubmenuIndexCarEmulateSettings) {
|
||||
/* <-- was outside the if block due to misplaced brace, now fixed */
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager,
|
||||
SubGhzSceneSavedMenu,
|
||||
SubmenuIndexCarEmulateSettings);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneCarEmulateSettings);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -206,6 +206,12 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
|
||||
SubGhzViewIdKeeloqDecrypt,
|
||||
subghz_view_keeloq_decrypt_get_view(subghz->subghz_keeloq_decrypt));
|
||||
|
||||
subghz->car_emulate_view = subghz_car_emulate_view_alloc();
|
||||
view_dispatcher_add_view(
|
||||
subghz->view_dispatcher,
|
||||
SubGhzViewIdCarEmulate,
|
||||
subghz_car_emulate_view_get_view(subghz->car_emulate_view));
|
||||
|
||||
//init threshold rssi
|
||||
subghz->threshold_rssi = subghz_threshold_rssi_alloc();
|
||||
|
||||
@@ -321,6 +327,10 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) {
|
||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdKeeloqDecrypt);
|
||||
subghz_view_keeloq_decrypt_free(subghz->subghz_keeloq_decrypt);
|
||||
|
||||
// Custom car-emulate view
|
||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdCarEmulate);
|
||||
subghz_car_emulate_view_free(subghz->car_emulate_view);
|
||||
|
||||
// Read RAW
|
||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
|
||||
subghz_read_raw_free(subghz->subghz_read_raw);
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
#include "helpers/subghz_txrx.h"
|
||||
#include "helpers/subghz_keeloq_keys.h"
|
||||
|
||||
#include "views/subghz_car_emulate.h"
|
||||
|
||||
#define SUBGHZ_MAX_LEN_NAME 64
|
||||
#define SUBGHZ_EXT_PRESET_NAME true
|
||||
#define SUBGHZ_RAW_THRESHOLD_MIN (-90.0f)
|
||||
@@ -76,6 +78,7 @@ struct SubGhz {
|
||||
SubGhzReadRAW* subghz_read_raw;
|
||||
SubGhzViewPsaDecrypt* subghz_psa_decrypt;
|
||||
SubGhzViewKeeloqDecrypt* subghz_keeloq_decrypt;
|
||||
SubGhzCarEmulateView* car_emulate_view;
|
||||
bool raw_send_only;
|
||||
|
||||
bool save_datetime_set;
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD "HoppingThreshold"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_LED_AND_POWER_AMP "LedAndPowerAmp"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_TX_POWER "TXPower"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_CUSTOM_CAR_EMULATE "CustomCarEmulate"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILTER "ProtocolFilter"
|
||||
|
||||
SubGhzLastSettings* subghz_last_settings_alloc(void) {
|
||||
SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings));
|
||||
@@ -50,6 +52,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
||||
instance->enable_preset_hopping = false;
|
||||
instance->preset_hopping_threshold = SUBGHZ_LAST_SETTING_DEFAULT_PRESET_HOPPING_THRESHOLD;
|
||||
instance->leds_and_amp = true;
|
||||
instance->protocol_filter[0] = '\0';
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
@@ -163,6 +166,27 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
||||
1)) {
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
if(!flipper_format_read_bool(
|
||||
fff_data_file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_CUSTOM_CAR_EMULATE,
|
||||
&instance->custom_car_emulate,
|
||||
1)) {
|
||||
instance->custom_car_emulate = false;
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
FuriString* filter_str = furi_string_alloc();
|
||||
if(flipper_format_read_string(
|
||||
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILTER, filter_str)) {
|
||||
strncpy(
|
||||
instance->protocol_filter,
|
||||
furi_string_get_cstr(filter_str),
|
||||
sizeof(instance->protocol_filter) - 1);
|
||||
instance->protocol_filter[sizeof(instance->protocol_filter) - 1] = '\0';
|
||||
} else {
|
||||
instance->protocol_filter[0] = '\0';
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
furi_string_free(filter_str);
|
||||
|
||||
} while(0);
|
||||
} else {
|
||||
@@ -281,6 +305,19 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
|
||||
file, SUBGHZ_LAST_SETTING_FIELD_LED_AND_POWER_AMP, &instance->leds_and_amp, 1)) {
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_write_bool(
|
||||
file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_CUSTOM_CAR_EMULATE,
|
||||
&instance->custom_car_emulate,
|
||||
1)) {
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_write_string_cstr(
|
||||
file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILTER,
|
||||
instance->protocol_filter)) {
|
||||
break;
|
||||
}
|
||||
|
||||
saved = true;
|
||||
} while(0);
|
||||
|
||||
@@ -30,6 +30,8 @@ typedef struct {
|
||||
float preset_hopping_threshold;
|
||||
bool leds_and_amp;
|
||||
uint8_t tx_power;
|
||||
bool custom_car_emulate;
|
||||
char protocol_filter[256]; /* comma-separated allowlist, empty = disabled */
|
||||
} SubGhzLastSettings;
|
||||
|
||||
SubGhzLastSettings* subghz_last_settings_alloc(void);
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
#include "subghz_car_emulate.h"
|
||||
#include "../helpers/subghz_custom_event.h"
|
||||
|
||||
#include <gui/elements.h>
|
||||
#include <input/input.h>
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "SubGhzCarEmulateView"
|
||||
|
||||
/* ── Model ──────────────────────────────────────────────────────────────── */
|
||||
typedef struct {
|
||||
char protocol_name[32];
|
||||
uint32_t serial;
|
||||
uint32_t counter;
|
||||
uint32_t original_counter;
|
||||
uint32_t freq;
|
||||
char preset[12];
|
||||
bool is_transmitting;
|
||||
uint8_t anim_frame;
|
||||
char label_ok[12];
|
||||
char label_up[12];
|
||||
char label_down[12];
|
||||
char label_left[12];
|
||||
char label_right[12];
|
||||
} SubGhzCarEmulateViewModel;
|
||||
|
||||
/* ── Handle ─────────────────────────────────────────────────────────────── */
|
||||
struct SubGhzCarEmulateView {
|
||||
View* view;
|
||||
SubGhzCarEmulateViewCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
/* ── Draw ───────────────────────────────────────────────────────────────── */
|
||||
static void subghz_car_emulate_view_draw(Canvas* canvas, void* model_ptr) {
|
||||
SubGhzCarEmulateViewModel* m = model_ptr;
|
||||
|
||||
m->anim_frame = (m->anim_frame + 1) % 8;
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
/* Header bar */
|
||||
canvas_draw_box(canvas, 0, 0, 128, 11);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, m->protocol_name);
|
||||
canvas_invert_color(canvas);
|
||||
|
||||
/* Info row 1: serial + counter */
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
char buf[32];
|
||||
|
||||
if(m->serial <= 0xFFFFFFUL) {
|
||||
snprintf(buf, sizeof(buf), "SN:%06lX", (unsigned long)(m->serial & 0xFFFFFFUL));
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "SN:%08lX", (unsigned long)m->serial);
|
||||
}
|
||||
canvas_draw_str(canvas, 2, 20, buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "CNT:%04lX", (unsigned long)m->counter);
|
||||
canvas_draw_str(canvas, 68, 20, buf);
|
||||
|
||||
if(m->counter > m->original_counter) {
|
||||
snprintf(buf, sizeof(buf), "+%ld", (long)(m->counter - m->original_counter));
|
||||
canvas_draw_str(canvas, 112, 20, buf);
|
||||
}
|
||||
|
||||
/* Info row 2: frequency + preset */
|
||||
snprintf(
|
||||
buf,
|
||||
sizeof(buf),
|
||||
"F:%lu.%02lu",
|
||||
(unsigned long)(m->freq / 1000000UL),
|
||||
(unsigned long)((m->freq % 1000000UL) / 10000UL));
|
||||
canvas_draw_str(canvas, 2, 30, buf);
|
||||
canvas_draw_str(canvas, 95, 30, m->preset);
|
||||
|
||||
/* ── Button labels ── */
|
||||
const uint8_t font_h = canvas_current_font_height(canvas);
|
||||
|
||||
/* Centre → UNLOCK (OK button) */
|
||||
{
|
||||
const char* lbl = m->label_ok;
|
||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||
canvas_draw_rbox(canvas, 64 - w / 2, 45 - font_h / 2, w, font_h, 3);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_str_aligned(canvas, 64, 49, AlignCenter, AlignBottom, lbl);
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
|
||||
/* Up → LOCK */
|
||||
{
|
||||
const char* lbl = m->label_up;
|
||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||
canvas_draw_rbox(canvas, 64 - w / 2, 33 - font_h / 2, w, font_h, 3);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_str_aligned(canvas, 64, 37, AlignCenter, AlignBottom, lbl);
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
|
||||
/* Left → PANIC */
|
||||
{
|
||||
const char* lbl = m->label_left;
|
||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||
canvas_draw_rbox(canvas, 0, 46 - font_h / 2, w, font_h, 3);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_str_aligned(canvas, w / 2, 50, AlignCenter, AlignBottom, lbl);
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
|
||||
/* Right → generic extra */
|
||||
{
|
||||
const char* lbl = m->label_right;
|
||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||
canvas_draw_rbox(canvas, 127 - w, 46 - font_h / 2, w, font_h, 3);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_str_aligned(canvas, 127 - w / 2, 50, AlignCenter, AlignBottom, lbl);
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
|
||||
/* Down → BOOT */
|
||||
{
|
||||
const char* lbl = m->label_down;
|
||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||
canvas_draw_rbox(canvas, 64 - w / 2, 57 - font_h / 2, w, font_h, 3);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_str_aligned(canvas, 64, 61, AlignCenter, AlignBottom, lbl);
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
|
||||
/* TX overlay */
|
||||
if(m->is_transmitting) {
|
||||
canvas_draw_rbox(canvas, 24, 18, 80, 18, 3);
|
||||
canvas_invert_color(canvas);
|
||||
int wave = m->anim_frame % 3;
|
||||
canvas_draw_str(canvas, 28 + wave * 2, 25, ")))");
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignCenter, "TX");
|
||||
canvas_invert_color(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Input ──────────────────────────────────────────────────────────────── */
|
||||
static bool subghz_car_emulate_view_input(InputEvent* event, void* context) {
|
||||
SubGhzCarEmulateView* instance = context;
|
||||
furi_assert(instance);
|
||||
|
||||
if(event->type == InputTypePress) {
|
||||
if(event->key == InputKeyBack) {
|
||||
if(instance->callback) {
|
||||
instance->callback(SubGhzCustomEventCarEmulateExit, instance->context);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Any directional / OK key → start TX */
|
||||
if(instance->callback) {
|
||||
/* Pack the raw InputKey into the upper bits of the event so the
|
||||
scene can read which button was pressed.
|
||||
Lower 16 bits = SubGhzCustomEventCarEmulateTransmit marker,
|
||||
upper 16 bits = InputKey value. */
|
||||
uint32_t ev = ((uint32_t)event->key << 16) |
|
||||
(uint32_t)SubGhzCustomEventCarEmulateTransmit;
|
||||
instance->callback(ev, instance->context);
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
if(event->key != InputKeyBack) {
|
||||
if(instance->callback) {
|
||||
instance->callback(SubGhzCustomEventCarEmulateStop, instance->context);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ── Alloc / Free ───────────────────────────────────────────────────────── */
|
||||
SubGhzCarEmulateView* subghz_car_emulate_view_alloc(void) {
|
||||
SubGhzCarEmulateView* instance = malloc(sizeof(SubGhzCarEmulateView));
|
||||
furi_check(instance);
|
||||
|
||||
instance->view = view_alloc();
|
||||
instance->callback = NULL;
|
||||
instance->context = NULL;
|
||||
|
||||
view_set_context(instance->view, instance);
|
||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubGhzCarEmulateViewModel));
|
||||
view_set_draw_callback(instance->view, subghz_car_emulate_view_draw);
|
||||
view_set_input_callback(instance->view, subghz_car_emulate_view_input);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_car_emulate_view_free(SubGhzCarEmulateView* instance) {
|
||||
furi_check(instance);
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* subghz_car_emulate_view_get_view(SubGhzCarEmulateView* instance) {
|
||||
furi_check(instance);
|
||||
return instance->view;
|
||||
}
|
||||
|
||||
void subghz_car_emulate_view_set_callback(
|
||||
SubGhzCarEmulateView* instance,
|
||||
SubGhzCarEmulateViewCallback callback,
|
||||
void* context) {
|
||||
furi_check(instance);
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
void subghz_car_emulate_view_set_data(
|
||||
SubGhzCarEmulateView* instance,
|
||||
const char* protocol_name,
|
||||
uint32_t serial,
|
||||
uint32_t counter,
|
||||
uint32_t original_counter,
|
||||
uint32_t freq,
|
||||
const char* preset,
|
||||
bool is_transmitting) {
|
||||
furi_check(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
SubGhzCarEmulateViewModel * m,
|
||||
{
|
||||
strncpy(m->protocol_name, protocol_name, sizeof(m->protocol_name) - 1);
|
||||
m->protocol_name[sizeof(m->protocol_name) - 1] = '\0';
|
||||
m->serial = serial;
|
||||
m->counter = counter;
|
||||
m->original_counter = original_counter;
|
||||
m->freq = freq;
|
||||
strncpy(m->preset, preset, sizeof(m->preset) - 1);
|
||||
m->preset[sizeof(m->preset) - 1] = '\0';
|
||||
m->is_transmitting = is_transmitting;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void subghz_car_emulate_view_set_labels(
|
||||
SubGhzCarEmulateView* instance,
|
||||
const char* ok,
|
||||
const char* up,
|
||||
const char* down,
|
||||
const char* left,
|
||||
const char* right) {
|
||||
furi_check(instance);
|
||||
with_view_model(
|
||||
instance->view,
|
||||
SubGhzCarEmulateViewModel * m,
|
||||
{
|
||||
strncpy(m->label_ok, ok ? ok : "", sizeof(m->label_ok) - 1);
|
||||
strncpy(m->label_up, up ? up : "", sizeof(m->label_up) - 1);
|
||||
strncpy(m->label_down, down ? down : "", sizeof(m->label_down) - 1);
|
||||
strncpy(m->label_left, left ? left : "", sizeof(m->label_left) - 1);
|
||||
strncpy(m->label_right, right ? right : "", sizeof(m->label_right) - 1);
|
||||
},
|
||||
true);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct SubGhzCarEmulateView SubGhzCarEmulateView;
|
||||
|
||||
typedef void (*SubGhzCarEmulateViewCallback)(uint32_t event, void* context);
|
||||
|
||||
SubGhzCarEmulateView* subghz_car_emulate_view_alloc(void);
|
||||
void subghz_car_emulate_view_free(SubGhzCarEmulateView* instance);
|
||||
View* subghz_car_emulate_view_get_view(SubGhzCarEmulateView* instance);
|
||||
|
||||
void subghz_car_emulate_view_set_callback(
|
||||
SubGhzCarEmulateView* instance,
|
||||
SubGhzCarEmulateViewCallback callback,
|
||||
void* context);
|
||||
|
||||
/** Update the fields shown on the view.
|
||||
* All strings are copied internally so the caller can free them after the call.
|
||||
*/
|
||||
void subghz_car_emulate_view_set_labels(
|
||||
SubGhzCarEmulateView* instance,
|
||||
const char* ok,
|
||||
const char* up,
|
||||
const char* down,
|
||||
const char* left,
|
||||
const char* right);
|
||||
|
||||
void subghz_car_emulate_view_set_data(
|
||||
SubGhzCarEmulateView* instance,
|
||||
const char* protocol_name,
|
||||
uint32_t serial,
|
||||
uint32_t counter,
|
||||
uint32_t original_counter,
|
||||
uint32_t freq,
|
||||
const char* preset,
|
||||
bool is_transmitting);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to the 24cxxprog EEPROM Programmer application will be documented in this file.
|
||||
|
||||
## [2.0.0] - 2026-03-11
|
||||
|
||||
### 🚀 Major Features Added
|
||||
|
||||
#### Dynamic Memory Support for All 24Cxx Chips
|
||||
- **Full chip type support**: Added complete support for all EEPROM sizes from 24C01 (128B) to 24C512 (64KB)
|
||||
- **Dynamic buffer allocation**: Memory buffers now automatically resize based on selected chip type
|
||||
- **Configurable in Settings**: Users can now select chip type in Settings menu, and all operations adapt automatically
|
||||
|
||||
### ✨ Enhancements
|
||||
|
||||
#### Memory Management
|
||||
- Replaced fixed 256-byte buffers with dynamic allocation:
|
||||
- `memory_data` - dynamically allocated based on chip size
|
||||
- `file_data` - dynamically allocated based on chip size
|
||||
- `verify_buffer` - dynamically allocated based on chip size
|
||||
- Added `get_eeprom_size()` helper function returning size in bytes for each chip type
|
||||
- Added `reallocate_buffers()` function for automatic buffer reallocation on chip type change
|
||||
- Memory size tracked in `memory_size` field (32-bit for chips up to 64KB)
|
||||
|
||||
#### Read/Write/Erase Operations
|
||||
- **Read operation**: Now reads entire EEPROM regardless of size (128B to 64KB)
|
||||
- **Write operation**: Supports writing to full address range of selected chip
|
||||
- **Erase operation**: Clears entire memory of selected chip type
|
||||
- **File operations**: Binary dumps now save/load full chip capacity
|
||||
|
||||
#### User Interface Improvements
|
||||
- Address display format adapts to memory size:
|
||||
- Small chips (≤256B): `0x00` format
|
||||
- Large chips (>256B): `0000` hex format (4 digits)
|
||||
- Progress indicators updated for all memory sizes
|
||||
- Navigation (Up/Down) works across entire address range
|
||||
- File size display shows actual chip capacity
|
||||
|
||||
#### File Naming
|
||||
- Filename generation now includes all chip types:
|
||||
- Examples: `24C01_2026-03-11_10-30.bin`, `24C256_2026-03-11_10-30.bin`
|
||||
- Automatic timestamp-based naming for all chip variants
|
||||
|
||||
### 🔧 Technical Changes
|
||||
|
||||
#### Type Updates
|
||||
- Changed address/size types from `uint8_t` to `uint32_t` for large memory support:
|
||||
- `current_address`: now `uint32_t`
|
||||
- `read_total_bytes`: now `uint32_t`
|
||||
- `write_total_bytes_async`: now `uint32_t`
|
||||
- `verify_total_bytes`: now `uint32_t`
|
||||
- `erase_current_addr`: now `uint32_t`
|
||||
- `progress_value`: now `uint32_t`
|
||||
- `file_size`: now `uint32_t`
|
||||
|
||||
#### Format Specifiers
|
||||
- Updated all `printf`/`snprintf` calls to use correct format for `uint32_t`:
|
||||
- Changed `%d` to `%lu` for unsigned long
|
||||
- Changed `%X` to `%lX` for hex unsigned long
|
||||
|
||||
#### Memory Safety
|
||||
- Added proper memory initialization in `reallocate_buffers()`
|
||||
- Added null pointer checks for all dynamically allocated buffers
|
||||
- Proper cleanup in `eeprom_app_free()` - all buffers freed correctly
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
- Fixed buffer overflow risk in memory operations for larger chips
|
||||
- Fixed format specifier warnings causing compilation errors
|
||||
- Fixed address boundary checking for chips larger than 256 bytes
|
||||
- Fixed progress bar calculations for larger memory sizes
|
||||
|
||||
### 🔄 Behavioral Changes
|
||||
- Settings → Chip Type now immediately reallocates buffers
|
||||
- Current address is reset to 0 if it exceeds new chip size after type change
|
||||
- File load operation respects maximum chip capacity (won't load more than chip can hold)
|
||||
|
||||
### 📋 Supported Chip Types
|
||||
|
||||
Complete support matrix:
|
||||
| Chip Type | Size | Status |
|
||||
|-----------|------|--------|
|
||||
| 24C01 | 128 bytes | ✅ Full Support |
|
||||
| 24C02 | 256 bytes | ✅ Full Support |
|
||||
| 24C04 | 512 bytes | ✅ Full Support |
|
||||
| 24C08 | 1 KB | ✅ Full Support |
|
||||
| 24C16 | 2 KB | ✅ Full Support |
|
||||
| 24C32 | 4 KB | ✅ Full Support |
|
||||
| 24C64 | 8 KB | ✅ Full Support |
|
||||
| 24C128 | 16 KB | ✅ Full Support |
|
||||
| 24C256 | 32 KB | ✅ Full Support |
|
||||
| 24C512 | 64 KB | ✅ Full Support |
|
||||
|
||||
### ⚠️ Breaking Changes
|
||||
- Binary dump files from previous versions (always 256 bytes) are incompatible with chip-specific sizes
|
||||
- Users should re-read and save new dumps after upgrading
|
||||
|
||||
---
|
||||
|
||||
## [1.0.0] - Previous Version
|
||||
|
||||
### Initial Release
|
||||
- Basic read/write/erase operations
|
||||
- Fixed 256-byte buffer (24C02 only)
|
||||
- I2C address configuration
|
||||
- File load/save operations
|
||||
- Basic hex viewer
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Dr.Mosfet
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,222 @@
|
||||
# 🔧 24cxxprog - EEPROM 24Cxx Programmer
|
||||
|
||||
<h2 align="center">A Comprehensive EEPROM Programmer for Flipper Zero</h2>
|
||||
|
||||
<div align="center">
|
||||
<table style="width:100%; border:none;">
|
||||
<tr style="border:none;">
|
||||
<td style="border:none; padding:10px;">
|
||||
<img src="screenshots/1.png" alt="Main Menu - Operations" style="width:100%;">
|
||||
<br>
|
||||
<em>Menu główne z operacjami (Odczyt, Zapis, Kasowanie)</em>
|
||||
</td>
|
||||
<td style="border:none; padding:10px;">
|
||||
<img src="screenshots/2.png" alt="Configuration Menu" style="width:100%;">
|
||||
<br>
|
||||
<em>Menu konfiguracji (Adres I2C, Rozmiar pamięci)</em>
|
||||
</td>
|
||||
<td style="border:none; padding:10px;">
|
||||
<img src="screenshots/3.png" alt="Data Display - EEPROM Contents" style="width:100%;">
|
||||
<br>
|
||||
<em>Wyświetlanie zawartości EEPROM (Dane heksadecymalne)</em>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
This is a **comprehensive EEPROM programmer application** designed for the **Flipper Zero** that interfaces with the **24Cxx series I2C memory chips**. The application provides a complete suite of tools for reading, writing, erasing, and managing EEPROM memory with a user-friendly interface on the Flipper's screen.
|
||||
|
||||
## ✨ Features Overview
|
||||
|
||||
### 📝 EEPROM Operations
|
||||
|
||||
Complete toolset for memory management:
|
||||
|
||||
* **Read Operations:** View complete EEPROM contents with address and hexadecimal data display.
|
||||
* **Write Operations:** Program custom data into specific memory addresses.
|
||||
* **Erase Functions:** Clear individual bytes, pages, or entire memory sections.
|
||||
* **Dump to Storage:** Export EEPROM contents to Flipper SD card for backup and analysis.
|
||||
* **Restore from Backup:** Load previously saved EEPROM data back into the chip.
|
||||
|
||||
### 🎨 User Interface & Experience
|
||||
|
||||
Intuitive interface optimized for Flipper Zero's display:
|
||||
|
||||
* **Main Menu:** Clear operation selection with visual feedback.
|
||||
* **Data Viewer:** Scrollable hex display showing actual EEPROM contents.
|
||||
* **Configuration Menu:** Easy access to sensor parameters and device settings.
|
||||
* **Address Navigation:** Precise control over memory location selection.
|
||||
* **Progress Indicator:** Real-time feedback during long operations.
|
||||
|
||||
### ⚙️ Configuration Options
|
||||
|
||||
Customize the programmer for your specific hardware:
|
||||
|
||||
* **I2C Address Selection:** Choose between multiple I2C addresses (**0x50-0x57**) for different chip variants.
|
||||
* **Memory Size Selection:** Automatically detect or manually set chip capacity (**1KB to 64KB** and larger).
|
||||
* **Page Size Configuration:** Adapt to different chip architectures (**8 bytes to 256 bytes per page**).
|
||||
* **Persistent Settings:** Configurations are automatically saved for quick access.
|
||||
|
||||
### 💻 Technical Features & Robustness
|
||||
|
||||
Built for reliability on the Flipper Zero platform:
|
||||
|
||||
* **I2C Protocol Support:** Robust communication with error checking.
|
||||
* **Address Validation:** Prevents out-of-bounds memory access.
|
||||
* **Timeout Protection:** Safeguards against communication errors.
|
||||
* **Error Handling:** Comprehensive error messages for troubleshooting.
|
||||
* **Non-blocking Operations:** Responsive UI that doesn't freeze during I2C transactions.
|
||||
* **Data Verification:** Verify written data integrity after programming.
|
||||
|
||||
## 🔋 Supported 24Cxx Chips
|
||||
|
||||
Comprehensive support for the entire 24Cxx family:
|
||||
|
||||
<table style="width:100%; border:1px solid #ddd; border-collapse: collapse; text-align: left;">
|
||||
<thead style="background-color: #f8f8f8;">
|
||||
<tr>
|
||||
<th style="padding: 8px; border:1px solid #ddd;">Chip Model</th>
|
||||
<th style="padding: 8px; border:1px solid #ddd;">Memory Size</th>
|
||||
<th style="padding: 8px; border:1px solid #ddd;">Page Size</th>
|
||||
<th style="padding: 8px; border:1px solid #ddd;">Address Range</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>24C01</strong></td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">128 Bytes</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">8 Bytes</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">0x00 - 0x7F</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>24C02</strong></td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">256 Bytes</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">8 Bytes</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">0x00 - 0xFF</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>24C04 - 24C16</strong></td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">512B - 2KB</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">16 Bytes</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">0x00 - 0xFFFF</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>24C32 - 24C64</strong></td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">4KB - 8KB</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">32 Bytes</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">0x0000 - 0x1FFF</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>24C128 - 24C512</strong></td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">16KB - 64KB</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">64 Bytes</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">0x0000 - 0xFFFF</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
---
|
||||
|
||||
## 🕹️ Navigation Guide
|
||||
|
||||
<table style="width:100%; border:1px solid #ddd; border-collapse: collapse; text-align: left;">
|
||||
<thead style="background-color: #f8f8f8;">
|
||||
<tr>
|
||||
<th style="padding: 8px; border:1px solid #ddd;">Screen</th>
|
||||
<th style="padding: 8px; border:1px solid #ddd;">D-Pad Up/Down</th>
|
||||
<th style="padding: 8px; border:1px solid #ddd;">D-Pad Left/Right</th>
|
||||
<th style="padding: 8px; border:1px solid #ddd;">OK Button</th>
|
||||
<th style="padding: 8px; border:1px solid #ddd;">Back Button</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>Main Menu</strong></td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Browse operations (Read, Write, Erase, Dump, Restore)</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">-</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Select operation</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>Exit</strong> application</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>Read/Write</strong></td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Navigate through addresses</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Adjust byte values (Write mode)</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Confirm operation</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Return to Main Menu</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>Configuration</strong></td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Navigate between settings</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Adjust parameter values</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Apply settings</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Cancel and return</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border:1px solid #ddd;"><strong>Data View</strong></td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Scroll data up/down</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Jump to address</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Show hex/ASCII toggle</td>
|
||||
<td style="padding: 8px; border:1px solid #ddd;">Exit data view</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## 🔌 Hardware Connections
|
||||
|
||||
Standard I2C pinout for Flipper Zero GPIO:
|
||||
|
||||
```
|
||||
24Cxx EEPROM Module Flipper Zero GPIO
|
||||
───────────────── ─────────────────
|
||||
SDA (Pin 5) ───→ GPIO_SDA (Pin 16)
|
||||
SCL (Pin 6) ───→ GPIO_SCL (Pin 15)
|
||||
GND (Pin 4) ───→ GND (Pin 8)
|
||||
VCC (Pin 8) ───→ 3.3V (Pin 9)
|
||||
|
||||
Optional Pull-ups: 4.7kΩ from SDA and SCL to 3.3V
|
||||
```
|
||||
|
||||
## 📋 Operation Details
|
||||
|
||||
### Read
|
||||
- Displays EEPROM contents in hexadecimal format
|
||||
- Shows address, data bytes, and ASCII representation
|
||||
- Scrollable for chips larger than display capacity
|
||||
|
||||
### Write
|
||||
- Enter target address and data values
|
||||
- Supports single byte or page programming
|
||||
- Automatic write cycle delay handling
|
||||
|
||||
### Erase
|
||||
- Clear individual bytes to 0xFF
|
||||
- Erase entire pages
|
||||
- Full chip erase with confirmation
|
||||
|
||||
### Dump
|
||||
- Export EEPROM to **`/ext/apps_data/24cxxprog/`** directory
|
||||
- Creates timestamped backup files
|
||||
- Preserves complete memory state
|
||||
|
||||
### Restore
|
||||
- Load previously dumped EEPROM data
|
||||
- Verify before writing
|
||||
- Restore to specified starting address
|
||||
|
||||
---
|
||||
|
||||
## 👨💻 Developer
|
||||
|
||||
This application was created by **Dr. Mosfet** for the Flipper Zero community.
|
||||
|
||||
**Repository:** [kamylwnb/24cxxprog](https://github.com/kamylwnb/24cxxprog)
|
||||
|
||||
**Version:** 1.0
|
||||
**Category:** GPIO / Tools
|
||||
**Platform:** Flipper Zero F7
|
||||
|
||||
---
|
||||
|
||||
**Happy EEPROM programming! 🔧**
|
||||
@@ -0,0 +1,22 @@
|
||||
App(
|
||||
appid="24cxxprog",
|
||||
name="24Cxx Programmer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="eeprom_app_24cxx",
|
||||
cdefines=["APP_24CXXPROG"],
|
||||
requires=[
|
||||
"gui",
|
||||
"i2c",
|
||||
],
|
||||
sources=[
|
||||
"i2c_24c02_app.cpp",
|
||||
"i2c_24c02.cpp",
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
order=21,
|
||||
fap_icon="icons/ikon.png",
|
||||
fap_category="GPIO",
|
||||
fap_author="@Dr.Mosfet",
|
||||
fap_version="2.0",
|
||||
fap_description="EEPROM 24Cxx programmer via I2C with read, write, erase and dump/restore options.",
|
||||
)
|
||||
@@ -0,0 +1,212 @@
|
||||
#include "i2c_24c02.hpp"
|
||||
#include "furi_hal_i2c.h"
|
||||
#include <furi.h>
|
||||
|
||||
EEPROM24C02::EEPROM24C02(uint8_t i2c_address_7bit)
|
||||
: _i2c_addr_8bit(i2c_address_7bit << 1) {
|
||||
}
|
||||
|
||||
bool EEPROM24C02::init() {
|
||||
// Just check if device is responding
|
||||
return isAvailable();
|
||||
}
|
||||
|
||||
bool EEPROM24C02::isAvailable() {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
|
||||
|
||||
// Try to read a dummy byte to check if device responds
|
||||
uint8_t dummy_data;
|
||||
bool success = furi_hal_i2c_rx(
|
||||
&furi_hal_i2c_handle_external, _i2c_addr_8bit, &dummy_data, 1, EEPROM_I2C_TIMEOUT);
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool EEPROM24C02::readByte(uint8_t memory_addr, uint8_t& data) {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
|
||||
|
||||
// Send memory address first
|
||||
bool success_tx = furi_hal_i2c_tx_ext(
|
||||
&furi_hal_i2c_handle_external,
|
||||
_i2c_addr_8bit,
|
||||
false,
|
||||
&memory_addr,
|
||||
1,
|
||||
FuriHalI2cBeginStart,
|
||||
FuriHalI2cEndAwaitRestart,
|
||||
EEPROM_I2C_TIMEOUT);
|
||||
|
||||
// Read the data
|
||||
bool success_rx = false;
|
||||
if(success_tx) {
|
||||
success_rx = furi_hal_i2c_rx_ext(
|
||||
&furi_hal_i2c_handle_external,
|
||||
_i2c_addr_8bit,
|
||||
false,
|
||||
&data,
|
||||
1,
|
||||
FuriHalI2cBeginRestart,
|
||||
FuriHalI2cEndStop,
|
||||
EEPROM_I2C_TIMEOUT);
|
||||
}
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
|
||||
|
||||
return success_tx && success_rx;
|
||||
}
|
||||
|
||||
bool EEPROM24C02::writeByte(uint8_t memory_addr, uint8_t data) {
|
||||
uint8_t write_buffer[2];
|
||||
write_buffer[0] = memory_addr;
|
||||
write_buffer[1] = data;
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
|
||||
|
||||
bool success = furi_hal_i2c_tx_ext(
|
||||
&furi_hal_i2c_handle_external,
|
||||
_i2c_addr_8bit,
|
||||
false,
|
||||
write_buffer,
|
||||
2,
|
||||
FuriHalI2cBeginStart,
|
||||
FuriHalI2cEndStop,
|
||||
EEPROM_I2C_TIMEOUT);
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
|
||||
|
||||
if(success) {
|
||||
// Wait for write cycle to complete (typically 5ms for 24C02)
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool EEPROM24C02::readBytes(uint8_t start_addr, uint8_t* buffer, uint8_t length) {
|
||||
if(length == 0 || buffer == nullptr) return false;
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
|
||||
|
||||
// Send start address
|
||||
bool success_tx = furi_hal_i2c_tx_ext(
|
||||
&furi_hal_i2c_handle_external,
|
||||
_i2c_addr_8bit,
|
||||
false,
|
||||
&start_addr,
|
||||
1,
|
||||
FuriHalI2cBeginStart,
|
||||
FuriHalI2cEndAwaitRestart,
|
||||
EEPROM_I2C_TIMEOUT);
|
||||
|
||||
// Sequential read
|
||||
bool success_rx = false;
|
||||
if(success_tx) {
|
||||
success_rx = furi_hal_i2c_rx_ext(
|
||||
&furi_hal_i2c_handle_external,
|
||||
_i2c_addr_8bit,
|
||||
false,
|
||||
buffer,
|
||||
length,
|
||||
FuriHalI2cBeginRestart,
|
||||
FuriHalI2cEndStop,
|
||||
EEPROM_I2C_TIMEOUT);
|
||||
}
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
|
||||
|
||||
return success_tx && success_rx;
|
||||
}
|
||||
|
||||
bool EEPROM24C02::writeBytes(uint8_t start_addr, const uint8_t* buffer, uint8_t length) {
|
||||
if(length == 0 || buffer == nullptr) return false;
|
||||
|
||||
// 24C02 has 8-byte page size - we need to handle page boundaries
|
||||
uint8_t bytes_written = 0;
|
||||
|
||||
while(bytes_written < length) {
|
||||
uint8_t current_addr = start_addr + bytes_written;
|
||||
uint8_t page_offset = current_addr % EEPROM_24C02_PAGE_SIZE;
|
||||
uint8_t bytes_in_page = EEPROM_24C02_PAGE_SIZE - page_offset;
|
||||
uint8_t bytes_to_write =
|
||||
(length - bytes_written < bytes_in_page) ? (length - bytes_written) : bytes_in_page;
|
||||
|
||||
// Prepare write buffer for this page
|
||||
uint8_t write_buffer[EEPROM_24C02_PAGE_SIZE + 1]; // +1 for address
|
||||
write_buffer[0] = start_addr + bytes_written;
|
||||
|
||||
for(uint8_t i = 0; i < bytes_to_write; i++) {
|
||||
write_buffer[i + 1] = buffer[bytes_written + i];
|
||||
}
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
|
||||
|
||||
bool success = furi_hal_i2c_tx_ext(
|
||||
&furi_hal_i2c_handle_external,
|
||||
_i2c_addr_8bit,
|
||||
false,
|
||||
write_buffer,
|
||||
bytes_to_write + 1,
|
||||
FuriHalI2cBeginStart,
|
||||
FuriHalI2cEndStop,
|
||||
EEPROM_I2C_TIMEOUT);
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
|
||||
|
||||
if(!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for write cycle to complete
|
||||
furi_delay_ms(10);
|
||||
|
||||
bytes_written += bytes_to_write;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EEPROM24C02::eraseAll() {
|
||||
// Fill entire memory with 0xFF
|
||||
uint8_t erase_buffer[EEPROM_24C02_PAGE_SIZE];
|
||||
for(uint8_t i = 0; i < EEPROM_24C02_PAGE_SIZE; i++) {
|
||||
erase_buffer[i] = 0xFF;
|
||||
}
|
||||
|
||||
// Erase page by page
|
||||
for(uint8_t page = 0; page < EEPROM_24C02_SIZE / EEPROM_24C02_PAGE_SIZE; page++) {
|
||||
uint8_t start_addr = page * EEPROM_24C02_PAGE_SIZE;
|
||||
if(!writeBytes(start_addr, erase_buffer, EEPROM_24C02_PAGE_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EEPROM24C02::eraseRange(uint8_t start_addr, uint8_t length) {
|
||||
if(length == 0) return false;
|
||||
|
||||
// Check if range goes beyond memory
|
||||
uint16_t end_addr = (uint16_t)start_addr + length;
|
||||
if(end_addr > EEPROM_24C02_SIZE) {
|
||||
length = EEPROM_24C02_SIZE - start_addr;
|
||||
}
|
||||
|
||||
// Fill range with 0xFF
|
||||
uint8_t erase_buffer[EEPROM_24C02_PAGE_SIZE];
|
||||
for(uint8_t i = 0; i < EEPROM_24C02_PAGE_SIZE; i++) {
|
||||
erase_buffer[i] = 0xFF;
|
||||
}
|
||||
|
||||
return writeBytes(start_addr, erase_buffer, length);
|
||||
}
|
||||
|
||||
void EEPROM24C02::setAddress(uint8_t i2c_address_7bit) {
|
||||
_i2c_addr_8bit = i2c_address_7bit << 1;
|
||||
}
|
||||
|
||||
uint8_t EEPROM24C02::getAddress() {
|
||||
return _i2c_addr_8bit >> 1;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// 24C02 EEPROM I2C addresses (7-bit)
|
||||
// Standard addresses: 0x50-0x57 (A0-A2 pins)
|
||||
#define EEPROM_24C02_BASE_ADDR 0x50
|
||||
#define EEPROM_24C02_MAX_ADDR 0x57
|
||||
|
||||
// Memory size for 24C02
|
||||
#define EEPROM_24C02_SIZE 256 // 2KB = 2048 bits = 256 bytes
|
||||
#define EEPROM_24C02_PAGE_SIZE 8 // Page write size
|
||||
|
||||
// I2C operation timeout
|
||||
#define EEPROM_I2C_TIMEOUT 100
|
||||
|
||||
class EEPROM24C02 {
|
||||
private:
|
||||
uint8_t _i2c_addr_8bit;
|
||||
|
||||
public:
|
||||
EEPROM24C02(uint8_t i2c_address_7bit);
|
||||
|
||||
// Initialize communication with EEPROM
|
||||
bool init();
|
||||
|
||||
// Read single byte from address
|
||||
bool readByte(uint8_t memory_addr, uint8_t& data);
|
||||
|
||||
// Write single byte to address
|
||||
bool writeByte(uint8_t memory_addr, uint8_t data);
|
||||
|
||||
// Read multiple bytes (sequential read)
|
||||
bool readBytes(uint8_t start_addr, uint8_t* buffer, uint8_t length);
|
||||
|
||||
// Write multiple bytes (page write)
|
||||
bool writeBytes(uint8_t start_addr, const uint8_t* buffer, uint8_t length);
|
||||
|
||||
// Erase entire memory (fill with 0xFF)
|
||||
bool eraseAll();
|
||||
|
||||
// Erase range of bytes
|
||||
bool eraseRange(uint8_t start_addr, uint8_t length);
|
||||
|
||||
// Check if EEPROM is responding
|
||||
bool isAvailable();
|
||||
|
||||
// Set I2C address
|
||||
void setAddress(uint8_t i2c_address_7bit);
|
||||
|
||||
// Get current I2C address
|
||||
uint8_t getAddress();
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/canvas.h>
|
||||
|
||||
static const uint8_t image_DolphinMafia_0_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0e, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xe0, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xfe, 0x7f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x55,
|
||||
0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xaa, 0x00,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x55, 0x15, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xaa, 0x2a, 0x00, 0x00, 0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x00, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0x2a, 0x00, 0x00, 0x08, 0xff, 0x3f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x55, 0x55, 0x55, 0x00, 0xf8, 0x00, 0xc0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0x2a, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x55, 0x55, 0x55, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0x2a, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x60, 0xd5, 0xff, 0xff, 0x3f, 0x20, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xa0, 0xfa, 0xff, 0xff, 0xff, 0xff, 0x03, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x60, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xe0, 0xff, 0xff, 0xbf, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
|
||||
0xff, 0xff, 0x57, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff,
|
||||
0xff, 0xaa, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x5f,
|
||||
0x15, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xaf, 0x02,
|
||||
0xf8, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x55, 0x01, 0xff,
|
||||
0x1f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x2a, 0xc0, 0x0f, 0xf8,
|
||||
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x5f, 0x15, 0xf0, 0x0f, 0xf8, 0x0f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf8, 0xff, 0xaf, 0x02, 0xf8, 0x0f, 0x1c, 0x0e, 0x1f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xfc, 0xff, 0x57, 0x15, 0xf8, 0x1f, 0x1e, 0xfe, 0x60, 0x00,
|
||||
0x00, 0x00, 0xd6, 0x00, 0x50, 0xfe, 0xff, 0xab, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x80, 0x00, 0x00,
|
||||
0x80, 0x01, 0xc8, 0x4e, 0xfe, 0xff, 0xf5, 0x17, 0xf0, 0xff, 0xcf, 0x00, 0x00, 0x01, 0x00, 0x40,
|
||||
0x00, 0x00, 0x20, 0xff, 0xff, 0xfb, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x60, 0x01, 0x00, 0x20, 0x00,
|
||||
0x00, 0x18, 0xff, 0xff, 0x5d, 0x05, 0xc0, 0xff, 0x03, 0x00, 0x70, 0xe1, 0x07, 0xa0, 0xa3, 0xb0,
|
||||
0x06, 0xff, 0xff, 0xaa, 0x00, 0x80, 0xff, 0x01, 0x00, 0xfc, 0x01, 0x00, 0x60, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0x5d, 0x05, 0xc0, 0x7f, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xfe,
|
||||
0xff, 0xae, 0x00, 0x20, 0x60, 0x00, 0xc0, 0x80, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x9f,
|
||||
0x55, 0x05, 0x10, 0x40, 0x00, 0x30, 0x80, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa,
|
||||
0x00, 0x10, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x05,
|
||||
0x00, 0x00, 0x00, 0x03, 0x40, 0x00, 0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0x00, 0x00,
|
||||
0x02, 0x80, 0x00, 0x20, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x05, 0x00, 0x02,
|
||||
0x60, 0x00, 0x10, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x0c, 0x18,
|
||||
0x00, 0x0c, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x15, 0x00, 0xf0, 0x07, 0x00,
|
||||
0x03, 0xc0, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
|
||||
0x20, 0x16, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x15, 0x00, 0x00, 0x00, 0x30, 0x00, 0x20,
|
||||
0x08, 0x21, 0x00, 0x00, 0x00, 0x00, 0x80, 0xab, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x20, 0x80,
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5d, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x40, 0x80, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0xc0, 0xea, 0x02, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x40, 0x40, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x40, 0x55, 0x57, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x80, 0x40, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0xc0, 0xaa, 0x3a, 0x00, 0x00, 0xfe, 0x05, 0x00, 0x80, 0x40, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0xe0, 0x55, 0xd5, 0x01, 0x00, 0xfc, 0x05, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0xf0, 0xab, 0x0a, 0x1e, 0x00, 0x70, 0x0c, 0x00, 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0xd8,
|
||||
0x57, 0x55, 0xe1, 0x01, 0x00, 0x14, 0x00, 0x80, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0xec, 0xaf,
|
||||
0x0a, 0x00, 0xfe, 0x07, 0x14, 0x00, 0xe0, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x7f, 0x55,
|
||||
0x05, 0x00, 0x18, 0x24, 0x00, 0x10, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0xeb, 0xff, 0x0a, 0x00,
|
||||
0x00, 0x20, 0x22, 0x00, 0x08, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0xf5, 0xff, 0x55, 0x05, 0x00,
|
||||
0x48, 0x22, 0x00, 0x04, 0x04, 0x10, 0x00, 0x00, 0x00, 0x80, 0xfa, 0xff, 0x0f, 0x00, 0x00, 0x8c,
|
||||
0x42, 0x00, 0x06, 0x08, 0x08, 0x00, 0x00, 0x00, 0x40, 0xf5, 0xff, 0x5f, 0x15, 0x00, 0x06, 0x4b,
|
||||
0x80, 0x09, 0x30, 0x04, 0x00, 0x00, 0x00, 0xc0, 0xfa, 0xff, 0xea, 0x00, 0x00, 0x07, 0x52, 0x40,
|
||||
0x10, 0xc0, 0x06, 0x00, 0x00, 0x00, 0x60, 0xf5, 0x7f, 0x55, 0x17, 0x80, 0x0f, 0x72, 0x30, 0x20,
|
||||
0x00, 0x07, 0x00, 0x00, 0x00, 0xb0, 0xfa, 0xbf, 0xaa, 0x38, 0xc0, 0x1f, 0xf4, 0xac, 0x42, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x50, 0xf5, 0x5f, 0x55, 0xd5, 0xe1, 0x3f, 0x74, 0x57, 0x81, 0x01, 0x02,
|
||||
0x00, 0x00, 0x00, 0xa8, 0xfa, 0xaf, 0xaa, 0x80, 0xf3, 0x7f, 0xf8, 0xaa, 0x0a, 0x06, 0x01, 0x00,
|
||||
0x00, 0x00};
|
||||
|
||||
void drawScreen_1(Canvas* canvas) {
|
||||
canvas_set_bitmap_mode(canvas, true);
|
||||
|
||||
// Layer 3
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 86, 22, "24cXX ");
|
||||
|
||||
// Layer 3
|
||||
canvas_draw_str(canvas, 77, 10, "Dr.Mosfet ");
|
||||
|
||||
// Layer 4
|
||||
canvas_draw_str(canvas, 67, 34, "Programmer");
|
||||
|
||||
// DolphinMafia
|
||||
canvas_draw_xbm(canvas, -9, 12, 119, 62, image_DolphinMafia_0_bits);
|
||||
}
|
||||
|
After Width: | Height: | Size: 86 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,325 @@
|
||||
#include <stdio.h>
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
static int matrix[6][7] = {0};
|
||||
static int cursorx = 3;
|
||||
static int cursory = 5;
|
||||
static int player = 1;
|
||||
static int scoreX = 0;
|
||||
static int scoreO = 0;
|
||||
|
||||
typedef struct {
|
||||
FuriMutex* mutex;
|
||||
} FourInRowState;
|
||||
|
||||
void init() {
|
||||
for(size_t i = 0; i < 6; i++) {
|
||||
for(size_t j = 0; j < 7; j++) {
|
||||
matrix[i][j] = 0;
|
||||
}
|
||||
}
|
||||
cursorx = 3;
|
||||
cursory = 5;
|
||||
player = 1;
|
||||
}
|
||||
|
||||
const NotificationSequence end = {
|
||||
&message_vibro_on,
|
||||
|
||||
&message_note_ds4,
|
||||
&message_delay_10,
|
||||
&message_sound_off,
|
||||
&message_delay_10,
|
||||
|
||||
&message_note_ds4,
|
||||
&message_delay_10,
|
||||
&message_sound_off,
|
||||
&message_delay_10,
|
||||
|
||||
&message_note_ds4,
|
||||
&message_delay_10,
|
||||
&message_sound_off,
|
||||
&message_delay_10,
|
||||
|
||||
&message_vibro_off,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void intToStr(int num, char* str) {
|
||||
int i = 0, sign = 0;
|
||||
|
||||
if(num < 0) {
|
||||
num = -num;
|
||||
sign = 1;
|
||||
}
|
||||
|
||||
do {
|
||||
str[i++] = num % 10 + '0';
|
||||
num /= 10;
|
||||
} while(num > 0);
|
||||
|
||||
if(sign) {
|
||||
str[i++] = '-';
|
||||
}
|
||||
|
||||
str[i] = '\0';
|
||||
|
||||
// Reverse the string
|
||||
int j, len = i;
|
||||
char temp;
|
||||
for(j = 0; j < len / 2; j++) {
|
||||
temp = str[j];
|
||||
str[j] = str[len - j - 1];
|
||||
str[len - j - 1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
int next_height(int x) {
|
||||
if(matrix[0][x] != 0) {
|
||||
return -1;
|
||||
}
|
||||
for(size_t y = 1; y < 6; y++) {
|
||||
if(matrix[y][x] != 0) {
|
||||
return y - 1;
|
||||
}
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
int wincheck() {
|
||||
for(size_t y = 0; y <= 2; y++) {
|
||||
for(size_t x = 0; x <= 6; x++) {
|
||||
if(matrix[y][x] != 0 && matrix[y][x] == matrix[y + 1][x] &&
|
||||
matrix[y][x] == matrix[y + 2][x] && matrix[y][x] == matrix[y + 3][x]) {
|
||||
return matrix[y][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t y = 0; y <= 5; y++) {
|
||||
for(size_t x = 0; x <= 3; x++) {
|
||||
if(matrix[y][x] != 0 && matrix[y][x] == matrix[y][x + 1] &&
|
||||
matrix[y][x] == matrix[y][x + 2] && matrix[y][x] == matrix[y][x + 3]) {
|
||||
return matrix[y][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t y = 0; y <= 2; y++) {
|
||||
for(size_t x = 0; x <= 3; x++) {
|
||||
if(matrix[y][x] != 0 && matrix[y][x] == matrix[y + 1][x + 1] &&
|
||||
matrix[y][x] == matrix[y + 2][x + 2] && matrix[y][x] == matrix[y + 3][x + 3]) {
|
||||
return matrix[y][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t y = 3; y <= 5; y++) {
|
||||
for(size_t x = 0; x <= 3; x++) {
|
||||
if(matrix[y][x] != 0 && matrix[y][x] == matrix[y - 1][x + 1] &&
|
||||
matrix[y][x] == matrix[y - 2][x + 2] && matrix[y][x] == matrix[y - 3][x + 3]) {
|
||||
return matrix[y][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool tf = true;
|
||||
for(size_t y = 0; y < 6; y++) {
|
||||
for(size_t x = 0; x < 7; x++) {
|
||||
if(matrix[y][x] == 0) {
|
||||
tf = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(tf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void draw_callback(Canvas* canvas, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
const FourInRowState* fourinrow_state = ctx;
|
||||
|
||||
furi_mutex_acquire(fourinrow_state->mutex, FuriWaitForever);
|
||||
canvas_clear(canvas);
|
||||
|
||||
if(wincheck() != -1) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
if(wincheck() == 0) {
|
||||
canvas_draw_str(canvas, 30, 35, "Draw! O_o");
|
||||
}
|
||||
if(wincheck() == 1) {
|
||||
canvas_draw_str(canvas, 30, 35, "Player X win!");
|
||||
}
|
||||
if(wincheck() == 2) {
|
||||
canvas_draw_str(canvas, 30, 35, "Player O win!");
|
||||
}
|
||||
|
||||
furi_mutex_release(fourinrow_state->mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < 6; i++) {
|
||||
for(size_t j = 0; j < 7; j++) {
|
||||
char el[2];
|
||||
switch(matrix[i][j]) {
|
||||
case 0:
|
||||
strcpy(el, "_\0");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
strcpy(el, "X\0");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
strcpy(el, "O\0");
|
||||
break;
|
||||
}
|
||||
canvas_draw_str(canvas, j * 10 + 10, i * 10 + 10, el);
|
||||
}
|
||||
}
|
||||
canvas_draw_str(canvas, cursorx * 10 + 8, cursory * 10 + 10, "[ ]");
|
||||
|
||||
if(player == 1) {
|
||||
canvas_draw_str(canvas, 80, 10, "Turn: X");
|
||||
}
|
||||
if(player == 2) {
|
||||
canvas_draw_str(canvas, 80, 10, "Turn: O");
|
||||
}
|
||||
char scX[1];
|
||||
intToStr(scoreX, scX);
|
||||
char scO[1];
|
||||
intToStr(scoreO, scO);
|
||||
|
||||
canvas_draw_str(canvas, 80, 20, "X:");
|
||||
canvas_draw_str(canvas, 90, 20, scX);
|
||||
|
||||
canvas_draw_str(canvas, 80, 30, "O:");
|
||||
canvas_draw_str(canvas, 90, 30, scO);
|
||||
|
||||
furi_mutex_release(fourinrow_state->mutex);
|
||||
}
|
||||
|
||||
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||
// Проверяем, что контекст не нулевой
|
||||
furi_assert(ctx);
|
||||
FuriMessageQueue* event_queue = ctx;
|
||||
|
||||
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
|
||||
}
|
||||
|
||||
int32_t four_in_row_app(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
// Текущее событие типа InputEvent
|
||||
InputEvent event;
|
||||
// Очередь событий на 8 элементов размера InputEvent
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
|
||||
|
||||
FourInRowState* fourinrow_state = malloc(sizeof(FourInRowState));
|
||||
|
||||
fourinrow_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); // Alloc Mutex
|
||||
if(!fourinrow_state->mutex) {
|
||||
FURI_LOG_E("4inRow", "cannot create mutex\r\n");
|
||||
furi_message_queue_free(event_queue);
|
||||
free(fourinrow_state);
|
||||
return 255;
|
||||
}
|
||||
|
||||
dolphin_deed(DolphinDeedPluginGameStart);
|
||||
|
||||
// Создаем новый view port
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
// Создаем callback отрисовки, без контекста
|
||||
view_port_draw_callback_set(view_port, draw_callback, fourinrow_state);
|
||||
// Создаем callback нажатий на клавиши, в качестве контекста передаем
|
||||
// нашу очередь сообщений, чтоб запихивать в неё эти события
|
||||
view_port_input_callback_set(view_port, input_callback, event_queue);
|
||||
|
||||
// Создаем GUI приложения
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
// Подключаем view port к GUI в полноэкранном режиме
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message_block(notification, &sequence_display_backlight_enforce_on);
|
||||
|
||||
// Бесконечный цикл обработки очереди событий
|
||||
while(1) {
|
||||
// Выбираем событие из очереди в переменную event (ждем бесконечно долго, если очередь пуста)
|
||||
// и проверяем, что у нас получилось это сделать
|
||||
if(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
|
||||
if((event.type == InputTypePress) && (event.key == InputKeyBack)) {
|
||||
break;
|
||||
}
|
||||
|
||||
furi_mutex_acquire(fourinrow_state->mutex, FuriWaitForever);
|
||||
if(wincheck() != -1) {
|
||||
notification_message(notification, &end);
|
||||
furi_delay_ms(1000);
|
||||
if(wincheck() == 1) {
|
||||
scoreX++;
|
||||
}
|
||||
if(wincheck() == 2) {
|
||||
scoreO++;
|
||||
}
|
||||
init();
|
||||
furi_mutex_release(fourinrow_state->mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(event.type == InputTypePress) {
|
||||
if(event.key == InputKeyOk) {
|
||||
int nh = next_height(cursorx);
|
||||
if(nh != -1) {
|
||||
matrix[nh][cursorx] = player;
|
||||
player = 3 - player;
|
||||
}
|
||||
}
|
||||
if(event.key == InputKeyUp) {
|
||||
//cursory--;
|
||||
}
|
||||
if(event.key == InputKeyDown) {
|
||||
//cursory++;
|
||||
}
|
||||
if(event.key == InputKeyLeft) {
|
||||
if(cursorx > 0) {
|
||||
cursorx--;
|
||||
}
|
||||
}
|
||||
if(event.key == InputKeyRight) {
|
||||
if(cursorx < 6) {
|
||||
cursorx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
furi_mutex_release(fourinrow_state->mutex);
|
||||
}
|
||||
view_port_update(view_port);
|
||||
}
|
||||
|
||||
// Чистим созданные объекты, связанные с интерфейсом
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
furi_record_close(RECORD_GUI);
|
||||
// Clear notification
|
||||
notification_message_block(notification, &sequence_display_backlight_enforce_auto);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
|
||||
furi_mutex_free(fourinrow_state->mutex);
|
||||
|
||||
free(fourinrow_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 200 B |
@@ -0,0 +1 @@
|
||||
Four in row for flipper zero!!
|
||||
@@ -0,0 +1,17 @@
|
||||
App(
|
||||
appid="4inrow",
|
||||
name="4 in row",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="four_in_row_app",
|
||||
requires=[
|
||||
"gui",
|
||||
],
|
||||
stack_size=1 * 1024,
|
||||
order=90,
|
||||
fap_icon="4inrow_10px.png",
|
||||
fap_category="Games",
|
||||
fap_author="leo-need-more-coffee",
|
||||
fap_weburl="https://github.com/leo-need-more-coffee/flipperzero-4inrow",
|
||||
fap_version="1.3",
|
||||
fap_description="4 in row Game",
|
||||
)
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,6 @@
|
||||
# Flipper-DVD-Bounce
|
||||
**simple dvd-bounce application for flipper**
|
||||
|
||||
Y'know how dvd players got that thing that bounces around?
|
||||
|
||||
*This is that*
|
||||
@@ -0,0 +1,15 @@
|
||||
# qv. https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppManifests.md
|
||||
|
||||
App(
|
||||
appid="dvd_bounce",
|
||||
name="DVD Bouncer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="bounce_moment",
|
||||
requires=[
|
||||
"gui",
|
||||
],
|
||||
stack_size=1 * 1024,
|
||||
fap_icon="iconimage.png",
|
||||
fap_category="Games",
|
||||
fap_icon_assets="assets",
|
||||
)
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,142 @@
|
||||
#include <string.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include "dvd_bounce_icons.h"
|
||||
|
||||
//init some variables
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int mode = 0;
|
||||
bool bounce_up = false;
|
||||
bool bounce_right = true;
|
||||
char mode_str[12];
|
||||
|
||||
//the thing to draw to the screen
|
||||
static void app_draw_callback(Canvas* canvas, void* ctx) {
|
||||
UNUSED(ctx);
|
||||
canvas_clear(canvas);
|
||||
|
||||
//draws the ball to positions x and y
|
||||
canvas_draw_icon(canvas, x, y, &I_Ok_btn_pressed_13x13);
|
||||
|
||||
//displays the current mode
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 8, "Mode:");
|
||||
//converts mode int to string
|
||||
itoa(mode, mode_str, 10);
|
||||
canvas_draw_str(canvas, 28, 8, mode_str);
|
||||
switch(mode) {
|
||||
case 1:
|
||||
canvas_draw_str(canvas, 2, 16, "Left/Right");
|
||||
break;
|
||||
case 2:
|
||||
canvas_draw_str(canvas, 2, 16, "Up/Down");
|
||||
break;
|
||||
default:
|
||||
canvas_draw_str(canvas, 2, 16, "Normal");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void app_input_callback(InputEvent* input_event, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
|
||||
FuriMessageQueue* event_queue = ctx;
|
||||
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
|
||||
}
|
||||
|
||||
int32_t bounce_moment(void* p) {
|
||||
UNUSED(p);
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
|
||||
|
||||
// Configure viewport
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, app_draw_callback, view_port);
|
||||
view_port_input_callback_set(view_port, app_input_callback, event_queue);
|
||||
|
||||
// Register viewport in GUI
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
InputEvent event;
|
||||
|
||||
bool running = true;
|
||||
while(running) {
|
||||
if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
|
||||
if((event.type == InputTypePress) || (event.type == InputTypeRepeat)) {
|
||||
//arrows move the ball by 10 in their respective directions
|
||||
switch(event.key) {
|
||||
case InputKeyUp:
|
||||
y += -10;
|
||||
break;
|
||||
|
||||
case InputKeyDown:
|
||||
y += 10;
|
||||
break;
|
||||
|
||||
case InputKeyLeft:
|
||||
x += -10;
|
||||
break;
|
||||
|
||||
case InputKeyRight:
|
||||
x += 10;
|
||||
break;
|
||||
//sets the ball to the middle of the screen and sets the current mode
|
||||
case InputKeyOk:
|
||||
x = 51;
|
||||
y = 19;
|
||||
if(mode == 2) {
|
||||
mode = 0;
|
||||
} else {
|
||||
mode += 1;
|
||||
}
|
||||
break;
|
||||
//exits the program if back is pressed
|
||||
default:
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//bunch of conditionals determining how the ball should move
|
||||
if(x <= 0) {
|
||||
bounce_up = false;
|
||||
}
|
||||
if(x >= 115) {
|
||||
bounce_up = true;
|
||||
}
|
||||
if(y <= 0) {
|
||||
bounce_right = true;
|
||||
}
|
||||
if(y >= 51) {
|
||||
bounce_right = false;
|
||||
}
|
||||
|
||||
if((bounce_up) && (mode != 2)) {
|
||||
x += -1;
|
||||
}
|
||||
if((!bounce_up) && (mode != 2)) {
|
||||
x += 1;
|
||||
}
|
||||
if((bounce_right) && (mode != 1)) {
|
||||
y += 1;
|
||||
}
|
||||
if((!bounce_right) && (mode != 1)) {
|
||||
y += -1;
|
||||
}
|
||||
|
||||
view_port_update(view_port);
|
||||
}
|
||||
//cleanup go brrrrr
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 170 B |
@@ -0,0 +1,52 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Struan Clark
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,58 @@
|
||||
# FlipBIP - BIP32/39/44
|
||||
|
||||
https://github.com/xtruan/FlipBIP
|
||||
|
||||
## Crypto toolkit for Flipper Zero
|
||||
- Using Trezor crypto libs from `core/v2.5.3` release
|
||||
|
||||
## Background
|
||||
|
||||
The goal of this project is to see how much crypto functionality can be brought to the Flipper Zero.
|
||||
|
||||
### Complete
|
||||
|
||||
- Trezor crypto C code ported into `crypto` subfolder
|
||||
- Adapted to use Flipper hardware RNG (see `crypto/rand.c`)
|
||||
- Imports and some C library functions modified for compatibility with FBT
|
||||
- Navigation and UI adapted from FAP Boilerplate app
|
||||
- BIP39 mnemonic generation
|
||||
- 24, 18, or 12 words configured in settings
|
||||
- BIP39 mnemonic to BIP39 seed generation
|
||||
- Hierarchical Deterministic (HD) wallet generation from seed
|
||||
- Generation of offline `m/44'/0'/0'/0` BTC wallet
|
||||
- Generation of offline `m/44'/60'/0'/0` ETH wallet (coded from the $SPORK Castle of ETHDenver 2023!)
|
||||
- Generation of offline `m/44'/3'/0'/0` DOGE wallet
|
||||
- Generation of offline `m/44'/133'/0'/0` ZEC transparent address wallet (by @wh00hw)
|
||||
- Similar features to: https://iancoleman.io/bip39/
|
||||
- Saving wallets to SD card
|
||||
- Wallets are saved to SD card upon creation in `apps_data/flipbip`
|
||||
- NOTE: `apps_data` folder must already exist on SD card!
|
||||
- Saved wallets can be viewed between app runs
|
||||
- Wallets are encrypted with a randomly generated key, and that key is also encrypted
|
||||
- `.flipbip.dat` and `.flipbip.key` files are both required to be in `apps_data/flipbip`
|
||||
- Backups of both these files `.flipbip.dat.bak` and `.flipbip.key.bak` are also maintained
|
||||
- If you want to externally back up your wallet, I recommend copying all these files, and storing the `key` and `dat` files seperately
|
||||
- NOTE: The wallets should be decently tough to crack off of a Flipper, however any Flipper with the app installed can load a wallet in the `apps_data/flipbip` directory if both the `key` and `dat` file are present
|
||||
- BIP39 passphrase support
|
||||
- Configured in settings, not persisted between runs for security
|
||||
- Import your own mnemonic
|
||||
- Lots of typing required but you can now use the wallet with an existing mnemonic you have saved
|
||||
- Useful to convert paper backup to keys and receive addresses without relying on a laptop or phone
|
||||
- Improved receive address generation features
|
||||
- Addresses are now generated at the same time as other pieces of wallet info
|
||||
- This slows down initial wallet load, but makes UI much more responsive
|
||||
- QR code files are now generated for each address and stored in the `apps_data/flipbip` directory
|
||||
- This app is required to view the QR code files: https://github.com/bmatcuk/flipperzero-qrcode
|
||||
- NOTE: This happens during the `View Wallet` step; you must view a wallet after generating/importing a wallet in order to ensure the address QR files are correct
|
||||
- Broke out crypto functionality into its own library using `fap_private_libs` feature
|
||||
|
||||
### Work in Progress
|
||||
|
||||
- More coin types
|
||||
- Support for more custom BIP32 wallet paths
|
||||
|
||||
### (FAR) Future
|
||||
|
||||
- Custom wallet security
|
||||
- User specified password
|
||||
- USB/Bluetooth wallet functionality
|
||||
@@ -0,0 +1,22 @@
|
||||
App(
|
||||
appid="flipbip",
|
||||
name="FlipBIP Crypto Wallet",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="flipbip_app",
|
||||
requires=[
|
||||
"gui",
|
||||
],
|
||||
stack_size=3 * 1024,
|
||||
order=10,
|
||||
fap_icon="flipbip_10px.png",
|
||||
fap_private_libs=[
|
||||
Lib(
|
||||
name="crypto",
|
||||
),
|
||||
],
|
||||
fap_category="Tools",
|
||||
fap_author="Struan Clark (xtruan)",
|
||||
fap_weburl="https://github.com/xtruan/FlipBIP",
|
||||
fap_version=(1, 17),
|
||||
fap_description="Crypto wallet for Flipper",
|
||||
)
|
||||
@@ -0,0 +1,239 @@
|
||||
#include "flipbip.h"
|
||||
#include "helpers/flipbip_file.h"
|
||||
// From: lib/crypto
|
||||
#include <memzero.h>
|
||||
#include <bip39.h>
|
||||
|
||||
#define MNEMONIC_MENU_DEFAULT "Import mnemonic seed"
|
||||
#define MNEMONIC_MENU_SUCCESS "Import seed (success)"
|
||||
#define MNEMONIC_MENU_FAILURE "Import seed (failed!)"
|
||||
|
||||
bool flipbip_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
FlipBip* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
void flipbip_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
FlipBip* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
//leave app if back button pressed
|
||||
bool flipbip_navigation_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
FlipBip* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void text_input_callback(void* context) {
|
||||
furi_assert(context);
|
||||
FlipBip* app = context;
|
||||
bool handled = false;
|
||||
|
||||
// check that there is text in the input
|
||||
if(strlen(app->input_text) > 0) {
|
||||
if(app->input_state == FlipBipTextInputPassphrase) {
|
||||
if(app->passphrase == FlipBipPassphraseOn) {
|
||||
strcpy(app->passphrase_text, app->input_text);
|
||||
}
|
||||
// clear input text
|
||||
memzero(app->input_text, TEXT_BUFFER_SIZE);
|
||||
// reset input state
|
||||
app->input_state = FlipBipTextInputDefault;
|
||||
handled = true;
|
||||
// switch back to settings view
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdSettings);
|
||||
} else if(app->input_state == FlipBipTextInputMnemonic) {
|
||||
if(app->import_from_mnemonic == 1) {
|
||||
strcpy(app->import_mnemonic_text, app->input_text);
|
||||
|
||||
int status = FlipBipStatusSuccess;
|
||||
// Check if the mnemonic is valid
|
||||
if(mnemonic_check(app->import_mnemonic_text) == 0)
|
||||
status = FlipBipStatusMnemonicCheckError; // 13 = mnemonic check error
|
||||
// Save the mnemonic to persistent storage
|
||||
else if(!flipbip_save_file_secure(app->import_mnemonic_text))
|
||||
status = FlipBipStatusSaveError; // 12 = save error
|
||||
|
||||
if(status == FlipBipStatusSuccess) {
|
||||
app->mnemonic_menu_text = MNEMONIC_MENU_SUCCESS;
|
||||
//notification_message(app->notification, &sequence_blink_cyan_100);
|
||||
//flipbip_play_happy_bump(app);
|
||||
} else {
|
||||
app->mnemonic_menu_text = MNEMONIC_MENU_FAILURE;
|
||||
//notification_message(app->notification, &sequence_blink_red_100);
|
||||
//flipbip_play_long_bump(app);
|
||||
}
|
||||
|
||||
memzero(app->import_mnemonic_text, TEXT_BUFFER_SIZE);
|
||||
}
|
||||
// clear input text
|
||||
memzero(app->input_text, TEXT_BUFFER_SIZE);
|
||||
// reset input state
|
||||
app->input_state = FlipBipTextInputDefault;
|
||||
handled = true;
|
||||
// exit scene 1 instance that's being used for text input and go back to menu
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
//view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdMenu);
|
||||
}
|
||||
}
|
||||
|
||||
if(!handled) {
|
||||
// clear input text
|
||||
memzero(app->input_text, TEXT_BUFFER_SIZE);
|
||||
// reset input state
|
||||
app->input_state = FlipBipTextInputDefault;
|
||||
// something went wrong, switch to menu view
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdMenu);
|
||||
}
|
||||
}
|
||||
|
||||
static void flipbip_scene_renew_dialog_callback(DialogExResult result, void* context) {
|
||||
FlipBip* app = context;
|
||||
if(result == DialogExResultRight) {
|
||||
app->wallet_create(app);
|
||||
} else {
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, FlipBipViewIdMenu);
|
||||
}
|
||||
}
|
||||
|
||||
static void flipbip_wallet_create(void* context) {
|
||||
FlipBip* app = context;
|
||||
furi_assert(app);
|
||||
scene_manager_set_scene_state(app->scene_manager, FlipBipSceneMenu, SubmenuIndexScene1New);
|
||||
scene_manager_next_scene(app->scene_manager, FlipBipSceneScene_1);
|
||||
}
|
||||
|
||||
FlipBip* flipbip_app_alloc() {
|
||||
FlipBip* app = malloc(sizeof(FlipBip));
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
//app->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// Turn backlight on, believe me this makes testing your app easier
|
||||
//notification_message(app->notification, &sequence_display_backlight_on);
|
||||
|
||||
// Scene additions
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
|
||||
|
||||
app->scene_manager = scene_manager_alloc(&flipbip_scene_handlers, app);
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, flipbip_navigation_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, flipbip_tick_event_callback, 100);
|
||||
view_dispatcher_set_custom_event_callback(app->view_dispatcher, flipbip_custom_event_callback);
|
||||
app->submenu = submenu_alloc();
|
||||
|
||||
// Settings
|
||||
app->bip39_strength = FlipBipStrength256; // 256 bits (24 words)
|
||||
app->passphrase = FlipBipPassphraseOff;
|
||||
|
||||
// Main menu
|
||||
app->bip44_coin = FlipBipCoinBTC0; // 0 (BTC)
|
||||
app->overwrite_saved_seed = 0;
|
||||
app->import_from_mnemonic = 0;
|
||||
app->mnemonic_menu_text = MNEMONIC_MENU_DEFAULT;
|
||||
|
||||
// Text input
|
||||
app->input_state = FlipBipTextInputDefault;
|
||||
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, FlipBipViewIdMenu, submenu_get_view(app->submenu));
|
||||
app->flipbip_scene_1 = flipbip_scene_1_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, FlipBipViewIdScene1, flipbip_scene_1_get_view(app->flipbip_scene_1));
|
||||
app->variable_item_list = variable_item_list_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
FlipBipViewIdSettings,
|
||||
variable_item_list_get_view(app->variable_item_list));
|
||||
|
||||
app->text_input = text_input_alloc();
|
||||
text_input_set_result_callback(
|
||||
app->text_input,
|
||||
text_input_callback,
|
||||
(void*)app,
|
||||
app->input_text,
|
||||
TEXT_BUFFER_SIZE,
|
||||
// clear default text
|
||||
true);
|
||||
//text_input_set_header_text(app->text_input, "Input");
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, FlipBipViewIdTextInput, text_input_get_view(app->text_input));
|
||||
|
||||
app->wallet_create = flipbip_wallet_create;
|
||||
app->renew_dialog = dialog_ex_alloc();
|
||||
dialog_ex_set_result_callback(app->renew_dialog, flipbip_scene_renew_dialog_callback);
|
||||
dialog_ex_set_context(app->renew_dialog, app);
|
||||
dialog_ex_set_left_button_text(app->renew_dialog, "No");
|
||||
dialog_ex_set_right_button_text(app->renew_dialog, "Yes");
|
||||
dialog_ex_set_header(
|
||||
app->renew_dialog,
|
||||
"Current wallet\nwill be deleted!\nProceed?",
|
||||
16,
|
||||
12,
|
||||
AlignLeft,
|
||||
AlignTop);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, FlipBipViewRenewConfirm, dialog_ex_get_view(app->renew_dialog));
|
||||
|
||||
// End Scene Additions
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void flipbip_app_free(FlipBip* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Scene manager
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
text_input_free(app->text_input);
|
||||
|
||||
// View Dispatcher
|
||||
view_dispatcher_remove_view(app->view_dispatcher, FlipBipViewIdMenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, FlipBipViewIdScene1);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, FlipBipViewIdSettings);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, FlipBipViewIdTextInput);
|
||||
submenu_free(app->submenu);
|
||||
|
||||
view_dispatcher_remove_view(app->view_dispatcher, FlipBipViewRenewConfirm);
|
||||
dialog_ex_free(app->renew_dialog);
|
||||
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
app->gui = NULL;
|
||||
//app->notification = NULL;
|
||||
|
||||
//Remove whatever is left
|
||||
memzero(app, sizeof(FlipBip));
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t flipbip_app(void* p) {
|
||||
UNUSED(p);
|
||||
FlipBip* app = flipbip_app_alloc();
|
||||
|
||||
// Disabled because causes exit on custom firmwares such as RM
|
||||
/*if(!furi_hal_region_is_provisioned()) {
|
||||
flipbip_app_free(app);
|
||||
return 1;
|
||||
}*/
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, FlipBipSceneMenu); //Start with menu
|
||||
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
flipbip_app_free(app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
//#include <notification/notification_messages.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include "scenes/flipbip_scene.h"
|
||||
#include "views/flipbip_scene_1.h"
|
||||
|
||||
#define FLIPBIP_VERSION "v1.17"
|
||||
|
||||
#define COIN_BTC 0
|
||||
#define COIN_DOGE 3
|
||||
#define COIN_ETH 60
|
||||
#define COIN_ZEC 133
|
||||
|
||||
#define TEXT_BUFFER_SIZE 256
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
// NotificationApp* notification;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Submenu* submenu;
|
||||
SceneManager* scene_manager;
|
||||
VariableItemList* variable_item_list;
|
||||
TextInput* text_input;
|
||||
DialogEx* renew_dialog;
|
||||
FlipBipScene1* flipbip_scene_1;
|
||||
char* mnemonic_menu_text;
|
||||
// Settings options
|
||||
int bip39_strength;
|
||||
int passphrase;
|
||||
// Main menu options
|
||||
int bip44_coin;
|
||||
int overwrite_saved_seed;
|
||||
int import_from_mnemonic;
|
||||
// Text input
|
||||
int input_state;
|
||||
char passphrase_text[TEXT_BUFFER_SIZE];
|
||||
char import_mnemonic_text[TEXT_BUFFER_SIZE];
|
||||
char input_text[TEXT_BUFFER_SIZE];
|
||||
|
||||
void (*wallet_create)(void* context);
|
||||
} FlipBip;
|
||||
|
||||
typedef enum {
|
||||
FlipBipViewIdStartscreen,
|
||||
FlipBipViewIdMenu,
|
||||
FlipBipViewIdScene1,
|
||||
FlipBipViewIdSettings,
|
||||
FlipBipViewIdTextInput,
|
||||
FlipBipViewRenewConfirm,
|
||||
} FlipBipViewId;
|
||||
|
||||
typedef enum {
|
||||
FlipBipStrength128,
|
||||
FlipBipStrength192,
|
||||
FlipBipStrength256,
|
||||
} FlipBipStrengthState;
|
||||
|
||||
typedef enum {
|
||||
FlipBipPassphraseOff,
|
||||
FlipBipPassphraseOn,
|
||||
} FlipBipPassphraseState;
|
||||
|
||||
typedef enum {
|
||||
FlipBipCoinBTC0,
|
||||
FlipBipCoinETH60,
|
||||
FlipBipCoinDOGE3,
|
||||
FlipBipCoinZEC133,
|
||||
} FlipBipCoin;
|
||||
|
||||
typedef enum {
|
||||
FlipBipTextInputDefault,
|
||||
FlipBipTextInputPassphrase,
|
||||
FlipBipTextInputMnemonic
|
||||
} FlipBipTextInputState;
|
||||
|
||||
typedef enum {
|
||||
FlipBipStatusSuccess = 0,
|
||||
FlipBipStatusReturn = 10,
|
||||
FlipBipStatusLoadError = 11,
|
||||
FlipBipStatusSaveError = 12,
|
||||
FlipBipStatusMnemonicCheckError = 13,
|
||||
} FlipBipStatus;
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexScene1BTC = 10,
|
||||
SubmenuIndexScene1ETH,
|
||||
SubmenuIndexScene1DOGE,
|
||||
SubmenuIndexScene1ZEC,
|
||||
SubmenuIndexScene1New,
|
||||
SubmenuIndexScene1Renew,
|
||||
SubmenuIndexScene1Import,
|
||||
SubmenuIndexSettings,
|
||||
SubmenuIndexNOP,
|
||||
} SubmenuIndex;
|
||||
|
After Width: | Height: | Size: 183 B |
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
FlipBipCustomEventScene1Up,
|
||||
FlipBipCustomEventScene1Down,
|
||||
FlipBipCustomEventScene1Left,
|
||||
FlipBipCustomEventScene1Right,
|
||||
FlipBipCustomEventScene1Ok,
|
||||
FlipBipCustomEventScene1Back,
|
||||
} FlipBipCustomEvent;
|
||||
@@ -0,0 +1,314 @@
|
||||
#include "flipbip_file.h"
|
||||
#include <storage/storage.h>
|
||||
#include <loader/loader.h>
|
||||
#include "../helpers/flipbip_string.h"
|
||||
// From: lib/crypto
|
||||
#include <memzero.h>
|
||||
#include <rand.h>
|
||||
|
||||
// #define FLIPBIP_APP_BASE_FOLDER APP_DATA_PATH("flipbip")
|
||||
#define FLIPBIP_APP_BASE_FOLDER EXT_PATH("apps_data/flipbip")
|
||||
#define FLIPBIP_APP_BASE_FOLDER_PATH(path) FLIPBIP_APP_BASE_FOLDER "/" path
|
||||
#define FLIPBIP_DAT_FILE_NAME ".flipbip.dat"
|
||||
// #define FLIPBIP_DAT_FILE_NAME ".flipbip.dat.txt"
|
||||
#define FLIPBIP_DAT_FILE_NAME_BAK ".flipbip.dat.bak"
|
||||
#define FLIPBIP_KEY_FILE_NAME ".flipbip.key"
|
||||
// #define FLIPBIP_KEY_FILE_NAME ".flipbip.key.txt"
|
||||
#define FLIPBIP_KEY_FILE_NAME_BAK ".flipbip.key.bak"
|
||||
#define FLIPBIP_DAT_PATH FLIPBIP_APP_BASE_FOLDER_PATH(FLIPBIP_DAT_FILE_NAME)
|
||||
#define FLIPBIP_DAT_PATH_BAK FLIPBIP_APP_BASE_FOLDER_PATH(FLIPBIP_DAT_FILE_NAME_BAK)
|
||||
#define FLIPBIP_KEY_PATH FLIPBIP_APP_BASE_FOLDER_PATH(FLIPBIP_KEY_FILE_NAME)
|
||||
#define FLIPBIP_KEY_PATH_BAK FLIPBIP_APP_BASE_FOLDER_PATH(FLIPBIP_KEY_FILE_NAME_BAK)
|
||||
|
||||
const char* TEXT_QRFILE = "Filetype: QRCode\n"
|
||||
"Version: 0\n"
|
||||
"Message: "; // 37 chars + 1 null
|
||||
#define FILE_HLEN 4
|
||||
#define FILE_KLEN 256
|
||||
#define FILE_SLEN 512
|
||||
#define FILE_MAX_PATH_LEN 48
|
||||
#define FILE_MAX_QRFILE_CONTENT 90
|
||||
const char* FILE_HSTR = "fb01";
|
||||
const char* FILE_K1 = "fb0131d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a"
|
||||
"baefe6d9ceb651842260e0d1e05e3b90d15e7d5ffaaabc0207bf200a117793a2";
|
||||
|
||||
bool flipbip_load_file(
|
||||
char* settings,
|
||||
size_t slen,
|
||||
const FlipBipFile file_type,
|
||||
const char* file_name) {
|
||||
bool ret = false;
|
||||
const char* path;
|
||||
char path_buf[FILE_MAX_PATH_LEN] = {0};
|
||||
if(file_type == FlipBipFileKey) {
|
||||
path = FLIPBIP_KEY_PATH;
|
||||
} else if(file_type == FlipBipFileDat) {
|
||||
path = FLIPBIP_DAT_PATH;
|
||||
} else {
|
||||
strcpy(path_buf, FLIPBIP_APP_BASE_FOLDER); // 22
|
||||
strcpy(path_buf + strlen(path_buf), "/");
|
||||
strcpy(path_buf + strlen(path_buf), file_name);
|
||||
path = path_buf;
|
||||
}
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
File* settings_file = storage_file_alloc(fs_api);
|
||||
if(storage_file_open(settings_file, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
char chr;
|
||||
size_t i = 0;
|
||||
while((storage_file_read(settings_file, &chr, 1) == 1) &&
|
||||
!storage_file_eof(settings_file) && !isspace(chr)) {
|
||||
if(i < slen) {
|
||||
settings[i] = chr;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
ret = true;
|
||||
} else {
|
||||
memzero(settings, strlen(settings));
|
||||
settings[0] = '\0';
|
||||
ret = false;
|
||||
}
|
||||
storage_file_close(settings_file);
|
||||
storage_file_free(settings_file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
if(strlen(settings) > 0) {
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
FileInfo layout_file_info;
|
||||
FS_Error file_check_err = storage_common_stat(fs_api, path, &layout_file_info);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
if(file_check_err != FSE_OK) {
|
||||
memzero(settings, strlen(settings));
|
||||
settings[0] = '\0';
|
||||
ret = false;
|
||||
}
|
||||
// if(layout_file_info.size != 256) {
|
||||
// memzero(settings, strlen(settings));
|
||||
// settings[0] = '\0';
|
||||
// }
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool flipbip_has_file(const FlipBipFile file_type, const char* file_name, const bool remove) {
|
||||
bool ret = false;
|
||||
const char* path;
|
||||
char path_buf[FILE_MAX_PATH_LEN] = {0};
|
||||
if(file_type == FlipBipFileKey) {
|
||||
path = FLIPBIP_KEY_PATH;
|
||||
} else if(file_type == FlipBipFileDat) {
|
||||
path = FLIPBIP_DAT_PATH;
|
||||
} else {
|
||||
strcpy(path_buf, FLIPBIP_APP_BASE_FOLDER); // 22
|
||||
strcpy(path_buf + strlen(path_buf), "/");
|
||||
strcpy(path_buf + strlen(path_buf), file_name);
|
||||
path = path_buf;
|
||||
}
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
if(remove) {
|
||||
ret = storage_simply_remove(fs_api, path);
|
||||
} else {
|
||||
ret = storage_file_exists(fs_api, path);
|
||||
}
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool flipbip_save_file(
|
||||
const char* settings,
|
||||
const FlipBipFile file_type,
|
||||
const char* file_name,
|
||||
const bool append) {
|
||||
bool ret = false;
|
||||
const char* path;
|
||||
const char* path_bak;
|
||||
char path_buf[FILE_MAX_PATH_LEN] = {0};
|
||||
if(file_type == FlipBipFileKey) {
|
||||
path = FLIPBIP_KEY_PATH;
|
||||
path_bak = FLIPBIP_KEY_PATH_BAK;
|
||||
} else if(file_type == FlipBipFileDat) {
|
||||
path = FLIPBIP_DAT_PATH;
|
||||
path_bak = FLIPBIP_DAT_PATH_BAK;
|
||||
} else {
|
||||
strcpy(path_buf, FLIPBIP_APP_BASE_FOLDER); // 22
|
||||
strcpy(path_buf + strlen(path_buf), "/");
|
||||
strcpy(path_buf + strlen(path_buf), file_name);
|
||||
path = path_buf;
|
||||
path_bak = NULL;
|
||||
}
|
||||
int open_mode = FSOM_OPEN_ALWAYS;
|
||||
if(append) {
|
||||
open_mode = FSOM_OPEN_APPEND;
|
||||
}
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
// // if the key file exists, we don't want to overwrite it
|
||||
// if (key_file && storage_file_exists(fs_api, path)) {
|
||||
// furi_record_close(RECORD_STORAGE);
|
||||
// ret = true;
|
||||
// return ret;
|
||||
// }
|
||||
// try to create the folder
|
||||
storage_simply_mkdir(fs_api, FLIPBIP_APP_BASE_FOLDER);
|
||||
|
||||
File* settings_file = storage_file_alloc(fs_api);
|
||||
if(storage_file_open(settings_file, path, FSAM_WRITE, open_mode)) {
|
||||
storage_file_write(settings_file, settings, strlen(settings));
|
||||
storage_file_write(settings_file, "\n", 1);
|
||||
ret = true;
|
||||
}
|
||||
storage_file_close(settings_file);
|
||||
storage_file_free(settings_file);
|
||||
|
||||
if(path_bak != NULL) {
|
||||
File* settings_file_bak = storage_file_alloc(fs_api);
|
||||
if(storage_file_open(settings_file_bak, path_bak, FSAM_WRITE, open_mode)) {
|
||||
storage_file_write(settings_file_bak, settings, strlen(settings));
|
||||
storage_file_write(settings_file_bak, "\n", 1);
|
||||
}
|
||||
storage_file_close(settings_file_bak);
|
||||
storage_file_free(settings_file_bak);
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool flipbip_save_qrfile(
|
||||
const char* qr_msg_prefix,
|
||||
const char* qr_msg_content,
|
||||
const char* file_name) {
|
||||
char qr_buf[FILE_MAX_QRFILE_CONTENT] = {0};
|
||||
strcpy(qr_buf, TEXT_QRFILE);
|
||||
strcpy(qr_buf + strlen(qr_buf), qr_msg_prefix);
|
||||
strcpy(qr_buf + strlen(qr_buf), qr_msg_content);
|
||||
return flipbip_save_file(qr_buf, FlipBipFileOther, file_name, false);
|
||||
}
|
||||
|
||||
bool flipbip_load_file_secure(char* settings) {
|
||||
const size_t dlen = FILE_HLEN + FILE_SLEN + 1;
|
||||
|
||||
// allocate memory for key/data
|
||||
char* data = malloc(dlen);
|
||||
memzero(data, dlen);
|
||||
|
||||
// load k2 from file
|
||||
if(!flipbip_load_file(data, dlen, FlipBipFileKey, NULL)) return false;
|
||||
|
||||
// check header
|
||||
if(data[0] != FILE_HSTR[0] || data[1] != FILE_HSTR[1] || data[2] != FILE_HSTR[2] ||
|
||||
data[3] != FILE_HSTR[3]) {
|
||||
memzero(data, dlen);
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
// seek --> header
|
||||
data += FILE_HLEN;
|
||||
|
||||
// prepare k1
|
||||
uint8_t k1[64];
|
||||
flipbip_xtob(FILE_K1, k1, strlen(FILE_K1) / 2);
|
||||
|
||||
// load k2 from file buffer (secured by k1)
|
||||
flipbip_cipher(k1, strlen(FILE_K1) / 2, data, data, FILE_KLEN);
|
||||
uint8_t k2[128];
|
||||
flipbip_xtob(data, k2, FILE_KLEN / 2);
|
||||
// zero k2 buffer
|
||||
memzero(data, FILE_KLEN);
|
||||
// seek <-- header
|
||||
data -= FILE_HLEN;
|
||||
|
||||
// load data from file
|
||||
if(!flipbip_load_file(data, dlen, FlipBipFileDat, NULL)) return false;
|
||||
|
||||
// check header
|
||||
if(data[0] != FILE_HSTR[0] || data[1] != FILE_HSTR[1] || data[2] != FILE_HSTR[2] ||
|
||||
data[3] != FILE_HSTR[3]) {
|
||||
memzero(data, dlen);
|
||||
free(data);
|
||||
memzero(k1, strlen(FILE_K1) / 2);
|
||||
memzero(k2, FILE_KLEN / 2);
|
||||
return false;
|
||||
}
|
||||
// seek --> header
|
||||
data += FILE_HLEN;
|
||||
|
||||
// load settings from file buffer (secured by k2)
|
||||
flipbip_cipher(k2, FILE_KLEN / 2, data, data, FILE_SLEN);
|
||||
flipbip_xtob(data, (unsigned char*)data, FILE_SLEN / 2);
|
||||
|
||||
// copy to output
|
||||
strcpy(settings, data);
|
||||
|
||||
// seek <-- header
|
||||
data -= FILE_HLEN;
|
||||
|
||||
// clear memory
|
||||
memzero(data, dlen);
|
||||
free(data);
|
||||
memzero(k1, strlen(FILE_K1) / 2);
|
||||
memzero(k2, FILE_KLEN / 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool flipbip_save_file_secure(const char* settings) {
|
||||
const size_t dlen = FILE_HLEN + FILE_SLEN + 1;
|
||||
|
||||
// cap settings to 256 bytes
|
||||
size_t len = strlen(settings);
|
||||
if(len > (FILE_SLEN / 2)) len = FILE_SLEN / 2;
|
||||
|
||||
// allocate memory for key/data
|
||||
char* data = malloc(dlen);
|
||||
memzero(data, dlen);
|
||||
|
||||
// write header
|
||||
strncpy(data, FILE_HSTR, FILE_HLEN);
|
||||
// seek --> header
|
||||
data += FILE_HLEN;
|
||||
|
||||
// prepare k1
|
||||
uint8_t k1[64];
|
||||
flipbip_xtob(FILE_K1, k1, strlen(FILE_K1) / 2);
|
||||
|
||||
// generate k2
|
||||
uint8_t k2[128];
|
||||
random_buffer(k2, FILE_KLEN / 2);
|
||||
|
||||
// write k2 to file buffer (secured by k1)
|
||||
flipbip_btox(k2, FILE_KLEN / 2, data);
|
||||
flipbip_cipher(k1, strlen(FILE_K1) / 2, data, data, FILE_KLEN);
|
||||
|
||||
// seek <-- header
|
||||
data -= FILE_HLEN;
|
||||
// save k2 to file
|
||||
flipbip_save_file(data, FlipBipFileKey, NULL, false);
|
||||
// seek --> header
|
||||
data += FILE_HLEN;
|
||||
// zero k2 memory
|
||||
memzero(data, FILE_KLEN);
|
||||
|
||||
// write settings to file buffer (secured by k2)
|
||||
flipbip_btox((uint8_t*)settings, len, data);
|
||||
flipbip_cipher(k2, FILE_KLEN / 2, data, data, FILE_SLEN);
|
||||
|
||||
// seek <-- header
|
||||
data -= FILE_HLEN;
|
||||
// save data to file
|
||||
flipbip_save_file(data, FlipBipFileDat, NULL, false);
|
||||
|
||||
// clear memory
|
||||
memzero(data, dlen);
|
||||
free(data);
|
||||
memzero(k1, strlen(FILE_K1) / 2);
|
||||
memzero(k2, FILE_KLEN / 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef enum {
|
||||
FlipBipFileDat,
|
||||
FlipBipFileKey,
|
||||
FlipBipFileOther,
|
||||
} FlipBipFile;
|
||||
|
||||
bool flipbip_has_file(const FlipBipFile file_type, const char* file_name, const bool remove);
|
||||
bool flipbip_load_file(
|
||||
char* settings,
|
||||
size_t slen,
|
||||
const FlipBipFile file_type,
|
||||
const char* file_name);
|
||||
bool flipbip_save_file(
|
||||
const char* settings,
|
||||
const FlipBipFile file_type,
|
||||
const char* file_name,
|
||||
const bool append);
|
||||
|
||||
bool flipbip_save_qrfile(
|
||||
const char* qr_msg_prefix,
|
||||
const char* qr_msg_content,
|
||||
const char* file_name);
|
||||
|
||||
bool flipbip_load_file_secure(char* settings);
|
||||
bool flipbip_save_file_secure(const char* settings);
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 the University 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 REGENTS 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 REGENTS 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.
|
||||
*/
|
||||
#include "flipbip_string.h"
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
// From: lib/crypto
|
||||
#include <memzero.h>
|
||||
#include <rc4.h>
|
||||
|
||||
char* flipbip_strtok(char* s, const char* delim) {
|
||||
static char* last;
|
||||
return flipbip_strtok_r(s, delim, &last);
|
||||
}
|
||||
char* flipbip_strtok_r(char* s, const char* delim, char** last) {
|
||||
char* spanp;
|
||||
int c, sc;
|
||||
char* tok;
|
||||
if(s == NULL && (s = *last) == NULL) return (NULL);
|
||||
/*
|
||||
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
|
||||
*/
|
||||
cont:
|
||||
c = *s++;
|
||||
for(spanp = (char*)delim; (sc = *spanp++) != 0;) {
|
||||
if(c == sc) goto cont;
|
||||
}
|
||||
if(c == 0) { /* no non-delimiter characters */
|
||||
*last = NULL;
|
||||
return (NULL);
|
||||
}
|
||||
tok = s - 1;
|
||||
/*
|
||||
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
|
||||
* Note that delim must have one NUL; we stop if we see that, too.
|
||||
*/
|
||||
for(;;) {
|
||||
c = *s++;
|
||||
spanp = (char*)delim;
|
||||
do {
|
||||
if((sc = *spanp++) == c) {
|
||||
if(c == 0)
|
||||
s = NULL;
|
||||
else
|
||||
s[-1] = 0;
|
||||
*last = s;
|
||||
return (tok);
|
||||
}
|
||||
} while(sc != 0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
void flipbip_btox(const unsigned char* in, int in_len, char* str) {
|
||||
for(int i = 0; i < in_len; i++) {
|
||||
unsigned char n;
|
||||
unsigned char x = in[i];
|
||||
|
||||
str += 2;
|
||||
*(str + (i * 2)) = '\0';
|
||||
|
||||
for(n = 2; n != 0; --n) {
|
||||
*(--str + (i * 2)) = "0123456789abcdef"[x & 0x0F];
|
||||
x >>= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
void flipbip_xtob(const char* str, unsigned char* out, int out_len) {
|
||||
int len = strlen(str) / 2;
|
||||
if(len > out_len) len = out_len;
|
||||
for(int i = 0; i < len; i++) {
|
||||
char c = 0;
|
||||
if(str[i * 2] >= '0' && str[i * 2] <= '9') c += (str[i * 2] - '0') << 4;
|
||||
if((str[i * 2] & ~0x20) >= 'A' && (str[i * 2] & ~0x20) <= 'F')
|
||||
c += (10 + (str[i * 2] & ~0x20) - 'A') << 4;
|
||||
if(str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') c += (str[i * 2 + 1] - '0');
|
||||
if((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F')
|
||||
c += (10 + (str[i * 2 + 1] & ~0x20) - 'A');
|
||||
out[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void flipbip_cipher(
|
||||
const unsigned char* key_in,
|
||||
const unsigned int key_len,
|
||||
const char* in,
|
||||
char* out,
|
||||
const unsigned int io_len) {
|
||||
if(io_len > 512) return;
|
||||
|
||||
RC4_CTX ctx;
|
||||
uint8_t buf[256];
|
||||
memzero(buf, 256);
|
||||
|
||||
flipbip_xtob(in, buf, io_len / 2);
|
||||
|
||||
rc4_init(&ctx, key_in, key_len);
|
||||
rc4_encrypt(&ctx, buf, 256);
|
||||
|
||||
flipbip_btox(buf, io_len / 2, out);
|
||||
|
||||
memzero(buf, 256);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
char* flipbip_strtok(char* s, const char* delim);
|
||||
char* flipbip_strtok_r(char* s, const char* delim, char** last);
|
||||
|
||||
void flipbip_btox(const unsigned char* in, int in_len, char* str);
|
||||
void flipbip_xtob(const char* str, unsigned char* out, int out_len);
|
||||
|
||||
void flipbip_cipher(
|
||||
const unsigned char* key_in,
|
||||
const unsigned int key_len,
|
||||
const char* in,
|
||||
char* out,
|
||||
const unsigned int io_len);
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,2 @@
|
||||
Tomas Dzetkulic <dzetkulic@gmail.com>
|
||||
Pavol Rusnak <stick@gk2.sk>
|
||||
@@ -0,0 +1,17 @@
|
||||
Tomas Dzetkulic <dzetkulic@gmail.com>
|
||||
Pavol Rusnak <stick@gk2.sk>
|
||||
Jochen Hoenicke <hoenicke@gmail.com>
|
||||
Dustin Laurence <dustin@laurences.net>
|
||||
Ondrej Mikle <ondrej.mikle@nic.cz>
|
||||
Roman Zeyde <roman.zeyde@gmail.com>
|
||||
Alex Beregszaszi <alex@rtfs.hu>
|
||||
netanelkl <netanel.keidar@gmail.com>
|
||||
Jan Pochyla <jpochyla@gmail.com>
|
||||
Ondrej Mikle <ondrej.mikle@gmail.com>
|
||||
Josh Billings <jdb6167@rit.edu>
|
||||
Adam Mackler <AdamMackler@gmail.com>
|
||||
Oleg Andreev <oleganza@gmail.com>
|
||||
mog <mog@rush.rldn.net>
|
||||
John Dvorak <johndvorak26@gmail.com>
|
||||
Christian Reitter <invd@inhq.net>
|
||||
Struan Clark <xtruan@users.noreply.github.com>
|
||||
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Tomas Dzetkulic
|
||||
Copyright (c) 2013 Pavol Rusnak
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,187 @@
|
||||
# CLANG_VERSION is empty if the compiler is not clang-based
|
||||
CLANG_VERSION = $(shell $(CC) --version | sed -nr 's/^.*clang version ([0-9.]+).*$$/\1/p')
|
||||
CLANG_VERSION_MAJOR = $(shell echo $(CLANG_VERSION) | cut -f1 -d.)
|
||||
|
||||
# determine specific version ranges
|
||||
ifneq ($(CLANG_VERSION),)
|
||||
$(if $(shell [ $(CLANG_VERSION_MAJOR) -ge 13 ] && echo "OK"), \
|
||||
$(eval CLANG_AT_LEAST_13 := true), \
|
||||
$(eval CLANG_AT_LEAST_13 := false))
|
||||
endif
|
||||
|
||||
ifeq ($(FUZZER),1)
|
||||
CC ?= clang
|
||||
LD ?= $(CC)
|
||||
SANFLAGS += -fsanitize=fuzzer
|
||||
|
||||
# only clang versions >= 13 support this feature
|
||||
ifeq ($(CLANG_AT_LEAST_13),true)
|
||||
$(info "info: using -fsanitize-ignorelist")
|
||||
SANFLAGS += -fsanitize-ignorelist=fuzzer/sanitizer_ignorelist.txt
|
||||
else
|
||||
$(info "info: not using -fsanitize-ignorelist")
|
||||
endif
|
||||
|
||||
# TODO is there a better solution, for example by disabling a specific optimization technique?
|
||||
# there is a clang optimization issue in relation with the blake2 code at -fsanitize=undefined
|
||||
$(warning "warning: disabling optimization on blake2 code as workaround")
|
||||
blake2b.o: OPTFLAGS += -O0
|
||||
blake2s.o: OPTFLAGS += -O0
|
||||
|
||||
else ifeq ($(ADDRESS_SANITIZER),1)
|
||||
SANFLAGS += -fsanitize=address,undefined
|
||||
endif
|
||||
|
||||
CC ?= cc
|
||||
|
||||
OPTFLAGS ?= -O3 -g
|
||||
|
||||
CFLAGS += $(OPTFLAGS) \
|
||||
$(SANFLAGS) \
|
||||
-std=gnu99 \
|
||||
-W \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wimplicit-function-declaration \
|
||||
-Wredundant-decls \
|
||||
-Wstrict-prototypes \
|
||||
-Wundef \
|
||||
-Wshadow \
|
||||
-Wpointer-arith \
|
||||
-Wformat \
|
||||
-Wreturn-type \
|
||||
-Wsign-compare \
|
||||
-Wmultichar \
|
||||
-Wformat-nonliteral \
|
||||
-Winit-self \
|
||||
-Wuninitialized \
|
||||
-Wformat-security \
|
||||
-Wno-missing-braces \
|
||||
-Werror
|
||||
|
||||
ZKP_CFLAGS = \
|
||||
-DECMULT_GEN_PREC_BITS=4 \
|
||||
-DECMULT_WINDOW_SIZE=8 \
|
||||
-DENABLE_MODULE_GENERATOR \
|
||||
-DENABLE_MODULE_RECOVERY \
|
||||
-DENABLE_MODULE_SCHNORRSIG \
|
||||
-DENABLE_MODULE_EXTRAKEYS
|
||||
ZKP_PATH = ../vendor/secp256k1-zkp
|
||||
# this is specific for 64-bit builds
|
||||
CFLAGS += -DSECP256K1_CONTEXT_SIZE=208
|
||||
|
||||
VALGRIND ?= 1
|
||||
ifeq ($(VALGRIND),1)
|
||||
CFLAGS += -DVALGRIND
|
||||
endif
|
||||
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I..
|
||||
CFLAGS += -DUSE_ETHEREUM=1
|
||||
CFLAGS += -DUSE_KECCAK=1
|
||||
CFLAGS += -DUSE_MONERO=1
|
||||
CFLAGS += -DUSE_NEM=1
|
||||
CFLAGS += -DUSE_CARDANO=1
|
||||
CFLAGS += $(shell pkg-config --cflags openssl)
|
||||
|
||||
# disable certain optimizations and features when small footprint is required
|
||||
ifdef SMALL
|
||||
CFLAGS += -DUSE_PRECOMPUTED_CP=0
|
||||
endif
|
||||
|
||||
SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c bip39_english.c pbkdf2.c base58.c base32.c
|
||||
SRCS += address.c
|
||||
SRCS += script.c
|
||||
SRCS += ripemd160.c
|
||||
SRCS += sha2.c
|
||||
SRCS += sha3.c
|
||||
SRCS += hasher.c
|
||||
SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c
|
||||
SRCS += ed25519_donna/curve25519_donna_32bit.c ed25519_donna/curve25519_donna_helpers.c ed25519_donna/modm_donna_32bit.c
|
||||
SRCS += ed25519_donna/ed25519_donna_basepoint_table.c ed25519_donna/ed25519_donna_32bit_tables.c ed25519_donna/ed25519_donna_impl_base.c
|
||||
SRCS += ed25519_donna/ed25519.c ed25519_donna/curve25519_donna_scalarmult_base.c ed25519_donna/ed25519_sha3.c ed25519_donna/ed25519_keccak.c
|
||||
SRCS += monero/base58.c
|
||||
SRCS += monero/serialize.c
|
||||
SRCS += monero/xmr.c
|
||||
SRCS += blake256.c
|
||||
SRCS += blake2b.c blake2s.c
|
||||
SRCS += chacha_drbg.c
|
||||
SRCS += groestl.c
|
||||
SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305_donna.c chacha20poly1305/rfc7539.c
|
||||
SRCS += rc4.c
|
||||
SRCS += nem.c
|
||||
SRCS += segwit_addr.c cash_addr.c
|
||||
SRCS += memzero.c
|
||||
SRCS += shamir.c
|
||||
SRCS += hmac_drbg.c
|
||||
SRCS += rfc6979.c
|
||||
SRCS += slip39.c
|
||||
SRCS += zkp_context.c
|
||||
SRCS += zkp_ecdsa.c
|
||||
SRCS += zkp_bip340.c
|
||||
SRCS += cardano.c
|
||||
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
OBJS += secp256k1-zkp.o
|
||||
OBJS += precomputed_ecmult.o
|
||||
OBJS += precomputed_ecmult_gen.o
|
||||
|
||||
TESTLIBS = $(shell pkg-config --libs check) -lpthread -lm
|
||||
TESTSSLLIBS = $(shell pkg-config --libs openssl)
|
||||
|
||||
all: tools tests
|
||||
|
||||
%.o: %.c %.h options.h
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
tests: tests/test_check tests/test_openssl tests/test_speed tests/libtrezor-crypto.so tests/aestst
|
||||
|
||||
tests/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o
|
||||
$(CC) $(CFLAGS) $^ -o $@
|
||||
|
||||
tests/test_check.o: tests/test_check_cardano.h tests/test_check_monero.h tests/test_check_cashaddr.h tests/test_check_segwit.h
|
||||
|
||||
tests/test_check: tests/test_check.o $(OBJS)
|
||||
$(CC) $(CFLAGS) tests/test_check.o $(OBJS) $(TESTLIBS) -o tests/test_check
|
||||
|
||||
tests/test_speed: tests/test_speed.o $(OBJS)
|
||||
$(CC) $(CFLAGS) tests/test_speed.o $(OBJS) -o tests/test_speed
|
||||
|
||||
tests/test_openssl: tests/test_openssl.o $(OBJS)
|
||||
$(CC) $(CFLAGS) tests/test_openssl.o $(OBJS) $(TESTSSLLIBS) -o tests/test_openssl
|
||||
|
||||
tests/libtrezor-crypto.so: $(SRCS) secp256k1-zkp.o precomputed_ecmult.o precomputed_ecmult_gen.o
|
||||
$(CC) $(CFLAGS) -DAES_128 -DAES_192 -fPIC -shared $(SRCS) secp256k1-zkp.o precomputed_ecmult.o precomputed_ecmult_gen.o -o tests/libtrezor-crypto.so
|
||||
|
||||
tools: tools/xpubaddrgen tools/mktable tools/bip39bruteforce
|
||||
|
||||
tools/xpubaddrgen: tools/xpubaddrgen.o $(OBJS)
|
||||
$(CC) $(CFLAGS) tools/xpubaddrgen.o $(OBJS) -o tools/xpubaddrgen
|
||||
|
||||
tools/mktable: tools/mktable.o $(OBJS)
|
||||
$(CC) $(CFLAGS) tools/mktable.o $(OBJS) -o tools/mktable
|
||||
|
||||
tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS)
|
||||
$(CC) $(CFLAGS) tools/bip39bruteforce.o $(OBJS) -o tools/bip39bruteforce
|
||||
|
||||
fuzzer: fuzzer/fuzzer.o $(OBJS)
|
||||
$(CC) $(CFLAGS) fuzzer/fuzzer.o $(OBJS) -o fuzzer/fuzzer
|
||||
|
||||
precomputed_ecmult.o:
|
||||
$(CC) $(CFLAGS) -Wno-unused-function $(ZKP_CFLAGS) -fPIC -c $(ZKP_PATH)/src/precomputed_ecmult.c -o precomputed_ecmult.o
|
||||
|
||||
precomputed_ecmult_gen.o:
|
||||
$(CC) $(CFLAGS) -Wno-unused-function $(ZKP_CFLAGS) -fPIC -c $(ZKP_PATH)/src/precomputed_ecmult_gen.c -o precomputed_ecmult_gen.o
|
||||
|
||||
secp256k1-zkp.o:
|
||||
$(CC) $(CFLAGS) -Wno-unused-function $(ZKP_CFLAGS) -fPIC -I$(ZKP_PATH) -I$(ZKP_PATH)/src -c $(ZKP_PATH)/src/secp256k1.c -o secp256k1-zkp.o
|
||||
|
||||
clean:
|
||||
rm -f *.o aes/*.o chacha20poly1305/*.o ed25519_donna/*.o monero/*.o
|
||||
rm -f tests/*.o tests/test_check tests/test_speed tests/test_openssl tests/libtrezor-crypto.so tests/aestst
|
||||
rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce
|
||||
rm -f fuzzer/*.o fuzzer/fuzzer
|
||||
rm -f secp256k1-zkp.o precomputed_ecmult.o precomputed_ecmult_gen.o
|
||||
|
||||
clean-fuzzer: clean
|
||||
rm -f crash-* fuzz-*.log slow-unit-* timeout-*
|
||||
@@ -0,0 +1,54 @@
|
||||
# trezor-crypto
|
||||
|
||||
Heavily optimized cryptography algorithms for embedded devices.
|
||||
|
||||
These include:
|
||||
- AES/Rijndael encryption/decryption
|
||||
- Big Number (256 bit) Arithmetics
|
||||
- BIP32 Hierarchical Deterministic Wallets
|
||||
- BIP39 Mnemonic code
|
||||
- ECDSA signing/verifying (supports secp256k1 and nist256p1 curves,
|
||||
uses RFC6979 for deterministic signatures)
|
||||
- ECDSA public key derivation
|
||||
- BIP340 Schnorr signature signing/verifying
|
||||
- Base32 (RFC4648 and custom alphabets)
|
||||
- Base58 address representation
|
||||
- Ed25519 signing/verifying (also SHA3 and Keccak variants)
|
||||
- ECDH using secp256k1, nist256p1 and Curve25519
|
||||
- HMAC-SHA256 and HMAC-SHA512
|
||||
- PBKDF2
|
||||
- RIPEMD-160
|
||||
- SHA1
|
||||
- SHA2-256/SHA2-512
|
||||
- SHA3/Keccak
|
||||
- BLAKE2s/BLAKE2b
|
||||
- Chacha20-Poly1305
|
||||
- unit tests (using Check - check.sf.net; in test_check.c)
|
||||
- tests against OpenSSL (in test_openssl.c)
|
||||
- integrated Wycheproof tests
|
||||
|
||||
Distibuted under MIT License.
|
||||
|
||||
## Some parts of the library come from external sources:
|
||||
|
||||
- AES: https://github.com/BrianGladman/aes
|
||||
- Base58: https://github.com/luke-jr/libbase58
|
||||
- BLAKE2s/BLAKE2b: https://github.com/BLAKE2/BLAKE2
|
||||
- RIPEMD-160: https://github.com/ARMmbed/mbedtls
|
||||
- SHA1/SHA2: http://www.aarongifford.com/computers/sha.html
|
||||
- SHA3: https://github.com/rhash/RHash
|
||||
- Curve25519: https://github.com/agl/curve25519-donna
|
||||
- Ed25519: https://github.com/floodyberry/ed25519-donna
|
||||
- Chacha20: https://github.com/wg/c20p1305
|
||||
- Poly1305: https://github.com/floodyberry/poly1305-donna
|
||||
|
||||
## Repo source:
|
||||
|
||||
```
|
||||
remote = git+ssh://git@github.com/trezor/trezor-crypto
|
||||
branch = master
|
||||
commit = 915b3dbbbf58c262865647728a3463b8785fc965
|
||||
parent = 6ad3294f31a1e7484b43c104ff2880b965198cad
|
||||
method = rebase
|
||||
cmdver = 0.4.0
|
||||
```
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2016 Daira Hopwood
|
||||
* Copyright (c) 2016 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "address.h"
|
||||
#include "bignum.h"
|
||||
|
||||
size_t address_prefix_bytes_len(uint32_t address_type) {
|
||||
if(address_type <= 0xFF) return 1;
|
||||
if(address_type <= 0xFFFF) return 2;
|
||||
if(address_type <= 0xFFFFFF) return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
void address_write_prefix_bytes(uint32_t address_type, uint8_t* out) {
|
||||
if(address_type > 0xFFFFFF) *(out++) = address_type >> 24;
|
||||
if(address_type > 0xFFFF) *(out++) = (address_type >> 16) & 0xFF;
|
||||
if(address_type > 0xFF) *(out++) = (address_type >> 8) & 0xFF;
|
||||
*(out++) = address_type & 0xFF;
|
||||
}
|
||||
|
||||
bool address_check_prefix(const uint8_t* addr, uint32_t address_type) {
|
||||
if(address_type <= 0xFF) {
|
||||
return address_type == (uint32_t)(addr[0]);
|
||||
}
|
||||
if(address_type <= 0xFFFF) {
|
||||
return address_type == (((uint32_t)addr[0] << 8) | ((uint32_t)addr[1]));
|
||||
}
|
||||
if(address_type <= 0xFFFFFF) {
|
||||
return address_type ==
|
||||
(((uint32_t)addr[0] << 16) | ((uint32_t)addr[1] << 8) | ((uint32_t)addr[2]));
|
||||
}
|
||||
return address_type == (((uint32_t)addr[0] << 24) | ((uint32_t)addr[1] << 16) |
|
||||
((uint32_t)addr[2] << 8) | ((uint32_t)addr[3]));
|
||||
}
|
||||
|
||||
#if USE_ETHEREUM
|
||||
#include "sha3.h"
|
||||
|
||||
void ethereum_address_checksum(const uint8_t* addr, char* address, bool rskip60, uint64_t chain_id) {
|
||||
const char* hex = "0123456789abcdef";
|
||||
address[0] = '0';
|
||||
address[1] = 'x';
|
||||
for(int i = 0; i < 20; i++) {
|
||||
address[2 + i * 2] = hex[(addr[i] >> 4) & 0xF];
|
||||
address[2 + i * 2 + 1] = hex[addr[i] & 0xF];
|
||||
}
|
||||
address[42] = 0;
|
||||
|
||||
SHA3_CTX ctx = {0};
|
||||
uint8_t hash[32] = {0};
|
||||
keccak_256_Init(&ctx);
|
||||
if(rskip60) {
|
||||
char prefix[16] = {0};
|
||||
int prefix_size =
|
||||
bn_format_uint64(chain_id, NULL, "0x", 0, 0, false, 0, prefix, sizeof(prefix));
|
||||
keccak_Update(&ctx, (const uint8_t*)prefix, prefix_size);
|
||||
}
|
||||
keccak_Update(&ctx, (const uint8_t*)(address + 2), 40);
|
||||
keccak_Final(&ctx, hash);
|
||||
|
||||
for(int i = 0; i < 20; i++) {
|
||||
if((hash[i] & 0x80) && address[2 + i * 2] >= 'a' && address[2 + i * 2] <= 'f') {
|
||||
address[2 + i * 2] -= 0x20;
|
||||
}
|
||||
if((hash[i] & 0x08) && address[2 + i * 2 + 1] >= 'a' && address[2 + i * 2 + 1] <= 'f') {
|
||||
address[2 + i * 2 + 1] -= 0x20;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2016 Daira Hopwood
|
||||
* Copyright (c) 2016 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __ADDRESS_H__
|
||||
#define __ADDRESS_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "options.h"
|
||||
|
||||
size_t address_prefix_bytes_len(uint32_t address_type);
|
||||
void address_write_prefix_bytes(uint32_t address_type, uint8_t* out);
|
||||
bool address_check_prefix(const uint8_t* addr, uint32_t address_type);
|
||||
#if USE_ETHEREUM
|
||||
void ethereum_address_checksum(const uint8_t* addr, char* address, bool rskip60, uint64_t chain_id);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 02/08/2018
|
||||
|
||||
This file contains the definitions required to use AES in C. See aesopt.h
|
||||
for optimisation details.
|
||||
*/
|
||||
|
||||
#ifndef _AES_H
|
||||
#define _AES_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define VOID_RETURN void
|
||||
#define INT_RETURN int
|
||||
#define ALIGN_OFFSET(x, n) (((intptr_t)(x)) & ((n)-1))
|
||||
#define ALIGN_FLOOR(x, n) ((uint8_t*)(x) - (((intptr_t)(x)) & ((n)-1)))
|
||||
#define ALIGN_CEIL(x, n) ((uint8_t*)(x) + (-((intptr_t)(x)) & ((n)-1)))
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// #define AES_128 /* if a fast 128 bit key scheduler is needed */
|
||||
// #define AES_192 /* if a fast 192 bit key scheduler is needed */
|
||||
#define AES_256 /* if a fast 256 bit key scheduler is needed */
|
||||
// #define AES_VAR /* if variable key size scheduler is needed */
|
||||
#if 1
|
||||
#define AES_MODES /* if support is needed for modes in the C code */
|
||||
#endif /* (these will use AES_NI if it is present) */
|
||||
#if 0 /* add this to make direct calls to the AES_NI */
|
||||
#/* implemented CBC and CTR modes available */
|
||||
#define ADD_AESNI_MODE_CALLS
|
||||
#endif
|
||||
|
||||
/* The following must also be set in assembler files if being used */
|
||||
|
||||
#define AES_ENCRYPT /* if support for encryption is needed */
|
||||
#define AES_DECRYPT /* if support for decryption is needed */
|
||||
|
||||
#define AES_BLOCK_SIZE_P2 4 /* AES block size as a power of 2 */
|
||||
#define AES_BLOCK_SIZE (1 << AES_BLOCK_SIZE_P2) /* AES block size */
|
||||
#define N_COLS 4 /* the number of columns in the state */
|
||||
|
||||
/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */
|
||||
/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */
|
||||
/* or 44, 52 or 60 32-bit words. */
|
||||
|
||||
#if defined(AES_VAR) || defined(AES_256)
|
||||
#define KS_LENGTH 60
|
||||
#elif defined(AES_192)
|
||||
#define KS_LENGTH 52
|
||||
#else
|
||||
#define KS_LENGTH 44
|
||||
#endif
|
||||
|
||||
#define AES_RETURN INT_RETURN
|
||||
|
||||
/* the character array 'inf' in the following structures is used */
|
||||
/* to hold AES context information. This AES code uses cx->inf.b[0] */
|
||||
/* to hold the number of rounds multiplied by 16. The other three */
|
||||
/* elements can be used by code that implements additional modes */
|
||||
|
||||
typedef union {
|
||||
uint32_t l;
|
||||
uint8_t b[4];
|
||||
} aes_inf;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4324)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && defined(_WIN64)
|
||||
#define ALIGNED_(x) __declspec(align(x))
|
||||
#elif defined(__GNUC__) && defined(__x86_64__)
|
||||
#define ALIGNED_(x) __attribute__((aligned(x)))
|
||||
#else
|
||||
#define ALIGNED_(x)
|
||||
#endif
|
||||
|
||||
typedef struct ALIGNED_(16) {
|
||||
uint32_t ks[KS_LENGTH];
|
||||
aes_inf inf;
|
||||
} aes_encrypt_ctx;
|
||||
|
||||
typedef struct ALIGNED_(16) {
|
||||
uint32_t ks[KS_LENGTH];
|
||||
aes_inf inf;
|
||||
} aes_decrypt_ctx;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(default : 4324)
|
||||
#endif
|
||||
|
||||
/* This routine must be called before first use if non-static */
|
||||
/* tables are being used */
|
||||
|
||||
AES_RETURN aes_init(void);
|
||||
|
||||
/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */
|
||||
/* those in the range 128 <= key_len <= 256 are given in bits */
|
||||
|
||||
#if defined(AES_ENCRYPT)
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
AES_RETURN aes_encrypt_key128(const unsigned char* key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
AES_RETURN aes_encrypt_key192(const unsigned char* key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
AES_RETURN aes_encrypt_key256(const unsigned char* key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_VAR)
|
||||
AES_RETURN aes_encrypt_key(const unsigned char* key, int key_len, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_encrypt(const unsigned char* in, unsigned char* out, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_DECRYPT)
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
AES_RETURN aes_decrypt_key128(const unsigned char* key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
AES_RETURN aes_decrypt_key192(const unsigned char* key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
AES_RETURN aes_decrypt_key256(const unsigned char* key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_VAR)
|
||||
AES_RETURN aes_decrypt_key(const unsigned char* key, int key_len, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_decrypt(const unsigned char* in, unsigned char* out, const aes_decrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_MODES)
|
||||
|
||||
/* Multiple calls to the following subroutines for multiple block */
|
||||
/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */
|
||||
/* long messages incrementally provided that the context AND the iv */
|
||||
/* are preserved between all such calls. For the ECB and CBC modes */
|
||||
/* each individual call within a series of incremental calls must */
|
||||
/* process only full blocks (i.e. len must be a multiple of 16) but */
|
||||
/* the CFB, OFB and CTR mode calls can handle multiple incremental */
|
||||
/* calls of any length. Each mode is reset when a new AES key is */
|
||||
/* set but ECB needs no reset and CBC can be reset without setting */
|
||||
/* a new key by setting a new IV value. To reset CFB, OFB and CTR */
|
||||
/* without setting the key, aes_mode_reset() must be called and the */
|
||||
/* IV must be set. NOTE: All these calls update the IV on exit so */
|
||||
/* this has to be reset if a new operation with the same IV as the */
|
||||
/* previous one is required (or decryption follows encryption with */
|
||||
/* the same IV array). */
|
||||
|
||||
AES_RETURN aes_test_alignment_detection(unsigned int n);
|
||||
|
||||
AES_RETURN aes_ecb_encrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_ecb_decrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
const aes_decrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cbc_encrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cbc_decrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
const aes_decrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cfb_encrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cfb_decrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
aes_encrypt_ctx cx[1]);
|
||||
|
||||
#define aes_ofb_encrypt aes_ofb_crypt
|
||||
#define aes_ofb_decrypt aes_ofb_crypt
|
||||
|
||||
AES_RETURN aes_ofb_crypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
aes_encrypt_ctx cx[1]);
|
||||
|
||||
typedef void cbuf_inc(unsigned char* cbuf);
|
||||
|
||||
#define aes_ctr_encrypt aes_ctr_crypt
|
||||
#define aes_ctr_decrypt aes_ctr_crypt
|
||||
|
||||
AES_RETURN aes_ctr_crypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* cbuf,
|
||||
cbuf_inc ctr_inc,
|
||||
aes_encrypt_ctx cx[1]);
|
||||
|
||||
void aes_ctr_cbuf_inc(unsigned char* cbuf);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,932 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
These subroutines implement multiple block AES modes for ECB, CBC, CFB,
|
||||
OFB and CTR encryption, The code provides support for the VIA Advanced
|
||||
Cryptography Engine (ACE).
|
||||
|
||||
NOTE: In the following subroutines, the AES contexts (ctx) must be
|
||||
16 byte aligned if VIA ACE is being used
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined(AES_MODES)
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER > 800)
|
||||
#pragma intrinsic(memcpy)
|
||||
#endif
|
||||
|
||||
#define BFR_BLOCKS 8
|
||||
|
||||
/* These values are used to detect long word alignment in order to */
|
||||
/* speed up some buffer operations. This facility may not work on */
|
||||
/* some machines so this define can be commented out if necessary */
|
||||
|
||||
#define FAST_BUFFER_OPERATIONS
|
||||
|
||||
#define lp32(x) ((uint32_t*)(x))
|
||||
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
|
||||
#include "aes_via_ace.h"
|
||||
|
||||
#pragma pack(16)
|
||||
|
||||
aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA;
|
||||
aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA;
|
||||
aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA;
|
||||
aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA;
|
||||
aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA;
|
||||
aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA;
|
||||
|
||||
/* NOTE: These control word macros must only be used after */
|
||||
/* a key has been set up because they depend on key size */
|
||||
/* See the VIA ACE documentation for key type information */
|
||||
/* and aes_via_ace.h for non-default NEH_KEY_TYPE values */
|
||||
|
||||
#ifndef NEH_KEY_TYPE
|
||||
#define NEH_KEY_TYPE NEH_HYBRID
|
||||
#endif
|
||||
|
||||
#if NEH_KEY_TYPE == NEH_LOAD
|
||||
#define kd_adr(c) ((uint8_t*)(c)->ks)
|
||||
#elif NEH_KEY_TYPE == NEH_GENERATE
|
||||
#define kd_adr(c) ((uint8_t*)(c)->ks + (c)->inf.b[0])
|
||||
#elif NEH_KEY_TYPE == NEH_HYBRID
|
||||
#define kd_adr(c) ((uint8_t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0))
|
||||
#else
|
||||
#error no key type defined for VIA ACE
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define aligned_array(type, name, no, stride) type name[no]
|
||||
#define aligned_auto(type, name, no, stride) type name[no]
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||
|
||||
#define via_cwd(cwd, ty, dir, len) unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4))
|
||||
|
||||
#else
|
||||
|
||||
#define via_cwd(cwd, ty, dir, len) \
|
||||
aligned_auto(unsigned long, cwd, 4, 16); \
|
||||
cwd[1] = cwd[2] = cwd[3] = 0; \
|
||||
cwd[0] = neh_##dir##_##ty##_key(len)
|
||||
|
||||
#endif
|
||||
|
||||
/* test the code for detecting and setting pointer alignment */
|
||||
|
||||
AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */
|
||||
{
|
||||
uint8_t p[16];
|
||||
uint32_t i = 0, count_eq = 0, count_neq = 0;
|
||||
|
||||
if(n < 4 || n > 16) return EXIT_FAILURE;
|
||||
|
||||
for(i = 0; i < n; ++i) {
|
||||
uint8_t *qf = ALIGN_FLOOR(p + i, n), *qh = ALIGN_CEIL(p + i, n);
|
||||
|
||||
if(qh == qf)
|
||||
++count_eq;
|
||||
else if(qh == qf + n)
|
||||
++count_neq;
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1]) {
|
||||
ctx->inf.b[2] = 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_ecb_encrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
const aes_encrypt_ctx ctx[1]) {
|
||||
int nb = len >> AES_BLOCK_SIZE_P2;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE;
|
||||
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
|
||||
if(ctx->inf.b[1] == 0xff) {
|
||||
uint8_t* ksp = (uint8_t*)(ctx->ks);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE;
|
||||
|
||||
if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) {
|
||||
via_ecb_op5(ksp, cwd, ibuf, obuf, nb);
|
||||
} else {
|
||||
aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip = NULL, *op = NULL;
|
||||
|
||||
while(nb) {
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ecb_op5(ksp, cwd, ip, op, m);
|
||||
|
||||
if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(ASSUME_VIA_ACE_PRESENT)
|
||||
while(nb--) {
|
||||
if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_ecb_decrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
const aes_decrypt_ctx ctx[1]) {
|
||||
int nb = len >> AES_BLOCK_SIZE_P2;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE;
|
||||
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
|
||||
if(ctx->inf.b[1] == 0xff) {
|
||||
uint8_t* ksp = kd_adr(ctx);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE;
|
||||
|
||||
if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) {
|
||||
via_ecb_op5(ksp, cwd, ibuf, obuf, nb);
|
||||
} else {
|
||||
aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip = NULL, *op = NULL;
|
||||
|
||||
while(nb) {
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ecb_op5(ksp, cwd, ip, op, m);
|
||||
|
||||
if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(ASSUME_VIA_ACE_PRESENT)
|
||||
while(nb--) {
|
||||
if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cbc_encrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
const aes_encrypt_ctx ctx[1]) {
|
||||
int nb = len >> AES_BLOCK_SIZE_P2;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE;
|
||||
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
|
||||
if(ctx->inf.b[1] == 0xff) {
|
||||
uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16) && !ALIGN_OFFSET(iv, 16)) {
|
||||
via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);
|
||||
} else {
|
||||
aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip = NULL, *op = NULL;
|
||||
|
||||
while(nb) {
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp);
|
||||
|
||||
if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
if(iv != ivp) memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(ASSUME_VIA_ACE_PRESENT)
|
||||
#ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(iv, 4))
|
||||
while(nb--) {
|
||||
lp32(iv)[0] ^= lp32(ibuf)[0];
|
||||
lp32(iv)[1] ^= lp32(ibuf)[1];
|
||||
lp32(iv)[2] ^= lp32(ibuf)[2];
|
||||
lp32(iv)[3] ^= lp32(ibuf)[3];
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
memcpy(obuf, iv, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while(nb--) {
|
||||
iv[0] ^= ibuf[0];
|
||||
iv[1] ^= ibuf[1];
|
||||
iv[2] ^= ibuf[2];
|
||||
iv[3] ^= ibuf[3];
|
||||
iv[4] ^= ibuf[4];
|
||||
iv[5] ^= ibuf[5];
|
||||
iv[6] ^= ibuf[6];
|
||||
iv[7] ^= ibuf[7];
|
||||
iv[8] ^= ibuf[8];
|
||||
iv[9] ^= ibuf[9];
|
||||
iv[10] ^= ibuf[10];
|
||||
iv[11] ^= ibuf[11];
|
||||
iv[12] ^= ibuf[12];
|
||||
iv[13] ^= ibuf[13];
|
||||
iv[14] ^= ibuf[14];
|
||||
iv[15] ^= ibuf[15];
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
memcpy(obuf, iv, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cbc_decrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
const aes_decrypt_ctx ctx[1]) {
|
||||
unsigned char tmp[AES_BLOCK_SIZE];
|
||||
int nb = len >> AES_BLOCK_SIZE_P2;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE;
|
||||
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
|
||||
if(ctx->inf.b[1] == 0xff) {
|
||||
uint8_t *ksp = kd_adr(ctx), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16) && !ALIGN_OFFSET(iv, 16)) {
|
||||
via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
} else {
|
||||
aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip = NULL, *op = NULL;
|
||||
|
||||
while(nb) {
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cbc_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
if(iv != ivp) memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(ASSUME_VIA_ACE_PRESENT)
|
||||
#ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(iv, 4))
|
||||
while(nb--) {
|
||||
memcpy(tmp, ibuf, AES_BLOCK_SIZE);
|
||||
if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
lp32(obuf)[0] ^= lp32(iv)[0];
|
||||
lp32(obuf)[1] ^= lp32(iv)[1];
|
||||
lp32(obuf)[2] ^= lp32(iv)[2];
|
||||
lp32(obuf)[3] ^= lp32(iv)[3];
|
||||
memcpy(iv, tmp, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while(nb--) {
|
||||
memcpy(tmp, ibuf, AES_BLOCK_SIZE);
|
||||
if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
obuf[0] ^= iv[0];
|
||||
obuf[1] ^= iv[1];
|
||||
obuf[2] ^= iv[2];
|
||||
obuf[3] ^= iv[3];
|
||||
obuf[4] ^= iv[4];
|
||||
obuf[5] ^= iv[5];
|
||||
obuf[6] ^= iv[6];
|
||||
obuf[7] ^= iv[7];
|
||||
obuf[8] ^= iv[8];
|
||||
obuf[9] ^= iv[9];
|
||||
obuf[10] ^= iv[10];
|
||||
obuf[11] ^= iv[11];
|
||||
obuf[12] ^= iv[12];
|
||||
obuf[13] ^= iv[13];
|
||||
obuf[14] ^= iv[14];
|
||||
obuf[15] ^= iv[15];
|
||||
memcpy(iv, tmp, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cfb_encrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
aes_encrypt_ctx ctx[1]) {
|
||||
int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len) {
|
||||
*obuf++ = (iv[b_pos++] ^= *ibuf++);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
|
||||
if(ctx->inf.b[1] == 0xff) {
|
||||
int m;
|
||||
uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) {
|
||||
via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
} else /* input, output or both are unaligned */
|
||||
{
|
||||
aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip = NULL, *op = NULL;
|
||||
|
||||
while(nb) {
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp);
|
||||
|
||||
if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv) memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
#ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(iv, 4))
|
||||
while(cnt + AES_BLOCK_SIZE <= len) {
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0];
|
||||
lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1];
|
||||
lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2];
|
||||
lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len) {
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
obuf[0] = iv[0] ^= ibuf[0];
|
||||
obuf[1] = iv[1] ^= ibuf[1];
|
||||
obuf[2] = iv[2] ^= ibuf[2];
|
||||
obuf[3] = iv[3] ^= ibuf[3];
|
||||
obuf[4] = iv[4] ^= ibuf[4];
|
||||
obuf[5] = iv[5] ^= ibuf[5];
|
||||
obuf[6] = iv[6] ^= ibuf[6];
|
||||
obuf[7] = iv[7] ^= ibuf[7];
|
||||
obuf[8] = iv[8] ^= ibuf[8];
|
||||
obuf[9] = iv[9] ^= ibuf[9];
|
||||
obuf[10] = iv[10] ^= ibuf[10];
|
||||
obuf[11] = iv[11] ^= ibuf[11];
|
||||
obuf[12] = iv[12] ^= ibuf[12];
|
||||
obuf[13] = iv[13] ^= ibuf[13];
|
||||
obuf[14] = iv[14] ^= ibuf[14];
|
||||
obuf[15] = iv[15] ^= ibuf[15];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len) {
|
||||
if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE) {
|
||||
*obuf++ = (iv[b_pos++] ^= *ibuf++);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint8_t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cfb_decrypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
aes_encrypt_ctx ctx[1]) {
|
||||
int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{
|
||||
uint8_t t;
|
||||
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len) {
|
||||
t = *ibuf++;
|
||||
*obuf++ = t ^ iv[b_pos];
|
||||
iv[b_pos++] = t;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
|
||||
if(ctx->inf.b[1] == 0xff) {
|
||||
int m;
|
||||
uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) {
|
||||
via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
} else /* input, output or both are unaligned */
|
||||
{
|
||||
aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip = NULL, *op = NULL;
|
||||
|
||||
while(nb) {
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf) /* input buffer is not aligned */
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cfb_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf) /* output buffer is not aligned */
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv) memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
#ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(iv, 4))
|
||||
while(cnt + AES_BLOCK_SIZE <= len) {
|
||||
uint32_t t;
|
||||
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t;
|
||||
t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t;
|
||||
t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t;
|
||||
t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len) {
|
||||
uint8_t t;
|
||||
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
t = ibuf[0], obuf[0] = t ^ iv[0], iv[0] = t;
|
||||
t = ibuf[1], obuf[1] = t ^ iv[1], iv[1] = t;
|
||||
t = ibuf[2], obuf[2] = t ^ iv[2], iv[2] = t;
|
||||
t = ibuf[3], obuf[3] = t ^ iv[3], iv[3] = t;
|
||||
t = ibuf[4], obuf[4] = t ^ iv[4], iv[4] = t;
|
||||
t = ibuf[5], obuf[5] = t ^ iv[5], iv[5] = t;
|
||||
t = ibuf[6], obuf[6] = t ^ iv[6], iv[6] = t;
|
||||
t = ibuf[7], obuf[7] = t ^ iv[7], iv[7] = t;
|
||||
t = ibuf[8], obuf[8] = t ^ iv[8], iv[8] = t;
|
||||
t = ibuf[9], obuf[9] = t ^ iv[9], iv[9] = t;
|
||||
t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t;
|
||||
t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t;
|
||||
t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t;
|
||||
t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t;
|
||||
t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t;
|
||||
t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len) {
|
||||
uint8_t t;
|
||||
|
||||
if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE) {
|
||||
t = *ibuf++;
|
||||
*obuf++ = t ^ iv[b_pos];
|
||||
iv[b_pos++] = t;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint8_t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_ofb_crypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* iv,
|
||||
aes_encrypt_ctx ctx[1]) {
|
||||
int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len) {
|
||||
*obuf++ = iv[b_pos++] ^ *ibuf++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
|
||||
if(ctx->inf.b[1] == 0xff) {
|
||||
int m;
|
||||
uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET(iv, 16)) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET(ibuf, 16) && !ALIGN_OFFSET(obuf, 16)) {
|
||||
via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
} else /* input, output or both are unaligned */
|
||||
{
|
||||
aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip = NULL, *op = NULL;
|
||||
|
||||
while(nb) {
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (ALIGN_OFFSET(ibuf, 16) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET(obuf, 16) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ofb_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv) memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
#ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(iv, 4))
|
||||
while(cnt + AES_BLOCK_SIZE <= len) {
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0];
|
||||
lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1];
|
||||
lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2];
|
||||
lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len) {
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
obuf[0] = iv[0] ^ ibuf[0];
|
||||
obuf[1] = iv[1] ^ ibuf[1];
|
||||
obuf[2] = iv[2] ^ ibuf[2];
|
||||
obuf[3] = iv[3] ^ ibuf[3];
|
||||
obuf[4] = iv[4] ^ ibuf[4];
|
||||
obuf[5] = iv[5] ^ ibuf[5];
|
||||
obuf[6] = iv[6] ^ ibuf[6];
|
||||
obuf[7] = iv[7] ^ ibuf[7];
|
||||
obuf[8] = iv[8] ^ ibuf[8];
|
||||
obuf[9] = iv[9] ^ ibuf[9];
|
||||
obuf[10] = iv[10] ^ ibuf[10];
|
||||
obuf[11] = iv[11] ^ ibuf[11];
|
||||
obuf[12] = iv[12] ^ ibuf[12];
|
||||
obuf[13] = iv[13] ^ ibuf[13];
|
||||
obuf[14] = iv[14] ^ ibuf[14];
|
||||
obuf[15] = iv[15] ^ ibuf[15];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len) {
|
||||
if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE) {
|
||||
*obuf++ = iv[b_pos++] ^ *ibuf++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint8_t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE)
|
||||
|
||||
AES_RETURN aes_ctr_crypt(
|
||||
const unsigned char* ibuf,
|
||||
unsigned char* obuf,
|
||||
int len,
|
||||
unsigned char* cbuf,
|
||||
cbuf_inc ctr_inc,
|
||||
aes_encrypt_ctx ctx[1]) {
|
||||
unsigned char* ip;
|
||||
int i = 0, blen = 0, b_pos = (int)(ctx->inf.b[2]);
|
||||
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
aligned_auto(uint8_t, buf, BFR_LENGTH, 16);
|
||||
if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET(ctx, 16)) return EXIT_FAILURE;
|
||||
#else
|
||||
uint8_t buf[BFR_LENGTH] = {0};
|
||||
#endif
|
||||
|
||||
if(b_pos) {
|
||||
memcpy(buf, cbuf, AES_BLOCK_SIZE);
|
||||
if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
|
||||
|
||||
while(b_pos < AES_BLOCK_SIZE && len) {
|
||||
*obuf++ = *ibuf++ ^ buf[b_pos++];
|
||||
--len;
|
||||
}
|
||||
|
||||
if(len) ctr_inc(cbuf), b_pos = 0;
|
||||
}
|
||||
|
||||
while(len) {
|
||||
blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen;
|
||||
|
||||
for(i = 0, ip = buf; i < (blen >> AES_BLOCK_SIZE_P2); ++i) {
|
||||
memcpy(ip, cbuf, AES_BLOCK_SIZE);
|
||||
ctr_inc(cbuf);
|
||||
ip += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if(blen & (AES_BLOCK_SIZE - 1)) memcpy(ip, cbuf, AES_BLOCK_SIZE), i++;
|
||||
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
if(ctx->inf.b[1] == 0xff) {
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
via_ecb_op5((ctx->ks), cwd, buf, buf, i);
|
||||
} else
|
||||
#endif
|
||||
if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
i = 0;
|
||||
ip = buf;
|
||||
#ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET(ibuf, 4) && !ALIGN_OFFSET(obuf, 4) && !ALIGN_OFFSET(ip, 4))
|
||||
while(i + AES_BLOCK_SIZE <= blen) {
|
||||
lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0];
|
||||
lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1];
|
||||
lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2];
|
||||
lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3];
|
||||
i += AES_BLOCK_SIZE;
|
||||
ip += AES_BLOCK_SIZE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while(i + AES_BLOCK_SIZE <= blen) {
|
||||
obuf[0] = ibuf[0] ^ ip[0];
|
||||
obuf[1] = ibuf[1] ^ ip[1];
|
||||
obuf[2] = ibuf[2] ^ ip[2];
|
||||
obuf[3] = ibuf[3] ^ ip[3];
|
||||
obuf[4] = ibuf[4] ^ ip[4];
|
||||
obuf[5] = ibuf[5] ^ ip[5];
|
||||
obuf[6] = ibuf[6] ^ ip[6];
|
||||
obuf[7] = ibuf[7] ^ ip[7];
|
||||
obuf[8] = ibuf[8] ^ ip[8];
|
||||
obuf[9] = ibuf[9] ^ ip[9];
|
||||
obuf[10] = ibuf[10] ^ ip[10];
|
||||
obuf[11] = ibuf[11] ^ ip[11];
|
||||
obuf[12] = ibuf[12] ^ ip[12];
|
||||
obuf[13] = ibuf[13] ^ ip[13];
|
||||
obuf[14] = ibuf[14] ^ ip[14];
|
||||
obuf[15] = ibuf[15] ^ ip[15];
|
||||
i += AES_BLOCK_SIZE;
|
||||
ip += AES_BLOCK_SIZE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
while(i++ < blen) *obuf++ = *ibuf++ ^ ip[b_pos++];
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint8_t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void aes_ctr_cbuf_inc(unsigned char* cbuf) {
|
||||
int i = AES_BLOCK_SIZE - 1;
|
||||
while(i >= 0) {
|
||||
cbuf[i]++;
|
||||
if(cbuf[i]) return; // if there was no overflow
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined(USE_INTEL_AES_IF_PRESENT)
|
||||
#include "aes_ni.h"
|
||||
#else
|
||||
/* map names here to provide the external API ('name' -> 'aes_name') */
|
||||
#define aes_xi(x) aes_##x
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define si(y, x, k, c) (s(y, c) = word_in(x, c) ^ (k)[c])
|
||||
#define so(y, x, c) word_out(y, c, s(x, c))
|
||||
|
||||
#if defined(ARRAYS)
|
||||
#define locals(y, x) x[4], y[4]
|
||||
#else
|
||||
#define locals(y, x) x##0, x##1, x##2, x##3, y##0, y##1, y##2, y##3
|
||||
#endif
|
||||
|
||||
#define l_copy(y, x) \
|
||||
s(y, 0) = s(x, 0); \
|
||||
s(y, 1) = s(x, 1); \
|
||||
s(y, 2) = s(x, 2); \
|
||||
s(y, 3) = s(x, 3);
|
||||
#define state_in(y, x, k) \
|
||||
si(y, x, k, 0); \
|
||||
si(y, x, k, 1); \
|
||||
si(y, x, k, 2); \
|
||||
si(y, x, k, 3)
|
||||
#define state_out(y, x) \
|
||||
so(y, x, 0); \
|
||||
so(y, x, 1); \
|
||||
so(y, x, 2); \
|
||||
so(y, x, 3)
|
||||
#define round(rm, y, x, k) \
|
||||
rm(y, x, k, 0); \
|
||||
rm(y, x, k, 1); \
|
||||
rm(y, x, k, 2); \
|
||||
rm(y, x, k, 3)
|
||||
|
||||
#if(FUNCS_IN_C & ENCRYPTION_IN_C)
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_WIN64) && !defined(__clang__)
|
||||
#pragma optimize("s", on)
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define fwd_var(x, r, c) \
|
||||
(r == 0 ? (c == 0 ? s(x, 0) : \
|
||||
c == 1 ? s(x, 1) : \
|
||||
c == 2 ? s(x, 2) : \
|
||||
s(x, 3)) : \
|
||||
r == 1 ? (c == 0 ? s(x, 1) : \
|
||||
c == 1 ? s(x, 2) : \
|
||||
c == 2 ? s(x, 3) : \
|
||||
s(x, 0)) : \
|
||||
r == 2 ? (c == 0 ? s(x, 2) : \
|
||||
c == 1 ? s(x, 3) : \
|
||||
c == 2 ? s(x, 0) : \
|
||||
s(x, 1)) : \
|
||||
(c == 0 ? s(x, 3) : \
|
||||
c == 1 ? s(x, 0) : \
|
||||
c == 2 ? s(x, 1) : \
|
||||
s(x, 2)))
|
||||
|
||||
#if defined(FT4_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y, x, k, c) (s(y, c) = (k)[c] ^ four_tables(x, t_use(f, n), fwd_var, rf1, c))
|
||||
#elif defined(FT1_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y, x, k, c) (s(y, c) = (k)[c] ^ one_table(x, upr, t_use(f, n), fwd_var, rf1, c))
|
||||
#else
|
||||
#define fwd_rnd(y, x, k, c) \
|
||||
(s(y, c) = (k)[c] ^ fwd_mcol(no_table(x, t_use(s, box), fwd_var, rf1, c)))
|
||||
#endif
|
||||
|
||||
#if defined(FL4_SET)
|
||||
#define fwd_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ four_tables(x, t_use(f, l), fwd_var, rf1, c))
|
||||
#elif defined(FL1_SET)
|
||||
#define fwd_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ one_table(x, ups, t_use(f, l), fwd_var, rf1, c))
|
||||
#else
|
||||
#define fwd_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ no_table(x, t_use(s, box), fwd_var, rf1, c))
|
||||
#endif
|
||||
|
||||
AES_RETURN
|
||||
aes_xi(encrypt)(const unsigned char* in, unsigned char* out, const aes_encrypt_ctx cx[1]) {
|
||||
uint32_t locals(b0, b1);
|
||||
const uint32_t* kp = NULL;
|
||||
#if defined(dec_fmvars)
|
||||
dec_fmvars; /* declare variables for fwd_mcol() if needed */
|
||||
#endif
|
||||
|
||||
if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE &&
|
||||
cx->inf.b[0] != 14 * AES_BLOCK_SIZE)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
kp = cx->ks;
|
||||
state_in(b0, in, kp);
|
||||
|
||||
#if(ENC_UNROLL == FULL)
|
||||
|
||||
switch(cx->inf.b[0]) {
|
||||
case 14 * AES_BLOCK_SIZE:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
//-fallthrough
|
||||
case 12 * AES_BLOCK_SIZE:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
//-fallthrough
|
||||
case 10 * AES_BLOCK_SIZE:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 3 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 4 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 5 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 6 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 7 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 8 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 9 * N_COLS);
|
||||
round(fwd_lrnd, b0, b1, kp + 10 * N_COLS);
|
||||
//-fallthrough
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if(ENC_UNROLL == PARTIAL)
|
||||
{
|
||||
uint32_t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) {
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b0, b1, kp);
|
||||
}
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
#else
|
||||
{
|
||||
uint32_t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) {
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp += N_COLS;
|
||||
round(fwd_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out, b0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if(FUNCS_IN_C & DECRYPTION_IN_C)
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_WIN64) && !defined(__clang__)
|
||||
#pragma optimize("t", on)
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define inv_var(x, r, c) \
|
||||
(r == 0 ? (c == 0 ? s(x, 0) : \
|
||||
c == 1 ? s(x, 1) : \
|
||||
c == 2 ? s(x, 2) : \
|
||||
s(x, 3)) : \
|
||||
r == 1 ? (c == 0 ? s(x, 3) : \
|
||||
c == 1 ? s(x, 0) : \
|
||||
c == 2 ? s(x, 1) : \
|
||||
s(x, 2)) : \
|
||||
r == 2 ? (c == 0 ? s(x, 2) : \
|
||||
c == 1 ? s(x, 3) : \
|
||||
c == 2 ? s(x, 0) : \
|
||||
s(x, 1)) : \
|
||||
(c == 0 ? s(x, 1) : \
|
||||
c == 1 ? s(x, 2) : \
|
||||
c == 2 ? s(x, 3) : \
|
||||
s(x, 0)))
|
||||
|
||||
#if defined(IT4_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y, x, k, c) (s(y, c) = (k)[c] ^ four_tables(x, t_use(i, n), inv_var, rf1, c))
|
||||
#elif defined(IT1_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y, x, k, c) (s(y, c) = (k)[c] ^ one_table(x, upr, t_use(i, n), inv_var, rf1, c))
|
||||
#else
|
||||
#define inv_rnd(y, x, k, c) \
|
||||
(s(y, c) = inv_mcol((k)[c] ^ no_table(x, t_use(i, box), inv_var, rf1, c)))
|
||||
#endif
|
||||
|
||||
#if defined(IL4_SET)
|
||||
#define inv_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ four_tables(x, t_use(i, l), inv_var, rf1, c))
|
||||
#elif defined(IL1_SET)
|
||||
#define inv_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ one_table(x, ups, t_use(i, l), inv_var, rf1, c))
|
||||
#else
|
||||
#define inv_lrnd(y, x, k, c) (s(y, c) = (k)[c] ^ no_table(x, t_use(i, box), inv_var, rf1, c))
|
||||
#endif
|
||||
|
||||
/* This code can work with the decryption key schedule in the */
|
||||
/* order that is used for encrytpion (where the 1st decryption */
|
||||
/* round key is at the high end ot the schedule) or with a key */
|
||||
/* schedule that has been reversed to put the 1st decryption */
|
||||
/* round key at the low end of the schedule in memory (when */
|
||||
/* AES_REV_DKS is defined) */
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define key_ofs 0
|
||||
#define rnd_key(n) (kp + n * N_COLS)
|
||||
#else
|
||||
#define key_ofs 1
|
||||
#define rnd_key(n) (kp - n * N_COLS)
|
||||
#endif
|
||||
|
||||
AES_RETURN
|
||||
aes_xi(decrypt)(const unsigned char* in, unsigned char* out, const aes_decrypt_ctx cx[1]) {
|
||||
uint32_t locals(b0, b1);
|
||||
#if defined(dec_imvars)
|
||||
dec_imvars; /* declare variables for inv_mcol() if needed */
|
||||
#endif
|
||||
const uint32_t* kp = NULL;
|
||||
|
||||
if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE &&
|
||||
cx->inf.b[0] != 14 * AES_BLOCK_SIZE)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0);
|
||||
state_in(b0, in, kp);
|
||||
|
||||
#if(DEC_UNROLL == FULL)
|
||||
|
||||
kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2));
|
||||
switch(cx->inf.b[0]) {
|
||||
case 14 * AES_BLOCK_SIZE:
|
||||
round(inv_rnd, b1, b0, rnd_key(-13));
|
||||
round(inv_rnd, b0, b1, rnd_key(-12));
|
||||
//-fallthrough
|
||||
case 12 * AES_BLOCK_SIZE:
|
||||
round(inv_rnd, b1, b0, rnd_key(-11));
|
||||
round(inv_rnd, b0, b1, rnd_key(-10));
|
||||
//-fallthrough
|
||||
case 10 * AES_BLOCK_SIZE:
|
||||
round(inv_rnd, b1, b0, rnd_key(-9));
|
||||
round(inv_rnd, b0, b1, rnd_key(-8));
|
||||
round(inv_rnd, b1, b0, rnd_key(-7));
|
||||
round(inv_rnd, b0, b1, rnd_key(-6));
|
||||
round(inv_rnd, b1, b0, rnd_key(-5));
|
||||
round(inv_rnd, b0, b1, rnd_key(-4));
|
||||
round(inv_rnd, b1, b0, rnd_key(-3));
|
||||
round(inv_rnd, b0, b1, rnd_key(-2));
|
||||
round(inv_rnd, b1, b0, rnd_key(-1));
|
||||
round(inv_lrnd, b0, b1, rnd_key(0));
|
||||
//-fallthrough
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if(DEC_UNROLL == PARTIAL)
|
||||
{
|
||||
uint32_t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) {
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b0, b1, kp);
|
||||
}
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
#else
|
||||
{
|
||||
uint32_t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) {
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp = rnd_key(1);
|
||||
round(inv_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out, b0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,662 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined(USE_INTEL_AES_IF_PRESENT)
|
||||
#include "aes_ni.h"
|
||||
#else
|
||||
/* map names here to provide the external API ('name' -> 'aes_name') */
|
||||
#define aes_xi(x) aes_##x
|
||||
#endif
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
#include "aes_via_ace.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initialise the key schedule from the user supplied key. The key
|
||||
length can be specified in bytes, with legal values of 16, 24
|
||||
and 32, or in bits, with legal values of 128, 192 and 256. These
|
||||
values correspond with Nk values of 4, 6 and 8 respectively.
|
||||
|
||||
The following macros implement a single cycle in the key
|
||||
schedule generation process. The number of cycles needed
|
||||
for each cx->n_col and nk value is:
|
||||
|
||||
nk = 4 5 6 7 8
|
||||
------------------------------
|
||||
cx->n_col = 4 10 9 8 7 7
|
||||
cx->n_col = 5 14 11 10 9 9
|
||||
cx->n_col = 6 19 15 12 11 11
|
||||
cx->n_col = 7 21 19 16 13 14
|
||||
cx->n_col = 8 29 23 19 17 14
|
||||
*/
|
||||
|
||||
#if defined(REDUCE_CODE_SIZE)
|
||||
#define ls_box ls_sub
|
||||
uint32_t ls_sub(const uint32_t t, const uint32_t n);
|
||||
#define inv_mcol im_sub
|
||||
uint32_t im_sub(const uint32_t x);
|
||||
#ifdef ENC_KS_UNROLL
|
||||
#undef ENC_KS_UNROLL
|
||||
#endif
|
||||
#ifdef DEC_KS_UNROLL
|
||||
#undef DEC_KS_UNROLL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if(FUNCS_IN_C & ENC_KEYING_IN_C)
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
|
||||
#define ke4(k, i) \
|
||||
{ \
|
||||
k[4 * (i) + 4] = ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
k[4 * (i) + 5] = ss[1] ^= ss[0]; \
|
||||
k[4 * (i) + 6] = ss[2] ^= ss[1]; \
|
||||
k[4 * (i) + 7] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(encrypt_key128)(const unsigned char* key, aes_encrypt_ctx cx[1]) {
|
||||
uint32_t ss[4];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke4(cx->ks, 0);
|
||||
ke4(cx->ks, 1);
|
||||
ke4(cx->ks, 2);
|
||||
ke4(cx->ks, 3);
|
||||
ke4(cx->ks, 4);
|
||||
ke4(cx->ks, 5);
|
||||
ke4(cx->ks, 6);
|
||||
ke4(cx->ks, 7);
|
||||
ke4(cx->ks, 8);
|
||||
#else
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < 9; ++i) ke4(cx->ks, i);
|
||||
}
|
||||
#endif
|
||||
ke4(cx->ks, 9);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 10 * AES_BLOCK_SIZE;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
|
||||
#define kef6(k, i) \
|
||||
{ \
|
||||
k[6 * (i) + 6] = ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
k[6 * (i) + 7] = ss[1] ^= ss[0]; \
|
||||
k[6 * (i) + 8] = ss[2] ^= ss[1]; \
|
||||
k[6 * (i) + 9] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke6(k, i) \
|
||||
{ \
|
||||
kef6(k, i); \
|
||||
k[6 * (i) + 10] = ss[4] ^= ss[3]; \
|
||||
k[6 * (i) + 11] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(encrypt_key192)(const unsigned char* key, aes_encrypt_ctx cx[1]) {
|
||||
uint32_t ss[6];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(key, 5);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke6(cx->ks, 0);
|
||||
ke6(cx->ks, 1);
|
||||
ke6(cx->ks, 2);
|
||||
ke6(cx->ks, 3);
|
||||
ke6(cx->ks, 4);
|
||||
ke6(cx->ks, 5);
|
||||
ke6(cx->ks, 6);
|
||||
#else
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < 7; ++i) ke6(cx->ks, i);
|
||||
}
|
||||
#endif
|
||||
kef6(cx->ks, 7);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 12 * AES_BLOCK_SIZE;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
|
||||
#define kef8(k, i) \
|
||||
{ \
|
||||
k[8 * (i) + 8] = ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
k[8 * (i) + 9] = ss[1] ^= ss[0]; \
|
||||
k[8 * (i) + 10] = ss[2] ^= ss[1]; \
|
||||
k[8 * (i) + 11] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke8(k, i) \
|
||||
{ \
|
||||
kef8(k, i); \
|
||||
k[8 * (i) + 12] = ss[4] ^= ls_box(ss[3], 0); \
|
||||
k[8 * (i) + 13] = ss[5] ^= ss[4]; \
|
||||
k[8 * (i) + 14] = ss[6] ^= ss[5]; \
|
||||
k[8 * (i) + 15] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(encrypt_key256)(const unsigned char* key, aes_encrypt_ctx cx[1]) {
|
||||
uint32_t ss[8];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(key, 5);
|
||||
cx->ks[6] = ss[6] = word_in(key, 6);
|
||||
cx->ks[7] = ss[7] = word_in(key, 7);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke8(cx->ks, 0);
|
||||
ke8(cx->ks, 1);
|
||||
ke8(cx->ks, 2);
|
||||
ke8(cx->ks, 3);
|
||||
ke8(cx->ks, 4);
|
||||
ke8(cx->ks, 5);
|
||||
#else
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < 6; ++i) ke8(cx->ks, i);
|
||||
}
|
||||
#endif
|
||||
kef8(cx->ks, 6);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 14 * AES_BLOCK_SIZE;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if(FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
|
||||
/* this is used to store the decryption round keys */
|
||||
/* in forward or reverse order */
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define v(n, i) ((n) - (i) + 2 * ((i)&3))
|
||||
#else
|
||||
#define v(n, i) (i)
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES
|
||||
#define ff(x) (x)
|
||||
#else
|
||||
#define ff(x) inv_mcol(x)
|
||||
#if defined(dec_imvars)
|
||||
#define d_vars dec_imvars
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
|
||||
#define k4e(k, i) \
|
||||
{ \
|
||||
k[v(40, (4 * (i)) + 4)] = ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ss[1] ^= ss[0]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ss[2] ^= ss[1]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
#define kdf4(k, i) \
|
||||
{ \
|
||||
ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \
|
||||
ss[1] = ss[1] ^ ss[3]; \
|
||||
ss[2] = ss[2] ^ ss[3]; \
|
||||
ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; \
|
||||
ss[4] ^= k[v(40, (4 * (i)))]; \
|
||||
k[v(40, (4 * (i)) + 4)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40, (4 * (i)) + 1)]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40, (4 * (i)) + 2)]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40, (4 * (i)) + 3)]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ff(ss[4]); \
|
||||
}
|
||||
|
||||
#define kd4(k, i) \
|
||||
{ \
|
||||
ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; \
|
||||
ss[4] = ff(ss[4]); \
|
||||
k[v(40, (4 * (i)) + 4)] = ss[4] ^= k[v(40, (4 * (i)))]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ss[4] ^= k[v(40, (4 * (i)) + 1)]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ss[4] ^= k[v(40, (4 * (i)) + 2)]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ss[4] ^= k[v(40, (4 * (i)) + 3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k, i) \
|
||||
{ \
|
||||
ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; \
|
||||
k[v(40, (4 * (i)) + 4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ss[1] ^ ss[3]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ss[0]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ss[1]; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define kdf4(k, i) \
|
||||
{ \
|
||||
ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(40, (4 * (i)) + 4)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ff(ss[3]); \
|
||||
}
|
||||
|
||||
#define kd4(k, i) \
|
||||
{ \
|
||||
ss[4] = ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
ss[0] ^= ss[4]; \
|
||||
ss[4] = ff(ss[4]); \
|
||||
k[v(40, (4 * (i)) + 4)] = ss[4] ^= k[v(40, (4 * (i)))]; \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ss[4] ^= k[v(40, (4 * (i)) + 1)]; \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ss[4] ^= k[v(40, (4 * (i)) + 2)]; \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ss[4] ^= k[v(40, (4 * (i)) + 3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k, i) \
|
||||
{ \
|
||||
ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(40, (4 * (i)) + 4)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ss[3]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_xi(decrypt_key128)(const unsigned char* key, aes_decrypt_ctx cx[1]) {
|
||||
uint32_t ss[5];
|
||||
#if defined(d_vars)
|
||||
d_vars;
|
||||
#endif
|
||||
|
||||
cx->ks[v(40, (0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(40, (1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(40, (2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(40, (3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
kdf4(cx->ks, 0);
|
||||
kd4(cx->ks, 1);
|
||||
kd4(cx->ks, 2);
|
||||
kd4(cx->ks, 3);
|
||||
kd4(cx->ks, 4);
|
||||
kd4(cx->ks, 5);
|
||||
kd4(cx->ks, 6);
|
||||
kd4(cx->ks, 7);
|
||||
kd4(cx->ks, 8);
|
||||
kdl4(cx->ks, 9);
|
||||
#else
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < 10; ++i) k4e(cx->ks, i);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 10 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 10 * AES_BLOCK_SIZE;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
|
||||
#define k6ef(k, i) \
|
||||
{ \
|
||||
k[v(48, (6 * (i)) + 6)] = ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(48, (6 * (i)) + 7)] = ss[1] ^= ss[0]; \
|
||||
k[v(48, (6 * (i)) + 8)] = ss[2] ^= ss[1]; \
|
||||
k[v(48, (6 * (i)) + 9)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k6e(k, i) \
|
||||
{ \
|
||||
k6ef(k, i); \
|
||||
k[v(48, (6 * (i)) + 10)] = ss[4] ^= ss[3]; \
|
||||
k[v(48, (6 * (i)) + 11)] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
#define kdf6(k, i) \
|
||||
{ \
|
||||
ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(48, (6 * (i)) + 6)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(48, (6 * (i)) + 7)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(48, (6 * (i)) + 8)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(48, (6 * (i)) + 9)] = ff(ss[3]); \
|
||||
ss[4] ^= ss[3]; \
|
||||
k[v(48, (6 * (i)) + 10)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; \
|
||||
k[v(48, (6 * (i)) + 11)] = ff(ss[5]); \
|
||||
}
|
||||
|
||||
#define kd6(k, i) \
|
||||
{ \
|
||||
ss[6] = ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
ss[0] ^= ss[6]; \
|
||||
ss[6] = ff(ss[6]); \
|
||||
k[v(48, (6 * (i)) + 6)] = ss[6] ^= k[v(48, (6 * (i)))]; \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(48, (6 * (i)) + 7)] = ss[6] ^= k[v(48, (6 * (i)) + 1)]; \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(48, (6 * (i)) + 8)] = ss[6] ^= k[v(48, (6 * (i)) + 2)]; \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(48, (6 * (i)) + 9)] = ss[6] ^= k[v(48, (6 * (i)) + 3)]; \
|
||||
ss[4] ^= ss[3]; \
|
||||
k[v(48, (6 * (i)) + 10)] = ss[6] ^= k[v(48, (6 * (i)) + 4)]; \
|
||||
ss[5] ^= ss[4]; \
|
||||
k[v(48, (6 * (i)) + 11)] = ss[6] ^= k[v(48, (6 * (i)) + 5)]; \
|
||||
}
|
||||
|
||||
#define kdl6(k, i) \
|
||||
{ \
|
||||
ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(48, (6 * (i)) + 6)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(48, (6 * (i)) + 7)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(48, (6 * (i)) + 8)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(48, (6 * (i)) + 9)] = ss[3]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(decrypt_key192)(const unsigned char* key, aes_decrypt_ctx cx[1]) {
|
||||
uint32_t ss[7];
|
||||
#if defined(d_vars)
|
||||
d_vars;
|
||||
#endif
|
||||
|
||||
cx->ks[v(48, (0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(48, (1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(48, (2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(48, (3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
ss[4] = word_in(key, 4);
|
||||
ss[5] = word_in(key, 5);
|
||||
cx->ks[v(48, (4))] = ff(ss[4]);
|
||||
cx->ks[v(48, (5))] = ff(ss[5]);
|
||||
kdf6(cx->ks, 0);
|
||||
kd6(cx->ks, 1);
|
||||
kd6(cx->ks, 2);
|
||||
kd6(cx->ks, 3);
|
||||
kd6(cx->ks, 4);
|
||||
kd6(cx->ks, 5);
|
||||
kd6(cx->ks, 6);
|
||||
kdl6(cx->ks, 7);
|
||||
#else
|
||||
cx->ks[v(48, (4))] = ss[4] = word_in(key, 4);
|
||||
cx->ks[v(48, (5))] = ss[5] = word_in(key, 5);
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for(i = 0; i < 7; ++i) k6e(cx->ks, i);
|
||||
k6ef(cx->ks, 7);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 12 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 12 * AES_BLOCK_SIZE;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
|
||||
#define k8ef(k, i) \
|
||||
{ \
|
||||
k[v(56, (8 * (i)) + 8)] = ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(56, (8 * (i)) + 9)] = ss[1] ^= ss[0]; \
|
||||
k[v(56, (8 * (i)) + 10)] = ss[2] ^= ss[1]; \
|
||||
k[v(56, (8 * (i)) + 11)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k8e(k, i) \
|
||||
{ \
|
||||
k8ef(k, i); \
|
||||
k[v(56, (8 * (i)) + 12)] = ss[4] ^= ls_box(ss[3], 0); \
|
||||
k[v(56, (8 * (i)) + 13)] = ss[5] ^= ss[4]; \
|
||||
k[v(56, (8 * (i)) + 14)] = ss[6] ^= ss[5]; \
|
||||
k[v(56, (8 * (i)) + 15)] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
#define kdf8(k, i) \
|
||||
{ \
|
||||
ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(56, (8 * (i)) + 8)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(56, (8 * (i)) + 9)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(56, (8 * (i)) + 10)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(56, (8 * (i)) + 11)] = ff(ss[3]); \
|
||||
ss[4] ^= ls_box(ss[3], 0); \
|
||||
k[v(56, (8 * (i)) + 12)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; \
|
||||
k[v(56, (8 * (i)) + 13)] = ff(ss[5]); \
|
||||
ss[6] ^= ss[5]; \
|
||||
k[v(56, (8 * (i)) + 14)] = ff(ss[6]); \
|
||||
ss[7] ^= ss[6]; \
|
||||
k[v(56, (8 * (i)) + 15)] = ff(ss[7]); \
|
||||
}
|
||||
|
||||
#define kd8(k, i) \
|
||||
{ \
|
||||
ss[8] = ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
ss[0] ^= ss[8]; \
|
||||
ss[8] = ff(ss[8]); \
|
||||
k[v(56, (8 * (i)) + 8)] = ss[8] ^= k[v(56, (8 * (i)))]; \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(56, (8 * (i)) + 9)] = ss[8] ^= k[v(56, (8 * (i)) + 1)]; \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(56, (8 * (i)) + 10)] = ss[8] ^= k[v(56, (8 * (i)) + 2)]; \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(56, (8 * (i)) + 11)] = ss[8] ^= k[v(56, (8 * (i)) + 3)]; \
|
||||
ss[8] = ls_box(ss[3], 0); \
|
||||
ss[4] ^= ss[8]; \
|
||||
ss[8] = ff(ss[8]); \
|
||||
k[v(56, (8 * (i)) + 12)] = ss[8] ^= k[v(56, (8 * (i)) + 4)]; \
|
||||
ss[5] ^= ss[4]; \
|
||||
k[v(56, (8 * (i)) + 13)] = ss[8] ^= k[v(56, (8 * (i)) + 5)]; \
|
||||
ss[6] ^= ss[5]; \
|
||||
k[v(56, (8 * (i)) + 14)] = ss[8] ^= k[v(56, (8 * (i)) + 6)]; \
|
||||
ss[7] ^= ss[6]; \
|
||||
k[v(56, (8 * (i)) + 15)] = ss[8] ^= k[v(56, (8 * (i)) + 7)]; \
|
||||
}
|
||||
|
||||
#define kdl8(k, i) \
|
||||
{ \
|
||||
ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(56, (8 * (i)) + 8)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(56, (8 * (i)) + 9)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(56, (8 * (i)) + 10)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(56, (8 * (i)) + 11)] = ss[3]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(decrypt_key256)(const unsigned char* key, aes_decrypt_ctx cx[1]) {
|
||||
uint32_t ss[9];
|
||||
#if defined(d_vars)
|
||||
d_vars;
|
||||
#endif
|
||||
|
||||
cx->ks[v(56, (0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(56, (1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(56, (2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(56, (3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
ss[4] = word_in(key, 4);
|
||||
ss[5] = word_in(key, 5);
|
||||
ss[6] = word_in(key, 6);
|
||||
ss[7] = word_in(key, 7);
|
||||
cx->ks[v(56, (4))] = ff(ss[4]);
|
||||
cx->ks[v(56, (5))] = ff(ss[5]);
|
||||
cx->ks[v(56, (6))] = ff(ss[6]);
|
||||
cx->ks[v(56, (7))] = ff(ss[7]);
|
||||
kdf8(cx->ks, 0);
|
||||
kd8(cx->ks, 1);
|
||||
kd8(cx->ks, 2);
|
||||
kd8(cx->ks, 3);
|
||||
kd8(cx->ks, 4);
|
||||
kd8(cx->ks, 5);
|
||||
kdl8(cx->ks, 6);
|
||||
#else
|
||||
cx->ks[v(56, (4))] = ss[4] = word_in(key, 4);
|
||||
cx->ks[v(56, (5))] = ss[5] = word_in(key, 5);
|
||||
cx->ks[v(56, (6))] = ss[6] = word_in(key, 6);
|
||||
cx->ks[v(56, (7))] = ss[7] = word_in(key, 7);
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for(i = 0; i < 6; ++i) k8e(cx->ks, i);
|
||||
k8ef(cx->ks, 6);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 14 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 14 * AES_BLOCK_SIZE;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_VAR)
|
||||
|
||||
AES_RETURN aes_encrypt_key(const unsigned char* key, int key_len, aes_encrypt_ctx cx[1]) {
|
||||
switch(key_len) {
|
||||
case 16:
|
||||
case 128:
|
||||
return aes_encrypt_key128(key, cx);
|
||||
case 24:
|
||||
case 192:
|
||||
return aes_encrypt_key192(key, cx);
|
||||
case 32:
|
||||
case 256:
|
||||
return aes_encrypt_key256(key, cx);
|
||||
default:
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
AES_RETURN aes_decrypt_key(const unsigned char* key, int key_len, aes_decrypt_ctx cx[1]) {
|
||||
switch(key_len) {
|
||||
case 16:
|
||||
case 128:
|
||||
return aes_decrypt_key128(key, cx);
|
||||
case 24:
|
||||
case 192:
|
||||
return aes_decrypt_key192(key, cx);
|
||||
case 32:
|
||||
case 256:
|
||||
return aes_decrypt_key256(key, cx);
|
||||
default:
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,793 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the compilation options for AES (Rijndael) and code
|
||||
that is common across encryption, key scheduling and table generation.
|
||||
|
||||
OPERATION
|
||||
|
||||
These source code files implement the AES algorithm Rijndael designed by
|
||||
Joan Daemen and Vincent Rijmen. This version is designed for the standard
|
||||
block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24
|
||||
and 32 bytes).
|
||||
|
||||
This version is designed for flexibility and speed using operations on
|
||||
32-bit words rather than operations on bytes. It can be compiled with
|
||||
either big or little endian internal byte order but is faster when the
|
||||
native byte order for the processor is used.
|
||||
|
||||
THE CIPHER INTERFACE
|
||||
|
||||
The cipher interface is implemented as an array of bytes in which lower
|
||||
AES bit sequence indexes map to higher numeric significance within bytes.
|
||||
|
||||
uint8_t (an unsigned 8-bit type)
|
||||
uint32_t (an unsigned 32-bit type)
|
||||
struct aes_encrypt_ctx (structure for the cipher encryption context)
|
||||
struct aes_decrypt_ctx (structure for the cipher decryption context)
|
||||
AES_RETURN the function return type
|
||||
|
||||
C subroutine calls:
|
||||
|
||||
AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out,
|
||||
const aes_decrypt_ctx cx[1]);
|
||||
|
||||
IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that
|
||||
you call aes_init() before AES is used so that the tables are initialised.
|
||||
|
||||
C++ aes class subroutines:
|
||||
|
||||
Class AESencrypt for encryption
|
||||
|
||||
Constructors:
|
||||
AESencrypt(void)
|
||||
AESencrypt(const unsigned char *key) - 128 bit key
|
||||
Members:
|
||||
AES_RETURN key128(const unsigned char *key)
|
||||
AES_RETURN key192(const unsigned char *key)
|
||||
AES_RETURN key256(const unsigned char *key)
|
||||
AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const
|
||||
|
||||
Class AESdecrypt for encryption
|
||||
Constructors:
|
||||
AESdecrypt(void)
|
||||
AESdecrypt(const unsigned char *key) - 128 bit key
|
||||
Members:
|
||||
AES_RETURN key128(const unsigned char *key)
|
||||
AES_RETURN key192(const unsigned char *key)
|
||||
AES_RETURN key256(const unsigned char *key)
|
||||
AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const
|
||||
*/
|
||||
|
||||
#if !defined(_AESOPT_H)
|
||||
#define _AESOPT_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "aescpp.h"
|
||||
#else
|
||||
#include "aes.h"
|
||||
#endif
|
||||
|
||||
/* PLATFORM SPECIFIC INCLUDES */
|
||||
|
||||
#define IS_BIG_ENDIAN 4321
|
||||
#define IS_LITTLE_ENDIAN 1234
|
||||
#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
|
||||
/* CONFIGURATION - THE USE OF DEFINES
|
||||
|
||||
Later in this section there are a number of defines that control the
|
||||
operation of the code. In each section, the purpose of each define is
|
||||
explained so that the relevant form can be included or excluded by
|
||||
setting either 1's or 0's respectively on the branches of the related
|
||||
#if clauses. The following local defines should not be changed.
|
||||
*/
|
||||
|
||||
#define ENCRYPTION_IN_C 1
|
||||
#define DECRYPTION_IN_C 2
|
||||
#define ENC_KEYING_IN_C 4
|
||||
#define DEC_KEYING_IN_C 8
|
||||
|
||||
#define NO_TABLES 0
|
||||
#define ONE_TABLE 1
|
||||
#define FOUR_TABLES 4
|
||||
#define NONE 0
|
||||
#define PARTIAL 1
|
||||
#define FULL 2
|
||||
|
||||
/* --- START OF USER CONFIGURED OPTIONS --- */
|
||||
|
||||
/* 1. BYTE ORDER WITHIN 32 BIT WORDS
|
||||
|
||||
The fundamental data processing units in Rijndael are 8-bit bytes. The
|
||||
input, output and key input are all enumerated arrays of bytes in which
|
||||
bytes are numbered starting at zero and increasing to one less than the
|
||||
number of bytes in the array in question. This enumeration is only used
|
||||
for naming bytes and does not imply any adjacency or order relationship
|
||||
from one byte to another. When these inputs and outputs are considered
|
||||
as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
|
||||
byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
|
||||
In this implementation bits are numbered from 0 to 7 starting at the
|
||||
numerically least significant end of each byte (bit n represents 2^n).
|
||||
|
||||
However, Rijndael can be implemented more efficiently using 32-bit
|
||||
words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
|
||||
into word[n]. While in principle these bytes can be assembled into words
|
||||
in any positions, this implementation only supports the two formats in
|
||||
which bytes in adjacent positions within words also have adjacent byte
|
||||
numbers. This order is called big-endian if the lowest numbered bytes
|
||||
in words have the highest numeric significance and little-endian if the
|
||||
opposite applies.
|
||||
|
||||
This code can work in either order irrespective of the order used by the
|
||||
machine on which it runs. Normally the internal byte order will be set
|
||||
to the order of the processor on which the code is to be run but this
|
||||
define can be used to reverse this in special situations
|
||||
|
||||
WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set.
|
||||
This define will hence be redefined later (in section 4) if necessary
|
||||
*/
|
||||
|
||||
#if 1
|
||||
#define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#elif 0
|
||||
#define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#elif 0
|
||||
#define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#else
|
||||
#error The algorithm byte order is not defined
|
||||
#endif
|
||||
|
||||
/* 2. Intel AES AND VIA ACE SUPPORT */
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__) && !defined(__BEOS__) || \
|
||||
defined(_WIN32) && defined(_M_IX86) && \
|
||||
!(defined(_WIN64) || defined(_WIN32_WCE) || defined(_MSC_VER) && (_MSC_VER <= 800))
|
||||
#define VIA_ACE_POSSIBLE
|
||||
#endif
|
||||
|
||||
/* AESNI is supported by all Windows x64 compilers, but for Linux/GCC
|
||||
we have to test for SSE 2, SSE 3, and AES to before enabling it; */
|
||||
#if !defined(INTEL_AES_POSSIBLE)
|
||||
#if defined(_WIN64) && defined(_MSC_VER) || defined(__GNUC__) && defined(__x86_64__) && \
|
||||
defined(__SSE2__) && defined(__SSE3__) && \
|
||||
defined(__AES__)
|
||||
#define INTEL_AES_POSSIBLE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define this option if support for the Intel AESNI is required
|
||||
If USE_INTEL_AES_IF_PRESENT is defined then AESNI will be used
|
||||
if it is detected (both present and enabled).
|
||||
|
||||
AESNI uses a decryption key schedule with the first decryption
|
||||
round key at the high end of the key scedule with the following
|
||||
round keys at lower positions in memory. So AES_REV_DKS must NOT
|
||||
be defined when AESNI will be used. Although it is unlikely that
|
||||
assembler code will be used with an AESNI build, if it is then
|
||||
AES_REV_DKS must NOT be defined when the assembler files are
|
||||
built (the definition of USE_INTEL_AES_IF_PRESENT in the assembler
|
||||
code files must match that here if they are used).
|
||||
*/
|
||||
|
||||
#if 0 && defined(INTEL_AES_POSSIBLE) && !defined(USE_INTEL_AES_IF_PRESENT)
|
||||
#define USE_INTEL_AES_IF_PRESENT
|
||||
#endif
|
||||
|
||||
/* Define this option if support for the VIA ACE is required. This uses
|
||||
inline assembler instructions and is only implemented for the Microsoft,
|
||||
Intel and GCC compilers. If VIA ACE is known to be present, then defining
|
||||
ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption
|
||||
code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if
|
||||
it is detected (both present and enabled) but the normal AES code will
|
||||
also be present.
|
||||
|
||||
When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte
|
||||
aligned; other input/output buffers do not need to be 16 byte aligned
|
||||
but there are very large performance gains if this can be arranged.
|
||||
VIA ACE also requires the decryption key schedule to be in reverse
|
||||
order (which later checks below ensure).
|
||||
|
||||
AES_REV_DKS must be set for assembler code used with a VIA ACE build
|
||||
*/
|
||||
|
||||
#if 0 && defined(VIA_ACE_POSSIBLE) && !defined(USE_VIA_ACE_IF_PRESENT)
|
||||
#define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
#if 0 && defined(VIA_ACE_POSSIBLE) && !defined(ASSUME_VIA_ACE_PRESENT)
|
||||
#define ASSUME_VIA_ACE_PRESENT
|
||||
#endif
|
||||
|
||||
/* 3. ASSEMBLER SUPPORT
|
||||
|
||||
This define (which can be on the command line) enables the use of the
|
||||
assembler code routines for encryption, decryption and key scheduling
|
||||
as follows:
|
||||
|
||||
ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
encryption, decryption and key scheduling
|
||||
ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
|
||||
Change one 'if 0' below to 'if 1' to select the version or define
|
||||
as a compilation option.
|
||||
*/
|
||||
|
||||
#if 0 && !defined(ASM_X86_V1C)
|
||||
#define ASM_X86_V1C
|
||||
#elif 0 && !defined(ASM_X86_V2)
|
||||
#define ASM_X86_V2
|
||||
#elif 0 && !defined(ASM_X86_V2C)
|
||||
#define ASM_X86_V2C
|
||||
#elif 0 && !defined(ASM_AMD64_C)
|
||||
#define ASM_AMD64_C
|
||||
#endif
|
||||
|
||||
#if defined(__i386) || defined(_M_IX86)
|
||||
#define A32_
|
||||
#elif defined(__x86_64__) || defined(_M_X64)
|
||||
#define A64_
|
||||
#endif
|
||||
|
||||
#if(defined(ASM_X86_V1C) || defined(ASM_X86_V2) || defined(ASM_X86_V2C)) && !defined(A32_) || \
|
||||
defined(ASM_AMD64_C) && !defined(A64_)
|
||||
#error Assembler code is only available for x86 and AMD64 systems
|
||||
#endif
|
||||
|
||||
/* 4. FAST INPUT/OUTPUT OPERATIONS.
|
||||
|
||||
On some machines it is possible to improve speed by transferring the
|
||||
bytes in the input and output arrays to and from the internal 32-bit
|
||||
variables by addressing these arrays as if they are arrays of 32-bit
|
||||
words. On some machines this will always be possible but there may
|
||||
be a large performance penalty if the byte arrays are not aligned on
|
||||
the normal word boundaries. On other machines this technique will
|
||||
lead to memory access errors when such 32-bit word accesses are not
|
||||
properly aligned. The option SAFE_IO avoids such problems but will
|
||||
often be slower on those machines that support misaligned access
|
||||
(especially so if care is taken to align the input and output byte
|
||||
arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
|
||||
assumed that access to byte arrays as if they are arrays of 32-bit
|
||||
words will not cause problems when such accesses are misaligned.
|
||||
*/
|
||||
#if 1 && !defined(_MSC_VER)
|
||||
#define SAFE_IO
|
||||
#endif
|
||||
|
||||
/* 5. LOOP UNROLLING
|
||||
|
||||
The code for encryption and decrytpion cycles through a number of rounds
|
||||
that can be implemented either in a loop or by expanding the code into a
|
||||
long sequence of instructions, the latter producing a larger program but
|
||||
one that will often be much faster. The latter is called loop unrolling.
|
||||
There are also potential speed advantages in expanding two iterations in
|
||||
a loop with half the number of iterations, which is called partial loop
|
||||
unrolling. The following options allow partial or full loop unrolling
|
||||
to be set independently for encryption and decryption
|
||||
*/
|
||||
#if 1
|
||||
#define ENC_UNROLL FULL
|
||||
#elif 0
|
||||
#define ENC_UNROLL PARTIAL
|
||||
#else
|
||||
#define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define DEC_UNROLL FULL
|
||||
#elif 0
|
||||
#define DEC_UNROLL PARTIAL
|
||||
#else
|
||||
#define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define ENC_KS_UNROLL
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define DEC_KS_UNROLL
|
||||
#endif
|
||||
|
||||
/* 6. FAST FINITE FIELD OPERATIONS
|
||||
|
||||
If this section is included, tables are used to provide faster finite
|
||||
field arithmetic (this has no effect if STATIC_TABLES is defined).
|
||||
*/
|
||||
#if 1
|
||||
#define FF_TABLES
|
||||
#endif
|
||||
|
||||
/* 7. INTERNAL STATE VARIABLE FORMAT
|
||||
|
||||
The internal state of Rijndael is stored in a number of local 32-bit
|
||||
word varaibles which can be defined either as an array or as individual
|
||||
names variables. Include this section if you want to store these local
|
||||
varaibles in arrays. Otherwise individual local variables will be used.
|
||||
*/
|
||||
#if 1
|
||||
#define ARRAYS
|
||||
#endif
|
||||
|
||||
/* 8. FIXED OR DYNAMIC TABLES
|
||||
|
||||
When this section is included the tables used by the code are compiled
|
||||
statically into the binary file. Otherwise the subroutine aes_init()
|
||||
must be called to compute them before the code is first used.
|
||||
*/
|
||||
#if 1 && !(defined(_MSC_VER) && (_MSC_VER <= 800))
|
||||
#define STATIC_TABLES
|
||||
#endif
|
||||
|
||||
/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES
|
||||
|
||||
In some systems it is better to mask longer values to extract bytes
|
||||
rather than using a cast. This option allows this choice.
|
||||
*/
|
||||
#if 0
|
||||
#define to_byte(x) ((uint8_t)(x))
|
||||
#else
|
||||
#define to_byte(x) ((x)&0xff)
|
||||
#endif
|
||||
|
||||
/* 10. TABLE ALIGNMENT
|
||||
|
||||
On some sytsems speed will be improved by aligning the AES large lookup
|
||||
tables on particular boundaries. This define should be set to a power of
|
||||
two giving the desired alignment. It can be left undefined if alignment
|
||||
is not needed. This option is specific to the Microsft VC++ compiler -
|
||||
it seems to sometimes cause trouble for the VC++ version 6 compiler.
|
||||
*/
|
||||
|
||||
#if 1 && defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
#define TABLE_ALIGN 32
|
||||
#endif
|
||||
|
||||
/* 11. REDUCE CODE AND TABLE SIZE
|
||||
|
||||
This replaces some expanded macros with function calls if AES_ASM_V2 or
|
||||
AES_ASM_V2C are defined
|
||||
*/
|
||||
|
||||
#if 1 && (defined(ASM_X86_V2) || defined(ASM_X86_V2C))
|
||||
#define REDUCE_CODE_SIZE
|
||||
#endif
|
||||
|
||||
/* 12. TABLE OPTIONS
|
||||
|
||||
This cipher proceeds by repeating in a number of cycles known as 'rounds'
|
||||
which are implemented by a round function which can optionally be speeded
|
||||
up using tables. The basic tables are each 256 32-bit words, with either
|
||||
one or four tables being required for each round function depending on
|
||||
how much speed is required. The encryption and decryption round functions
|
||||
are different and the last encryption and decrytpion round functions are
|
||||
different again making four different round functions in all.
|
||||
|
||||
This means that:
|
||||
1. Normal encryption and decryption rounds can each use either 0, 1
|
||||
or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
2. The last encryption and decryption rounds can also use either 0, 1
|
||||
or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
|
||||
Include or exclude the appropriate definitions below to set the number
|
||||
of tables used by this implementation.
|
||||
*/
|
||||
|
||||
#if 1 /* set tables for the normal encryption round */
|
||||
#define ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last encryption round */
|
||||
#define LAST_ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define LAST_ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define LAST_ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the normal decryption round */
|
||||
#define DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last decryption round */
|
||||
#define LAST_DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define LAST_DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define LAST_DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
/* The decryption key schedule can be speeded up with tables in the same
|
||||
way that the round functions can. Include or exclude the following
|
||||
defines to set this requirement.
|
||||
*/
|
||||
#if 1
|
||||
#define KEY_SCHED FOUR_TABLES
|
||||
#elif 0
|
||||
#define KEY_SCHED ONE_TABLE
|
||||
#else
|
||||
#define KEY_SCHED NO_TABLES
|
||||
#endif
|
||||
|
||||
/* ---- END OF USER CONFIGURED OPTIONS ---- */
|
||||
|
||||
/* VIA ACE support is only available for VC++ and GCC */
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__GNUC__)
|
||||
#if defined(ASSUME_VIA_ACE_PRESENT)
|
||||
#undef ASSUME_VIA_ACE_PRESENT
|
||||
#endif
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
#undef USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ASSUME_VIA_ACE_PRESENT) && !defined(USE_VIA_ACE_IF_PRESENT)
|
||||
#define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
/* define to reverse decryption key schedule */
|
||||
#if 1 || defined(USE_VIA_ACE_IF_PRESENT) && !defined(AES_REV_DKS)
|
||||
#define AES_REV_DKS
|
||||
#endif
|
||||
|
||||
/* Intel AESNI uses a decryption key schedule in the encryption order */
|
||||
#if defined(USE_INTEL_AES_IF_PRESENT) && defined(AES_REV_DKS)
|
||||
#undef AES_REV_DKS
|
||||
#endif
|
||||
|
||||
/* Assembler support requires the use of platform byte order */
|
||||
|
||||
#if(defined(ASM_X86_V1C) || defined(ASM_X86_V2C) || defined(ASM_AMD64_C)) && \
|
||||
(ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER)
|
||||
#undef ALGORITHM_BYTE_ORDER
|
||||
#define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#endif
|
||||
|
||||
/* In this implementation the columns of the state array are each held in
|
||||
32-bit words. The state array can be held in various ways: in an array
|
||||
of words, in a number of individual word variables or in a number of
|
||||
processor registers. The following define maps a variable name x and
|
||||
a column number c to the way the state array variable is to be held.
|
||||
The first define below maps the state into an array x[c] whereas the
|
||||
second form maps the state into a number of individual variables x0,
|
||||
x1, etc. Another form could map individual state colums to machine
|
||||
register names.
|
||||
*/
|
||||
|
||||
#if defined(ARRAYS)
|
||||
#define s(x, c) x[c]
|
||||
#else
|
||||
#define s(x, c) x##c
|
||||
#endif
|
||||
|
||||
/* This implementation provides subroutines for encryption, decryption
|
||||
and for setting the three key lengths (separately) for encryption
|
||||
and decryption. Since not all functions are needed, masks are set
|
||||
up here to determine which will be implemented in C
|
||||
*/
|
||||
|
||||
#if !defined(AES_ENCRYPT)
|
||||
#define EFUNCS_IN_C 0
|
||||
#elif defined(ASSUME_VIA_ACE_PRESENT) || defined(ASM_X86_V1C) || defined(ASM_X86_V2C) || \
|
||||
defined(ASM_AMD64_C)
|
||||
#define EFUNCS_IN_C ENC_KEYING_IN_C
|
||||
#elif !defined(ASM_X86_V2)
|
||||
#define EFUNCS_IN_C (ENCRYPTION_IN_C | ENC_KEYING_IN_C)
|
||||
#else
|
||||
#define EFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#if !defined(AES_DECRYPT)
|
||||
#define DFUNCS_IN_C 0
|
||||
#elif defined(ASSUME_VIA_ACE_PRESENT) || defined(ASM_X86_V1C) || defined(ASM_X86_V2C) || \
|
||||
defined(ASM_AMD64_C)
|
||||
#define DFUNCS_IN_C DEC_KEYING_IN_C
|
||||
#elif !defined(ASM_X86_V2)
|
||||
#define DFUNCS_IN_C (DECRYPTION_IN_C | DEC_KEYING_IN_C)
|
||||
#else
|
||||
#define DFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#define FUNCS_IN_C (EFUNCS_IN_C | DFUNCS_IN_C)
|
||||
|
||||
/* END OF CONFIGURATION OPTIONS */
|
||||
|
||||
#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2))
|
||||
|
||||
/* Disable or report errors on some combinations of options */
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES
|
||||
#undef LAST_ENC_ROUND
|
||||
#define LAST_ENC_ROUND NO_TABLES
|
||||
#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
|
||||
#undef LAST_ENC_ROUND
|
||||
#define LAST_ENC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
|
||||
#undef ENC_UNROLL
|
||||
#define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES
|
||||
#undef LAST_DEC_ROUND
|
||||
#define LAST_DEC_ROUND NO_TABLES
|
||||
#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
|
||||
#undef LAST_DEC_ROUND
|
||||
#define LAST_DEC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
|
||||
#undef DEC_UNROLL
|
||||
#define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if defined(bswap32)
|
||||
#define aes_sw32 bswap32
|
||||
#elif defined(bswap_32)
|
||||
#define aes_sw32 bswap_32
|
||||
#else
|
||||
#define brot(x, n) (((uint32_t)(x) << n) | ((uint32_t)(x) >> (32 - n)))
|
||||
#define aes_sw32(x) ((brot((x), 8) & 0x00ff00ff) | (brot((x), 24) & 0xff00ff00))
|
||||
#endif
|
||||
|
||||
/* upr(x,n): rotates bytes within words by n positions, moving bytes to
|
||||
higher index positions with wrap around into low positions
|
||||
ups(x,n): moves bytes by n positions to higher index positions in
|
||||
words but without wrap around
|
||||
bval(x,n): extracts a byte from a word
|
||||
|
||||
WARNING: The definitions given here are intended only for use with
|
||||
unsigned variables and with shift counts that are compile
|
||||
time constants
|
||||
*/
|
||||
|
||||
#if(ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN)
|
||||
#define upr(x, n) (((uint32_t)(x) << (8 * (n))) | ((uint32_t)(x) >> (32 - 8 * (n))))
|
||||
#define ups(x, n) ((uint32_t)(x) << (8 * (n)))
|
||||
#define bval(x, n) to_byte((x) >> (8 * (n)))
|
||||
#define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0))
|
||||
#endif
|
||||
|
||||
#if(ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN)
|
||||
#define upr(x, n) (((uint32_t)(x) >> (8 * (n))) | ((uint32_t)(x) << (32 - 8 * (n))))
|
||||
#define ups(x, n) ((uint32_t)(x) >> (8 * (n)))
|
||||
#define bval(x, n) to_byte((x) >> (24 - 8 * (n)))
|
||||
#define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (b3))
|
||||
#endif
|
||||
|
||||
#if defined(SAFE_IO)
|
||||
#define word_in(x, c) \
|
||||
bytes2word( \
|
||||
((const uint8_t*)(x) + 4 * c)[0], \
|
||||
((const uint8_t*)(x) + 4 * c)[1], \
|
||||
((const uint8_t*)(x) + 4 * c)[2], \
|
||||
((const uint8_t*)(x) + 4 * c)[3])
|
||||
#define word_out(x, c, v) \
|
||||
{ \
|
||||
((uint8_t*)(x) + 4 * c)[0] = bval(v, 0); \
|
||||
((uint8_t*)(x) + 4 * c)[1] = bval(v, 1); \
|
||||
((uint8_t*)(x) + 4 * c)[2] = bval(v, 2); \
|
||||
((uint8_t*)(x) + 4 * c)[3] = bval(v, 3); \
|
||||
}
|
||||
#elif(ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER)
|
||||
#define word_in(x, c) (*((uint32_t*)(x) + (c)))
|
||||
#define word_out(x, c, v) (*((uint32_t*)(x) + (c)) = (v))
|
||||
#else
|
||||
#define word_in(x, c) aes_sw32(*((uint32_t*)(x) + (c)))
|
||||
#define word_out(x, c, v) (*((uint32_t*)(x) + (c)) = aes_sw32(v))
|
||||
#endif
|
||||
|
||||
/* the finite field modular polynomial and elements */
|
||||
|
||||
#define WPOLY 0x011b
|
||||
#define BPOLY 0x1b
|
||||
|
||||
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
|
||||
|
||||
#define gf_c1 0x80808080
|
||||
#define gf_c2 0x7f7f7f7f
|
||||
#define gf_mulx(x) ((((x)&gf_c2) << 1) ^ ((((x)&gf_c1) >> 7) * BPOLY))
|
||||
|
||||
/* The following defines provide alternative definitions of gf_mulx that might
|
||||
give improved performance if a fast 32-bit multiply is not available. Note
|
||||
that a temporary variable u needs to be defined where gf_mulx is used.
|
||||
|
||||
#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6))
|
||||
#define gf_c4 (0x01010101 * BPOLY)
|
||||
#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4)
|
||||
*/
|
||||
|
||||
/* Work out which tables are needed for the different options */
|
||||
|
||||
#if defined(ASM_X86_V1C)
|
||||
#if defined(ENC_ROUND)
|
||||
#undef ENC_ROUND
|
||||
#endif
|
||||
#define ENC_ROUND FOUR_TABLES
|
||||
#if defined(LAST_ENC_ROUND)
|
||||
#undef LAST_ENC_ROUND
|
||||
#endif
|
||||
#define LAST_ENC_ROUND FOUR_TABLES
|
||||
#if defined(DEC_ROUND)
|
||||
#undef DEC_ROUND
|
||||
#endif
|
||||
#define DEC_ROUND FOUR_TABLES
|
||||
#if defined(LAST_DEC_ROUND)
|
||||
#undef LAST_DEC_ROUND
|
||||
#endif
|
||||
#define LAST_DEC_ROUND FOUR_TABLES
|
||||
#if defined(KEY_SCHED)
|
||||
#undef KEY_SCHED
|
||||
#define KEY_SCHED FOUR_TABLES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if(FUNCS_IN_C & ENCRYPTION_IN_C) || defined(ASM_X86_V1C)
|
||||
#if ENC_ROUND == ONE_TABLE
|
||||
#define FT1_SET
|
||||
#elif ENC_ROUND == FOUR_TABLES
|
||||
#define FT4_SET
|
||||
#else
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#if LAST_ENC_ROUND == ONE_TABLE
|
||||
#define FL1_SET
|
||||
#elif LAST_ENC_ROUND == FOUR_TABLES
|
||||
#define FL4_SET
|
||||
#elif !defined(SBX_SET)
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if(FUNCS_IN_C & DECRYPTION_IN_C) || defined(ASM_X86_V1C)
|
||||
#if DEC_ROUND == ONE_TABLE
|
||||
#define IT1_SET
|
||||
#elif DEC_ROUND == FOUR_TABLES
|
||||
#define IT4_SET
|
||||
#else
|
||||
#define ISB_SET
|
||||
#endif
|
||||
#if LAST_DEC_ROUND == ONE_TABLE
|
||||
#define IL1_SET
|
||||
#elif LAST_DEC_ROUND == FOUR_TABLES
|
||||
#define IL4_SET
|
||||
#elif !defined(ISB_SET)
|
||||
#define ISB_SET
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !(defined(REDUCE_CODE_SIZE) && (defined(ASM_X86_V2) || defined(ASM_X86_V2C)))
|
||||
#if((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C))
|
||||
#if KEY_SCHED == ONE_TABLE
|
||||
#if !defined(FL1_SET) && !defined(FL4_SET)
|
||||
#define LS1_SET
|
||||
#endif
|
||||
#elif KEY_SCHED == FOUR_TABLES
|
||||
#if !defined(FL4_SET)
|
||||
#define LS4_SET
|
||||
#endif
|
||||
#elif !defined(SBX_SET)
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#endif
|
||||
#if(FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
#if KEY_SCHED == ONE_TABLE
|
||||
#define IM1_SET
|
||||
#elif KEY_SCHED == FOUR_TABLES
|
||||
#define IM4_SET
|
||||
#elif !defined(SBX_SET)
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* generic definitions of Rijndael macros that use tables */
|
||||
|
||||
#define no_table(x, box, vf, rf, c) \
|
||||
bytes2word( \
|
||||
box[bval(vf(x, 0, c), rf(0, c))], \
|
||||
box[bval(vf(x, 1, c), rf(1, c))], \
|
||||
box[bval(vf(x, 2, c), rf(2, c))], \
|
||||
box[bval(vf(x, 3, c), rf(3, c))])
|
||||
|
||||
#define one_table(x, op, tab, vf, rf, c) \
|
||||
(tab[bval(vf(x, 0, c), rf(0, c))] ^ op(tab[bval(vf(x, 1, c), rf(1, c))], 1) ^ \
|
||||
op(tab[bval(vf(x, 2, c), rf(2, c))], 2) ^ op(tab[bval(vf(x, 3, c), rf(3, c))], 3))
|
||||
|
||||
#define four_tables(x, tab, vf, rf, c) \
|
||||
(tab[0][bval(vf(x, 0, c), rf(0, c))] ^ tab[1][bval(vf(x, 1, c), rf(1, c))] ^ \
|
||||
tab[2][bval(vf(x, 2, c), rf(2, c))] ^ tab[3][bval(vf(x, 3, c), rf(3, c))])
|
||||
|
||||
#define vf1(x, r, c) (x)
|
||||
#define rf1(r, c) (r)
|
||||
#define rf2(r, c) ((8 + r - c) & 3)
|
||||
|
||||
/* perform forward and inverse column mix operation on four bytes in long word x in */
|
||||
/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */
|
||||
|
||||
#if !(defined(REDUCE_CODE_SIZE) && (defined(ASM_X86_V2) || defined(ASM_X86_V2C)))
|
||||
|
||||
#if defined(FM4_SET) /* not currently used */
|
||||
#define fwd_mcol(x) four_tables(x, t_use(f, m), vf1, rf1, 0)
|
||||
#elif defined(FM1_SET) /* not currently used */
|
||||
#define fwd_mcol(x) one_table(x, upr, t_use(f, m), vf1, rf1, 0)
|
||||
#else
|
||||
#define dec_fmvars uint32_t g2
|
||||
#define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1))
|
||||
#endif
|
||||
|
||||
#if defined(IM4_SET)
|
||||
#define inv_mcol(x) four_tables(x, t_use(i, m), vf1, rf1, 0)
|
||||
#elif defined(IM1_SET)
|
||||
#define inv_mcol(x) one_table(x, upr, t_use(i, m), vf1, rf1, 0)
|
||||
#else
|
||||
#define dec_imvars uint32_t g2, g4, g9
|
||||
#define inv_mcol(x) \
|
||||
(g2 = gf_mulx(x), \
|
||||
g4 = gf_mulx(g2), \
|
||||
g9 = (x) ^ gf_mulx(g4), \
|
||||
g4 ^= g9, \
|
||||
(x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1))
|
||||
#endif
|
||||
|
||||
#if defined(FL4_SET)
|
||||
#define ls_box(x, c) four_tables(x, t_use(f, l), vf1, rf2, c)
|
||||
#elif defined(LS4_SET)
|
||||
#define ls_box(x, c) four_tables(x, t_use(l, s), vf1, rf2, c)
|
||||
#elif defined(FL1_SET)
|
||||
#define ls_box(x, c) one_table(x, upr, t_use(f, l), vf1, rf2, c)
|
||||
#elif defined(LS1_SET)
|
||||
#define ls_box(x, c) one_table(x, upr, t_use(l, s), vf1, rf2, c)
|
||||
#else
|
||||
#define ls_box(x, c) no_table(x, t_use(s, box), vf1, rf2, c)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ASM_X86_V1C) && defined(AES_DECRYPT) && !defined(ISB_SET)
|
||||
#define ISB_SET
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#define DO_TABLES
|
||||
|
||||
#include "aes.h"
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined(STATIC_TABLES)
|
||||
|
||||
#define sb_data(w) \
|
||||
{ \
|
||||
w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5), w(0x30), w(0x01), \
|
||||
w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76), w(0xca), w(0x82), w(0xc9), \
|
||||
w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), \
|
||||
w(0x9c), w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), \
|
||||
w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), \
|
||||
w(0x31), w(0x15), w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), \
|
||||
w(0x9a), w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75), \
|
||||
w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0), w(0x52), \
|
||||
w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84), w(0x53), w(0xd1), \
|
||||
w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), \
|
||||
w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), w(0xaa), w(0xfb), \
|
||||
w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), \
|
||||
w(0x3c), w(0x9f), w(0xa8), w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), \
|
||||
w(0x38), w(0xf5), w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), \
|
||||
w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17), \
|
||||
w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73), w(0x60), \
|
||||
w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), \
|
||||
w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), w(0x32), w(0x3a), \
|
||||
w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), w(0xc2), w(0xd3), w(0xac), w(0x62), \
|
||||
w(0x91), w(0x95), w(0xe4), w(0x79), w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), \
|
||||
w(0xd5), w(0x4e), w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), \
|
||||
w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), \
|
||||
w(0xc6), w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a), \
|
||||
w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), \
|
||||
w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), w(0xe1), w(0xf8), \
|
||||
w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94), w(0x9b), w(0x1e), w(0x87), \
|
||||
w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), \
|
||||
w(0xbf), w(0xe6), w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), \
|
||||
w(0x54), w(0xbb), w(0x16) \
|
||||
}
|
||||
|
||||
#define isb_data(w) \
|
||||
{ \
|
||||
w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38), w(0xbf), w(0x40), \
|
||||
w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb), w(0x7c), w(0xe3), w(0x39), \
|
||||
w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87), w(0x34), w(0x8e), w(0x43), w(0x44), \
|
||||
w(0xc4), w(0xde), w(0xe9), w(0xcb), w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), \
|
||||
w(0xc2), w(0x23), w(0x3d), w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), \
|
||||
w(0xc3), w(0x4e), w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), \
|
||||
w(0xb2), w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25), \
|
||||
w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16), w(0xd4), \
|
||||
w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92), w(0x6c), w(0x70), \
|
||||
w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda), w(0x5e), w(0x15), w(0x46), \
|
||||
w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84), w(0x90), w(0xd8), w(0xab), w(0x00), \
|
||||
w(0x8c), w(0xbc), w(0xd3), w(0x0a), w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), \
|
||||
w(0xb3), w(0x45), w(0x06), w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), \
|
||||
w(0x0f), w(0x02), w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), \
|
||||
w(0x6b), w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea), \
|
||||
w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73), w(0x96), \
|
||||
w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85), w(0xe2), w(0xf9), \
|
||||
w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), w(0x47), w(0xf1), w(0x1a), \
|
||||
w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), w(0x6f), w(0xb7), w(0x62), w(0x0e), \
|
||||
w(0xaa), w(0x18), w(0xbe), w(0x1b), w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), \
|
||||
w(0xd2), w(0x79), w(0x20), w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), \
|
||||
w(0x5a), w(0xf4), w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), \
|
||||
w(0x31), w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f), \
|
||||
w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), w(0x2d), \
|
||||
w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), w(0xa0), w(0xe0), \
|
||||
w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0), w(0xc8), w(0xeb), w(0xbb), \
|
||||
w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61), w(0x17), w(0x2b), w(0x04), w(0x7e), \
|
||||
w(0xba), w(0x77), w(0xd6), w(0x26), w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), \
|
||||
w(0x21), w(0x0c), w(0x7d) \
|
||||
}
|
||||
|
||||
#define mm_data(w) \
|
||||
{ \
|
||||
w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07), w(0x08), w(0x09), \
|
||||
w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f), w(0x10), w(0x11), w(0x12), \
|
||||
w(0x13), w(0x14), w(0x15), w(0x16), w(0x17), w(0x18), w(0x19), w(0x1a), w(0x1b), \
|
||||
w(0x1c), w(0x1d), w(0x1e), w(0x1f), w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), \
|
||||
w(0x25), w(0x26), w(0x27), w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), \
|
||||
w(0x2e), w(0x2f), w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), \
|
||||
w(0x37), w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f), \
|
||||
w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47), w(0x48), \
|
||||
w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f), w(0x50), w(0x51), \
|
||||
w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57), w(0x58), w(0x59), w(0x5a), \
|
||||
w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f), w(0x60), w(0x61), w(0x62), w(0x63), \
|
||||
w(0x64), w(0x65), w(0x66), w(0x67), w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), \
|
||||
w(0x6d), w(0x6e), w(0x6f), w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), \
|
||||
w(0x76), w(0x77), w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), \
|
||||
w(0x7f), w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87), \
|
||||
w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f), w(0x90), \
|
||||
w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97), w(0x98), w(0x99), \
|
||||
w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f), w(0xa0), w(0xa1), w(0xa2), \
|
||||
w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7), w(0xa8), w(0xa9), w(0xaa), w(0xab), \
|
||||
w(0xac), w(0xad), w(0xae), w(0xaf), w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), \
|
||||
w(0xb5), w(0xb6), w(0xb7), w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), \
|
||||
w(0xbe), w(0xbf), w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), \
|
||||
w(0xc7), w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf), \
|
||||
w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7), w(0xd8), \
|
||||
w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf), w(0xe0), w(0xe1), \
|
||||
w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7), w(0xe8), w(0xe9), w(0xea), \
|
||||
w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef), w(0xf0), w(0xf1), w(0xf2), w(0xf3), \
|
||||
w(0xf4), w(0xf5), w(0xf6), w(0xf7), w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), \
|
||||
w(0xfd), w(0xfe), w(0xff) \
|
||||
}
|
||||
|
||||
#define rc_data(w) \
|
||||
{ w(0x01), w(0x02), w(0x04), w(0x08), w(0x10), w(0x20), w(0x40), w(0x80), w(0x1b), w(0x36) }
|
||||
|
||||
#define h0(x) (x)
|
||||
|
||||
#define w0(p) bytes2word(p, 0, 0, 0)
|
||||
#define w1(p) bytes2word(0, p, 0, 0)
|
||||
#define w2(p) bytes2word(0, 0, p, 0)
|
||||
#define w3(p) bytes2word(0, 0, 0, p)
|
||||
|
||||
#define u0(p) bytes2word(f2(p), p, p, f3(p))
|
||||
#define u1(p) bytes2word(f3(p), f2(p), p, p)
|
||||
#define u2(p) bytes2word(p, f3(p), f2(p), p)
|
||||
#define u3(p) bytes2word(p, p, f3(p), f2(p))
|
||||
|
||||
#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p))
|
||||
#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p))
|
||||
#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p))
|
||||
#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p))
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(STATIC_TABLES) || !defined(FF_TABLES)
|
||||
|
||||
#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY))
|
||||
#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY))
|
||||
#define f8(x) \
|
||||
((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) ^ (((x >> 5) & 4) * WPOLY))
|
||||
#define f3(x) (f2(x) ^ x)
|
||||
#define f9(x) (f8(x) ^ x)
|
||||
#define fb(x) (f8(x) ^ f2(x) ^ x)
|
||||
#define fd(x) (f8(x) ^ f4(x) ^ x)
|
||||
#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
|
||||
|
||||
#else
|
||||
|
||||
#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
|
||||
#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
|
||||
#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
|
||||
#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
|
||||
#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
|
||||
#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
|
||||
|
||||
#endif
|
||||
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(STATIC_TABLES)
|
||||
|
||||
/* implemented in case of wrong call for fixed tables */
|
||||
|
||||
AES_RETURN aes_init(void) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#else /* Generate the tables for the dynamic table option */
|
||||
|
||||
#if defined(FF_TABLES)
|
||||
|
||||
#define gf_inv(x) ((x) ? pow[255 - log[x]] : 0)
|
||||
|
||||
#else
|
||||
|
||||
/* It will generally be sensible to use tables to compute finite
|
||||
field multiplies and inverses but where memory is scarse this
|
||||
code might sometimes be better. But it only has effect during
|
||||
initialisation so its pretty unimportant in overall terms.
|
||||
*/
|
||||
|
||||
/* return 2 ^ (n - 1) where n is the bit number of the highest bit
|
||||
set in x with x in the range 1 < x < 0x00000200. This form is
|
||||
used so that locals within fi can be bytes rather than words
|
||||
*/
|
||||
|
||||
static uint8_t hibit(const uint32_t x) {
|
||||
uint8_t r = (uint8_t)((x >> 1) | (x >> 2));
|
||||
|
||||
r |= (r >> 2);
|
||||
r |= (r >> 4);
|
||||
return (r + 1) >> 1;
|
||||
}
|
||||
|
||||
/* return the inverse of the finite field element x */
|
||||
|
||||
static uint8_t gf_inv(const uint8_t x) {
|
||||
uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
|
||||
|
||||
if(x < 2) return x;
|
||||
|
||||
for(;;) {
|
||||
if(n1)
|
||||
while(n2 >= n1) /* divide polynomial p2 by p1 */
|
||||
{
|
||||
n2 /= n1; /* shift smaller polynomial left */
|
||||
p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
|
||||
v2 ^= v1 * n2; /* shift accumulated value and */
|
||||
n2 = hibit(p2); /* add into result */
|
||||
}
|
||||
else
|
||||
return v1;
|
||||
|
||||
if(n2) /* repeat with values swapped */
|
||||
while(n1 >= n2) {
|
||||
n1 /= n2;
|
||||
p1 ^= p2 * n1;
|
||||
v1 ^= v2 * n1;
|
||||
n1 = hibit(p1);
|
||||
}
|
||||
else
|
||||
return v2;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* The forward and inverse affine transformations used in the S-box */
|
||||
uint8_t fwd_affine(const uint8_t x) {
|
||||
uint32_t w = x;
|
||||
w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
|
||||
return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
|
||||
}
|
||||
|
||||
uint8_t inv_affine(const uint8_t x) {
|
||||
uint32_t w = x;
|
||||
w = (w << 1) ^ (w << 3) ^ (w << 6);
|
||||
return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
|
||||
}
|
||||
|
||||
static int init = 0;
|
||||
|
||||
AES_RETURN aes_init(void) {
|
||||
uint32_t i, w;
|
||||
|
||||
#if defined(FF_TABLES)
|
||||
|
||||
uint8_t pow[512] = {0}, log[256] = {0};
|
||||
|
||||
if(init) return EXIT_SUCCESS;
|
||||
/* log and power tables for GF(2^8) finite field with
|
||||
WPOLY as modular polynomial - the simplest primitive
|
||||
root is 0x03, used here to generate the tables
|
||||
*/
|
||||
|
||||
i = 0;
|
||||
w = 1;
|
||||
do {
|
||||
pow[i] = (uint8_t)w;
|
||||
pow[i + 255] = (uint8_t)w;
|
||||
log[w] = (uint8_t)i++;
|
||||
w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0);
|
||||
} while(w != 1);
|
||||
|
||||
#else
|
||||
if(init) return EXIT_SUCCESS;
|
||||
#endif
|
||||
|
||||
for(i = 0, w = 1; i < RC_LENGTH; ++i) {
|
||||
t_set(r, c)[i] = bytes2word(w, 0, 0, 0);
|
||||
w = f2(w);
|
||||
}
|
||||
|
||||
for(i = 0; i < 256; ++i) {
|
||||
uint8_t b;
|
||||
|
||||
b = fwd_affine(gf_inv((uint8_t)i));
|
||||
w = bytes2word(f2(b), b, b, f3(b));
|
||||
|
||||
#if defined(SBX_SET)
|
||||
t_set(s, box)[i] = b;
|
||||
#endif
|
||||
|
||||
#if defined(FT1_SET) /* tables for a normal encryption round */
|
||||
t_set(f, n)[i] = w;
|
||||
#endif
|
||||
#if defined(FT4_SET)
|
||||
t_set(f, n)[0][i] = w;
|
||||
t_set(f, n)[1][i] = upr(w, 1);
|
||||
t_set(f, n)[2][i] = upr(w, 2);
|
||||
t_set(f, n)[3][i] = upr(w, 3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
|
||||
#if defined(FL1_SET) /* tables for last encryption round (may also */
|
||||
t_set(f, l)[i] = w; /* be used in the key schedule) */
|
||||
#endif
|
||||
#if defined(FL4_SET)
|
||||
t_set(f, l)[0][i] = w;
|
||||
t_set(f, l)[1][i] = upr(w, 1);
|
||||
t_set(f, l)[2][i] = upr(w, 2);
|
||||
t_set(f, l)[3][i] = upr(w, 3);
|
||||
#endif
|
||||
|
||||
#if defined(LS1_SET) /* table for key schedule if t_set(f,l) above is*/
|
||||
t_set(l, s)[i] = w; /* not of the required form */
|
||||
#endif
|
||||
#if defined(LS4_SET)
|
||||
t_set(l, s)[0][i] = w;
|
||||
t_set(l, s)[1][i] = upr(w, 1);
|
||||
t_set(l, s)[2][i] = upr(w, 2);
|
||||
t_set(l, s)[3][i] = upr(w, 3);
|
||||
#endif
|
||||
|
||||
b = gf_inv(inv_affine((uint8_t)i));
|
||||
w = bytes2word(fe(b), f9(b), fd(b), fb(b));
|
||||
|
||||
#if defined(IM1_SET) /* tables for the inverse mix column operation */
|
||||
t_set(i, m)[b] = w;
|
||||
#endif
|
||||
#if defined(IM4_SET)
|
||||
t_set(i, m)[0][b] = w;
|
||||
t_set(i, m)[1][b] = upr(w, 1);
|
||||
t_set(i, m)[2][b] = upr(w, 2);
|
||||
t_set(i, m)[3][b] = upr(w, 3);
|
||||
#endif
|
||||
|
||||
#if defined(ISB_SET)
|
||||
t_set(i, box)[i] = b;
|
||||
#endif
|
||||
#if defined(IT1_SET) /* tables for a normal decryption round */
|
||||
t_set(i, n)[i] = w;
|
||||
#endif
|
||||
#if defined(IT4_SET)
|
||||
t_set(i, n)[0][i] = w;
|
||||
t_set(i, n)[1][i] = upr(w, 1);
|
||||
t_set(i, n)[2][i] = upr(w, 2);
|
||||
t_set(i, n)[3][i] = upr(w, 3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
#if defined(IL1_SET) /* tables for last decryption round */
|
||||
t_set(i, l)[i] = w;
|
||||
#endif
|
||||
#if defined(IL4_SET)
|
||||
t_set(i, l)[0][i] = w;
|
||||
t_set(i, l)[1][i] = upr(w, 1);
|
||||
t_set(i, l)[2][i] = upr(w, 2);
|
||||
t_set(i, l)[3][i] = upr(w, 3);
|
||||
#endif
|
||||
}
|
||||
init = 1;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
Automatic code initialisation (suggested by by Henrik S. Gaßmann)
|
||||
based on code provided by Joe Lowe and placed in the public domain at:
|
||||
http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma section(".CRT$XCU", read)
|
||||
|
||||
__declspec(allocate(".CRT$XCU")) void(__cdecl* aes_startup)(void) = aes_init;
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
static void aes_startup(void) __attribute__((constructor));
|
||||
|
||||
static void aes_startup(void) {
|
||||
aes_init();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#pragma message("dynamic tables must be initialised manually on your system")
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the code for declaring the tables needed to implement
|
||||
AES. The file aesopt.h is assumed to be included before this header file.
|
||||
If there are no global variables, the definitions here can be used to put
|
||||
the AES tables in a structure so that a pointer can then be added to the
|
||||
AES context to pass them to the AES routines that need them. If this
|
||||
facility is used, the calling program has to ensure that this pointer is
|
||||
managed appropriately. In particular, the value of the t_dec(in,it) item
|
||||
in the table structure must be set to zero in order to ensure that the
|
||||
tables are initialised. In practice the three code sequences in aeskey.c
|
||||
that control the calls to aes_init() and the aes_init() routine itself will
|
||||
have to be changed for a specific implementation. If global variables are
|
||||
available it will generally be preferable to use them with the precomputed
|
||||
STATIC_TABLES option that uses static global tables.
|
||||
|
||||
The following defines can be used to control the way the tables
|
||||
are defined, initialised and used in embedded environments that
|
||||
require special features for these purposes
|
||||
|
||||
the 't_dec' construction is used to declare fixed table arrays
|
||||
the 't_set' construction is used to set fixed table values
|
||||
the 't_use' construction is used to access fixed table values
|
||||
|
||||
256 byte tables:
|
||||
|
||||
t_xxx(s,box) => forward S box
|
||||
t_xxx(i,box) => inverse S box
|
||||
|
||||
256 32-bit word OR 4 x 256 32-bit word tables:
|
||||
|
||||
t_xxx(f,n) => forward normal round
|
||||
t_xxx(f,l) => forward last round
|
||||
t_xxx(i,n) => inverse normal round
|
||||
t_xxx(i,l) => inverse last round
|
||||
t_xxx(l,s) => key schedule table
|
||||
t_xxx(i,m) => key schedule table
|
||||
|
||||
Other variables and tables:
|
||||
|
||||
t_xxx(r,c) => the rcon table
|
||||
*/
|
||||
|
||||
#if !defined(_AESTAB_H)
|
||||
#define _AESTAB_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define t_dec(m, n) t_##m##n
|
||||
#define t_set(m, n) t_##m##n
|
||||
#define t_use(m, n) t_##m##n
|
||||
|
||||
#if defined(STATIC_TABLES)
|
||||
#if !defined(__GNUC__) && (defined(__MSDOS__) || defined(__WIN16__))
|
||||
/* make tables far data to avoid using too much DGROUP space (PG) */
|
||||
#define CONST const far
|
||||
#else
|
||||
#define CONST const
|
||||
#endif
|
||||
#else
|
||||
#define CONST
|
||||
#endif
|
||||
|
||||
#if defined(DO_TABLES)
|
||||
#define EXTERN
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && defined(TABLE_ALIGN)
|
||||
#define ALIGN __declspec(align(TABLE_ALIGN))
|
||||
#else
|
||||
#define ALIGN
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) && (__WATCOMC__ >= 1100)
|
||||
#define XP_DIR __cdecl
|
||||
#else
|
||||
#define XP_DIR
|
||||
#endif
|
||||
|
||||
#if defined(DO_TABLES) && defined(STATIC_TABLES)
|
||||
#define d_1(t, n, b, e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e)
|
||||
#define d_4(t, n, b, e, f, g, h) EXTERN ALIGN CONST XP_DIR t n[4][256] = {b(e), b(f), b(g), b(h)}
|
||||
EXTERN ALIGN CONST uint32_t t_dec(r, c)[RC_LENGTH] = rc_data(w0);
|
||||
#else
|
||||
#define d_1(t, n, b, e) EXTERN ALIGN CONST XP_DIR t n[256]
|
||||
#define d_4(t, n, b, e, f, g, h) EXTERN ALIGN CONST XP_DIR t n[4][256]
|
||||
EXTERN ALIGN CONST uint32_t t_dec(r, c)[RC_LENGTH];
|
||||
#endif
|
||||
|
||||
#if defined(SBX_SET)
|
||||
d_1(uint8_t, t_dec(s, box), sb_data, h0);
|
||||
#endif
|
||||
#if defined(ISB_SET)
|
||||
d_1(uint8_t, t_dec(i, box), isb_data, h0);
|
||||
#endif
|
||||
|
||||
#if defined(FT1_SET)
|
||||
d_1(uint32_t, t_dec(f, n), sb_data, u0);
|
||||
#endif
|
||||
#if defined(FT4_SET)
|
||||
d_4(uint32_t, t_dec(f, n), sb_data, u0, u1, u2, u3);
|
||||
#endif
|
||||
|
||||
#if defined(FL1_SET)
|
||||
d_1(uint32_t, t_dec(f, l), sb_data, w0);
|
||||
#endif
|
||||
#if defined(FL4_SET)
|
||||
d_4(uint32_t, t_dec(f, l), sb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
|
||||
#if defined(IT1_SET)
|
||||
d_1(uint32_t, t_dec(i, n), isb_data, v0);
|
||||
#endif
|
||||
#if defined(IT4_SET)
|
||||
d_4(uint32_t, t_dec(i, n), isb_data, v0, v1, v2, v3);
|
||||
#endif
|
||||
|
||||
#if defined(IL1_SET)
|
||||
d_1(uint32_t, t_dec(i, l), isb_data, w0);
|
||||
#endif
|
||||
#if defined(IL4_SET)
|
||||
d_4(uint32_t, t_dec(i, l), isb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
|
||||
#if defined(LS1_SET)
|
||||
#if defined(FL1_SET)
|
||||
#undef LS1_SET
|
||||
#else
|
||||
d_1(uint32_t, t_dec(l, s), sb_data, w0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LS4_SET)
|
||||
#if defined(FL4_SET)
|
||||
#undef LS4_SET
|
||||
#else
|
||||
d_4(uint32_t, t_dec(l, s), sb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(IM1_SET)
|
||||
d_1(uint32_t, t_dec(i, m), mm_data, v0);
|
||||
#endif
|
||||
#if defined(IM4_SET)
|
||||
d_4(uint32_t, t_dec(i, m), mm_data, v0, v1, v2, v3);
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
1. source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
2. binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation;
|
||||
|
||||
3. the name of the copyright holder is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
// Correct Output (for variable block size - AES_BLOCK_SIZE undefined):
|
||||
|
||||
// lengths: block = 16 bytes, key = 16 bytes
|
||||
// key = 2b7e151628aed2a6abf7158809cf4f3c
|
||||
// input = 3243f6a8885a308d313198a2e0370734
|
||||
// encrypt = 3925841d02dc09fbdc118597196a0b32
|
||||
// decrypt = 3243f6a8885a308d313198a2e0370734
|
||||
|
||||
// lengths: block = 16 bytes, key = 24 bytes
|
||||
// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5
|
||||
// input = 3243f6a8885a308d313198a2e0370734
|
||||
// encrypt = f9fb29aefc384a250340d833b87ebc00
|
||||
// decrypt = 3243f6a8885a308d313198a2e0370734
|
||||
|
||||
// lengths: block = 16 bytes, key = 32 bytes
|
||||
// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe
|
||||
// input = 3243f6a8885a308d313198a2e0370734
|
||||
// encrypt = 1a6e6c2c662e7da6501ffb62bc9e93f3
|
||||
// decrypt = 3243f6a8885a308d313198a2e0370734
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aes.h"
|
||||
#include "aestst.h"
|
||||
|
||||
void out_state(long s0, long s1, long s2, long s3) {
|
||||
printf("\n%08lx%08lx%08lx%08lx", s0, s1, s2, s3);
|
||||
}
|
||||
|
||||
void oblk(char m[], unsigned char v[], unsigned long n) {
|
||||
unsigned long i;
|
||||
|
||||
printf("\n%s", m);
|
||||
|
||||
for(i = 0; i < n; ++i) printf("%02x", v[i]);
|
||||
}
|
||||
|
||||
void message(const char* s) {
|
||||
printf("%s", s);
|
||||
}
|
||||
|
||||
unsigned char pih[32] = // hex digits of pi
|
||||
{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98,
|
||||
0xa2, 0xe0, 0x37, 0x07, 0x34, 0x4a, 0x40, 0x93, 0x82, 0x22, 0x99,
|
||||
0xf3, 0x1d, 0x00, 0x82, 0xef, 0xa9, 0x8e, 0xc4, 0xe6, 0xc8};
|
||||
|
||||
unsigned char exh[32] = // hex digits of e
|
||||
{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15,
|
||||
0x88, 0x09, 0xcf, 0x4f, 0x3c, 0x76, 0x2e, 0x71, 0x60, 0xf3, 0x8b,
|
||||
0x4d, 0xa5, 0x6a, 0x78, 0x4d, 0x90, 0x45, 0x19, 0x0c, 0xfe};
|
||||
|
||||
unsigned char res[3][32] = {
|
||||
{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
|
||||
{0xf9, 0xfb, 0x29, 0xae, 0xfc, 0x38, 0x4a, 0x25, 0x03, 0x40, 0xd8, 0x33, 0xb8, 0x7e, 0xbc, 0x00},
|
||||
{0x1a, 0x6e, 0x6c, 0x2c, 0x66, 0x2e, 0x7d, 0xa6, 0x50, 0x1f, 0xfb, 0x62, 0xbc, 0x9e, 0x93, 0xf3}};
|
||||
|
||||
// void cycles(volatile uint64_t *rtn)
|
||||
// {
|
||||
// #if defined( _MSCVER )
|
||||
// __asm // read the Pentium Time Stamp Counter
|
||||
// { cpuid
|
||||
// rdtsc
|
||||
// mov ecx,rtn
|
||||
// mov [ecx],eax
|
||||
// mov [ecx+4],edx
|
||||
// cpuid
|
||||
// }
|
||||
// #elif defined( __GNUC__ )
|
||||
// #if defined(__aarch64__)
|
||||
// __asm__ __volatile__("mrs %0, cntvct_el0": "=r" (*rtn));
|
||||
// #else
|
||||
// __asm__ __volatile__("rdtsc": "=A" (*rtn));
|
||||
// #endif
|
||||
// #endif
|
||||
// }
|
||||
|
||||
int main(void) {
|
||||
unsigned char out[32], ret[32], err = 0;
|
||||
f_ectx alge[1];
|
||||
f_dctx algd[1];
|
||||
|
||||
aes_init();
|
||||
|
||||
message("\nRun tests for the AES algorithm");
|
||||
|
||||
memset(&alge, 0, sizeof(aes_encrypt_ctx));
|
||||
memset(&algd, 0, sizeof(aes_decrypt_ctx));
|
||||
|
||||
#if defined(AES_128)
|
||||
memset(out, 0xcc, 16);
|
||||
memset(ret, 0xcc, 16);
|
||||
printf("\n\n// lengths: block = 16, bytes, key = 16 bytes");
|
||||
f_enc_key128(alge, exh);
|
||||
oblk("// key = ", exh, 16);
|
||||
oblk("// input = ", pih, 16);
|
||||
do_enc(alge, pih, out, 1);
|
||||
oblk("// encrypt = ", out, 16);
|
||||
if(memcmp(out, res[0], 16)) {
|
||||
message(" error");
|
||||
err += 1;
|
||||
}
|
||||
f_dec_key128(algd, exh);
|
||||
do_dec(algd, out, ret, 1);
|
||||
oblk("// decrypt = ", ret, 16);
|
||||
if(memcmp(ret, pih, 16)) {
|
||||
message(" error");
|
||||
err += 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(AES_192)
|
||||
memset(out, 0xcc, 16);
|
||||
memset(ret, 0xcc, 16);
|
||||
printf("\n\n// lengths: block = 16, bytes, key = 24 bytes");
|
||||
f_enc_key192(alge, exh);
|
||||
oblk("// key = ", exh, 24);
|
||||
oblk("// input = ", pih, 16);
|
||||
do_enc(alge, pih, out, 1);
|
||||
oblk("// encrypt = ", out, 16);
|
||||
if(memcmp(out, res[1], 16)) {
|
||||
message(" error");
|
||||
err += 4;
|
||||
}
|
||||
f_dec_key192(algd, exh);
|
||||
do_dec(algd, out, ret, 1);
|
||||
oblk("// decrypt = ", ret, 16);
|
||||
if(memcmp(ret, pih, 16)) {
|
||||
message(" error");
|
||||
err += 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(AES_256)
|
||||
memset(out, 0xcc, 16);
|
||||
memset(ret, 0xcc, 16);
|
||||
printf("\n\n// lengths: block = 16, bytes, key = 32 bytes");
|
||||
f_enc_key256(alge, exh);
|
||||
oblk("// key = ", exh, 32);
|
||||
oblk("// input = ", pih, 16);
|
||||
do_enc(alge, pih, out, 1);
|
||||
oblk("// encrypt = ", out, 16);
|
||||
if(memcmp(out, res[2], 16)) {
|
||||
message(" error");
|
||||
err += 16;
|
||||
}
|
||||
f_dec_key256(algd, exh);
|
||||
do_dec(algd, out, ret, 1);
|
||||
oblk("// decrypt = ", ret, 16);
|
||||
if(memcmp(ret, pih, 16)) {
|
||||
message(" error");
|
||||
err += 32;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!err)
|
||||
message("\n\nThese values are all correct\n\n");
|
||||
else
|
||||
message("\n\nSome values are in error\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
// The following definitions are required for testing only, They are not needed
|
||||
// for AES (Rijndael) implementation. They are used to allow C, C++ and DLL
|
||||
// data access and subroutine calls to be expressed in the same form in the
|
||||
// testing code.
|
||||
|
||||
#ifndef AESTST_H
|
||||
#define AESTST_H
|
||||
|
||||
#define f_info(x) (x)->inf.b[2]
|
||||
#define f_ectx aes_encrypt_ctx
|
||||
#define f_enc_key128(a, b) aes_encrypt_key128((b), (a))
|
||||
#define f_enc_key192(a, b) aes_encrypt_key192((b), (a))
|
||||
#define f_enc_key256(a, b) aes_encrypt_key256((b), (a))
|
||||
#define f_enc_key(a, b, c) aes_encrypt_key((b), (c), (a))
|
||||
#define f_enc_blk(a, b, c) aes_encrypt((b), (c), (a))
|
||||
|
||||
#define f_dctx aes_decrypt_ctx
|
||||
#define f_dec_key128(a, b) aes_decrypt_key128((b), (a))
|
||||
#define f_dec_key192(a, b) aes_decrypt_key192((b), (a))
|
||||
#define f_dec_key256(a, b) aes_decrypt_key256((b), (a))
|
||||
#define f_dec_key(a, b, c) aes_decrypt_key((b), (c), (a))
|
||||
#define f_dec_blk(a, b, c) aes_decrypt((b), (c), (a))
|
||||
|
||||
#define f_talign(a, b) aes_test_alignment_detection(b)
|
||||
#define f_mode_reset(a) aes_mode_reset(a)
|
||||
#define f_ecb_enc(a, b, c, d) aes_ecb_encrypt((b), (c), (d), (a))
|
||||
#define f_ecb_dec(a, b, c, d) aes_ecb_decrypt((b), (c), (d), (a))
|
||||
#define f_cbc_enc(a, b, c, d, e) aes_cbc_encrypt((b), (c), (d), (e), (a))
|
||||
#define f_cbc_dec(a, b, c, d, e) aes_cbc_decrypt((b), (c), (d), (e), (a))
|
||||
#define f_cfb_enc(a, b, c, d, e) aes_cfb_encrypt((b), (c), (d), (e), (a))
|
||||
#define f_cfb_dec(a, b, c, d, e) aes_cfb_decrypt((b), (c), (d), (e), (a))
|
||||
#define f_ofb_cry(a, b, c, d, e) aes_ofb_crypt((b), (c), (d), (e), (a))
|
||||
#define f_ctr_cry(a, b, c, d, e, f) aes_ctr_crypt((b), (c), (d), (e), (f), (a))
|
||||
|
||||
#define ek_name128 "aes_encrypt_key128"
|
||||
#define ek_name192 "aes_encrypt_key192"
|
||||
#define ek_name256 "aes_encrypt_key256"
|
||||
#define ek_name "aes_encrypt_key"
|
||||
#define eb_name "aes_encrypt"
|
||||
|
||||
#define dk_name128 "aes_decrypt_key128"
|
||||
#define dk_name192 "aes_decrypt_key192"
|
||||
#define dk_name256 "aes_decrypt_key256"
|
||||
#define dk_name "aes_decrypt_key"
|
||||
#define db_name "aes_decrypt"
|
||||
|
||||
#define eres_name "aes_mode_reset"
|
||||
#define ecbe_name "aes_ecb_encrypt"
|
||||
#define ecbd_name "aes_ecb_decrypt"
|
||||
#define cbce_name "aes_cbc_encrypt"
|
||||
#define cbcd_name "aes_cbc_decrypt"
|
||||
#define cfbe_name "aes_cfb_encrypt"
|
||||
#define cfbd_name "aes_cfb_decrypt"
|
||||
#define ofb_name "aes_ofb_crypt"
|
||||
#define ctr_name "aes_ctr_crypt"
|
||||
|
||||
#ifndef AES_N_BLOCK
|
||||
#define do_enc(a, b, c, d) f_enc_blk(a, b, c)
|
||||
#define do_dec(a, b, c, d) f_dec_blk(a, b, c)
|
||||
#else
|
||||
#define do_enc(a, b, c, d) f_ecb_enc(a, b, c, 1)
|
||||
#define do_dec(a, b, c, d) f_ecb_dec(a, b, c, 1)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* Copyright (c) 2017 Saleem Rashid
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "base32.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
const char* BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789";
|
||||
|
||||
static inline void base32_5to8(const uint8_t* in, uint8_t length, uint8_t* out);
|
||||
static inline bool
|
||||
base32_8to5(const uint8_t* in, uint8_t length, uint8_t* out, const char* alphabet);
|
||||
static inline void base32_8to5_raw(const uint8_t* in, uint8_t length, uint8_t* out);
|
||||
|
||||
static inline int base32_encode_character(uint8_t decoded, const char* alphabet);
|
||||
static inline int base32_decode_character(char encoded, const char* alphabet);
|
||||
|
||||
char* base32_encode(
|
||||
const uint8_t* in,
|
||||
size_t inlen,
|
||||
char* out,
|
||||
size_t outlen,
|
||||
const char* alphabet) {
|
||||
size_t length = base32_encoded_length(inlen);
|
||||
if(outlen <= length) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
base32_encode_unsafe(in, inlen, (uint8_t*)out);
|
||||
|
||||
for(size_t i = 0; i < length; i++) {
|
||||
int ret = base32_encode_character(out[i], alphabet);
|
||||
|
||||
if(ret == -1) {
|
||||
return NULL;
|
||||
} else {
|
||||
out[i] = ret;
|
||||
}
|
||||
}
|
||||
|
||||
out[length] = '\0';
|
||||
return &out[length];
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
base32_decode(const char* in, size_t inlen, uint8_t* out, size_t outlen, const char* alphabet) {
|
||||
size_t length = base32_decoded_length(inlen);
|
||||
if(outlen < length) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!base32_decode_unsafe((uint8_t*)in, inlen, (uint8_t*)out, alphabet)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &out[length];
|
||||
}
|
||||
|
||||
void base32_encode_unsafe(const uint8_t* in, size_t inlen, uint8_t* out) {
|
||||
uint8_t remainder = inlen % 5;
|
||||
size_t limit = inlen - remainder;
|
||||
|
||||
size_t i = 0, j = 0;
|
||||
for(i = 0, j = 0; i < limit; i += 5, j += 8) {
|
||||
base32_5to8(&in[i], 5, &out[j]);
|
||||
}
|
||||
|
||||
if(remainder) base32_5to8(&in[i], remainder, &out[j]);
|
||||
}
|
||||
|
||||
bool base32_decode_unsafe(const uint8_t* in, size_t inlen, uint8_t* out, const char* alphabet) {
|
||||
uint8_t remainder = inlen % 8;
|
||||
size_t limit = inlen - remainder;
|
||||
|
||||
size_t i = 0, j = 0;
|
||||
for(i = 0, j = 0; i < limit; i += 8, j += 5) {
|
||||
if(!base32_8to5(&in[i], 8, &out[j], alphabet)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t base32_encoded_length(size_t inlen) {
|
||||
uint8_t remainder = inlen % 5;
|
||||
|
||||
return (inlen / 5) * 8 + (remainder * 8 + 4) / 5;
|
||||
}
|
||||
|
||||
size_t base32_decoded_length(size_t inlen) {
|
||||
uint8_t remainder = inlen % 8;
|
||||
|
||||
return (inlen / 8) * 5 + (remainder * 5) / 8;
|
||||
}
|
||||
|
||||
void base32_5to8(const uint8_t* in, uint8_t length, uint8_t* out) {
|
||||
if(length >= 1) {
|
||||
out[0] = (in[0] >> 3);
|
||||
out[1] = (in[0] & 7) << 2;
|
||||
}
|
||||
|
||||
if(length >= 2) {
|
||||
out[1] |= (in[1] >> 6);
|
||||
out[2] = (in[1] >> 1) & 31;
|
||||
out[3] = (in[1] & 1) << 4;
|
||||
}
|
||||
|
||||
if(length >= 3) {
|
||||
out[3] |= (in[2] >> 4);
|
||||
out[4] = (in[2] & 15) << 1;
|
||||
}
|
||||
|
||||
if(length >= 4) {
|
||||
out[4] |= (in[3] >> 7);
|
||||
out[5] = (in[3] >> 2) & 31;
|
||||
out[6] = (in[3] & 3) << 3;
|
||||
}
|
||||
|
||||
if(length >= 5) {
|
||||
out[6] |= (in[4] >> 5);
|
||||
out[7] = (in[4] & 31);
|
||||
}
|
||||
}
|
||||
|
||||
bool base32_8to5(const uint8_t* in, uint8_t length, uint8_t* out, const char* alphabet) {
|
||||
if(length == 1 || length == 3 || length == 6 || length > 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(alphabet) {
|
||||
uint8_t decoded[length];
|
||||
memset(decoded, 0, sizeof(decoded));
|
||||
|
||||
for(size_t i = 0; i < length; i++) {
|
||||
int ret = base32_decode_character(in[i], alphabet);
|
||||
|
||||
if(ret == -1) {
|
||||
return false;
|
||||
} else {
|
||||
decoded[i] = ret;
|
||||
}
|
||||
}
|
||||
|
||||
base32_8to5_raw(decoded, length, out);
|
||||
} else {
|
||||
base32_8to5_raw(in, length, out);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void base32_8to5_raw(const uint8_t* in, uint8_t length, uint8_t* out) {
|
||||
if(length >= 2) {
|
||||
out[0] = (in[0] << 3);
|
||||
out[0] |= (in[1] >> 2);
|
||||
}
|
||||
|
||||
if(length >= 4) {
|
||||
out[1] = (in[1] & 3) << 6;
|
||||
out[1] |= (in[2] << 1);
|
||||
out[1] |= (in[3] >> 4);
|
||||
}
|
||||
|
||||
if(length >= 5) {
|
||||
out[2] = (in[3] & 15) << 4;
|
||||
out[2] |= (in[4] >> 1);
|
||||
}
|
||||
|
||||
if(length >= 7) {
|
||||
out[3] = (in[4] & 1) << 7;
|
||||
out[3] |= (in[5] << 2);
|
||||
out[3] |= (in[6] >> 3);
|
||||
}
|
||||
|
||||
if(length >= 8) {
|
||||
out[4] = (in[6] & 7) << 5;
|
||||
out[4] |= (in[7] & 31);
|
||||
}
|
||||
}
|
||||
|
||||
int base32_encode_character(uint8_t decoded, const char* alphabet) {
|
||||
if(decoded >> 5) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(alphabet == BASE32_ALPHABET_RFC4648) {
|
||||
if(decoded < 26) {
|
||||
return 'A' + decoded;
|
||||
} else {
|
||||
return '2' - 26 + decoded;
|
||||
}
|
||||
}
|
||||
|
||||
return alphabet[decoded];
|
||||
}
|
||||
|
||||
int base32_decode_character(char encoded, const char* alphabet) {
|
||||
if(alphabet == BASE32_ALPHABET_RFC4648) {
|
||||
if(encoded >= 'A' && encoded <= 'Z') {
|
||||
return encoded - 'A';
|
||||
} else if(encoded >= 'a' && encoded <= 'z') {
|
||||
return encoded - 'a';
|
||||
} else if(encoded >= '2' && encoded <= '7') {
|
||||
return encoded - '2' + 26;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const char* occurrence = strchr(alphabet, encoded);
|
||||
|
||||
if(occurrence) {
|
||||
return occurrence - alphabet;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2017 Saleem Rashid
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __BASE32_H__
|
||||
#define __BASE32_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern const char* BASE32_ALPHABET_RFC4648;
|
||||
|
||||
char* base32_encode(const uint8_t* in, size_t inlen, char* out, size_t outlen, const char* alphabet);
|
||||
void base32_encode_unsafe(const uint8_t* in, size_t inlen, uint8_t* out);
|
||||
|
||||
uint8_t*
|
||||
base32_decode(const char* in, size_t inlen, uint8_t* out, size_t outlen, const char* alphabet);
|
||||
bool base32_decode_unsafe(const uint8_t* in, size_t inlen, uint8_t* out, const char* alphabet);
|
||||
|
||||
size_t base32_encoded_length(size_t inlen);
|
||||
size_t base32_decoded_length(size_t inlen);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Copyright (c) 2012-2014 Luke Dashjr
|
||||
* Copyright (c) 2013-2014 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "base58.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "memzero.h"
|
||||
#include "ripemd160.h"
|
||||
#include "sha2.h"
|
||||
|
||||
const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
const int8_t b58digits_map[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9,
|
||||
10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, -1, -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44,
|
||||
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
typedef uint64_t b58_maxint_t;
|
||||
typedef uint32_t b58_almostmaxint_t;
|
||||
#define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8)
|
||||
static const b58_almostmaxint_t b58_almostmaxint_mask =
|
||||
((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1);
|
||||
|
||||
// Decodes a null-terminated Base58 string `b58` to binary and writes the result
|
||||
// at the end of the buffer `bin` of size `*binszp`. On success `*binszp` is set
|
||||
// to the number of valid bytes at the end of the buffer.
|
||||
bool b58tobin(void* bin, size_t* binszp, const char* b58) {
|
||||
size_t binsz = *binszp;
|
||||
|
||||
if(binsz == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char* b58u = (const unsigned char*)b58;
|
||||
unsigned char* binu = bin;
|
||||
size_t outisz = (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t);
|
||||
b58_almostmaxint_t outi[outisz];
|
||||
b58_maxint_t t = 0;
|
||||
b58_almostmaxint_t c = 0;
|
||||
size_t i = 0, j = 0;
|
||||
uint8_t bytesleft = binsz % sizeof(b58_almostmaxint_t);
|
||||
b58_almostmaxint_t zeromask = bytesleft ? (b58_almostmaxint_mask << (bytesleft * 8)) : 0;
|
||||
unsigned zerocount = 0;
|
||||
|
||||
size_t b58sz = strlen(b58);
|
||||
|
||||
memzero(outi, sizeof(outi));
|
||||
|
||||
// Leading zeros, just count
|
||||
for(i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount;
|
||||
|
||||
for(; i < b58sz; ++i) {
|
||||
if(b58u[i] & 0x80)
|
||||
// High-bit set on invalid digit
|
||||
return false;
|
||||
if(b58digits_map[b58u[i]] == -1)
|
||||
// Invalid base58 digit
|
||||
return false;
|
||||
c = (unsigned)b58digits_map[b58u[i]];
|
||||
for(j = outisz; j--;) {
|
||||
t = ((b58_maxint_t)outi[j]) * 58 + c;
|
||||
c = t >> b58_almostmaxint_bits;
|
||||
outi[j] = t & b58_almostmaxint_mask;
|
||||
}
|
||||
if(c)
|
||||
// Output number too big (carry to the next int32)
|
||||
return false;
|
||||
if(outi[0] & zeromask)
|
||||
// Output number too big (last int32 filled too far)
|
||||
return false;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
if(bytesleft) {
|
||||
for(i = bytesleft; i > 0; --i) {
|
||||
*(binu++) = (outi[0] >> (8 * (i - 1))) & 0xff;
|
||||
}
|
||||
++j;
|
||||
}
|
||||
|
||||
for(; j < outisz; ++j) {
|
||||
for(i = sizeof(*outi); i > 0; --i) {
|
||||
*(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
// locate the most significant byte
|
||||
binu = bin;
|
||||
for(i = 0; i < binsz; ++i) {
|
||||
if(binu[i]) break;
|
||||
}
|
||||
|
||||
// prepend the correct number of null-bytes
|
||||
if(zerocount > i) {
|
||||
/* result too large */
|
||||
return false;
|
||||
}
|
||||
*binszp = binsz - i + zerocount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int b58check(const void* bin, size_t binsz, HasherType hasher_type, const char* base58str) {
|
||||
unsigned char buf[32] = {0};
|
||||
const uint8_t* binc = bin;
|
||||
unsigned i = 0;
|
||||
if(binsz < 4) return -4;
|
||||
hasher_Raw(hasher_type, bin, binsz - 4, buf);
|
||||
if(memcmp(&binc[binsz - 4], buf, 4)) return -1;
|
||||
|
||||
// Check number of zeros is correct AFTER verifying checksum (to avoid
|
||||
// possibility of accessing base58str beyond the end)
|
||||
for(i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) {
|
||||
} // Just finding the end of zeros, nothing to do in loop
|
||||
if(binc[i] == '\0' || base58str[i] == '1') return -3;
|
||||
|
||||
return binc[0];
|
||||
}
|
||||
|
||||
bool b58enc(char* b58, size_t* b58sz, const void* data, size_t binsz) {
|
||||
const uint8_t* bin = data;
|
||||
int carry = 0;
|
||||
size_t i = 0, j = 0, high = 0, zcount = 0;
|
||||
size_t size = 0;
|
||||
|
||||
while(zcount < binsz && !bin[zcount]) ++zcount;
|
||||
|
||||
size = (binsz - zcount) * 138 / 100 + 1;
|
||||
uint8_t buf[size];
|
||||
memzero(buf, size);
|
||||
|
||||
for(i = zcount, high = size - 1; i < binsz; ++i, high = j) {
|
||||
for(carry = bin[i], j = size - 1; (j > high) || carry; --j) {
|
||||
carry += 256 * buf[j];
|
||||
buf[j] = carry % 58;
|
||||
carry /= 58;
|
||||
if(!j) {
|
||||
// Otherwise j wraps to maxint which is > high
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(j = 0; j < size && !buf[j]; ++j)
|
||||
;
|
||||
|
||||
if(*b58sz <= zcount + size - j) {
|
||||
*b58sz = zcount + size - j + 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(zcount) memset(b58, '1', zcount);
|
||||
for(i = zcount; j < size; ++i, ++j) b58[i] = b58digits_ordered[buf[j]];
|
||||
b58[i] = '\0';
|
||||
*b58sz = i + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int base58_encode_check(
|
||||
const uint8_t* data,
|
||||
int datalen,
|
||||
HasherType hasher_type,
|
||||
char* str,
|
||||
int strsize) {
|
||||
if(datalen > 128) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t buf[datalen + 32];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
uint8_t* hash = buf + datalen;
|
||||
memcpy(buf, data, datalen);
|
||||
hasher_Raw(hasher_type, data, datalen, hash);
|
||||
size_t res = strsize;
|
||||
bool success = b58enc(str, &res, buf, datalen + 4);
|
||||
memzero(buf, sizeof(buf));
|
||||
return success ? res : 0;
|
||||
}
|
||||
|
||||
int base58_decode_check(const char* str, HasherType hasher_type, uint8_t* data, int datalen) {
|
||||
if(datalen > 128) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t d[datalen + 4];
|
||||
memset(d, 0, sizeof(d));
|
||||
size_t res = datalen + 4;
|
||||
if(b58tobin(d, &res, str) != true) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t* nd = d + datalen + 4 - res;
|
||||
if(b58check(nd, res, hasher_type, str) < 0) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(data, nd, res - 4);
|
||||
return res - 4;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Tomas Dzetkulic
|
||||
* Copyright (c) 2013-2014 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __BASE58_H__
|
||||
#define __BASE58_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "hasher.h"
|
||||
#include "options.h"
|
||||
|
||||
extern const char b58digits_ordered[];
|
||||
extern const int8_t b58digits_map[];
|
||||
|
||||
int base58_encode_check(
|
||||
const uint8_t* data,
|
||||
int len,
|
||||
HasherType hasher_type,
|
||||
char* str,
|
||||
int strsize);
|
||||
int base58_decode_check(const char* str, HasherType hasher_type, uint8_t* data, int datalen);
|
||||
|
||||
// Private
|
||||
bool b58tobin(void* bin, size_t* binszp, const char* b58);
|
||||
int b58check(const void* bin, size_t binsz, HasherType hasher_type, const char* base58str);
|
||||
bool b58enc(char* b58, size_t* b58sz, const void* data, size_t binsz);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Tomas Dzetkulic
|
||||
* Copyright (c) 2013-2014 Pavol Rusnak
|
||||
* Copyright (c) 2016 Alex Beregszaszi
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __BIGNUM_H__
|
||||
#define __BIGNUM_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#define BN_LIMBS 9
|
||||
#define BN_BITS_PER_LIMB 29
|
||||
#define BN_BASE (1u << BN_BITS_PER_LIMB)
|
||||
#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1)
|
||||
#define BN_EXTRA_BITS (32 - BN_BITS_PER_LIMB)
|
||||
#define BN_BITS_LAST_LIMB (256 - (BN_LIMBS - 1) * BN_BITS_PER_LIMB)
|
||||
|
||||
// Represents the number sum([val[i] * 2**(29*i) for i in range(9))
|
||||
typedef struct {
|
||||
uint32_t val[BN_LIMBS];
|
||||
} bignum256;
|
||||
|
||||
static inline uint32_t read_be(const uint8_t* data) {
|
||||
return (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) | (((uint32_t)data[2]) << 8) |
|
||||
(((uint32_t)data[3]));
|
||||
}
|
||||
|
||||
static inline void write_be(uint8_t* data, uint32_t x) {
|
||||
data[0] = x >> 24;
|
||||
data[1] = x >> 16;
|
||||
data[2] = x >> 8;
|
||||
data[3] = x;
|
||||
}
|
||||
|
||||
static inline uint32_t read_le(const uint8_t* data) {
|
||||
return (((uint32_t)data[3]) << 24) | (((uint32_t)data[2]) << 16) | (((uint32_t)data[1]) << 8) |
|
||||
(((uint32_t)data[0]));
|
||||
}
|
||||
|
||||
static inline void write_le(uint8_t* data, uint32_t x) {
|
||||
data[3] = x >> 24;
|
||||
data[2] = x >> 16;
|
||||
data[1] = x >> 8;
|
||||
data[0] = x;
|
||||
}
|
||||
|
||||
void bn_read_be(const uint8_t* in_number, bignum256* out_number);
|
||||
void bn_write_be(const bignum256* in_number, uint8_t* out_number);
|
||||
void bn_read_le(const uint8_t* in_number, bignum256* out_number);
|
||||
void bn_write_le(const bignum256* in_number, uint8_t* out_number);
|
||||
void bn_read_uint32(uint32_t in_number, bignum256* out_number);
|
||||
void bn_read_uint64(uint64_t in_number, bignum256* out_number);
|
||||
int bn_bitcount(const bignum256* x);
|
||||
unsigned int bn_digitcount(const bignum256* x);
|
||||
void bn_zero(bignum256* x);
|
||||
void bn_one(bignum256* x);
|
||||
int bn_is_zero(const bignum256* x);
|
||||
int bn_is_one(const bignum256* x);
|
||||
int bn_is_less(const bignum256* x, const bignum256* y);
|
||||
int bn_is_equal(const bignum256* x, const bignum256* y);
|
||||
void bn_cmov(
|
||||
bignum256* res,
|
||||
volatile uint32_t cond,
|
||||
const bignum256* truecase,
|
||||
const bignum256* falsecase);
|
||||
void bn_cnegate(volatile uint32_t cond, bignum256* x, const bignum256* prime);
|
||||
void bn_lshift(bignum256* x);
|
||||
void bn_rshift(bignum256* x);
|
||||
void bn_setbit(bignum256* x, uint16_t i);
|
||||
void bn_clearbit(bignum256* x, uint16_t i);
|
||||
uint32_t bn_testbit(const bignum256* x, uint16_t i);
|
||||
void bn_xor(bignum256* res, const bignum256* x, const bignum256* y);
|
||||
void bn_mult_half(bignum256* x, const bignum256* prime);
|
||||
void bn_mult_k(bignum256* x, uint8_t k, const bignum256* prime);
|
||||
void bn_mod(bignum256* x, const bignum256* prime);
|
||||
void bn_multiply(const bignum256* k, bignum256* x, const bignum256* prime);
|
||||
void bn_fast_mod(bignum256* x, const bignum256* prime);
|
||||
void bn_power_mod(const bignum256* x, const bignum256* e, const bignum256* prime, bignum256* res);
|
||||
void bn_sqrt(bignum256* x, const bignum256* prime);
|
||||
uint32_t inverse_mod_power_two(uint32_t a, uint32_t n);
|
||||
void bn_divide_base(bignum256* x, const bignum256* prime);
|
||||
void bn_normalize(bignum256* x);
|
||||
void bn_add(bignum256* x, const bignum256* y);
|
||||
void bn_addmod(bignum256* x, const bignum256* y, const bignum256* prime);
|
||||
void bn_addi(bignum256* x, uint32_t y);
|
||||
void bn_subi(bignum256* x, uint32_t y, const bignum256* prime);
|
||||
void bn_subtractmod(const bignum256* x, const bignum256* y, bignum256* res, const bignum256* prime);
|
||||
void bn_subtract(const bignum256* x, const bignum256* y, bignum256* res);
|
||||
void bn_long_division(bignum256* x, uint32_t d, bignum256* q, uint32_t* r);
|
||||
void bn_divmod58(bignum256* x, uint32_t* r);
|
||||
void bn_divmod1000(bignum256* x, uint32_t* r);
|
||||
void bn_inverse(bignum256* x, const bignum256* prime);
|
||||
size_t bn_format(
|
||||
const bignum256* amount,
|
||||
const char* prefix,
|
||||
const char* suffix,
|
||||
unsigned int decimals,
|
||||
int exponent,
|
||||
bool trailing,
|
||||
char thousands,
|
||||
char* output,
|
||||
size_t output_length);
|
||||
|
||||
// Returns (uint32_t) in_number
|
||||
// Assumes in_number < 2**32
|
||||
// Assumes in_number is normalized
|
||||
static inline uint32_t bn_write_uint32(const bignum256* in_number) {
|
||||
return in_number->val[0] | (in_number->val[1] << BN_BITS_PER_LIMB);
|
||||
}
|
||||
|
||||
// Returns (uint64_t) in_number
|
||||
// Assumes in_number < 2**64
|
||||
// Assumes in_number is normalized
|
||||
static inline uint64_t bn_write_uint64(const bignum256* in_number) {
|
||||
uint64_t acc;
|
||||
acc = in_number->val[2];
|
||||
acc <<= BN_BITS_PER_LIMB;
|
||||
acc |= in_number->val[1];
|
||||
acc <<= BN_BITS_PER_LIMB;
|
||||
acc |= in_number->val[0];
|
||||
return acc;
|
||||
}
|
||||
|
||||
// y = x
|
||||
static inline void bn_copy(const bignum256* x, bignum256* y) {
|
||||
*y = *x;
|
||||
}
|
||||
|
||||
// Returns x % 2 == 0
|
||||
static inline int bn_is_even(const bignum256* x) {
|
||||
return (x->val[0] & 1) == 0;
|
||||
}
|
||||
|
||||
// Returns x % 2 == 0
|
||||
static inline int bn_is_odd(const bignum256* x) {
|
||||
return (x->val[0] & 1) == 1;
|
||||
}
|
||||
|
||||
static inline size_t bn_format_uint64(
|
||||
uint64_t amount,
|
||||
const char* prefix,
|
||||
const char* suffix,
|
||||
unsigned int decimals,
|
||||
int exponent,
|
||||
bool trailing,
|
||||
char thousands,
|
||||
char* output,
|
||||
size_t output_length) {
|
||||
bignum256 bn_amount;
|
||||
bn_read_uint64(amount, &bn_amount);
|
||||
|
||||
return bn_format(
|
||||
&bn_amount, prefix, suffix, decimals, exponent, trailing, thousands, output, output_length);
|
||||
}
|
||||
|
||||
static inline size_t bn_format_amount(
|
||||
uint64_t amount,
|
||||
const char* prefix,
|
||||
const char* suffix,
|
||||
unsigned int decimals,
|
||||
char* output,
|
||||
size_t output_length) {
|
||||
return bn_format_uint64(
|
||||
amount, prefix, suffix, decimals, 0, false, ',', output, output_length);
|
||||
}
|
||||
|
||||
#if USE_BN_PRINT
|
||||
void bn_print(const bignum256* x);
|
||||
void bn_print_raw(const bignum256* x);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,887 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2016 Tomas Dzetkulic
|
||||
* Copyright (c) 2013-2016 Pavol Rusnak
|
||||
* Copyright (c) 2015-2016 Jochen Hoenicke
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "address.h"
|
||||
#if USE_NEM
|
||||
#include "aes/aes.h"
|
||||
#endif
|
||||
#include "base58.h"
|
||||
#include "bignum.h"
|
||||
#include "bip32.h"
|
||||
#include "cardano.h"
|
||||
#include "curves.h"
|
||||
#include "ecdsa.h"
|
||||
#include "ed25519_donna/ed25519_sha3.h"
|
||||
#include "ed25519_donna/ed25519.h"
|
||||
#include "hmac.h"
|
||||
#include "nist256p1.h"
|
||||
#include "secp256k1.h"
|
||||
#include "sha2.h"
|
||||
#include "sha3.h"
|
||||
#if USE_KECCAK
|
||||
#include "ed25519_donna/ed25519_keccak.h"
|
||||
#endif
|
||||
#if USE_NEM
|
||||
#include "nem.h"
|
||||
#endif
|
||||
#include "memzero.h"
|
||||
|
||||
const curve_info ed25519_info = {
|
||||
.bip32_name = ED25519_SEED_NAME,
|
||||
.params = NULL,
|
||||
.hasher_base58 = HASHER_SHA2D,
|
||||
.hasher_sign = HASHER_SHA2D,
|
||||
.hasher_pubkey = HASHER_SHA2_RIPEMD,
|
||||
.hasher_script = HASHER_SHA2,
|
||||
};
|
||||
|
||||
const curve_info ed25519_sha3_info = {
|
||||
.bip32_name = "ed25519-sha3 seed",
|
||||
.params = NULL,
|
||||
.hasher_base58 = HASHER_SHA2D,
|
||||
.hasher_sign = HASHER_SHA2D,
|
||||
.hasher_pubkey = HASHER_SHA2_RIPEMD,
|
||||
.hasher_script = HASHER_SHA2,
|
||||
};
|
||||
|
||||
#if USE_KECCAK
|
||||
const curve_info ed25519_keccak_info = {
|
||||
.bip32_name = "ed25519-keccak seed",
|
||||
.params = NULL,
|
||||
.hasher_base58 = HASHER_SHA2D,
|
||||
.hasher_sign = HASHER_SHA2D,
|
||||
.hasher_pubkey = HASHER_SHA2_RIPEMD,
|
||||
.hasher_script = HASHER_SHA2,
|
||||
};
|
||||
#endif
|
||||
|
||||
const curve_info curve25519_info = {
|
||||
.bip32_name = "curve25519 seed",
|
||||
.params = NULL,
|
||||
.hasher_base58 = HASHER_SHA2D,
|
||||
.hasher_sign = HASHER_SHA2D,
|
||||
.hasher_pubkey = HASHER_SHA2_RIPEMD,
|
||||
.hasher_script = HASHER_SHA2,
|
||||
};
|
||||
|
||||
int hdnode_from_xpub(
|
||||
uint32_t depth,
|
||||
uint32_t child_num,
|
||||
const uint8_t* chain_code,
|
||||
const uint8_t* public_key,
|
||||
const char* curve,
|
||||
HDNode* out) {
|
||||
const curve_info* info = get_curve_by_name(curve);
|
||||
if(info == 0) {
|
||||
return 0;
|
||||
}
|
||||
if(public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey
|
||||
return 0;
|
||||
}
|
||||
out->curve = info;
|
||||
out->depth = depth;
|
||||
out->child_num = child_num;
|
||||
memcpy(out->chain_code, chain_code, 32);
|
||||
memzero(out->private_key, 32);
|
||||
memzero(out->private_key_extension, 32);
|
||||
memcpy(out->public_key, public_key, 33);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hdnode_from_xprv(
|
||||
uint32_t depth,
|
||||
uint32_t child_num,
|
||||
const uint8_t* chain_code,
|
||||
const uint8_t* private_key,
|
||||
const char* curve,
|
||||
HDNode* out) {
|
||||
bool failed = false;
|
||||
const curve_info* info = get_curve_by_name(curve);
|
||||
if(info == 0) {
|
||||
failed = true;
|
||||
} else if(info->params) {
|
||||
bignum256 a = {0};
|
||||
bn_read_be(private_key, &a);
|
||||
if(bn_is_zero(&a)) { // == 0
|
||||
failed = true;
|
||||
} else {
|
||||
if(!bn_is_less(&a, &info->params->order)) { // >= order
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
memzero(&a, sizeof(a));
|
||||
}
|
||||
|
||||
if(failed) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
out->curve = info;
|
||||
out->depth = depth;
|
||||
out->child_num = child_num;
|
||||
memcpy(out->chain_code, chain_code, 32);
|
||||
memcpy(out->private_key, private_key, 32);
|
||||
memzero(out->public_key, sizeof(out->public_key));
|
||||
memzero(out->private_key_extension, sizeof(out->private_key_extension));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hdnode_from_seed(const uint8_t* seed, int seed_len, const char* curve, HDNode* out) {
|
||||
static CONFIDENTIAL uint8_t I[32 + 32];
|
||||
memzero(out, sizeof(HDNode));
|
||||
out->depth = 0;
|
||||
out->child_num = 0;
|
||||
out->curve = get_curve_by_name(curve);
|
||||
if(out->curve == 0) {
|
||||
return 0;
|
||||
}
|
||||
static CONFIDENTIAL HMAC_SHA512_CTX ctx;
|
||||
hmac_sha512_Init(&ctx, (const uint8_t*)out->curve->bip32_name, strlen(out->curve->bip32_name));
|
||||
hmac_sha512_Update(&ctx, seed, seed_len);
|
||||
hmac_sha512_Final(&ctx, I);
|
||||
|
||||
if(out->curve->params) {
|
||||
bignum256 a = {0};
|
||||
while(true) {
|
||||
bn_read_be(I, &a);
|
||||
if(!bn_is_zero(&a) // != 0
|
||||
&& bn_is_less(&a, &out->curve->params->order)) { // < order
|
||||
break;
|
||||
}
|
||||
hmac_sha512_Init(
|
||||
&ctx, (const uint8_t*)out->curve->bip32_name, strlen(out->curve->bip32_name));
|
||||
hmac_sha512_Update(&ctx, I, sizeof(I));
|
||||
hmac_sha512_Final(&ctx, I);
|
||||
}
|
||||
memzero(&a, sizeof(a));
|
||||
}
|
||||
memcpy(out->private_key, I, 32);
|
||||
memcpy(out->chain_code, I + 32, 32);
|
||||
memzero(out->public_key, sizeof(out->public_key));
|
||||
memzero(I, sizeof(I));
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t hdnode_fingerprint(HDNode* node) {
|
||||
uint8_t digest[32] = {0};
|
||||
uint32_t fingerprint = 0;
|
||||
|
||||
hdnode_fill_public_key(node);
|
||||
hasher_Raw(node->curve->hasher_pubkey, node->public_key, 33, digest);
|
||||
fingerprint = ((uint32_t)digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3];
|
||||
memzero(digest, sizeof(digest));
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
int hdnode_private_ckd_bip32(HDNode* inout, uint32_t i) {
|
||||
static CONFIDENTIAL uint8_t data[1 + 32 + 4];
|
||||
static CONFIDENTIAL uint8_t I[32 + 32];
|
||||
static CONFIDENTIAL bignum256 a, b;
|
||||
|
||||
#if USE_CARDANO
|
||||
if(inout->curve == &ed25519_cardano_info) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(i & 0x80000000) { // private derivation
|
||||
data[0] = 0;
|
||||
memcpy(data + 1, inout->private_key, 32);
|
||||
} else { // public derivation
|
||||
if(!inout->curve->params) {
|
||||
return 0;
|
||||
}
|
||||
if(hdnode_fill_public_key(inout) != 0) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(data, inout->public_key, 33);
|
||||
}
|
||||
write_be(data + 33, i);
|
||||
|
||||
bn_read_be(inout->private_key, &a);
|
||||
|
||||
static CONFIDENTIAL HMAC_SHA512_CTX ctx;
|
||||
hmac_sha512_Init(&ctx, inout->chain_code, 32);
|
||||
hmac_sha512_Update(&ctx, data, sizeof(data));
|
||||
hmac_sha512_Final(&ctx, I);
|
||||
|
||||
if(inout->curve->params) {
|
||||
while(true) {
|
||||
bool failed = false;
|
||||
bn_read_be(I, &b);
|
||||
if(!bn_is_less(&b, &inout->curve->params->order)) { // >= order
|
||||
failed = true;
|
||||
} else {
|
||||
bn_add(&b, &a);
|
||||
bn_mod(&b, &inout->curve->params->order);
|
||||
if(bn_is_zero(&b)) {
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!failed) {
|
||||
bn_write_be(&b, inout->private_key);
|
||||
break;
|
||||
}
|
||||
|
||||
data[0] = 1;
|
||||
memcpy(data + 1, I + 32, 32);
|
||||
hmac_sha512_Init(&ctx, inout->chain_code, 32);
|
||||
hmac_sha512_Update(&ctx, data, sizeof(data));
|
||||
hmac_sha512_Final(&ctx, I);
|
||||
}
|
||||
} else {
|
||||
memcpy(inout->private_key, I, 32);
|
||||
}
|
||||
|
||||
memcpy(inout->chain_code, I + 32, 32);
|
||||
inout->depth++;
|
||||
inout->child_num = i;
|
||||
memzero(inout->public_key, sizeof(inout->public_key));
|
||||
|
||||
// making sure to wipe our memory
|
||||
memzero(&a, sizeof(a));
|
||||
memzero(&b, sizeof(b));
|
||||
memzero(I, sizeof(I));
|
||||
memzero(data, sizeof(data));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hdnode_private_ckd(HDNode* inout, uint32_t i) {
|
||||
#if USE_CARDANO
|
||||
if(inout->curve == &ed25519_cardano_info) {
|
||||
return hdnode_private_ckd_cardano(inout, i);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return hdnode_private_ckd_bip32(inout, i);
|
||||
}
|
||||
}
|
||||
|
||||
int hdnode_public_ckd_cp(
|
||||
const ecdsa_curve* curve,
|
||||
const curve_point* parent,
|
||||
const uint8_t* parent_chain_code,
|
||||
uint32_t i,
|
||||
curve_point* child,
|
||||
uint8_t* child_chain_code) {
|
||||
uint8_t data[(1 + 32) + 4] = {0};
|
||||
uint8_t I[32 + 32] = {0};
|
||||
bignum256 c = {0};
|
||||
|
||||
if(i & 0x80000000) { // private derivation
|
||||
return 0;
|
||||
}
|
||||
|
||||
data[0] = 0x02 | (parent->y.val[0] & 0x01);
|
||||
bn_write_be(&parent->x, data + 1);
|
||||
write_be(data + 33, i);
|
||||
|
||||
while(true) {
|
||||
hmac_sha512(parent_chain_code, 32, data, sizeof(data), I);
|
||||
bn_read_be(I, &c);
|
||||
if(bn_is_less(&c, &curve->order)) { // < order
|
||||
scalar_multiply(curve, &c, child); // b = c * G
|
||||
point_add(curve, parent, child); // b = a + b
|
||||
if(!point_is_infinity(child)) {
|
||||
if(child_chain_code) {
|
||||
memcpy(child_chain_code, I + 32, 32);
|
||||
}
|
||||
|
||||
// Wipe all stack data.
|
||||
memzero(data, sizeof(data));
|
||||
memzero(I, sizeof(I));
|
||||
memzero(&c, sizeof(c));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
data[0] = 1;
|
||||
memcpy(data + 1, I + 32, 32);
|
||||
}
|
||||
}
|
||||
|
||||
int hdnode_public_ckd(HDNode* inout, uint32_t i) {
|
||||
curve_point parent = {0}, child = {0};
|
||||
|
||||
if(!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &parent)) {
|
||||
return 0;
|
||||
}
|
||||
if(!hdnode_public_ckd_cp(
|
||||
inout->curve->params, &parent, inout->chain_code, i, &child, inout->chain_code)) {
|
||||
return 0;
|
||||
}
|
||||
memzero(inout->private_key, 32);
|
||||
inout->depth++;
|
||||
inout->child_num = i;
|
||||
inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01);
|
||||
bn_write_be(&child.x, inout->public_key + 1);
|
||||
|
||||
// Wipe all stack data.
|
||||
memzero(&parent, sizeof(parent));
|
||||
memzero(&child, sizeof(child));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void hdnode_public_ckd_address_optimized(
|
||||
const curve_point* pub,
|
||||
const uint8_t* chain_code,
|
||||
uint32_t i,
|
||||
uint32_t version,
|
||||
HasherType hasher_pubkey,
|
||||
HasherType hasher_base58,
|
||||
char* addr,
|
||||
int addrsize,
|
||||
int addrformat) {
|
||||
uint8_t child_pubkey[33] = {0};
|
||||
curve_point b = {0};
|
||||
|
||||
hdnode_public_ckd_cp(&secp256k1, pub, chain_code, i, &b, NULL);
|
||||
child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01);
|
||||
bn_write_be(&b.x, child_pubkey + 1);
|
||||
|
||||
switch(addrformat) {
|
||||
case 1: // Segwit-in-P2SH
|
||||
ecdsa_get_address_segwit_p2sh(
|
||||
child_pubkey, version, hasher_pubkey, hasher_base58, addr, addrsize);
|
||||
break;
|
||||
default: // normal address
|
||||
ecdsa_get_address(child_pubkey, version, hasher_pubkey, hasher_base58, addr, addrsize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_BIP32_CACHE
|
||||
static bool private_ckd_cache_root_set = false;
|
||||
static CONFIDENTIAL HDNode private_ckd_cache_root;
|
||||
static int private_ckd_cache_index = 0;
|
||||
|
||||
static CONFIDENTIAL struct {
|
||||
bool set;
|
||||
size_t depth;
|
||||
uint32_t i[BIP32_CACHE_MAXDEPTH];
|
||||
HDNode node;
|
||||
} private_ckd_cache[BIP32_CACHE_SIZE];
|
||||
|
||||
void bip32_cache_clear(void) {
|
||||
private_ckd_cache_root_set = false;
|
||||
private_ckd_cache_index = 0;
|
||||
memzero(&private_ckd_cache_root, sizeof(private_ckd_cache_root));
|
||||
memzero(private_ckd_cache, sizeof(private_ckd_cache));
|
||||
}
|
||||
|
||||
int hdnode_private_ckd_cached(
|
||||
HDNode* inout,
|
||||
const uint32_t* i,
|
||||
size_t i_count,
|
||||
uint32_t* fingerprint) {
|
||||
if(i_count == 0) {
|
||||
// no way how to compute parent fingerprint
|
||||
return 1;
|
||||
}
|
||||
if(i_count == 1) {
|
||||
if(fingerprint) {
|
||||
*fingerprint = hdnode_fingerprint(inout);
|
||||
}
|
||||
if(hdnode_private_ckd(inout, i[0]) == 0) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
// if root is not set or not the same
|
||||
if(!private_ckd_cache_root_set ||
|
||||
memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) {
|
||||
// clear the cache
|
||||
private_ckd_cache_index = 0;
|
||||
memzero(private_ckd_cache, sizeof(private_ckd_cache));
|
||||
// setup new root
|
||||
memcpy(&private_ckd_cache_root, inout, sizeof(HDNode));
|
||||
private_ckd_cache_root_set = true;
|
||||
} else {
|
||||
// try to find parent
|
||||
int j = 0;
|
||||
for(j = 0; j < BIP32_CACHE_SIZE; j++) {
|
||||
if(private_ckd_cache[j].set && private_ckd_cache[j].depth == i_count - 1 &&
|
||||
memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0 &&
|
||||
private_ckd_cache[j].node.curve == inout->curve) {
|
||||
memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// else derive parent
|
||||
if(!found) {
|
||||
size_t k = 0;
|
||||
for(k = 0; k < i_count - 1; k++) {
|
||||
if(hdnode_private_ckd(inout, i[k]) == 0) return 0;
|
||||
}
|
||||
// and save it
|
||||
memzero(
|
||||
&(private_ckd_cache[private_ckd_cache_index]),
|
||||
sizeof(private_ckd_cache[private_ckd_cache_index]));
|
||||
private_ckd_cache[private_ckd_cache_index].set = true;
|
||||
private_ckd_cache[private_ckd_cache_index].depth = i_count - 1;
|
||||
memcpy(private_ckd_cache[private_ckd_cache_index].i, i, (i_count - 1) * sizeof(uint32_t));
|
||||
memcpy(&(private_ckd_cache[private_ckd_cache_index].node), inout, sizeof(HDNode));
|
||||
private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE;
|
||||
}
|
||||
|
||||
if(fingerprint) {
|
||||
*fingerprint = hdnode_fingerprint(inout);
|
||||
}
|
||||
if(hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int hdnode_get_address_raw(HDNode* node, uint32_t version, uint8_t* addr_raw) {
|
||||
if(hdnode_fill_public_key(node) != 0) {
|
||||
return 1;
|
||||
}
|
||||
ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_pubkey, addr_raw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdnode_get_address(HDNode* node, uint32_t version, char* addr, int addrsize) {
|
||||
if(hdnode_fill_public_key(node) != 0) {
|
||||
return 1;
|
||||
}
|
||||
ecdsa_get_address(
|
||||
node->public_key,
|
||||
version,
|
||||
node->curve->hasher_pubkey,
|
||||
node->curve->hasher_base58,
|
||||
addr,
|
||||
addrsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdnode_fill_public_key(HDNode* node) {
|
||||
if(node->public_key[0] != 0) return 0;
|
||||
|
||||
#if USE_BIP32_25519_CURVES
|
||||
if(node->curve->params) {
|
||||
if(ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key) != 0) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
node->public_key[0] = 1;
|
||||
if(node->curve == &ed25519_info) {
|
||||
ed25519_publickey(node->private_key, node->public_key + 1);
|
||||
} else if(node->curve == &ed25519_sha3_info) {
|
||||
ed25519_publickey_sha3(node->private_key, node->public_key + 1);
|
||||
#if USE_KECCAK
|
||||
} else if(node->curve == &ed25519_keccak_info) {
|
||||
ed25519_publickey_keccak(node->private_key, node->public_key + 1);
|
||||
#endif
|
||||
} else if(node->curve == &curve25519_info) {
|
||||
curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key);
|
||||
#if USE_CARDANO
|
||||
} else if(node->curve == &ed25519_cardano_info) {
|
||||
ed25519_publickey_ext(node->private_key, node->public_key + 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
if(ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key) != 0) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if USE_ETHEREUM
|
||||
int hdnode_get_ethereum_pubkeyhash(const HDNode* node, uint8_t* pubkeyhash) {
|
||||
uint8_t buf[65] = {0};
|
||||
//SHA3_CTX ctx = {0};
|
||||
SHA3_CTX* ctx = malloc(sizeof(SHA3_CTX));
|
||||
memzero(ctx, sizeof(SHA3_CTX));
|
||||
|
||||
/* get uncompressed public key */
|
||||
if(ecdsa_get_public_key65(node->curve->params, node->private_key, buf) != 0) {
|
||||
memzero(ctx, sizeof(SHA3_CTX));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* compute sha3 of x and y coordinate without 04 prefix */
|
||||
sha3_256_Init(ctx);
|
||||
sha3_Update(ctx, buf + 1, 64);
|
||||
keccak_Final(ctx, buf);
|
||||
|
||||
memzero(ctx, sizeof(SHA3_CTX));
|
||||
free(ctx);
|
||||
|
||||
/* result are the least significant 160 bits */
|
||||
memcpy(pubkeyhash, buf + 12, 20);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_NEM
|
||||
int hdnode_get_nem_address(HDNode* node, uint8_t version, char* address) {
|
||||
if(node->curve != &ed25519_keccak_info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(hdnode_fill_public_key(node) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nem_get_address(&node->public_key[1], version, address);
|
||||
}
|
||||
|
||||
int hdnode_get_nem_shared_key(
|
||||
const HDNode* node,
|
||||
const ed25519_public_key peer_public_key,
|
||||
const uint8_t* salt,
|
||||
ed25519_public_key mul,
|
||||
uint8_t* shared_key) {
|
||||
if(node->curve != &ed25519_keccak_info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// sizeof(ed25519_public_key) == SHA3_256_DIGEST_LENGTH
|
||||
if(mul == NULL) mul = shared_key;
|
||||
|
||||
if(ed25519_scalarmult_keccak(mul, node->private_key, peer_public_key)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < 32; i++) {
|
||||
shared_key[i] = mul[i] ^ salt[i];
|
||||
}
|
||||
|
||||
keccak_256(shared_key, 32, shared_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hdnode_nem_encrypt(
|
||||
const HDNode* node,
|
||||
const ed25519_public_key public_key,
|
||||
const uint8_t* iv_immut,
|
||||
const uint8_t* salt,
|
||||
const uint8_t* payload,
|
||||
size_t size,
|
||||
uint8_t* buffer) {
|
||||
uint8_t last_block[AES_BLOCK_SIZE] = {0};
|
||||
uint8_t remainder = size % AES_BLOCK_SIZE;
|
||||
|
||||
// Round down to last whole block
|
||||
size -= remainder;
|
||||
// Copy old last block
|
||||
memcpy(last_block, &payload[size], remainder);
|
||||
// Pad new last block with number of missing bytes
|
||||
memset(&last_block[remainder], AES_BLOCK_SIZE - remainder, AES_BLOCK_SIZE - remainder);
|
||||
|
||||
// the IV gets mutated, so we make a copy not to touch the original
|
||||
uint8_t iv[AES_BLOCK_SIZE] = {0};
|
||||
memcpy(iv, iv_immut, AES_BLOCK_SIZE);
|
||||
|
||||
uint8_t shared_key[SHA3_256_DIGEST_LENGTH] = {0};
|
||||
if(!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
aes_encrypt_ctx ctx = {0};
|
||||
|
||||
int ret = aes_encrypt_key256(shared_key, &ctx);
|
||||
memzero(shared_key, sizeof(shared_key));
|
||||
|
||||
if(ret != EXIT_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(aes_cbc_encrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(aes_cbc_encrypt(last_block, &buffer[size], sizeof(last_block), iv, &ctx) != EXIT_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hdnode_nem_decrypt(
|
||||
const HDNode* node,
|
||||
const ed25519_public_key public_key,
|
||||
uint8_t* iv,
|
||||
const uint8_t* salt,
|
||||
const uint8_t* payload,
|
||||
size_t size,
|
||||
uint8_t* buffer) {
|
||||
uint8_t shared_key[SHA3_256_DIGEST_LENGTH] = {0};
|
||||
|
||||
if(!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
aes_decrypt_ctx ctx = {0};
|
||||
|
||||
int ret = aes_decrypt_key256(shared_key, &ctx);
|
||||
memzero(shared_key, sizeof(shared_key));
|
||||
|
||||
if(ret != EXIT_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(aes_cbc_decrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// msg is a data to be signed
|
||||
// msg_len is the message length
|
||||
int hdnode_sign(
|
||||
HDNode* node,
|
||||
const uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
HasherType hasher_sign,
|
||||
uint8_t* sig,
|
||||
uint8_t* pby,
|
||||
int (*is_canonical)(uint8_t by, uint8_t sig[64])) {
|
||||
if(node->curve->params) {
|
||||
return ecdsa_sign(
|
||||
node->curve->params,
|
||||
hasher_sign,
|
||||
node->private_key,
|
||||
msg,
|
||||
msg_len,
|
||||
sig,
|
||||
pby,
|
||||
is_canonical);
|
||||
} else if(node->curve == &curve25519_info) {
|
||||
return 1; // signatures are not supported
|
||||
} else {
|
||||
if(node->curve == &ed25519_info) {
|
||||
ed25519_sign(msg, msg_len, node->private_key, sig);
|
||||
} else if(node->curve == &ed25519_sha3_info) {
|
||||
ed25519_sign_sha3(msg, msg_len, node->private_key, sig);
|
||||
#if USE_KECCAK
|
||||
} else if(node->curve == &ed25519_keccak_info) {
|
||||
ed25519_sign_keccak(msg, msg_len, node->private_key, sig);
|
||||
#endif
|
||||
} else {
|
||||
return 1; // unknown or unsupported curve
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int hdnode_sign_digest(
|
||||
HDNode* node,
|
||||
const uint8_t* digest,
|
||||
uint8_t* sig,
|
||||
uint8_t* pby,
|
||||
int (*is_canonical)(uint8_t by, uint8_t sig[64])) {
|
||||
if(node->curve->params) {
|
||||
return ecdsa_sign_digest(
|
||||
node->curve->params, node->private_key, digest, sig, pby, is_canonical);
|
||||
} else if(node->curve == &curve25519_info) {
|
||||
return 1; // signatures are not supported
|
||||
} else {
|
||||
return hdnode_sign(node, digest, 32, 0, sig, pby, is_canonical);
|
||||
}
|
||||
}
|
||||
|
||||
int hdnode_get_shared_key(
|
||||
const HDNode* node,
|
||||
const uint8_t* peer_public_key,
|
||||
uint8_t* session_key,
|
||||
int* result_size) {
|
||||
// Use elliptic curve Diffie-Helman to compute shared session key
|
||||
if(node->curve->params) {
|
||||
if(ecdh_multiply(node->curve->params, node->private_key, peer_public_key, session_key) !=
|
||||
0) {
|
||||
return 1;
|
||||
}
|
||||
*result_size = 65;
|
||||
return 0;
|
||||
} else if(node->curve == &curve25519_info) {
|
||||
session_key[0] = 0x04;
|
||||
if(peer_public_key[0] != 0x40) {
|
||||
return 1; // Curve25519 public key should start with 0x40 byte.
|
||||
}
|
||||
curve25519_scalarmult(session_key + 1, node->private_key, peer_public_key + 1);
|
||||
*result_size = 33;
|
||||
return 0;
|
||||
} else {
|
||||
*result_size = 0;
|
||||
return 1; // ECDH is not supported
|
||||
}
|
||||
}
|
||||
|
||||
static int hdnode_serialize(
|
||||
const HDNode* node,
|
||||
uint32_t fingerprint,
|
||||
uint32_t version,
|
||||
bool use_private,
|
||||
char* str,
|
||||
int strsize) {
|
||||
uint8_t node_data[78] = {0};
|
||||
write_be(node_data, version);
|
||||
node_data[4] = node->depth;
|
||||
write_be(node_data + 5, fingerprint);
|
||||
write_be(node_data + 9, node->child_num);
|
||||
memcpy(node_data + 13, node->chain_code, 32);
|
||||
if(use_private) {
|
||||
node_data[45] = 0;
|
||||
memcpy(node_data + 46, node->private_key, 32);
|
||||
} else {
|
||||
memcpy(node_data + 45, node->public_key, 33);
|
||||
}
|
||||
int ret = base58_encode_check(
|
||||
node_data, sizeof(node_data), node->curve->hasher_base58, str, strsize);
|
||||
memzero(node_data, sizeof(node_data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hdnode_serialize_public(
|
||||
const HDNode* node,
|
||||
uint32_t fingerprint,
|
||||
uint32_t version,
|
||||
char* str,
|
||||
int strsize) {
|
||||
return hdnode_serialize(node, fingerprint, version, false, str, strsize);
|
||||
}
|
||||
|
||||
int hdnode_serialize_private(
|
||||
const HDNode* node,
|
||||
uint32_t fingerprint,
|
||||
uint32_t version,
|
||||
char* str,
|
||||
int strsize) {
|
||||
return hdnode_serialize(node, fingerprint, version, true, str, strsize);
|
||||
}
|
||||
|
||||
// check for validity of curve point in case of public data not performed
|
||||
static int hdnode_deserialize(
|
||||
const char* str,
|
||||
uint32_t version,
|
||||
bool use_private,
|
||||
const char* curve,
|
||||
HDNode* node,
|
||||
uint32_t* fingerprint) {
|
||||
uint8_t node_data[78] = {0};
|
||||
memzero(node, sizeof(HDNode));
|
||||
node->curve = get_curve_by_name(curve);
|
||||
if(base58_decode_check(str, node->curve->hasher_base58, node_data, sizeof(node_data)) !=
|
||||
sizeof(node_data)) {
|
||||
return -1;
|
||||
}
|
||||
uint32_t ver = read_be(node_data);
|
||||
if(ver != version) {
|
||||
return -3; // invalid version
|
||||
}
|
||||
if(use_private) {
|
||||
// invalid data
|
||||
if(node_data[45]) {
|
||||
return -2;
|
||||
}
|
||||
memcpy(node->private_key, node_data + 46, 32);
|
||||
memzero(node->public_key, sizeof(node->public_key));
|
||||
} else {
|
||||
memzero(node->private_key, sizeof(node->private_key));
|
||||
memcpy(node->public_key, node_data + 45, 33);
|
||||
}
|
||||
node->depth = node_data[4];
|
||||
if(fingerprint) {
|
||||
*fingerprint = read_be(node_data + 5);
|
||||
}
|
||||
node->child_num = read_be(node_data + 9);
|
||||
memcpy(node->chain_code, node_data + 13, 32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdnode_deserialize_public(
|
||||
const char* str,
|
||||
uint32_t version,
|
||||
const char* curve,
|
||||
HDNode* node,
|
||||
uint32_t* fingerprint) {
|
||||
return hdnode_deserialize(str, version, false, curve, node, fingerprint);
|
||||
}
|
||||
|
||||
int hdnode_deserialize_private(
|
||||
const char* str,
|
||||
uint32_t version,
|
||||
const char* curve,
|
||||
HDNode* node,
|
||||
uint32_t* fingerprint) {
|
||||
return hdnode_deserialize(str, version, true, curve, node, fingerprint);
|
||||
}
|
||||
|
||||
const curve_info* get_curve_by_name(const char* curve_name) {
|
||||
if(curve_name == 0) {
|
||||
return 0;
|
||||
}
|
||||
if(strcmp(curve_name, SECP256K1_NAME) == 0) {
|
||||
return &secp256k1_info;
|
||||
}
|
||||
if(strcmp(curve_name, SECP256K1_DECRED_NAME) == 0) {
|
||||
return &secp256k1_decred_info;
|
||||
}
|
||||
if(strcmp(curve_name, SECP256K1_GROESTL_NAME) == 0) {
|
||||
return &secp256k1_groestl_info;
|
||||
}
|
||||
if(strcmp(curve_name, SECP256K1_SMART_NAME) == 0) {
|
||||
return &secp256k1_smart_info;
|
||||
}
|
||||
if(strcmp(curve_name, NIST256P1_NAME) == 0) {
|
||||
return &nist256p1_info;
|
||||
}
|
||||
if(strcmp(curve_name, ED25519_NAME) == 0) {
|
||||
return &ed25519_info;
|
||||
}
|
||||
#if USE_CARDANO
|
||||
if(strcmp(curve_name, ED25519_CARDANO_NAME) == 0) {
|
||||
return &ed25519_cardano_info;
|
||||
}
|
||||
#endif
|
||||
if(strcmp(curve_name, ED25519_SHA3_NAME) == 0) {
|
||||
return &ed25519_sha3_info;
|
||||
}
|
||||
#if USE_KECCAK
|
||||
if(strcmp(curve_name, ED25519_KECCAK_NAME) == 0) {
|
||||
return &ed25519_keccak_info;
|
||||
}
|
||||
#endif
|
||||
if(strcmp(curve_name, CURVE25519_NAME) == 0) {
|
||||
return &curve25519_info;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Tomas Dzetkulic
|
||||
* Copyright (c) 2013-2014 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __BIP32_H__
|
||||
#define __BIP32_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "ecdsa.h"
|
||||
#include "ed25519_donna/ed25519.h"
|
||||
#include "options.h"
|
||||
|
||||
// Maximum length of a Base58Check-encoded extended public or private key.
|
||||
#define XPUB_MAXLEN 112
|
||||
|
||||
// Maximum length of a Base58Check-encoded address.
|
||||
#define ADDRESS_MAXLEN 39
|
||||
|
||||
typedef struct {
|
||||
const char* bip32_name; // string for generating BIP32 xprv from seed
|
||||
const ecdsa_curve* params; // ecdsa curve parameters, null for ed25519
|
||||
|
||||
HasherType hasher_base58;
|
||||
HasherType hasher_sign;
|
||||
HasherType hasher_pubkey;
|
||||
HasherType hasher_script;
|
||||
} curve_info;
|
||||
|
||||
typedef struct {
|
||||
uint32_t depth;
|
||||
uint32_t child_num;
|
||||
uint8_t chain_code[32];
|
||||
|
||||
uint8_t private_key[32];
|
||||
uint8_t private_key_extension[32];
|
||||
|
||||
uint8_t public_key[33];
|
||||
const curve_info* curve;
|
||||
} HDNode;
|
||||
|
||||
int hdnode_from_xpub(
|
||||
uint32_t depth,
|
||||
uint32_t child_num,
|
||||
const uint8_t* chain_code,
|
||||
const uint8_t* public_key,
|
||||
const char* curve,
|
||||
HDNode* out);
|
||||
|
||||
int hdnode_from_xprv(
|
||||
uint32_t depth,
|
||||
uint32_t child_num,
|
||||
const uint8_t* chain_code,
|
||||
const uint8_t* private_key,
|
||||
const char* curve,
|
||||
HDNode* out);
|
||||
|
||||
int hdnode_from_seed(const uint8_t* seed, int seed_len, const char* curve, HDNode* out);
|
||||
|
||||
#define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000))
|
||||
|
||||
int hdnode_private_ckd(HDNode* inout, uint32_t i);
|
||||
|
||||
int hdnode_public_ckd_cp(
|
||||
const ecdsa_curve* curve,
|
||||
const curve_point* parent,
|
||||
const uint8_t* parent_chain_code,
|
||||
uint32_t i,
|
||||
curve_point* child,
|
||||
uint8_t* child_chain_code);
|
||||
|
||||
int hdnode_public_ckd(HDNode* inout, uint32_t i);
|
||||
|
||||
void hdnode_public_ckd_address_optimized(
|
||||
const curve_point* pub,
|
||||
const uint8_t* chain_code,
|
||||
uint32_t i,
|
||||
uint32_t version,
|
||||
HasherType hasher_pubkey,
|
||||
HasherType hasher_base58,
|
||||
char* addr,
|
||||
int addrsize,
|
||||
int addrformat);
|
||||
|
||||
#if USE_BIP32_CACHE
|
||||
void bip32_cache_clear(void);
|
||||
int hdnode_private_ckd_cached(
|
||||
HDNode* inout,
|
||||
const uint32_t* i,
|
||||
size_t i_count,
|
||||
uint32_t* fingerprint);
|
||||
#endif
|
||||
|
||||
uint32_t hdnode_fingerprint(HDNode* node);
|
||||
|
||||
int hdnode_fill_public_key(HDNode* node);
|
||||
|
||||
#if USE_ETHEREUM
|
||||
int hdnode_get_ethereum_pubkeyhash(const HDNode* node, uint8_t* pubkeyhash);
|
||||
#endif
|
||||
|
||||
#if USE_NEM
|
||||
int hdnode_get_nem_address(HDNode* node, uint8_t version, char* address);
|
||||
int hdnode_get_nem_shared_key(
|
||||
const HDNode* node,
|
||||
const ed25519_public_key peer_public_key,
|
||||
const uint8_t* salt,
|
||||
ed25519_public_key mul,
|
||||
uint8_t* shared_key);
|
||||
int hdnode_nem_encrypt(
|
||||
const HDNode* node,
|
||||
const ed25519_public_key public_key,
|
||||
const uint8_t* iv,
|
||||
const uint8_t* salt,
|
||||
const uint8_t* payload,
|
||||
size_t size,
|
||||
uint8_t* buffer);
|
||||
int hdnode_nem_decrypt(
|
||||
const HDNode* node,
|
||||
const ed25519_public_key public_key,
|
||||
uint8_t* iv,
|
||||
const uint8_t* salt,
|
||||
const uint8_t* payload,
|
||||
size_t size,
|
||||
uint8_t* buffer);
|
||||
#endif
|
||||
|
||||
int hdnode_sign(
|
||||
HDNode* node,
|
||||
const uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
HasherType hasher_sign,
|
||||
uint8_t* sig,
|
||||
uint8_t* pby,
|
||||
int (*is_canonical)(uint8_t by, uint8_t sig[64]));
|
||||
int hdnode_sign_digest(
|
||||
HDNode* node,
|
||||
const uint8_t* digest,
|
||||
uint8_t* sig,
|
||||
uint8_t* pby,
|
||||
int (*is_canonical)(uint8_t by, uint8_t sig[64]));
|
||||
|
||||
int hdnode_get_shared_key(
|
||||
const HDNode* node,
|
||||
const uint8_t* peer_public_key,
|
||||
uint8_t* session_key,
|
||||
int* result_size);
|
||||
|
||||
int hdnode_serialize_public(
|
||||
const HDNode* node,
|
||||
uint32_t fingerprint,
|
||||
uint32_t version,
|
||||
char* str,
|
||||
int strsize);
|
||||
|
||||
int hdnode_serialize_private(
|
||||
const HDNode* node,
|
||||
uint32_t fingerprint,
|
||||
uint32_t version,
|
||||
char* str,
|
||||
int strsize);
|
||||
|
||||
int hdnode_deserialize_public(
|
||||
const char* str,
|
||||
uint32_t version,
|
||||
const char* curve,
|
||||
HDNode* node,
|
||||
uint32_t* fingerprint);
|
||||
|
||||
int hdnode_deserialize_private(
|
||||
const char* str,
|
||||
uint32_t version,
|
||||
const char* curve,
|
||||
HDNode* node,
|
||||
uint32_t* fingerprint);
|
||||
|
||||
int hdnode_get_address_raw(HDNode* node, uint32_t version, uint8_t* addr_raw);
|
||||
int hdnode_get_address(HDNode* node, uint32_t version, char* addr, int addrsize);
|
||||
|
||||
const curve_info* get_curve_by_name(const char* curve_name);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,288 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Tomas Dzetkulic
|
||||
* Copyright (c) 2013-2014 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bip39.h"
|
||||
#include "hmac.h"
|
||||
#include "memzero.h"
|
||||
#include "options.h"
|
||||
#include "pbkdf2.h"
|
||||
#include "rand.h"
|
||||
#include "sha2.h"
|
||||
|
||||
#if USE_BIP39_CACHE
|
||||
|
||||
static int bip39_cache_index = 0;
|
||||
|
||||
static CONFIDENTIAL struct {
|
||||
bool set;
|
||||
char mnemonic[256];
|
||||
char passphrase[64];
|
||||
uint8_t seed[512 / 8];
|
||||
} bip39_cache[BIP39_CACHE_SIZE];
|
||||
|
||||
void bip39_cache_clear(void) {
|
||||
memzero(bip39_cache, sizeof(bip39_cache));
|
||||
bip39_cache_index = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const char* mnemonic_generate(int strength) {
|
||||
if(strength % 32 || strength < 128 || strength > 256) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t data[32] = {0};
|
||||
random_buffer(data, 32);
|
||||
const char* r = mnemonic_from_data(data, strength / 8);
|
||||
memzero(data, sizeof(data));
|
||||
return r;
|
||||
}
|
||||
|
||||
static CONFIDENTIAL char mnemo[24 * 10];
|
||||
|
||||
const char* mnemonic_from_data(const uint8_t* data, int len) {
|
||||
if(len % 4 || len < 16 || len > 32) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t bits[32 + 1] = {0};
|
||||
|
||||
sha256_Raw(data, len, bits);
|
||||
// checksum
|
||||
bits[len] = bits[0];
|
||||
// data
|
||||
memcpy(bits, data, len);
|
||||
|
||||
int mlen = len * 3 / 4;
|
||||
|
||||
int i = 0, j = 0, idx = 0;
|
||||
char* p = mnemo;
|
||||
for(i = 0; i < mlen; i++) {
|
||||
idx = 0;
|
||||
for(j = 0; j < 11; j++) {
|
||||
idx <<= 1;
|
||||
idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0;
|
||||
}
|
||||
strcpy(p, BIP39_WORDLIST_ENGLISH[idx]);
|
||||
p += strlen(BIP39_WORDLIST_ENGLISH[idx]);
|
||||
*p = (i < mlen - 1) ? ' ' : 0;
|
||||
p++;
|
||||
}
|
||||
memzero(bits, sizeof(bits));
|
||||
|
||||
return mnemo;
|
||||
}
|
||||
|
||||
void mnemonic_clear(void) {
|
||||
memzero(mnemo, sizeof(mnemo));
|
||||
}
|
||||
|
||||
int mnemonic_to_bits(const char* mnemonic, uint8_t* bits) {
|
||||
if(!mnemonic) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t i = 0, n = 0;
|
||||
|
||||
while(mnemonic[i]) {
|
||||
if(mnemonic[i] == ' ') {
|
||||
n++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
n++;
|
||||
|
||||
// check that number of words is valid for BIP-39:
|
||||
// (a) between 128 and 256 bits of initial entropy (12 - 24 words)
|
||||
// (b) number of bits divisible by 33 (1 checksum bit per 32 input bits)
|
||||
// - that is, (n * 11) % 33 == 0, so n % 3 == 0
|
||||
if(n < 12 || n > 24 || (n % 3)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char current_word[10] = {0};
|
||||
uint32_t j = 0, ki = 0, bi = 0;
|
||||
uint8_t result[32 + 1] = {0};
|
||||
|
||||
memzero(result, sizeof(result));
|
||||
i = 0;
|
||||
while(mnemonic[i]) {
|
||||
j = 0;
|
||||
while(mnemonic[i] != ' ' && mnemonic[i] != 0) {
|
||||
if(j >= sizeof(current_word) - 1) {
|
||||
return 0;
|
||||
}
|
||||
current_word[j] = mnemonic[i];
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
current_word[j] = 0;
|
||||
if(mnemonic[i] != 0) {
|
||||
i++;
|
||||
}
|
||||
int k = mnemonic_find_word(current_word);
|
||||
if(k < 0) { // word not found
|
||||
return 0;
|
||||
}
|
||||
for(ki = 0; ki < 11; ki++) {
|
||||
if(k & (1 << (10 - ki))) {
|
||||
result[bi / 8] |= 1 << (7 - (bi % 8));
|
||||
}
|
||||
bi++;
|
||||
}
|
||||
}
|
||||
if(bi != n * 11) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(bits, result, sizeof(result));
|
||||
memzero(result, sizeof(result));
|
||||
|
||||
// returns amount of entropy + checksum BITS
|
||||
return n * 11;
|
||||
}
|
||||
|
||||
int mnemonic_check(const char* mnemonic) {
|
||||
uint8_t bits[32 + 1] = {0};
|
||||
int mnemonic_bits_len = mnemonic_to_bits(mnemonic, bits);
|
||||
if(mnemonic_bits_len != (12 * 11) && mnemonic_bits_len != (18 * 11) &&
|
||||
mnemonic_bits_len != (24 * 11)) {
|
||||
return 0;
|
||||
}
|
||||
int words = mnemonic_bits_len / 11;
|
||||
|
||||
uint8_t checksum = bits[words * 4 / 3];
|
||||
sha256_Raw(bits, words * 4 / 3, bits);
|
||||
if(words == 12) {
|
||||
return (bits[0] & 0xF0) == (checksum & 0xF0); // compare first 4 bits
|
||||
} else if(words == 18) {
|
||||
return (bits[0] & 0xFC) == (checksum & 0xFC); // compare first 6 bits
|
||||
} else if(words == 24) {
|
||||
return bits[0] == checksum; // compare 8 bits
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// passphrase must be at most 256 characters otherwise it would be truncated
|
||||
void mnemonic_to_seed(
|
||||
const char* mnemonic,
|
||||
const char* passphrase,
|
||||
uint8_t seed[512 / 8],
|
||||
void (*progress_callback)(uint32_t current, uint32_t total)) {
|
||||
int mnemoniclen = strlen(mnemonic);
|
||||
int passphraselen = strlen(passphrase);
|
||||
if(passphraselen > 256) passphraselen = 256;
|
||||
#if USE_BIP39_CACHE
|
||||
// check cache
|
||||
if(mnemoniclen < 256 && passphraselen < 64) {
|
||||
for(int i = 0; i < BIP39_CACHE_SIZE; i++) {
|
||||
if(!bip39_cache[i].set) continue;
|
||||
if(strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue;
|
||||
if(strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue;
|
||||
// found the correct entry
|
||||
memcpy(seed, bip39_cache[i].seed, 512 / 8);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
uint8_t salt[8 + 256] = {0};
|
||||
memcpy(salt, "mnemonic", 8);
|
||||
memcpy(salt + 8, passphrase, passphraselen);
|
||||
static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx;
|
||||
pbkdf2_hmac_sha512_Init(
|
||||
&pctx, (const uint8_t*)mnemonic, mnemoniclen, salt, passphraselen + 8, 1);
|
||||
if(progress_callback) {
|
||||
progress_callback(0, BIP39_PBKDF2_ROUNDS);
|
||||
}
|
||||
for(int i = 0; i < 16; i++) {
|
||||
pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16);
|
||||
if(progress_callback) {
|
||||
progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16, BIP39_PBKDF2_ROUNDS);
|
||||
}
|
||||
}
|
||||
pbkdf2_hmac_sha512_Final(&pctx, seed);
|
||||
memzero(salt, sizeof(salt));
|
||||
#if USE_BIP39_CACHE
|
||||
// store to cache
|
||||
if(mnemoniclen < 256 && passphraselen < 64) {
|
||||
bip39_cache[bip39_cache_index].set = true;
|
||||
strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic);
|
||||
strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase);
|
||||
memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8);
|
||||
bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// binary search for finding the word in the wordlist
|
||||
int mnemonic_find_word(const char* word) {
|
||||
int lo = 0, hi = BIP39_WORD_COUNT - 1;
|
||||
while(lo <= hi) {
|
||||
int mid = lo + (hi - lo) / 2;
|
||||
int cmp = strcmp(word, BIP39_WORDLIST_ENGLISH[mid]);
|
||||
if(cmp == 0) {
|
||||
return mid;
|
||||
}
|
||||
if(cmp > 0) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid - 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* mnemonic_complete_word(const char* prefix, int len) {
|
||||
// we need to perform linear search,
|
||||
// because we want to return the first match
|
||||
for(int i = 0; i < BIP39_WORD_COUNT; i++) {
|
||||
if(strncmp(BIP39_WORDLIST_ENGLISH[i], prefix, len) == 0) {
|
||||
return BIP39_WORDLIST_ENGLISH[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* mnemonic_get_word(int index) {
|
||||
if(index >= 0 && index < BIP39_WORD_COUNT) {
|
||||
return BIP39_WORDLIST_ENGLISH[index];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t mnemonic_word_completion_mask(const char* prefix, int len) {
|
||||
if(len <= 0) {
|
||||
return 0x3ffffff; // all letters (bits 1-26 set)
|
||||
}
|
||||
uint32_t res = 0;
|
||||
for(int i = 0; i < BIP39_WORD_COUNT; i++) {
|
||||
const char* word = BIP39_WORDLIST_ENGLISH[i];
|
||||
if(strncmp(word, prefix, len) == 0 && word[len] >= 'a' && word[len] <= 'z') {
|
||||
res |= 1 << (word[len] - 'a');
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Tomas Dzetkulic
|
||||
* Copyright (c) 2013-2014 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __BIP39_H__
|
||||
#define __BIP39_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#define BIP39_WORD_COUNT 2048
|
||||
#define BIP39_PBKDF2_ROUNDS 2048
|
||||
|
||||
#if USE_BIP39_CACHE
|
||||
void bip39_cache_clear(void);
|
||||
#endif
|
||||
|
||||
extern const char* const BIP39_WORDLIST_ENGLISH[BIP39_WORD_COUNT];
|
||||
|
||||
const char* mnemonic_generate(int strength); // strength in bits
|
||||
const char* mnemonic_from_data(const uint8_t* data, int len);
|
||||
void mnemonic_clear(void);
|
||||
|
||||
int mnemonic_check(const char* mnemonic);
|
||||
|
||||
int mnemonic_to_bits(const char* mnemonic, uint8_t* bits);
|
||||
|
||||
// passphrase must be at most 256 characters otherwise it would be truncated
|
||||
void mnemonic_to_seed(
|
||||
const char* mnemonic,
|
||||
const char* passphrase,
|
||||
uint8_t seed[512 / 8],
|
||||
void (*progress_callback)(uint32_t current, uint32_t total));
|
||||
|
||||
int mnemonic_find_word(const char* word);
|
||||
const char* mnemonic_complete_word(const char* prefix, int len);
|
||||
const char* mnemonic_get_word(int index);
|
||||
uint32_t mnemonic_word_completion_mask(const char* prefix, int len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Tomas Dzetkulic
|
||||
* Copyright (c) 2013-2014 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "bip39.h"
|
||||
|
||||
const char* const BIP39_WORDLIST_ENGLISH[BIP39_WORD_COUNT] = {
|
||||
"abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract",
|
||||
"absurd", "abuse", "access", "accident", "account", "accuse", "achieve", "acid",
|
||||
"acoustic", "acquire", "across", "act", "action", "actor", "actress", "actual",
|
||||
"adapt", "add", "addict", "address", "adjust", "admit", "adult", "advance",
|
||||
"advice", "aerobic", "affair", "afford", "afraid", "again", "age", "agent",
|
||||
"agree", "ahead", "aim", "air", "airport", "aisle", "alarm", "album",
|
||||
"alcohol", "alert", "alien", "all", "alley", "allow", "almost", "alone",
|
||||
"alpha", "already", "also", "alter", "always", "amateur", "amazing", "among",
|
||||
"amount", "amused", "analyst", "anchor", "ancient", "anger", "angle", "angry",
|
||||
"animal", "ankle", "announce", "annual", "another", "answer", "antenna", "antique",
|
||||
"anxiety", "any", "apart", "apology", "appear", "apple", "approve", "april",
|
||||
"arch", "arctic", "area", "arena", "argue", "arm", "armed", "armor",
|
||||
"army", "around", "arrange", "arrest", "arrive", "arrow", "art", "artefact",
|
||||
"artist", "artwork", "ask", "aspect", "assault", "asset", "assist", "assume",
|
||||
"asthma", "athlete", "atom", "attack", "attend", "attitude", "attract", "auction",
|
||||
"audit", "august", "aunt", "author", "auto", "autumn", "average", "avocado",
|
||||
"avoid", "awake", "aware", "away", "awesome", "awful", "awkward", "axis",
|
||||
"baby", "bachelor", "bacon", "badge", "bag", "balance", "balcony", "ball",
|
||||
"bamboo", "banana", "banner", "bar", "barely", "bargain", "barrel", "base",
|
||||
"basic", "basket", "battle", "beach", "bean", "beauty", "because", "become",
|
||||
"beef", "before", "begin", "behave", "behind", "believe", "below", "belt",
|
||||
"bench", "benefit", "best", "betray", "better", "between", "beyond", "bicycle",
|
||||
"bid", "bike", "bind", "biology", "bird", "birth", "bitter", "black",
|
||||
"blade", "blame", "blanket", "blast", "bleak", "bless", "blind", "blood",
|
||||
"blossom", "blouse", "blue", "blur", "blush", "board", "boat", "body",
|
||||
"boil", "bomb", "bone", "bonus", "book", "boost", "border", "boring",
|
||||
"borrow", "boss", "bottom", "bounce", "box", "boy", "bracket", "brain",
|
||||
"brand", "brass", "brave", "bread", "breeze", "brick", "bridge", "brief",
|
||||
"bright", "bring", "brisk", "broccoli", "broken", "bronze", "broom", "brother",
|
||||
"brown", "brush", "bubble", "buddy", "budget", "buffalo", "build", "bulb",
|
||||
"bulk", "bullet", "bundle", "bunker", "burden", "burger", "burst", "bus",
|
||||
"business", "busy", "butter", "buyer", "buzz", "cabbage", "cabin", "cable",
|
||||
"cactus", "cage", "cake", "call", "calm", "camera", "camp", "can",
|
||||
"canal", "cancel", "candy", "cannon", "canoe", "canvas", "canyon", "capable",
|
||||
"capital", "captain", "car", "carbon", "card", "cargo", "carpet", "carry",
|
||||
"cart", "case", "cash", "casino", "castle", "casual", "cat", "catalog",
|
||||
"catch", "category", "cattle", "caught", "cause", "caution", "cave", "ceiling",
|
||||
"celery", "cement", "census", "century", "cereal", "certain", "chair", "chalk",
|
||||
"champion", "change", "chaos", "chapter", "charge", "chase", "chat", "cheap",
|
||||
"check", "cheese", "chef", "cherry", "chest", "chicken", "chief", "child",
|
||||
"chimney", "choice", "choose", "chronic", "chuckle", "chunk", "churn", "cigar",
|
||||
"cinnamon", "circle", "citizen", "city", "civil", "claim", "clap", "clarify",
|
||||
"claw", "clay", "clean", "clerk", "clever", "click", "client", "cliff",
|
||||
"climb", "clinic", "clip", "clock", "clog", "close", "cloth", "cloud",
|
||||
"clown", "club", "clump", "cluster", "clutch", "coach", "coast", "coconut",
|
||||
"code", "coffee", "coil", "coin", "collect", "color", "column", "combine",
|
||||
"come", "comfort", "comic", "common", "company", "concert", "conduct", "confirm",
|
||||
"congress", "connect", "consider", "control", "convince", "cook", "cool", "copper",
|
||||
"copy", "coral", "core", "corn", "correct", "cost", "cotton", "couch",
|
||||
"country", "couple", "course", "cousin", "cover", "coyote", "crack", "cradle",
|
||||
"craft", "cram", "crane", "crash", "crater", "crawl", "crazy", "cream",
|
||||
"credit", "creek", "crew", "cricket", "crime", "crisp", "critic", "crop",
|
||||
"cross", "crouch", "crowd", "crucial", "cruel", "cruise", "crumble", "crunch",
|
||||
"crush", "cry", "crystal", "cube", "culture", "cup", "cupboard", "curious",
|
||||
"current", "curtain", "curve", "cushion", "custom", "cute", "cycle", "dad",
|
||||
"damage", "damp", "dance", "danger", "daring", "dash", "daughter", "dawn",
|
||||
"day", "deal", "debate", "debris", "decade", "december", "decide", "decline",
|
||||
"decorate", "decrease", "deer", "defense", "define", "defy", "degree", "delay",
|
||||
"deliver", "demand", "demise", "denial", "dentist", "deny", "depart", "depend",
|
||||
"deposit", "depth", "deputy", "derive", "describe", "desert", "design", "desk",
|
||||
"despair", "destroy", "detail", "detect", "develop", "device", "devote", "diagram",
|
||||
"dial", "diamond", "diary", "dice", "diesel", "diet", "differ", "digital",
|
||||
"dignity", "dilemma", "dinner", "dinosaur", "direct", "dirt", "disagree", "discover",
|
||||
"disease", "dish", "dismiss", "disorder", "display", "distance", "divert", "divide",
|
||||
"divorce", "dizzy", "doctor", "document", "dog", "doll", "dolphin", "domain",
|
||||
"donate", "donkey", "donor", "door", "dose", "double", "dove", "draft",
|
||||
"dragon", "drama", "drastic", "draw", "dream", "dress", "drift", "drill",
|
||||
"drink", "drip", "drive", "drop", "drum", "dry", "duck", "dumb",
|
||||
"dune", "during", "dust", "dutch", "duty", "dwarf", "dynamic", "eager",
|
||||
"eagle", "early", "earn", "earth", "easily", "east", "easy", "echo",
|
||||
"ecology", "economy", "edge", "edit", "educate", "effort", "egg", "eight",
|
||||
"either", "elbow", "elder", "electric", "elegant", "element", "elephant", "elevator",
|
||||
"elite", "else", "embark", "embody", "embrace", "emerge", "emotion", "employ",
|
||||
"empower", "empty", "enable", "enact", "end", "endless", "endorse", "enemy",
|
||||
"energy", "enforce", "engage", "engine", "enhance", "enjoy", "enlist", "enough",
|
||||
"enrich", "enroll", "ensure", "enter", "entire", "entry", "envelope", "episode",
|
||||
"equal", "equip", "era", "erase", "erode", "erosion", "error", "erupt",
|
||||
"escape", "essay", "essence", "estate", "eternal", "ethics", "evidence", "evil",
|
||||
"evoke", "evolve", "exact", "example", "excess", "exchange", "excite", "exclude",
|
||||
"excuse", "execute", "exercise", "exhaust", "exhibit", "exile", "exist", "exit",
|
||||
"exotic", "expand", "expect", "expire", "explain", "expose", "express", "extend",
|
||||
"extra", "eye", "eyebrow", "fabric", "face", "faculty", "fade", "faint",
|
||||
"faith", "fall", "false", "fame", "family", "famous", "fan", "fancy",
|
||||
"fantasy", "farm", "fashion", "fat", "fatal", "father", "fatigue", "fault",
|
||||
"favorite", "feature", "february", "federal", "fee", "feed", "feel", "female",
|
||||
"fence", "festival", "fetch", "fever", "few", "fiber", "fiction", "field",
|
||||
"figure", "file", "film", "filter", "final", "find", "fine", "finger",
|
||||
"finish", "fire", "firm", "first", "fiscal", "fish", "fit", "fitness",
|
||||
"fix", "flag", "flame", "flash", "flat", "flavor", "flee", "flight",
|
||||
"flip", "float", "flock", "floor", "flower", "fluid", "flush", "fly",
|
||||
"foam", "focus", "fog", "foil", "fold", "follow", "food", "foot",
|
||||
"force", "forest", "forget", "fork", "fortune", "forum", "forward", "fossil",
|
||||
"foster", "found", "fox", "fragile", "frame", "frequent", "fresh", "friend",
|
||||
"fringe", "frog", "front", "frost", "frown", "frozen", "fruit", "fuel",
|
||||
"fun", "funny", "furnace", "fury", "future", "gadget", "gain", "galaxy",
|
||||
"gallery", "game", "gap", "garage", "garbage", "garden", "garlic", "garment",
|
||||
"gas", "gasp", "gate", "gather", "gauge", "gaze", "general", "genius",
|
||||
"genre", "gentle", "genuine", "gesture", "ghost", "giant", "gift", "giggle",
|
||||
"ginger", "giraffe", "girl", "give", "glad", "glance", "glare", "glass",
|
||||
"glide", "glimpse", "globe", "gloom", "glory", "glove", "glow", "glue",
|
||||
"goat", "goddess", "gold", "good", "goose", "gorilla", "gospel", "gossip",
|
||||
"govern", "gown", "grab", "grace", "grain", "grant", "grape", "grass",
|
||||
"gravity", "great", "green", "grid", "grief", "grit", "grocery", "group",
|
||||
"grow", "grunt", "guard", "guess", "guide", "guilt", "guitar", "gun",
|
||||
"gym", "habit", "hair", "half", "hammer", "hamster", "hand", "happy",
|
||||
"harbor", "hard", "harsh", "harvest", "hat", "have", "hawk", "hazard",
|
||||
"head", "health", "heart", "heavy", "hedgehog", "height", "hello", "helmet",
|
||||
"help", "hen", "hero", "hidden", "high", "hill", "hint", "hip",
|
||||
"hire", "history", "hobby", "hockey", "hold", "hole", "holiday", "hollow",
|
||||
"home", "honey", "hood", "hope", "horn", "horror", "horse", "hospital",
|
||||
"host", "hotel", "hour", "hover", "hub", "huge", "human", "humble",
|
||||
"humor", "hundred", "hungry", "hunt", "hurdle", "hurry", "hurt", "husband",
|
||||
"hybrid", "ice", "icon", "idea", "identify", "idle", "ignore", "ill",
|
||||
"illegal", "illness", "image", "imitate", "immense", "immune", "impact", "impose",
|
||||
"improve", "impulse", "inch", "include", "income", "increase", "index", "indicate",
|
||||
"indoor", "industry", "infant", "inflict", "inform", "inhale", "inherit", "initial",
|
||||
"inject", "injury", "inmate", "inner", "innocent", "input", "inquiry", "insane",
|
||||
"insect", "inside", "inspire", "install", "intact", "interest", "into", "invest",
|
||||
"invite", "involve", "iron", "island", "isolate", "issue", "item", "ivory",
|
||||
"jacket", "jaguar", "jar", "jazz", "jealous", "jeans", "jelly", "jewel",
|
||||
"job", "join", "joke", "journey", "joy", "judge", "juice", "jump",
|
||||
"jungle", "junior", "junk", "just", "kangaroo", "keen", "keep", "ketchup",
|
||||
"key", "kick", "kid", "kidney", "kind", "kingdom", "kiss", "kit",
|
||||
"kitchen", "kite", "kitten", "kiwi", "knee", "knife", "knock", "know",
|
||||
"lab", "label", "labor", "ladder", "lady", "lake", "lamp", "language",
|
||||
"laptop", "large", "later", "latin", "laugh", "laundry", "lava", "law",
|
||||
"lawn", "lawsuit", "layer", "lazy", "leader", "leaf", "learn", "leave",
|
||||
"lecture", "left", "leg", "legal", "legend", "leisure", "lemon", "lend",
|
||||
"length", "lens", "leopard", "lesson", "letter", "level", "liar", "liberty",
|
||||
"library", "license", "life", "lift", "light", "like", "limb", "limit",
|
||||
"link", "lion", "liquid", "list", "little", "live", "lizard", "load",
|
||||
"loan", "lobster", "local", "lock", "logic", "lonely", "long", "loop",
|
||||
"lottery", "loud", "lounge", "love", "loyal", "lucky", "luggage", "lumber",
|
||||
"lunar", "lunch", "luxury", "lyrics", "machine", "mad", "magic", "magnet",
|
||||
"maid", "mail", "main", "major", "make", "mammal", "man", "manage",
|
||||
"mandate", "mango", "mansion", "manual", "maple", "marble", "march", "margin",
|
||||
"marine", "market", "marriage", "mask", "mass", "master", "match", "material",
|
||||
"math", "matrix", "matter", "maximum", "maze", "meadow", "mean", "measure",
|
||||
"meat", "mechanic", "medal", "media", "melody", "melt", "member", "memory",
|
||||
"mention", "menu", "mercy", "merge", "merit", "merry", "mesh", "message",
|
||||
"metal", "method", "middle", "midnight", "milk", "million", "mimic", "mind",
|
||||
"minimum", "minor", "minute", "miracle", "mirror", "misery", "miss", "mistake",
|
||||
"mix", "mixed", "mixture", "mobile", "model", "modify", "mom", "moment",
|
||||
"monitor", "monkey", "monster", "month", "moon", "moral", "more", "morning",
|
||||
"mosquito", "mother", "motion", "motor", "mountain", "mouse", "move", "movie",
|
||||
"much", "muffin", "mule", "multiply", "muscle", "museum", "mushroom", "music",
|
||||
"must", "mutual", "myself", "mystery", "myth", "naive", "name", "napkin",
|
||||
"narrow", "nasty", "nation", "nature", "near", "neck", "need", "negative",
|
||||
"neglect", "neither", "nephew", "nerve", "nest", "net", "network", "neutral",
|
||||
"never", "news", "next", "nice", "night", "noble", "noise", "nominee",
|
||||
"noodle", "normal", "north", "nose", "notable", "note", "nothing", "notice",
|
||||
"novel", "now", "nuclear", "number", "nurse", "nut", "oak", "obey",
|
||||
"object", "oblige", "obscure", "observe", "obtain", "obvious", "occur", "ocean",
|
||||
"october", "odor", "off", "offer", "office", "often", "oil", "okay",
|
||||
"old", "olive", "olympic", "omit", "once", "one", "onion", "online",
|
||||
"only", "open", "opera", "opinion", "oppose", "option", "orange", "orbit",
|
||||
"orchard", "order", "ordinary", "organ", "orient", "original", "orphan", "ostrich",
|
||||
"other", "outdoor", "outer", "output", "outside", "oval", "oven", "over",
|
||||
"own", "owner", "oxygen", "oyster", "ozone", "pact", "paddle", "page",
|
||||
"pair", "palace", "palm", "panda", "panel", "panic", "panther", "paper",
|
||||
"parade", "parent", "park", "parrot", "party", "pass", "patch", "path",
|
||||
"patient", "patrol", "pattern", "pause", "pave", "payment", "peace", "peanut",
|
||||
"pear", "peasant", "pelican", "pen", "penalty", "pencil", "people", "pepper",
|
||||
"perfect", "permit", "person", "pet", "phone", "photo", "phrase", "physical",
|
||||
"piano", "picnic", "picture", "piece", "pig", "pigeon", "pill", "pilot",
|
||||
"pink", "pioneer", "pipe", "pistol", "pitch", "pizza", "place", "planet",
|
||||
"plastic", "plate", "play", "please", "pledge", "pluck", "plug", "plunge",
|
||||
"poem", "poet", "point", "polar", "pole", "police", "pond", "pony",
|
||||
"pool", "popular", "portion", "position", "possible", "post", "potato", "pottery",
|
||||
"poverty", "powder", "power", "practice", "praise", "predict", "prefer", "prepare",
|
||||
"present", "pretty", "prevent", "price", "pride", "primary", "print", "priority",
|
||||
"prison", "private", "prize", "problem", "process", "produce", "profit", "program",
|
||||
"project", "promote", "proof", "property", "prosper", "protect", "proud", "provide",
|
||||
"public", "pudding", "pull", "pulp", "pulse", "pumpkin", "punch", "pupil",
|
||||
"puppy", "purchase", "purity", "purpose", "purse", "push", "put", "puzzle",
|
||||
"pyramid", "quality", "quantum", "quarter", "question", "quick", "quit", "quiz",
|
||||
"quote", "rabbit", "raccoon", "race", "rack", "radar", "radio", "rail",
|
||||
"rain", "raise", "rally", "ramp", "ranch", "random", "range", "rapid",
|
||||
"rare", "rate", "rather", "raven", "raw", "razor", "ready", "real",
|
||||
"reason", "rebel", "rebuild", "recall", "receive", "recipe", "record", "recycle",
|
||||
"reduce", "reflect", "reform", "refuse", "region", "regret", "regular", "reject",
|
||||
"relax", "release", "relief", "rely", "remain", "remember", "remind", "remove",
|
||||
"render", "renew", "rent", "reopen", "repair", "repeat", "replace", "report",
|
||||
"require", "rescue", "resemble", "resist", "resource", "response", "result", "retire",
|
||||
"retreat", "return", "reunion", "reveal", "review", "reward", "rhythm", "rib",
|
||||
"ribbon", "rice", "rich", "ride", "ridge", "rifle", "right", "rigid",
|
||||
"ring", "riot", "ripple", "risk", "ritual", "rival", "river", "road",
|
||||
"roast", "robot", "robust", "rocket", "romance", "roof", "rookie", "room",
|
||||
"rose", "rotate", "rough", "round", "route", "royal", "rubber", "rude",
|
||||
"rug", "rule", "run", "runway", "rural", "sad", "saddle", "sadness",
|
||||
"safe", "sail", "salad", "salmon", "salon", "salt", "salute", "same",
|
||||
"sample", "sand", "satisfy", "satoshi", "sauce", "sausage", "save", "say",
|
||||
"scale", "scan", "scare", "scatter", "scene", "scheme", "school", "science",
|
||||
"scissors", "scorpion", "scout", "scrap", "screen", "script", "scrub", "sea",
|
||||
"search", "season", "seat", "second", "secret", "section", "security", "seed",
|
||||
"seek", "segment", "select", "sell", "seminar", "senior", "sense", "sentence",
|
||||
"series", "service", "session", "settle", "setup", "seven", "shadow", "shaft",
|
||||
"shallow", "share", "shed", "shell", "sheriff", "shield", "shift", "shine",
|
||||
"ship", "shiver", "shock", "shoe", "shoot", "shop", "short", "shoulder",
|
||||
"shove", "shrimp", "shrug", "shuffle", "shy", "sibling", "sick", "side",
|
||||
"siege", "sight", "sign", "silent", "silk", "silly", "silver", "similar",
|
||||
"simple", "since", "sing", "siren", "sister", "situate", "six", "size",
|
||||
"skate", "sketch", "ski", "skill", "skin", "skirt", "skull", "slab",
|
||||
"slam", "sleep", "slender", "slice", "slide", "slight", "slim", "slogan",
|
||||
"slot", "slow", "slush", "small", "smart", "smile", "smoke", "smooth",
|
||||
"snack", "snake", "snap", "sniff", "snow", "soap", "soccer", "social",
|
||||
"sock", "soda", "soft", "solar", "soldier", "solid", "solution", "solve",
|
||||
"someone", "song", "soon", "sorry", "sort", "soul", "sound", "soup",
|
||||
"source", "south", "space", "spare", "spatial", "spawn", "speak", "special",
|
||||
"speed", "spell", "spend", "sphere", "spice", "spider", "spike", "spin",
|
||||
"spirit", "split", "spoil", "sponsor", "spoon", "sport", "spot", "spray",
|
||||
"spread", "spring", "spy", "square", "squeeze", "squirrel", "stable", "stadium",
|
||||
"staff", "stage", "stairs", "stamp", "stand", "start", "state", "stay",
|
||||
"steak", "steel", "stem", "step", "stereo", "stick", "still", "sting",
|
||||
"stock", "stomach", "stone", "stool", "story", "stove", "strategy", "street",
|
||||
"strike", "strong", "struggle", "student", "stuff", "stumble", "style", "subject",
|
||||
"submit", "subway", "success", "such", "sudden", "suffer", "sugar", "suggest",
|
||||
"suit", "summer", "sun", "sunny", "sunset", "super", "supply", "supreme",
|
||||
"sure", "surface", "surge", "surprise", "surround", "survey", "suspect", "sustain",
|
||||
"swallow", "swamp", "swap", "swarm", "swear", "sweet", "swift", "swim",
|
||||
"swing", "switch", "sword", "symbol", "symptom", "syrup", "system", "table",
|
||||
"tackle", "tag", "tail", "talent", "talk", "tank", "tape", "target",
|
||||
"task", "taste", "tattoo", "taxi", "teach", "team", "tell", "ten",
|
||||
"tenant", "tennis", "tent", "term", "test", "text", "thank", "that",
|
||||
"theme", "then", "theory", "there", "they", "thing", "this", "thought",
|
||||
"three", "thrive", "throw", "thumb", "thunder", "ticket", "tide", "tiger",
|
||||
"tilt", "timber", "time", "tiny", "tip", "tired", "tissue", "title",
|
||||
"toast", "tobacco", "today", "toddler", "toe", "together", "toilet", "token",
|
||||
"tomato", "tomorrow", "tone", "tongue", "tonight", "tool", "tooth", "top",
|
||||
"topic", "topple", "torch", "tornado", "tortoise", "toss", "total", "tourist",
|
||||
"toward", "tower", "town", "toy", "track", "trade", "traffic", "tragic",
|
||||
"train", "transfer", "trap", "trash", "travel", "tray", "treat", "tree",
|
||||
"trend", "trial", "tribe", "trick", "trigger", "trim", "trip", "trophy",
|
||||
"trouble", "truck", "true", "truly", "trumpet", "trust", "truth", "try",
|
||||
"tube", "tuition", "tumble", "tuna", "tunnel", "turkey", "turn", "turtle",
|
||||
"twelve", "twenty", "twice", "twin", "twist", "two", "type", "typical",
|
||||
"ugly", "umbrella", "unable", "unaware", "uncle", "uncover", "under", "undo",
|
||||
"unfair", "unfold", "unhappy", "uniform", "unique", "unit", "universe", "unknown",
|
||||
"unlock", "until", "unusual", "unveil", "update", "upgrade", "uphold", "upon",
|
||||
"upper", "upset", "urban", "urge", "usage", "use", "used", "useful",
|
||||
"useless", "usual", "utility", "vacant", "vacuum", "vague", "valid", "valley",
|
||||
"valve", "van", "vanish", "vapor", "various", "vast", "vault", "vehicle",
|
||||
"velvet", "vendor", "venture", "venue", "verb", "verify", "version", "very",
|
||||
"vessel", "veteran", "viable", "vibrant", "vicious", "victory", "video", "view",
|
||||
"village", "vintage", "violin", "virtual", "virus", "visa", "visit", "visual",
|
||||
"vital", "vivid", "vocal", "voice", "void", "volcano", "volume", "vote",
|
||||
"voyage", "wage", "wagon", "wait", "walk", "wall", "walnut", "want",
|
||||
"warfare", "warm", "warrior", "wash", "wasp", "waste", "water", "wave",
|
||||
"way", "wealth", "weapon", "wear", "weasel", "weather", "web", "wedding",
|
||||
"weekend", "weird", "welcome", "west", "wet", "whale", "what", "wheat",
|
||||
"wheel", "when", "where", "whip", "whisper", "wide", "width", "wife",
|
||||
"wild", "will", "win", "window", "wine", "wing", "wink", "winner",
|
||||
"winter", "wire", "wisdom", "wise", "wish", "witness", "wolf", "woman",
|
||||
"wonder", "wood", "wool", "word", "work", "world", "worry", "worth",
|
||||
"wrap", "wreck", "wrestle", "wrist", "write", "wrong", "yard", "year",
|
||||
"yellow", "you", "young", "youth", "zebra", "zero", "zone", "zoo",
|
||||
};
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
BLAKE reference C implementation
|
||||
|
||||
Copyright (c) 2012 Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
#include "blake256.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define U8TO32_BIG(p) \
|
||||
(((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | ((uint32_t)((p)[2]) << 8) | \
|
||||
((uint32_t)((p)[3])))
|
||||
|
||||
#define U32TO8_BIG(p, v) \
|
||||
(p)[0] = (uint8_t)((v) >> 24); \
|
||||
(p)[1] = (uint8_t)((v) >> 16); \
|
||||
(p)[2] = (uint8_t)((v) >> 8); \
|
||||
(p)[3] = (uint8_t)((v));
|
||||
|
||||
static const uint8_t sigma[][16] = {
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
||||
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
||||
{7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
||||
{9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
||||
{2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
|
||||
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
|
||||
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
|
||||
{6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
|
||||
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
||||
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
||||
{7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
||||
{9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
||||
{2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}};
|
||||
|
||||
static const uint32_t u256[16] = {
|
||||
0x243f6a88,
|
||||
0x85a308d3,
|
||||
0x13198a2e,
|
||||
0x03707344,
|
||||
0xa4093822,
|
||||
0x299f31d0,
|
||||
0x082efa98,
|
||||
0xec4e6c89,
|
||||
0x452821e6,
|
||||
0x38d01377,
|
||||
0xbe5466cf,
|
||||
0x34e90c6c,
|
||||
0xc0ac29b7,
|
||||
0xc97c50dd,
|
||||
0x3f84d5b5,
|
||||
0xb5470917};
|
||||
|
||||
static const uint8_t padding[129] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
static void blake256_compress(BLAKE256_CTX* S, const uint8_t* block) {
|
||||
uint32_t v[16] = {0}, m[16] = {0}, i = 0;
|
||||
#define ROT(x, n) (((x) << (32 - n)) | ((x) >> (n)))
|
||||
#define G(a, b, c, d, e) \
|
||||
v[a] += (m[sigma[i][e]] ^ u256[sigma[i][e + 1]]) + v[b]; \
|
||||
v[d] = ROT(v[d] ^ v[a], 16); \
|
||||
v[c] += v[d]; \
|
||||
v[b] = ROT(v[b] ^ v[c], 12); \
|
||||
v[a] += (m[sigma[i][e + 1]] ^ u256[sigma[i][e]]) + v[b]; \
|
||||
v[d] = ROT(v[d] ^ v[a], 8); \
|
||||
v[c] += v[d]; \
|
||||
v[b] = ROT(v[b] ^ v[c], 7);
|
||||
|
||||
for(i = 0; i < 16; ++i) m[i] = U8TO32_BIG(block + i * 4);
|
||||
|
||||
for(i = 0; i < 8; ++i) v[i] = S->h[i];
|
||||
|
||||
v[8] = S->s[0] ^ u256[0];
|
||||
v[9] = S->s[1] ^ u256[1];
|
||||
v[10] = S->s[2] ^ u256[2];
|
||||
v[11] = S->s[3] ^ u256[3];
|
||||
v[12] = u256[4];
|
||||
v[13] = u256[5];
|
||||
v[14] = u256[6];
|
||||
v[15] = u256[7];
|
||||
|
||||
/* don't xor t when the block is only padding */
|
||||
if(!S->nullt) {
|
||||
v[12] ^= S->t[0];
|
||||
v[13] ^= S->t[0];
|
||||
v[14] ^= S->t[1];
|
||||
v[15] ^= S->t[1];
|
||||
}
|
||||
|
||||
for(i = 0; i < 14; ++i) {
|
||||
/* column step */
|
||||
G(0, 4, 8, 12, 0);
|
||||
G(1, 5, 9, 13, 2);
|
||||
G(2, 6, 10, 14, 4);
|
||||
G(3, 7, 11, 15, 6);
|
||||
/* diagonal step */
|
||||
G(0, 5, 10, 15, 8);
|
||||
G(1, 6, 11, 12, 10);
|
||||
G(2, 7, 8, 13, 12);
|
||||
G(3, 4, 9, 14, 14);
|
||||
}
|
||||
|
||||
for(i = 0; i < 16; ++i) S->h[i % 8] ^= v[i];
|
||||
|
||||
for(i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4];
|
||||
}
|
||||
|
||||
void blake256_Init(BLAKE256_CTX* S) {
|
||||
S->h[0] = 0x6a09e667;
|
||||
S->h[1] = 0xbb67ae85;
|
||||
S->h[2] = 0x3c6ef372;
|
||||
S->h[3] = 0xa54ff53a;
|
||||
S->h[4] = 0x510e527f;
|
||||
S->h[5] = 0x9b05688c;
|
||||
S->h[6] = 0x1f83d9ab;
|
||||
S->h[7] = 0x5be0cd19;
|
||||
S->t[0] = S->t[1] = S->buflen = S->nullt = 0;
|
||||
S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0;
|
||||
}
|
||||
|
||||
void blake256_Update(BLAKE256_CTX* S, const uint8_t* in, size_t inlen) {
|
||||
size_t left = S->buflen;
|
||||
size_t fill = 64 - left;
|
||||
|
||||
/* data left and data received fill a block */
|
||||
if(left && (inlen >= fill)) {
|
||||
memcpy((void*)(S->buf + left), (void*)in, fill);
|
||||
S->t[0] += 512;
|
||||
|
||||
if(S->t[0] == 0) S->t[1]++;
|
||||
|
||||
blake256_compress(S, S->buf);
|
||||
in += fill;
|
||||
inlen -= fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
/* compress blocks of data received */
|
||||
while(inlen >= 64) {
|
||||
S->t[0] += 512;
|
||||
|
||||
if(S->t[0] == 0) S->t[1]++;
|
||||
|
||||
blake256_compress(S, in);
|
||||
in += 64;
|
||||
inlen -= 64;
|
||||
}
|
||||
|
||||
/* store any data left */
|
||||
if(inlen > 0) {
|
||||
memcpy((void*)(S->buf + left), (void*)in, (size_t)inlen);
|
||||
}
|
||||
S->buflen = left + inlen;
|
||||
}
|
||||
|
||||
void blake256_Final(BLAKE256_CTX* S, uint8_t* out) {
|
||||
uint8_t msglen[8] = {0}, zo = 0x01, oo = 0x81;
|
||||
uint32_t lo = S->t[0] + (S->buflen << 3), hi = S->t[1];
|
||||
|
||||
/* support for hashing more than 2^32 bits */
|
||||
if(lo < (S->buflen << 3)) hi++;
|
||||
|
||||
U32TO8_BIG(msglen + 0, hi);
|
||||
U32TO8_BIG(msglen + 4, lo);
|
||||
|
||||
if(S->buflen == 55) /* one padding byte */
|
||||
{
|
||||
S->t[0] -= 8;
|
||||
blake256_Update(S, &oo, 1);
|
||||
} else {
|
||||
if(S->buflen < 55) /* enough space to fill the block */
|
||||
{
|
||||
if(!S->buflen) S->nullt = 1;
|
||||
|
||||
S->t[0] -= 440 - (S->buflen << 3);
|
||||
blake256_Update(S, padding, 55 - S->buflen);
|
||||
} else /* need 2 compressions */
|
||||
{
|
||||
S->t[0] -= 512 - (S->buflen << 3);
|
||||
blake256_Update(S, padding, 64 - S->buflen);
|
||||
S->t[0] -= 440;
|
||||
blake256_Update(S, padding + 1, 55);
|
||||
S->nullt = 1;
|
||||
}
|
||||
|
||||
blake256_Update(S, &zo, 1);
|
||||
S->t[0] -= 8;
|
||||
}
|
||||
|
||||
S->t[0] -= 64;
|
||||
blake256_Update(S, msglen, 8);
|
||||
U32TO8_BIG(out + 0, S->h[0]);
|
||||
U32TO8_BIG(out + 4, S->h[1]);
|
||||
U32TO8_BIG(out + 8, S->h[2]);
|
||||
U32TO8_BIG(out + 12, S->h[3]);
|
||||
U32TO8_BIG(out + 16, S->h[4]);
|
||||
U32TO8_BIG(out + 20, S->h[5]);
|
||||
U32TO8_BIG(out + 24, S->h[6]);
|
||||
U32TO8_BIG(out + 28, S->h[7]);
|
||||
}
|
||||
|
||||
void blake256(const uint8_t* in, size_t inlen, uint8_t* out) {
|
||||
BLAKE256_CTX S = {0};
|
||||
blake256_Init(&S);
|
||||
blake256_Update(&S, in, inlen);
|
||||
blake256_Final(&S, out);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2014-2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 the copyright holder 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.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#ifndef __BLAKE256_H__
|
||||
#define __BLAKE256_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define BLAKE256_DIGEST_LENGTH 32
|
||||
#define BLAKE256_BLOCK_LENGTH 64
|
||||
|
||||
typedef struct {
|
||||
uint32_t h[8], s[4], t[2];
|
||||
size_t buflen;
|
||||
uint8_t nullt;
|
||||
uint8_t buf[64];
|
||||
} BLAKE256_CTX;
|
||||
|
||||
void blake256_Init(BLAKE256_CTX*);
|
||||
void blake256_Update(BLAKE256_CTX*, const uint8_t*, size_t);
|
||||
void blake256_Final(BLAKE256_CTX*, uint8_t*);
|
||||
|
||||
void blake256(const uint8_t*, size_t, uint8_t*);
|
||||
|
||||
#endif /* __BLAKE256_H__ */
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
#include "byte_order.h"
|
||||
|
||||
static inline uint32_t load32(const void* src) {
|
||||
uint32_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
REVERSE32(w, w);
|
||||
#endif
|
||||
return w;
|
||||
}
|
||||
|
||||
static inline uint64_t load64(const void* src) {
|
||||
uint64_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
REVERSE64(w, w);
|
||||
#endif
|
||||
return w;
|
||||
}
|
||||
|
||||
static inline void store16(void* dst, uint16_t w) {
|
||||
memcpy(dst, &w, sizeof w);
|
||||
}
|
||||
|
||||
static inline void store32(void* dst, uint32_t w) {
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
REVERSE32(w, w);
|
||||
#endif
|
||||
memcpy(dst, &w, sizeof w);
|
||||
}
|
||||
|
||||
static inline void store64(void* dst, uint64_t w) {
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
REVERSE64(w, w);
|
||||
#endif
|
||||
memcpy(dst, &w, sizeof w);
|
||||
}
|
||||
|
||||
static inline uint32_t rotr32(const uint32_t w, const unsigned c) {
|
||||
return (w >> c) | (w << (32 - c));
|
||||
}
|
||||
|
||||
static inline uint64_t rotr64(const uint64_t w, const unsigned c) {
|
||||
return (w >> c) | (w << (64 - c));
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "blake2b.h"
|
||||
#include "blake2_common.h"
|
||||
#include "memzero.h"
|
||||
|
||||
typedef struct blake2b_param__ {
|
||||
uint8_t digest_length; /* 1 */
|
||||
uint8_t key_length; /* 2 */
|
||||
uint8_t fanout; /* 3 */
|
||||
uint8_t depth; /* 4 */
|
||||
uint32_t leaf_length; /* 8 */
|
||||
uint32_t node_offset; /* 12 */
|
||||
uint32_t xof_length; /* 16 */
|
||||
uint8_t node_depth; /* 17 */
|
||||
uint8_t inner_length; /* 18 */
|
||||
uint8_t reserved[14]; /* 32 */
|
||||
uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
|
||||
uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
|
||||
} __attribute__((packed)) blake2b_param;
|
||||
|
||||
static const uint64_t blake2b_IV[8] = {
|
||||
0x6a09e667f3bcc908ULL,
|
||||
0xbb67ae8584caa73bULL,
|
||||
0x3c6ef372fe94f82bULL,
|
||||
0xa54ff53a5f1d36f1ULL,
|
||||
0x510e527fade682d1ULL,
|
||||
0x9b05688c2b3e6c1fULL,
|
||||
0x1f83d9abfb41bd6bULL,
|
||||
0x5be0cd19137e2179ULL};
|
||||
|
||||
static const uint8_t blake2b_sigma[12][16] = {
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
||||
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
||||
{7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
||||
{9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
||||
{2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
|
||||
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
|
||||
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
|
||||
{6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
|
||||
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}};
|
||||
|
||||
static void blake2b_set_lastnode(blake2b_state* S) {
|
||||
S->f[1] = (uint64_t)-1;
|
||||
}
|
||||
|
||||
/* Some helper functions, not necessarily useful */
|
||||
static int blake2b_is_lastblock(const blake2b_state* S) {
|
||||
return S->f[0] != 0;
|
||||
}
|
||||
|
||||
static void blake2b_set_lastblock(blake2b_state* S) {
|
||||
if(S->last_node) blake2b_set_lastnode(S);
|
||||
|
||||
S->f[0] = (uint64_t)-1;
|
||||
}
|
||||
|
||||
static void blake2b_increment_counter(blake2b_state* S, const uint64_t inc) {
|
||||
S->t[0] += inc;
|
||||
S->t[1] += (S->t[0] < inc);
|
||||
}
|
||||
|
||||
static void blake2b_init0(blake2b_state* S) {
|
||||
size_t i = 0;
|
||||
memzero(S, sizeof(blake2b_state));
|
||||
|
||||
for(i = 0; i < 8; ++i) S->h[i] = blake2b_IV[i];
|
||||
}
|
||||
|
||||
/* init xors IV with input parameter block */
|
||||
int blake2b_init_param(blake2b_state* S, const blake2b_param* P) {
|
||||
const uint8_t* p = (const uint8_t*)(P);
|
||||
size_t i = 0;
|
||||
|
||||
blake2b_init0(S);
|
||||
|
||||
/* IV XOR ParamBlock */
|
||||
for(i = 0; i < 8; ++i) S->h[i] ^= load64(p + sizeof(S->h[i]) * i);
|
||||
|
||||
S->outlen = P->digest_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sequential blake2b initialization */
|
||||
int blake2b_Init(blake2b_state* S, size_t outlen) {
|
||||
blake2b_param P[1] = {0};
|
||||
|
||||
if((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1;
|
||||
|
||||
P->digest_length = (uint8_t)outlen;
|
||||
P->key_length = 0;
|
||||
P->fanout = 1;
|
||||
P->depth = 1;
|
||||
store32(&P->leaf_length, 0);
|
||||
store32(&P->node_offset, 0);
|
||||
store32(&P->xof_length, 0);
|
||||
P->node_depth = 0;
|
||||
P->inner_length = 0;
|
||||
memzero(P->reserved, sizeof(P->reserved));
|
||||
memzero(P->salt, sizeof(P->salt));
|
||||
memzero(P->personal, sizeof(P->personal));
|
||||
return blake2b_init_param(S, P);
|
||||
}
|
||||
|
||||
int blake2b_InitPersonal(
|
||||
blake2b_state* S,
|
||||
size_t outlen,
|
||||
const void* personal,
|
||||
size_t personal_len) {
|
||||
blake2b_param P[1] = {0};
|
||||
|
||||
if((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1;
|
||||
if((!personal) || (personal_len != BLAKE2B_PERSONALBYTES)) return -1;
|
||||
|
||||
P->digest_length = (uint8_t)outlen;
|
||||
P->key_length = 0;
|
||||
P->fanout = 1;
|
||||
P->depth = 1;
|
||||
store32(&P->leaf_length, 0);
|
||||
store32(&P->node_offset, 0);
|
||||
store32(&P->xof_length, 0);
|
||||
P->node_depth = 0;
|
||||
P->inner_length = 0;
|
||||
memzero(P->reserved, sizeof(P->reserved));
|
||||
memzero(P->salt, sizeof(P->salt));
|
||||
memcpy(P->personal, personal, BLAKE2B_PERSONALBYTES);
|
||||
return blake2b_init_param(S, P);
|
||||
}
|
||||
|
||||
int blake2b_InitKey(blake2b_state* S, size_t outlen, const void* key, size_t keylen) {
|
||||
blake2b_param P[1] = {0};
|
||||
|
||||
if((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1;
|
||||
|
||||
if(!key || !keylen || keylen > BLAKE2B_KEYBYTES) return -1;
|
||||
|
||||
P->digest_length = (uint8_t)outlen;
|
||||
P->key_length = (uint8_t)keylen;
|
||||
P->fanout = 1;
|
||||
P->depth = 1;
|
||||
store32(&P->leaf_length, 0);
|
||||
store32(&P->node_offset, 0);
|
||||
store32(&P->xof_length, 0);
|
||||
P->node_depth = 0;
|
||||
P->inner_length = 0;
|
||||
memzero(P->reserved, sizeof(P->reserved));
|
||||
memzero(P->salt, sizeof(P->salt));
|
||||
memzero(P->personal, sizeof(P->personal));
|
||||
|
||||
if(blake2b_init_param(S, P) < 0) return -1;
|
||||
|
||||
{
|
||||
uint8_t block[BLAKE2B_BLOCKBYTES] = {0};
|
||||
memzero(block, BLAKE2B_BLOCKBYTES);
|
||||
memcpy(block, key, keylen);
|
||||
blake2b_Update(S, block, BLAKE2B_BLOCKBYTES);
|
||||
memzero(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define G(r, i, a, b, c, d) \
|
||||
do { \
|
||||
a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \
|
||||
d = rotr64(d ^ a, 32); \
|
||||
c = c + d; \
|
||||
b = rotr64(b ^ c, 24); \
|
||||
a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \
|
||||
d = rotr64(d ^ a, 16); \
|
||||
c = c + d; \
|
||||
b = rotr64(b ^ c, 63); \
|
||||
} while(0)
|
||||
|
||||
#define ROUND(r) \
|
||||
do { \
|
||||
G(r, 0, v[0], v[4], v[8], v[12]); \
|
||||
G(r, 1, v[1], v[5], v[9], v[13]); \
|
||||
G(r, 2, v[2], v[6], v[10], v[14]); \
|
||||
G(r, 3, v[3], v[7], v[11], v[15]); \
|
||||
G(r, 4, v[0], v[5], v[10], v[15]); \
|
||||
G(r, 5, v[1], v[6], v[11], v[12]); \
|
||||
G(r, 6, v[2], v[7], v[8], v[13]); \
|
||||
G(r, 7, v[3], v[4], v[9], v[14]); \
|
||||
} while(0)
|
||||
|
||||
static void blake2b_compress(blake2b_state* S, const uint8_t block[BLAKE2B_BLOCKBYTES]) {
|
||||
uint64_t m[16] = {0};
|
||||
uint64_t v[16] = {0};
|
||||
size_t i = 0;
|
||||
|
||||
for(i = 0; i < 16; ++i) {
|
||||
m[i] = load64(block + i * sizeof(m[i]));
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; ++i) {
|
||||
v[i] = S->h[i];
|
||||
}
|
||||
|
||||
v[8] = blake2b_IV[0];
|
||||
v[9] = blake2b_IV[1];
|
||||
v[10] = blake2b_IV[2];
|
||||
v[11] = blake2b_IV[3];
|
||||
v[12] = blake2b_IV[4] ^ S->t[0];
|
||||
v[13] = blake2b_IV[5] ^ S->t[1];
|
||||
v[14] = blake2b_IV[6] ^ S->f[0];
|
||||
v[15] = blake2b_IV[7] ^ S->f[1];
|
||||
|
||||
ROUND(0);
|
||||
ROUND(1);
|
||||
ROUND(2);
|
||||
ROUND(3);
|
||||
ROUND(4);
|
||||
ROUND(5);
|
||||
ROUND(6);
|
||||
ROUND(7);
|
||||
ROUND(8);
|
||||
ROUND(9);
|
||||
ROUND(10);
|
||||
ROUND(11);
|
||||
|
||||
for(i = 0; i < 8; ++i) {
|
||||
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
|
||||
}
|
||||
}
|
||||
|
||||
#undef G
|
||||
#undef ROUND
|
||||
|
||||
int blake2b_Update(blake2b_state* S, const void* pin, size_t inlen) {
|
||||
const unsigned char* in = (const unsigned char*)pin;
|
||||
if(inlen > 0) {
|
||||
size_t left = S->buflen;
|
||||
size_t fill = BLAKE2B_BLOCKBYTES - left;
|
||||
if(inlen > fill) {
|
||||
S->buflen = 0;
|
||||
memcpy(S->buf + left, in, fill); /* Fill buffer */
|
||||
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
|
||||
blake2b_compress(S, S->buf); /* Compress */
|
||||
in += fill;
|
||||
inlen -= fill;
|
||||
while(inlen > BLAKE2B_BLOCKBYTES) {
|
||||
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
|
||||
blake2b_compress(S, in);
|
||||
in += BLAKE2B_BLOCKBYTES;
|
||||
inlen -= BLAKE2B_BLOCKBYTES;
|
||||
}
|
||||
}
|
||||
memcpy(S->buf + S->buflen, in, inlen);
|
||||
S->buflen += inlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2b_Final(blake2b_state* S, void* out, size_t outlen) {
|
||||
uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
|
||||
size_t i = 0;
|
||||
|
||||
if(out == NULL || outlen < S->outlen) return -1;
|
||||
|
||||
if(blake2b_is_lastblock(S)) return -1;
|
||||
|
||||
blake2b_increment_counter(S, S->buflen);
|
||||
blake2b_set_lastblock(S);
|
||||
memzero(S->buf + S->buflen, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */
|
||||
blake2b_compress(S, S->buf);
|
||||
|
||||
for(i = 0; i < 8; ++i) /* Output full hash to temp buffer */
|
||||
store64(buffer + sizeof(S->h[i]) * i, S->h[i]);
|
||||
|
||||
memcpy(out, buffer, S->outlen);
|
||||
memzero(buffer, sizeof(buffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2b(const uint8_t* msg, uint32_t msg_len, void* out, size_t outlen) {
|
||||
BLAKE2B_CTX ctx;
|
||||
if(0 != blake2b_Init(&ctx, outlen)) return -1;
|
||||
if(0 != blake2b_Update(&ctx, msg, msg_len)) return -1;
|
||||
if(0 != blake2b_Final(&ctx, out, outlen)) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2b_Key(
|
||||
const uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
const void* key,
|
||||
size_t keylen,
|
||||
void* out,
|
||||
size_t outlen) {
|
||||
BLAKE2B_CTX ctx;
|
||||
if(0 != blake2b_InitKey(&ctx, outlen, key, keylen)) return -1;
|
||||
if(0 != blake2b_Update(&ctx, msg, msg_len)) return -1;
|
||||
if(0 != blake2b_Final(&ctx, out, outlen)) return -1;
|
||||
return 0;
|
||||
}
|
||||