Compare commits
8 Commits
dev-46f3a5c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 018a5feb29 | |||
| 4478f99dfe | |||
| ad4c171054 | |||
| 048fcc39e4 | |||
| f5c211041b | |||
| 589a2e36f2 | |||
| 161e26f2dc | |||
| bf9ca01621 |
@@ -1,47 +1,48 @@
|
||||
name: Build Dev Firmware
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build firmware
|
||||
run: |
|
||||
export DIST_SUFFIX=Flipper-ARF
|
||||
chmod +x fbt
|
||||
./fbt COMPACT=1 DEBUG=0 updater_package
|
||||
|
||||
- name: Generate tag name
|
||||
id: tag
|
||||
run: echo "TAG=dev-$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Detect firmware updater
|
||||
id: firmware
|
||||
run: |
|
||||
DIR=$(ls -d dist/f7-* | head -n 1)
|
||||
FILE="$DIR/flipper-z-f7-update-Flipper-ARF.tgz"
|
||||
|
||||
if [ ! -f "$FILE" ]; then
|
||||
echo "Firmware file not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "FILE=$FILE" >> $GITHUB_OUTPUT
|
||||
- name: Read changelog
|
||||
id: changelog
|
||||
run: |
|
||||
{
|
||||
echo 'CHANGELOG<<EOF'
|
||||
cat CHANGELOG.md
|
||||
echo 'EOF'
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ steps.tag.outputs.TAG }}
|
||||
name: Dev Build ${{ steps.tag.outputs.TAG }}
|
||||
body: ${{ steps.changelog.outputs.CHANGELOG }}
|
||||
files: ${{ steps.firmware.outputs.FILE }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef __BLAKE2B_H__
|
||||
#define __BLAKE2B_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum blake2b_constant {
|
||||
BLAKE2B_BLOCKBYTES = 128,
|
||||
BLAKE2B_OUTBYTES = 64,
|
||||
BLAKE2B_KEYBYTES = 64,
|
||||
BLAKE2B_SALTBYTES = 16,
|
||||
BLAKE2B_PERSONALBYTES = 16
|
||||
};
|
||||
|
||||
typedef struct __blake2b_state {
|
||||
uint64_t h[8];
|
||||
uint64_t t[2];
|
||||
uint64_t f[2];
|
||||
uint8_t buf[BLAKE2B_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
size_t outlen;
|
||||
uint8_t last_node;
|
||||
} blake2b_state;
|
||||
|
||||
#define BLAKE2B_CTX blake2b_state
|
||||
#define BLAKE2B_BLOCK_LENGTH BLAKE2B_BLOCKBYTES
|
||||
#define BLAKE2B_DIGEST_LENGTH BLAKE2B_OUTBYTES
|
||||
#define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES
|
||||
|
||||
int blake2b_Init(blake2b_state* S, size_t outlen);
|
||||
int blake2b_InitKey(blake2b_state* S, size_t outlen, const void* key, size_t keylen);
|
||||
int blake2b_InitPersonal(
|
||||
blake2b_state* S,
|
||||
size_t outlen,
|
||||
const void* personal,
|
||||
size_t personal_len);
|
||||
int blake2b_Update(blake2b_state* S, const void* pin, size_t inlen);
|
||||
int blake2b_Final(blake2b_state* S, void* out, size_t outlen);
|
||||
|
||||
int blake2b(const uint8_t* msg, uint32_t msg_len, void* out, size_t outlen);
|
||||
int blake2b_Key(
|
||||
const uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
const void* key,
|
||||
size_t keylen,
|
||||
void* out,
|
||||
size_t outlen);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
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 "blake2s.h"
|
||||
#include "blake2_common.h"
|
||||
#include "memzero.h"
|
||||
|
||||
typedef struct blake2s_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 */
|
||||
uint16_t xof_length; /* 14 */
|
||||
uint8_t node_depth; /* 15 */
|
||||
uint8_t inner_length; /* 16 */
|
||||
/* uint8_t reserved[0]; */
|
||||
uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */
|
||||
uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */
|
||||
} __attribute__((packed)) blake2s_param;
|
||||
|
||||
static const uint32_t blake2s_IV[8] = {
|
||||
0x6A09E667UL,
|
||||
0xBB67AE85UL,
|
||||
0x3C6EF372UL,
|
||||
0xA54FF53AUL,
|
||||
0x510E527FUL,
|
||||
0x9B05688CUL,
|
||||
0x1F83D9ABUL,
|
||||
0x5BE0CD19UL};
|
||||
|
||||
static const uint8_t blake2s_sigma[10][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},
|
||||
};
|
||||
|
||||
static void blake2s_set_lastnode(blake2s_state* S) {
|
||||
S->f[1] = (uint32_t)-1;
|
||||
}
|
||||
|
||||
/* Some helper functions, not necessarily useful */
|
||||
static int blake2s_is_lastblock(const blake2s_state* S) {
|
||||
return S->f[0] != 0;
|
||||
}
|
||||
|
||||
static void blake2s_set_lastblock(blake2s_state* S) {
|
||||
if(S->last_node) blake2s_set_lastnode(S);
|
||||
|
||||
S->f[0] = (uint32_t)-1;
|
||||
}
|
||||
|
||||
static void blake2s_increment_counter(blake2s_state* S, const uint32_t inc) {
|
||||
S->t[0] += inc;
|
||||
S->t[1] += (S->t[0] < inc);
|
||||
}
|
||||
|
||||
static void blake2s_init0(blake2s_state* S) {
|
||||
size_t i = 0;
|
||||
memzero(S, sizeof(blake2s_state));
|
||||
|
||||
for(i = 0; i < 8; ++i) S->h[i] = blake2s_IV[i];
|
||||
}
|
||||
|
||||
/* init2 xors IV with input parameter block */
|
||||
int blake2s_init_param(blake2s_state* S, const blake2s_param* P) {
|
||||
const unsigned char* p = (const unsigned char*)(P);
|
||||
size_t i = 0;
|
||||
|
||||
blake2s_init0(S);
|
||||
|
||||
/* IV XOR ParamBlock */
|
||||
for(i = 0; i < 8; ++i) S->h[i] ^= load32(&p[i * 4]);
|
||||
|
||||
S->outlen = P->digest_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sequential blake2s initialization */
|
||||
int blake2s_Init(blake2s_state* S, size_t outlen) {
|
||||
blake2s_param P[1] = {0};
|
||||
|
||||
if((!outlen) || (outlen > BLAKE2S_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);
|
||||
store16(&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 blake2s_init_param(S, P);
|
||||
}
|
||||
|
||||
int blake2s_InitPersonal(
|
||||
blake2s_state* S,
|
||||
size_t outlen,
|
||||
const void* personal,
|
||||
size_t personal_len) {
|
||||
blake2s_param P[1] = {0};
|
||||
|
||||
if((!outlen) || (outlen > BLAKE2S_OUTBYTES)) return -1;
|
||||
if((!personal) || (personal_len != BLAKE2S_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);
|
||||
store16(&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, BLAKE2S_PERSONALBYTES);
|
||||
return blake2s_init_param(S, P);
|
||||
}
|
||||
|
||||
int blake2s_InitKey(blake2s_state* S, size_t outlen, const void* key, size_t keylen) {
|
||||
blake2s_param P[1] = {0};
|
||||
|
||||
if((!outlen) || (outlen > BLAKE2S_OUTBYTES)) return -1;
|
||||
|
||||
if(!key || !keylen || keylen > BLAKE2S_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);
|
||||
store16(&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(blake2s_init_param(S, P) < 0) return -1;
|
||||
|
||||
{
|
||||
uint8_t block[BLAKE2S_BLOCKBYTES] = {0};
|
||||
memzero(block, BLAKE2S_BLOCKBYTES);
|
||||
memcpy(block, key, keylen);
|
||||
blake2s_Update(S, block, BLAKE2S_BLOCKBYTES);
|
||||
memzero(block, BLAKE2S_BLOCKBYTES); /* Burn the key from stack */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define G(r, i, a, b, c, d) \
|
||||
do { \
|
||||
a = a + b + m[blake2s_sigma[r][2 * i + 0]]; \
|
||||
d = rotr32(d ^ a, 16); \
|
||||
c = c + d; \
|
||||
b = rotr32(b ^ c, 12); \
|
||||
a = a + b + m[blake2s_sigma[r][2 * i + 1]]; \
|
||||
d = rotr32(d ^ a, 8); \
|
||||
c = c + d; \
|
||||
b = rotr32(b ^ c, 7); \
|
||||
} 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 blake2s_compress(blake2s_state* S, const uint8_t in[BLAKE2S_BLOCKBYTES]) {
|
||||
uint32_t m[16] = {0};
|
||||
uint32_t v[16] = {0};
|
||||
size_t i = 0;
|
||||
|
||||
for(i = 0; i < 16; ++i) {
|
||||
m[i] = load32(in + i * sizeof(m[i]));
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; ++i) {
|
||||
v[i] = S->h[i];
|
||||
}
|
||||
|
||||
v[8] = blake2s_IV[0];
|
||||
v[9] = blake2s_IV[1];
|
||||
v[10] = blake2s_IV[2];
|
||||
v[11] = blake2s_IV[3];
|
||||
v[12] = S->t[0] ^ blake2s_IV[4];
|
||||
v[13] = S->t[1] ^ blake2s_IV[5];
|
||||
v[14] = S->f[0] ^ blake2s_IV[6];
|
||||
v[15] = S->f[1] ^ blake2s_IV[7];
|
||||
|
||||
ROUND(0);
|
||||
ROUND(1);
|
||||
ROUND(2);
|
||||
ROUND(3);
|
||||
ROUND(4);
|
||||
ROUND(5);
|
||||
ROUND(6);
|
||||
ROUND(7);
|
||||
ROUND(8);
|
||||
ROUND(9);
|
||||
|
||||
for(i = 0; i < 8; ++i) {
|
||||
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
|
||||
}
|
||||
}
|
||||
|
||||
#undef G
|
||||
#undef ROUND
|
||||
|
||||
int blake2s_Update(blake2s_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 = BLAKE2S_BLOCKBYTES - left;
|
||||
if(inlen > fill) {
|
||||
S->buflen = 0;
|
||||
memcpy(S->buf + left, in, fill); /* Fill buffer */
|
||||
blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);
|
||||
blake2s_compress(S, S->buf); /* Compress */
|
||||
in += fill;
|
||||
inlen -= fill;
|
||||
while(inlen > BLAKE2S_BLOCKBYTES) {
|
||||
blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);
|
||||
blake2s_compress(S, in);
|
||||
in += BLAKE2S_BLOCKBYTES;
|
||||
inlen -= BLAKE2S_BLOCKBYTES;
|
||||
}
|
||||
}
|
||||
memcpy(S->buf + S->buflen, in, inlen);
|
||||
S->buflen += inlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2s_Final(blake2s_state* S, void* out, size_t outlen) {
|
||||
uint8_t buffer[BLAKE2S_OUTBYTES] = {0};
|
||||
size_t i = 0;
|
||||
|
||||
if(out == NULL || outlen < S->outlen) return -1;
|
||||
|
||||
if(blake2s_is_lastblock(S)) return -1;
|
||||
|
||||
blake2s_increment_counter(S, (uint32_t)S->buflen);
|
||||
blake2s_set_lastblock(S);
|
||||
memzero(S->buf + S->buflen, BLAKE2S_BLOCKBYTES - S->buflen); /* Padding */
|
||||
blake2s_compress(S, S->buf);
|
||||
|
||||
for(i = 0; i < 8; ++i) /* Output full hash to temp buffer */
|
||||
store32(buffer + sizeof(S->h[i]) * i, S->h[i]);
|
||||
|
||||
memcpy(out, buffer, outlen);
|
||||
memzero(buffer, sizeof(buffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2s(const uint8_t* msg, uint32_t msg_len, void* out, size_t outlen) {
|
||||
BLAKE2S_CTX ctx;
|
||||
if(0 != blake2s_Init(&ctx, outlen)) return -1;
|
||||
if(0 != blake2s_Update(&ctx, msg, msg_len)) return -1;
|
||||
if(0 != blake2s_Final(&ctx, out, outlen)) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2s_Key(
|
||||
const uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
const void* key,
|
||||
size_t keylen,
|
||||
void* out,
|
||||
size_t outlen) {
|
||||
BLAKE2S_CTX ctx;
|
||||
if(0 != blake2s_InitKey(&ctx, outlen, key, keylen)) return -1;
|
||||
if(0 != blake2s_Update(&ctx, msg, msg_len)) return -1;
|
||||
if(0 != blake2s_Final(&ctx, out, outlen)) return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef __BLAKE2S_H__
|
||||
#define __BLAKE2S_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum blake2s_constant {
|
||||
BLAKE2S_BLOCKBYTES = 64,
|
||||
BLAKE2S_OUTBYTES = 32,
|
||||
BLAKE2S_KEYBYTES = 32,
|
||||
BLAKE2S_SALTBYTES = 8,
|
||||
BLAKE2S_PERSONALBYTES = 8
|
||||
};
|
||||
|
||||
typedef struct __blake2s_state {
|
||||
uint32_t h[8];
|
||||
uint32_t t[2];
|
||||
uint32_t f[2];
|
||||
uint8_t buf[BLAKE2S_BLOCKBYTES];
|
||||
uint32_t buflen;
|
||||
uint8_t outlen;
|
||||
uint8_t last_node;
|
||||
} blake2s_state;
|
||||
|
||||
#define BLAKE2S_CTX blake2s_state
|
||||
#define BLAKE2S_BLOCK_LENGTH BLAKE2S_BLOCKBYTES
|
||||
#define BLAKE2S_DIGEST_LENGTH BLAKE2S_OUTBYTES
|
||||
#define BLAKE2S_KEY_LENGTH BLAKE2S_KEYBYTES
|
||||
|
||||
int blake2s_Init(blake2s_state* S, size_t outlen);
|
||||
int blake2s_InitKey(blake2s_state* S, size_t outlen, const void* key, size_t keylen);
|
||||
int blake2s_InitPersonal(
|
||||
blake2s_state* S,
|
||||
size_t outlen,
|
||||
const void* personal,
|
||||
size_t personal_len);
|
||||
int blake2s_Update(blake2s_state* S, const void* pin, size_t inlen);
|
||||
int blake2s_Final(blake2s_state* S, void* out, size_t outlen);
|
||||
|
||||
int blake2s(const uint8_t* msg, uint32_t msg_len, void* out, size_t outlen);
|
||||
int blake2s_Key(
|
||||
const uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
const void* key,
|
||||
size_t keylen,
|
||||
void* out,
|
||||
size_t outlen);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef __BYTE_ORDER_H__
|
||||
#define __BYTE_ORDER_H__
|
||||
|
||||
// FROM sha2.h:
|
||||
/*
|
||||
* BYTE_ORDER NOTE:
|
||||
*
|
||||
* Please make sure that your system defines BYTE_ORDER. If your
|
||||
* architecture is little-endian, make sure it also defines
|
||||
* LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
|
||||
* equivalent.
|
||||
*
|
||||
* If your system does not define the above, then you can do so by
|
||||
* hand like this:
|
||||
*
|
||||
* #define LITTLE_ENDIAN 1234
|
||||
* #define BIG_ENDIAN 4321
|
||||
*
|
||||
* And for little-endian machines, add:
|
||||
*
|
||||
* #define BYTE_ORDER LITTLE_ENDIAN
|
||||
*
|
||||
* Or for big-endian machines:
|
||||
*
|
||||
* #define BYTE_ORDER BIG_ENDIAN
|
||||
*
|
||||
* The FreeBSD machine this was written on defines BYTE_ORDER
|
||||
* appropriately by including <sys/types.h> (which in turn includes
|
||||
* <machine/endian.h> where the appropriate definitions are actually
|
||||
* made).
|
||||
*/
|
||||
|
||||
#ifndef LITTLE_ENDIAN
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#define BIG_ENDIAN 4321
|
||||
#endif
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#define REVERSE32(w, x) \
|
||||
{ \
|
||||
uint32_t tmp = (w); \
|
||||
tmp = (tmp >> 16) | (tmp << 16); \
|
||||
(x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
|
||||
}
|
||||
|
||||
#define REVERSE64(w, x) \
|
||||
{ \
|
||||
uint64_t tmp = (w); \
|
||||
tmp = (tmp >> 32) | (tmp << 32); \
|
||||
tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
|
||||
(x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | ((tmp & 0x0000ffff0000ffffULL) << 16); \
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,307 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2021 SatoshiLabs
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bignum.h"
|
||||
#include "bip32.h"
|
||||
#include "cardano.h"
|
||||
#include "curves.h"
|
||||
#include "hasher.h"
|
||||
#include "hmac.h"
|
||||
#include "memzero.h"
|
||||
#include "options.h"
|
||||
#include "pbkdf2.h"
|
||||
#include "sha2.h"
|
||||
|
||||
#if USE_CARDANO
|
||||
|
||||
#define CARDANO_MAX_NODE_DEPTH 1048576
|
||||
|
||||
const curve_info ed25519_cardano_info = {
|
||||
.bip32_name = ED25519_CARDANO_NAME,
|
||||
.params = NULL,
|
||||
.hasher_base58 = HASHER_SHA2D,
|
||||
.hasher_sign = HASHER_SHA2D,
|
||||
.hasher_pubkey = HASHER_SHA2_RIPEMD,
|
||||
.hasher_script = HASHER_SHA2,
|
||||
};
|
||||
|
||||
static void scalar_multiply8(const uint8_t* src, int bytes, uint8_t* dst) {
|
||||
uint8_t prev_acc = 0;
|
||||
for(int i = 0; i < bytes; i++) {
|
||||
dst[i] = (src[i] << 3) + (prev_acc & 0x7);
|
||||
prev_acc = src[i] >> 5;
|
||||
}
|
||||
dst[bytes] = src[bytes - 1] >> 5;
|
||||
}
|
||||
|
||||
static void scalar_add_256bits(const uint8_t* src1, const uint8_t* src2, uint8_t* dst) {
|
||||
uint16_t r = 0;
|
||||
for(int i = 0; i < 32; i++) {
|
||||
r = r + (uint16_t)src1[i] + (uint16_t)src2[i];
|
||||
dst[i] = r & 0xff;
|
||||
r >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void cardano_ed25519_tweak_bits(uint8_t private_key[32]) {
|
||||
private_key[0] &= 0xf8;
|
||||
private_key[31] &= 0x1f;
|
||||
private_key[31] |= 0x40;
|
||||
}
|
||||
|
||||
int hdnode_private_ckd_cardano(HDNode* inout, uint32_t index) {
|
||||
if(inout->curve != &ed25519_cardano_info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(inout->depth >= CARDANO_MAX_NODE_DEPTH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// checks for hardened/non-hardened derivation, keysize 32 means we are
|
||||
// dealing with public key and thus non-h, keysize 64 is for private key
|
||||
int keysize = 32;
|
||||
if(index & 0x80000000) {
|
||||
keysize = 64;
|
||||
}
|
||||
|
||||
static CONFIDENTIAL uint8_t data[1 + 64 + 4];
|
||||
static CONFIDENTIAL uint8_t z[32 + 32];
|
||||
static CONFIDENTIAL uint8_t priv_key[64];
|
||||
static CONFIDENTIAL uint8_t res_key[64];
|
||||
|
||||
write_le(data + keysize + 1, index);
|
||||
|
||||
memcpy(priv_key, inout->private_key, 32);
|
||||
memcpy(priv_key + 32, inout->private_key_extension, 32);
|
||||
|
||||
if(keysize == 64) { // private derivation
|
||||
data[0] = 0;
|
||||
memcpy(data + 1, inout->private_key, 32);
|
||||
memcpy(data + 1 + 32, inout->private_key_extension, 32);
|
||||
} else { // public derivation
|
||||
if(hdnode_fill_public_key(inout) != 0) {
|
||||
return 0;
|
||||
}
|
||||
data[0] = 2;
|
||||
memcpy(data + 1, inout->public_key + 1, 32);
|
||||
}
|
||||
|
||||
static CONFIDENTIAL HMAC_SHA512_CTX ctx;
|
||||
hmac_sha512_Init(&ctx, inout->chain_code, 32);
|
||||
hmac_sha512_Update(&ctx, data, 1 + keysize + 4);
|
||||
hmac_sha512_Final(&ctx, z);
|
||||
|
||||
static CONFIDENTIAL uint8_t zl8[32];
|
||||
memzero(zl8, 32);
|
||||
|
||||
/* get 8 * Zl */
|
||||
scalar_multiply8(z, 28, zl8);
|
||||
/* Kl = 8*Zl + parent(K)l */
|
||||
scalar_add_256bits(zl8, priv_key, res_key);
|
||||
|
||||
/* Kr = Zr + parent(K)r */
|
||||
scalar_add_256bits(z + 32, priv_key + 32, res_key + 32);
|
||||
|
||||
memcpy(inout->private_key, res_key, 32);
|
||||
memcpy(inout->private_key_extension, res_key + 32, 32);
|
||||
|
||||
if(keysize == 64) {
|
||||
data[0] = 1;
|
||||
} else {
|
||||
data[0] = 3;
|
||||
}
|
||||
hmac_sha512_Init(&ctx, inout->chain_code, 32);
|
||||
hmac_sha512_Update(&ctx, data, 1 + keysize + 4);
|
||||
hmac_sha512_Final(&ctx, z);
|
||||
|
||||
memcpy(inout->chain_code, z + 32, 32);
|
||||
inout->depth++;
|
||||
inout->child_num = index;
|
||||
memzero(inout->public_key, sizeof(inout->public_key));
|
||||
|
||||
// making sure to wipe our memory
|
||||
memzero(z, sizeof(z));
|
||||
memzero(data, sizeof(data));
|
||||
memzero(priv_key, sizeof(priv_key));
|
||||
memzero(res_key, sizeof(res_key));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hdnode_from_secret_cardano(const uint8_t secret[CARDANO_SECRET_LENGTH], HDNode* out) {
|
||||
memzero(out, sizeof(HDNode));
|
||||
out->depth = 0;
|
||||
out->child_num = 0;
|
||||
out->curve = &ed25519_cardano_info;
|
||||
memcpy(out->private_key, secret, 32);
|
||||
memcpy(out->private_key_extension, secret + 32, 32);
|
||||
memcpy(out->chain_code, secret + 64, 32);
|
||||
|
||||
cardano_ed25519_tweak_bits(out->private_key);
|
||||
|
||||
out->public_key[0] = 0;
|
||||
if(hdnode_fill_public_key(out) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Derives the root Cardano secret from a master secret, aka seed, as defined in
|
||||
// SLIP-0023.
|
||||
int secret_from_seed_cardano_slip23(
|
||||
const uint8_t* seed,
|
||||
int seed_len,
|
||||
uint8_t secret_out[CARDANO_SECRET_LENGTH]) {
|
||||
static CONFIDENTIAL uint8_t I[SHA512_DIGEST_LENGTH];
|
||||
static CONFIDENTIAL HMAC_SHA512_CTX ctx;
|
||||
|
||||
hmac_sha512_Init(&ctx, (const uint8_t*)ED25519_CARDANO_NAME, strlen(ED25519_CARDANO_NAME));
|
||||
hmac_sha512_Update(&ctx, seed, seed_len);
|
||||
hmac_sha512_Final(&ctx, I);
|
||||
|
||||
sha512_Raw(I, 32, secret_out);
|
||||
|
||||
memcpy(secret_out + SHA512_DIGEST_LENGTH, I + 32, 32);
|
||||
cardano_ed25519_tweak_bits(secret_out);
|
||||
|
||||
memzero(I, sizeof(I));
|
||||
memzero(&ctx, sizeof(ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Derives the root Cardano secret from a BIP-32 master secret via the Ledger
|
||||
// derivation:
|
||||
// https://github.com/cardano-foundation/CIPs/blob/09d7d8ee1bd64f7e6b20b5a6cae088039dce00cb/CIP-0003/Ledger.md
|
||||
int secret_from_seed_cardano_ledger(
|
||||
const uint8_t* seed,
|
||||
int seed_len,
|
||||
uint8_t secret_out[CARDANO_SECRET_LENGTH]) {
|
||||
static CONFIDENTIAL uint8_t chain_code[SHA256_DIGEST_LENGTH];
|
||||
static CONFIDENTIAL uint8_t root_key[SHA512_DIGEST_LENGTH];
|
||||
static CONFIDENTIAL HMAC_SHA256_CTX ctx;
|
||||
static CONFIDENTIAL HMAC_SHA512_CTX sctx;
|
||||
|
||||
const uint8_t* intermediate_result = seed;
|
||||
int intermediate_result_len = seed_len;
|
||||
do {
|
||||
// STEP 1: derive a master secret like in BIP-32/SLIP-10
|
||||
hmac_sha512_Init(&sctx, (const uint8_t*)ED25519_SEED_NAME, strlen(ED25519_SEED_NAME));
|
||||
hmac_sha512_Update(&sctx, intermediate_result, intermediate_result_len);
|
||||
hmac_sha512_Final(&sctx, root_key);
|
||||
|
||||
// STEP 2: check that the resulting key does not have a particular bit set,
|
||||
// otherwise iterate like in SLIP-10
|
||||
intermediate_result = root_key;
|
||||
intermediate_result_len = sizeof(root_key);
|
||||
} while(root_key[31] & 0x20);
|
||||
|
||||
// STEP 3: calculate the chain code as a HMAC-SHA256 of "\x01" + seed,
|
||||
// key is "ed25519 seed"
|
||||
hmac_sha256_Init(&ctx, (const unsigned char*)ED25519_SEED_NAME, strlen(ED25519_SEED_NAME));
|
||||
hmac_sha256_Update(&ctx, (const unsigned char*)"\x01", 1);
|
||||
hmac_sha256_Update(&ctx, seed, seed_len);
|
||||
hmac_sha256_Final(&ctx, chain_code);
|
||||
|
||||
// STEP 4: extract information into output
|
||||
_Static_assert(
|
||||
SHA512_DIGEST_LENGTH + SHA256_DIGEST_LENGTH == CARDANO_SECRET_LENGTH,
|
||||
"Invalid configuration of Cardano secret size");
|
||||
memcpy(secret_out, root_key, SHA512_DIGEST_LENGTH);
|
||||
memcpy(secret_out + SHA512_DIGEST_LENGTH, chain_code, SHA256_DIGEST_LENGTH);
|
||||
|
||||
// STEP 5: tweak bits of the private key
|
||||
cardano_ed25519_tweak_bits(secret_out);
|
||||
|
||||
memzero(&ctx, sizeof(ctx));
|
||||
memzero(&sctx, sizeof(sctx));
|
||||
memzero(root_key, sizeof(root_key));
|
||||
memzero(chain_code, sizeof(chain_code));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define CARDANO_ICARUS_STEPS 32
|
||||
_Static_assert(
|
||||
CARDANO_ICARUS_PBKDF2_ROUNDS % CARDANO_ICARUS_STEPS == 0,
|
||||
"CARDANO_ICARUS_STEPS does not divide CARDANO_ICARUS_PBKDF2_ROUNDS");
|
||||
#define CARDANO_ICARUS_ROUNDS_PER_STEP (CARDANO_ICARUS_PBKDF2_ROUNDS / CARDANO_ICARUS_STEPS)
|
||||
|
||||
// Derives the root Cardano HDNode from a passphrase and the entropy encoded in
|
||||
// a BIP-0039 mnemonic using the Icarus derivation scheme, aka V2 derivation
|
||||
// scheme:
|
||||
// https://github.com/cardano-foundation/CIPs/blob/09d7d8ee1bd64f7e6b20b5a6cae088039dce00cb/CIP-0003/Icarus.md
|
||||
int secret_from_entropy_cardano_icarus(
|
||||
const uint8_t* pass,
|
||||
int pass_len,
|
||||
const uint8_t* entropy,
|
||||
int entropy_len,
|
||||
uint8_t secret_out[CARDANO_SECRET_LENGTH],
|
||||
void (*progress_callback)(uint32_t, uint32_t)) {
|
||||
static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx;
|
||||
static CONFIDENTIAL uint8_t digest[SHA512_DIGEST_LENGTH];
|
||||
uint32_t progress = 0;
|
||||
|
||||
// PASS 1: first 64 bytes
|
||||
pbkdf2_hmac_sha512_Init(&pctx, pass, pass_len, entropy, entropy_len, 1);
|
||||
if(progress_callback) {
|
||||
progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2);
|
||||
}
|
||||
for(int i = 0; i < CARDANO_ICARUS_STEPS; i++) {
|
||||
pbkdf2_hmac_sha512_Update(&pctx, CARDANO_ICARUS_ROUNDS_PER_STEP);
|
||||
if(progress_callback) {
|
||||
progress += CARDANO_ICARUS_ROUNDS_PER_STEP;
|
||||
progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2);
|
||||
}
|
||||
}
|
||||
pbkdf2_hmac_sha512_Final(&pctx, digest);
|
||||
|
||||
memcpy(secret_out, digest, SHA512_DIGEST_LENGTH);
|
||||
|
||||
// PASS 2: remaining 32 bytes
|
||||
pbkdf2_hmac_sha512_Init(&pctx, pass, pass_len, entropy, entropy_len, 2);
|
||||
if(progress_callback) {
|
||||
progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2);
|
||||
}
|
||||
for(int i = 0; i < CARDANO_ICARUS_STEPS; i++) {
|
||||
pbkdf2_hmac_sha512_Update(&pctx, CARDANO_ICARUS_ROUNDS_PER_STEP);
|
||||
if(progress_callback) {
|
||||
progress += CARDANO_ICARUS_ROUNDS_PER_STEP;
|
||||
progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2);
|
||||
}
|
||||
}
|
||||
pbkdf2_hmac_sha512_Final(&pctx, digest);
|
||||
|
||||
memcpy(
|
||||
secret_out + SHA512_DIGEST_LENGTH, digest, CARDANO_SECRET_LENGTH - SHA512_DIGEST_LENGTH);
|
||||
|
||||
cardano_ed25519_tweak_bits(secret_out);
|
||||
|
||||
memzero(&pctx, sizeof(pctx));
|
||||
memzero(digest, sizeof(digest));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // USE_CARDANO
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2021 SatoshiLabs
|
||||
*
|
||||
* 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 __CARDANO_H__
|
||||
#define __CARDANO_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bip32.h"
|
||||
#include "options.h"
|
||||
|
||||
#if USE_CARDANO
|
||||
|
||||
#define CARDANO_SECRET_LENGTH 96
|
||||
#define CARDANO_ICARUS_PBKDF2_ROUNDS 4096
|
||||
|
||||
extern const curve_info ed25519_cardano_info;
|
||||
|
||||
int hdnode_private_ckd_cardano(HDNode* inout, uint32_t i);
|
||||
|
||||
int secret_from_entropy_cardano_icarus(
|
||||
const uint8_t* pass,
|
||||
int pass_len,
|
||||
const uint8_t* entropy,
|
||||
int entropy_len,
|
||||
uint8_t secret_out[CARDANO_SECRET_LENGTH],
|
||||
void (*progress_callback)(uint32_t current, uint32_t total));
|
||||
int secret_from_seed_cardano_ledger(
|
||||
const uint8_t* seed,
|
||||
int seed_len,
|
||||
uint8_t secret_out[CARDANO_SECRET_LENGTH]);
|
||||
int secret_from_seed_cardano_slip23(
|
||||
const uint8_t* seed,
|
||||
int seed_len,
|
||||
uint8_t secret_out[CARDANO_SECRET_LENGTH]);
|
||||
|
||||
int hdnode_from_secret_cardano(const uint8_t secret[CARDANO_SECRET_LENGTH], HDNode* out);
|
||||
|
||||
#endif // USE_CARDANO
|
||||
|
||||
#endif // __CARDANO_H__
|
||||
@@ -0,0 +1,188 @@
|
||||
/* Copyright (c) 2017 Jochen Hoenicke
|
||||
* based on code Copyright (c) 2017 Peter Wuille
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cash_addr.h"
|
||||
|
||||
#define MAX_CASHADDR_SIZE 129
|
||||
#define MAX_BASE32_SIZE 104
|
||||
#define MAX_DATA_SIZE 65
|
||||
#define MAX_HRP_SIZE 20
|
||||
#define CHECKSUM_SIZE 8
|
||||
|
||||
uint64_t cashaddr_polymod_step(uint64_t pre) {
|
||||
uint8_t b = pre >> 35;
|
||||
return ((pre & 0x7FFFFFFFFULL) << 5) ^ (-((b >> 0) & 1) & 0x98f2bc8e61ULL) ^
|
||||
(-((b >> 1) & 1) & 0x79b76d99e2ULL) ^ (-((b >> 2) & 1) & 0xf33e5fb3c4ULL) ^
|
||||
(-((b >> 3) & 1) & 0xae2eabe2a8ULL) ^ (-((b >> 4) & 1) & 0x1e4f43e470ULL);
|
||||
}
|
||||
|
||||
static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
||||
|
||||
static const int8_t charset_rev[128] = {
|
||||
-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, 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29,
|
||||
-1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14,
|
||||
6, 4, 2, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27,
|
||||
19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1};
|
||||
|
||||
int cash_encode(char* output, const char* hrp, const uint8_t* data, size_t data_len) {
|
||||
uint64_t chk = 1;
|
||||
size_t i = 0;
|
||||
while(hrp[i] != 0) {
|
||||
int ch = hrp[i];
|
||||
if(ch < 33 || ch > 126) {
|
||||
return 0;
|
||||
}
|
||||
*(output++) = ch;
|
||||
chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f);
|
||||
++i;
|
||||
}
|
||||
if(i + 1 + data_len + CHECKSUM_SIZE > MAX_CASHADDR_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
chk = cashaddr_polymod_step(chk);
|
||||
*(output++) = ':';
|
||||
for(i = 0; i < data_len; ++i) {
|
||||
if(*data >> 5) return 0;
|
||||
chk = cashaddr_polymod_step(chk) ^ (*data);
|
||||
*(output++) = charset[*(data++)];
|
||||
}
|
||||
for(i = 0; i < CHECKSUM_SIZE; ++i) {
|
||||
chk = cashaddr_polymod_step(chk);
|
||||
}
|
||||
chk ^= 1;
|
||||
for(i = 0; i < CHECKSUM_SIZE; ++i) {
|
||||
*(output++) = charset[(chk >> ((CHECKSUM_SIZE - 1 - i) * 5)) & 0x1f];
|
||||
}
|
||||
*output = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cash_decode(char* hrp, uint8_t* data, size_t* data_len, const char* input) {
|
||||
uint64_t chk = 1;
|
||||
size_t i = 0;
|
||||
size_t input_len = strlen(input);
|
||||
size_t hrp_len = 0;
|
||||
int have_lower = 0, have_upper = 0;
|
||||
if(input_len < CHECKSUM_SIZE || input_len > MAX_CASHADDR_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
*data_len = 0;
|
||||
while(*data_len < input_len && input[(input_len - 1) - *data_len] != ':') {
|
||||
++(*data_len);
|
||||
}
|
||||
hrp_len = input_len - (1 + *data_len);
|
||||
if(1 + *data_len >= input_len || hrp_len > MAX_HRP_SIZE || *data_len < CHECKSUM_SIZE ||
|
||||
*data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
// subtract checksum
|
||||
*(data_len) -= CHECKSUM_SIZE;
|
||||
for(i = 0; i < hrp_len; ++i) {
|
||||
int ch = input[i];
|
||||
if(ch < 33 || ch > 126) {
|
||||
return 0;
|
||||
}
|
||||
if(ch >= 'a' && ch <= 'z') {
|
||||
have_lower = 1;
|
||||
} else if(ch >= 'A' && ch <= 'Z') {
|
||||
have_upper = 1;
|
||||
ch = (ch - 'A') + 'a';
|
||||
}
|
||||
hrp[i] = ch;
|
||||
chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f);
|
||||
}
|
||||
hrp[i] = 0;
|
||||
chk = cashaddr_polymod_step(chk);
|
||||
++i;
|
||||
while(i < input_len) {
|
||||
int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]];
|
||||
if(input[i] >= 'a' && input[i] <= 'z') have_lower = 1;
|
||||
if(input[i] >= 'A' && input[i] <= 'Z') have_upper = 1;
|
||||
if(v == -1) {
|
||||
return 0;
|
||||
}
|
||||
chk = cashaddr_polymod_step(chk) ^ v;
|
||||
if(i + CHECKSUM_SIZE < input_len) {
|
||||
data[i - (1 + hrp_len)] = v;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
if(have_lower && have_upper) {
|
||||
return 0;
|
||||
}
|
||||
return chk == 1;
|
||||
}
|
||||
|
||||
static int convert_bits(
|
||||
uint8_t* out,
|
||||
size_t* outlen,
|
||||
int outbits,
|
||||
const uint8_t* in,
|
||||
size_t inlen,
|
||||
int inbits,
|
||||
int pad) {
|
||||
uint32_t val = 0;
|
||||
int bits = 0;
|
||||
uint32_t maxv = (((uint32_t)1) << outbits) - 1;
|
||||
while(inlen--) {
|
||||
val = (val << inbits) | *(in++);
|
||||
bits += inbits;
|
||||
while(bits >= outbits) {
|
||||
bits -= outbits;
|
||||
out[(*outlen)++] = (val >> bits) & maxv;
|
||||
}
|
||||
}
|
||||
if(pad) {
|
||||
if(bits) {
|
||||
out[(*outlen)++] = (val << (outbits - bits)) & maxv;
|
||||
}
|
||||
} else if(((val << (outbits - bits)) & maxv) || bits >= inbits) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cash_addr_encode(char* output, const char* hrp, const uint8_t* data, size_t data_len) {
|
||||
uint8_t base32[MAX_BASE32_SIZE] = {0};
|
||||
size_t base32len = 0;
|
||||
if(data_len < 2 || data_len > MAX_DATA_SIZE) return 0;
|
||||
convert_bits(base32, &base32len, 5, data, data_len, 8, 1);
|
||||
return cash_encode(output, hrp, base32, base32len);
|
||||
}
|
||||
|
||||
int cash_addr_decode(uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) {
|
||||
uint8_t data[MAX_BASE32_SIZE] = {0};
|
||||
char hrp_actual[MAX_HRP_SIZE + 1] = {0};
|
||||
size_t data_len = 0;
|
||||
if(!cash_decode(hrp_actual, data, &data_len, addr)) return 0;
|
||||
if(data_len == 0 || data_len > MAX_BASE32_SIZE) return 0;
|
||||
if(strncmp(hrp, hrp_actual, MAX_HRP_SIZE + 1) != 0) return 0;
|
||||
*witdata_len = 0;
|
||||
if(!convert_bits(witdata, witdata_len, 8, data, data_len, 5, 0)) return 0;
|
||||
if(*witdata_len < 2 || *witdata_len > MAX_DATA_SIZE) return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Copyright (c) 2017 Jochen Hoenicke, Pieter Wuille
|
||||
*
|
||||
* 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 _CASH_ADDR_H_
|
||||
#define _CASH_ADDR_H_ 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Encode a Cashaddr address
|
||||
*
|
||||
* Out: output: Pointer to a buffer of size 105 + strlen(hrp) that will be
|
||||
* updated to contain the null-terminated address.
|
||||
* In: hrp: Pointer to the null-terminated human readable part to use
|
||||
* (chain/network specific).
|
||||
* prog: Data bytes for the hash (between 21 and 65 bytes).
|
||||
* prog_len: Number of data bytes in prog.
|
||||
* Returns 1 if successful.
|
||||
*/
|
||||
int cash_addr_encode(char* output, const char* hrp, const uint8_t* prog, size_t prog_len);
|
||||
|
||||
/** Decode a CashAddr address
|
||||
*
|
||||
* Out: prog: Pointer to a buffer of size 65 that will be updated to
|
||||
* contain the witness program bytes.
|
||||
* prog_len: Pointer to a size_t that will be updated to contain the
|
||||
* length of bytes in prog. hrp: Pointer to the null-terminated human
|
||||
* readable part that is expected (chain/network specific). addr: Pointer to
|
||||
* the null-terminated address. Returns 1 if successful.
|
||||
*/
|
||||
int cash_addr_decode(uint8_t* prog, size_t* prog_len, const char* hrp, const char* addr);
|
||||
|
||||
/** Encode a Cash string
|
||||
*
|
||||
* Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that
|
||||
* will be updated to contain the null-terminated Cash string.
|
||||
* In: hrp : Pointer to the null-terminated human readable part.
|
||||
* data : Pointer to an array of 5-bit values.
|
||||
* data_len: Length of the data array.
|
||||
* Returns 1 if successful.
|
||||
*/
|
||||
int cash_encode(char* output, const char* hrp, const uint8_t* data, size_t data_len);
|
||||
|
||||
/** Decode a Cash string
|
||||
*
|
||||
* Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be
|
||||
* updated to contain the null-terminated human readable part.
|
||||
* data: Pointer to a buffer of size strlen(input) - 8 that will
|
||||
* hold the encoded 5-bit data values.
|
||||
* data_len: Pointer to a size_t that will be updated to be the number
|
||||
* of entries in data.
|
||||
* In: input: Pointer to a null-terminated Cash string.
|
||||
* Returns 1 if succesful.
|
||||
*/
|
||||
int cash_decode(char* hrp, uint8_t* data, size_t* data_len, const char* input);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2016 Will Glozer
|
||||
|
||||
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,63 @@
|
||||
// Implementations of the XChaCha20 + Poly1305 and ChaCha20 + Poly1305
|
||||
// AEAD constructions with a goal of simplicity and correctness rather
|
||||
// than performance.
|
||||
|
||||
#include "chacha20poly1305.h"
|
||||
#include "ecrypt_portable.h"
|
||||
|
||||
void hchacha20(ECRYPT_ctx* x, u8* c);
|
||||
|
||||
// Initialize the XChaCha20 + Poly1305 context for encryption or decryption
|
||||
// using a 32 byte key and 24 byte nonce. The key and the first 16 bytes of
|
||||
// the nonce are used as input to HChaCha20 to derive the Chacha20 key.
|
||||
void xchacha20poly1305_init(
|
||||
chacha20poly1305_ctx* ctx,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[24]) {
|
||||
unsigned char subkey[32] = {0};
|
||||
unsigned char block0[64] = {0};
|
||||
ECRYPT_ctx tmp = {0};
|
||||
|
||||
// Generate the Chacha20 key by applying HChaCha20 to the
|
||||
// original key and the first 16 bytes of the nonce.
|
||||
ECRYPT_keysetup(&tmp, key, 256, 16);
|
||||
tmp.input[12] = U8TO32_LITTLE(nonce + 0);
|
||||
tmp.input[13] = U8TO32_LITTLE(nonce + 4);
|
||||
tmp.input[14] = U8TO32_LITTLE(nonce + 8);
|
||||
tmp.input[15] = U8TO32_LITTLE(nonce + 12);
|
||||
hchacha20(&tmp, subkey);
|
||||
|
||||
// Initialize Chacha20 with the newly generated key and
|
||||
// the last 8 bytes of the nonce.
|
||||
ECRYPT_keysetup(&ctx->chacha20, subkey, 256, 16);
|
||||
ECRYPT_ivsetup(&ctx->chacha20, nonce + 16);
|
||||
|
||||
// Encrypt 64 bytes of zeros and use the first 32 bytes
|
||||
// as the Poly1305 key.
|
||||
ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64);
|
||||
poly1305_init(&ctx->poly1305, block0);
|
||||
}
|
||||
|
||||
// Encrypt n bytes of plaintext where n must be evenly divisible by the
|
||||
// Chacha20 blocksize of 64, except for the final n bytes of plaintext.
|
||||
void chacha20poly1305_encrypt(chacha20poly1305_ctx* ctx, const uint8_t* in, uint8_t* out, size_t n) {
|
||||
ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n);
|
||||
poly1305_update(&ctx->poly1305, out, n);
|
||||
}
|
||||
|
||||
// Decrypt n bytes of ciphertext where n must be evenly divisible by the
|
||||
// Chacha20 blocksize of 64, except for the final n bytes of ciphertext.
|
||||
void chacha20poly1305_decrypt(chacha20poly1305_ctx* ctx, const uint8_t* in, uint8_t* out, size_t n) {
|
||||
poly1305_update(&ctx->poly1305, in, n);
|
||||
ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n);
|
||||
}
|
||||
|
||||
// Include authenticated data in the Poly1305 MAC.
|
||||
void chacha20poly1305_auth(chacha20poly1305_ctx* ctx, const uint8_t* in, size_t n) {
|
||||
poly1305_update(&ctx->poly1305, in, n);
|
||||
}
|
||||
|
||||
// Compute NaCl secretbox-style Poly1305 MAC.
|
||||
void chacha20poly1305_finish(chacha20poly1305_ctx* ctx, uint8_t mac[16]) {
|
||||
poly1305_finish(&ctx->poly1305, mac);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef CHACHA20POLY1305_H
|
||||
#define CHACHA20POLY1305_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ecrypt_sync.h"
|
||||
#include "poly1305_donna.h"
|
||||
|
||||
typedef struct {
|
||||
ECRYPT_ctx chacha20;
|
||||
poly1305_context poly1305;
|
||||
} chacha20poly1305_ctx;
|
||||
|
||||
void xchacha20poly1305_init(
|
||||
chacha20poly1305_ctx* ctx,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[24]);
|
||||
void chacha20poly1305_encrypt(chacha20poly1305_ctx* ctx, const uint8_t* in, uint8_t* out, size_t n);
|
||||
void chacha20poly1305_decrypt(chacha20poly1305_ctx* ctx, const uint8_t* in, uint8_t* out, size_t n);
|
||||
void chacha20poly1305_auth(chacha20poly1305_ctx* ctx, const uint8_t* in, size_t n);
|
||||
void chacha20poly1305_finish(chacha20poly1305_ctx* ctx, uint8_t mac[16]);
|
||||
|
||||
#endif // CHACHA20POLY1305_H
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
chacha-merged.c version 20080118
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include "ecrypt_sync.h"
|
||||
#include "ecrypt_portable.h"
|
||||
|
||||
#define ROTATE(v, c) (ROTL32(v, c))
|
||||
#define XOR(v, w) ((v) ^ (w))
|
||||
#define PLUS(v, w) (U32V((v) + (w)))
|
||||
#define PLUSONE(v) (PLUS((v), 1))
|
||||
|
||||
#define QUARTERROUND(a, b, c, d) \
|
||||
a = PLUS(a, b); \
|
||||
d = ROTATE(XOR(d, a), 16); \
|
||||
c = PLUS(c, d); \
|
||||
b = ROTATE(XOR(b, c), 12); \
|
||||
a = PLUS(a, b); \
|
||||
d = ROTATE(XOR(d, a), 8); \
|
||||
c = PLUS(c, d); \
|
||||
b = ROTATE(XOR(b, c), 7);
|
||||
|
||||
void ECRYPT_init(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const char sigma[16] = "expand 32-byte k";
|
||||
static const char tau[16] = "expand 16-byte k";
|
||||
|
||||
void ECRYPT_keysetup(ECRYPT_ctx* x, const u8* k, u32 kbits, u32 ivbits) {
|
||||
(void)ivbits;
|
||||
const char* constants = (const char*)0;
|
||||
|
||||
x->input[4] = U8TO32_LITTLE(k + 0);
|
||||
x->input[5] = U8TO32_LITTLE(k + 4);
|
||||
x->input[6] = U8TO32_LITTLE(k + 8);
|
||||
x->input[7] = U8TO32_LITTLE(k + 12);
|
||||
if(kbits == 256) { /* recommended */
|
||||
k += 16;
|
||||
constants = sigma;
|
||||
} else { /* kbits == 128 */
|
||||
constants = tau;
|
||||
}
|
||||
x->input[8] = U8TO32_LITTLE(k + 0);
|
||||
x->input[9] = U8TO32_LITTLE(k + 4);
|
||||
x->input[10] = U8TO32_LITTLE(k + 8);
|
||||
x->input[11] = U8TO32_LITTLE(k + 12);
|
||||
x->input[0] = U8TO32_LITTLE(constants + 0);
|
||||
x->input[1] = U8TO32_LITTLE(constants + 4);
|
||||
x->input[2] = U8TO32_LITTLE(constants + 8);
|
||||
x->input[3] = U8TO32_LITTLE(constants + 12);
|
||||
}
|
||||
|
||||
void ECRYPT_ivsetup(ECRYPT_ctx* x, const u8* iv) {
|
||||
x->input[12] = 0;
|
||||
x->input[13] = 0;
|
||||
x->input[14] = U8TO32_LITTLE(iv + 0);
|
||||
x->input[15] = U8TO32_LITTLE(iv + 4);
|
||||
}
|
||||
|
||||
void ECRYPT_ctrsetup(ECRYPT_ctx* x, const u8* ctr) {
|
||||
x->input[12] = U8TO32_LITTLE(ctr + 0);
|
||||
x->input[13] = U8TO32_LITTLE(ctr + 4);
|
||||
}
|
||||
|
||||
void ECRYPT_encrypt_bytes(ECRYPT_ctx* x, const u8* m, u8* c, u32 bytes) {
|
||||
u32 x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0, x10 = 0,
|
||||
x11 = 0, x12 = 0, x13 = 0, x14 = 0, x15 = 0;
|
||||
u32 j0 = 0, j1 = 0, j2 = 0, j3 = 0, j4 = 0, j5 = 0, j6 = 0, j7 = 0, j8 = 0, j9 = 0, j10 = 0,
|
||||
j11 = 0, j12 = 0, j13 = 0, j14 = 0, j15 = 0;
|
||||
u8* ctarget = 0;
|
||||
u8 tmp[64] = {0};
|
||||
int i = 0;
|
||||
|
||||
if(!bytes) return;
|
||||
|
||||
j0 = x->input[0];
|
||||
j1 = x->input[1];
|
||||
j2 = x->input[2];
|
||||
j3 = x->input[3];
|
||||
j4 = x->input[4];
|
||||
j5 = x->input[5];
|
||||
j6 = x->input[6];
|
||||
j7 = x->input[7];
|
||||
j8 = x->input[8];
|
||||
j9 = x->input[9];
|
||||
j10 = x->input[10];
|
||||
j11 = x->input[11];
|
||||
j12 = x->input[12];
|
||||
j13 = x->input[13];
|
||||
j14 = x->input[14];
|
||||
j15 = x->input[15];
|
||||
|
||||
for(;;) {
|
||||
if(bytes < 64) {
|
||||
for(i = 0; i < (int)bytes; ++i) tmp[i] = m[i];
|
||||
m = tmp;
|
||||
ctarget = c;
|
||||
c = tmp;
|
||||
}
|
||||
x0 = j0;
|
||||
x1 = j1;
|
||||
x2 = j2;
|
||||
x3 = j3;
|
||||
x4 = j4;
|
||||
x5 = j5;
|
||||
x6 = j6;
|
||||
x7 = j7;
|
||||
x8 = j8;
|
||||
x9 = j9;
|
||||
x10 = j10;
|
||||
x11 = j11;
|
||||
x12 = j12;
|
||||
x13 = j13;
|
||||
x14 = j14;
|
||||
x15 = j15;
|
||||
for(i = 20; i > 0; i -= 2) {
|
||||
QUARTERROUND(x0, x4, x8, x12)
|
||||
QUARTERROUND(x1, x5, x9, x13)
|
||||
QUARTERROUND(x2, x6, x10, x14)
|
||||
QUARTERROUND(x3, x7, x11, x15)
|
||||
QUARTERROUND(x0, x5, x10, x15)
|
||||
QUARTERROUND(x1, x6, x11, x12)
|
||||
QUARTERROUND(x2, x7, x8, x13)
|
||||
QUARTERROUND(x3, x4, x9, x14)
|
||||
}
|
||||
x0 = PLUS(x0, j0);
|
||||
x1 = PLUS(x1, j1);
|
||||
x2 = PLUS(x2, j2);
|
||||
x3 = PLUS(x3, j3);
|
||||
x4 = PLUS(x4, j4);
|
||||
x5 = PLUS(x5, j5);
|
||||
x6 = PLUS(x6, j6);
|
||||
x7 = PLUS(x7, j7);
|
||||
x8 = PLUS(x8, j8);
|
||||
x9 = PLUS(x9, j9);
|
||||
x10 = PLUS(x10, j10);
|
||||
x11 = PLUS(x11, j11);
|
||||
x12 = PLUS(x12, j12);
|
||||
x13 = PLUS(x13, j13);
|
||||
x14 = PLUS(x14, j14);
|
||||
x15 = PLUS(x15, j15);
|
||||
|
||||
x0 = XOR(x0, U8TO32_LITTLE(m + 0));
|
||||
x1 = XOR(x1, U8TO32_LITTLE(m + 4));
|
||||
x2 = XOR(x2, U8TO32_LITTLE(m + 8));
|
||||
x3 = XOR(x3, U8TO32_LITTLE(m + 12));
|
||||
x4 = XOR(x4, U8TO32_LITTLE(m + 16));
|
||||
x5 = XOR(x5, U8TO32_LITTLE(m + 20));
|
||||
x6 = XOR(x6, U8TO32_LITTLE(m + 24));
|
||||
x7 = XOR(x7, U8TO32_LITTLE(m + 28));
|
||||
x8 = XOR(x8, U8TO32_LITTLE(m + 32));
|
||||
x9 = XOR(x9, U8TO32_LITTLE(m + 36));
|
||||
x10 = XOR(x10, U8TO32_LITTLE(m + 40));
|
||||
x11 = XOR(x11, U8TO32_LITTLE(m + 44));
|
||||
x12 = XOR(x12, U8TO32_LITTLE(m + 48));
|
||||
x13 = XOR(x13, U8TO32_LITTLE(m + 52));
|
||||
x14 = XOR(x14, U8TO32_LITTLE(m + 56));
|
||||
x15 = XOR(x15, U8TO32_LITTLE(m + 60));
|
||||
|
||||
j12 = PLUSONE(j12);
|
||||
if(!j12) {
|
||||
j13 = PLUSONE(j13);
|
||||
/* stopping at 2^70 bytes per nonce is user's responsibility */
|
||||
}
|
||||
|
||||
U32TO8_LITTLE(c + 0, x0);
|
||||
U32TO8_LITTLE(c + 4, x1);
|
||||
U32TO8_LITTLE(c + 8, x2);
|
||||
U32TO8_LITTLE(c + 12, x3);
|
||||
U32TO8_LITTLE(c + 16, x4);
|
||||
U32TO8_LITTLE(c + 20, x5);
|
||||
U32TO8_LITTLE(c + 24, x6);
|
||||
U32TO8_LITTLE(c + 28, x7);
|
||||
U32TO8_LITTLE(c + 32, x8);
|
||||
U32TO8_LITTLE(c + 36, x9);
|
||||
U32TO8_LITTLE(c + 40, x10);
|
||||
U32TO8_LITTLE(c + 44, x11);
|
||||
U32TO8_LITTLE(c + 48, x12);
|
||||
U32TO8_LITTLE(c + 52, x13);
|
||||
U32TO8_LITTLE(c + 56, x14);
|
||||
U32TO8_LITTLE(c + 60, x15);
|
||||
|
||||
if(bytes <= 64) {
|
||||
if(bytes < 64) {
|
||||
for(i = 0; i < (int)bytes; ++i) ctarget[i] = c[i];
|
||||
}
|
||||
x->input[12] = j12;
|
||||
x->input[13] = j13;
|
||||
return;
|
||||
}
|
||||
bytes -= 64;
|
||||
c += 64;
|
||||
m += 64;
|
||||
}
|
||||
}
|
||||
|
||||
void ECRYPT_decrypt_bytes(ECRYPT_ctx* x, const u8* c, u8* m, u32 bytes) {
|
||||
ECRYPT_encrypt_bytes(x, c, m, bytes);
|
||||
}
|
||||
|
||||
void ECRYPT_keystream_bytes(ECRYPT_ctx* x, u8* stream, u32 bytes) {
|
||||
u32 i = 0;
|
||||
for(i = 0; i < bytes; ++i) stream[i] = 0;
|
||||
ECRYPT_encrypt_bytes(x, stream, stream, bytes);
|
||||
}
|
||||
|
||||
void hchacha20(ECRYPT_ctx* x, u8* c) {
|
||||
u32 x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0, x10 = 0,
|
||||
x11 = 0, x12 = 0, x13 = 0, x14 = 0, x15 = 0;
|
||||
int i = 0;
|
||||
|
||||
x0 = x->input[0];
|
||||
x1 = x->input[1];
|
||||
x2 = x->input[2];
|
||||
x3 = x->input[3];
|
||||
x4 = x->input[4];
|
||||
x5 = x->input[5];
|
||||
x6 = x->input[6];
|
||||
x7 = x->input[7];
|
||||
x8 = x->input[8];
|
||||
x9 = x->input[9];
|
||||
x10 = x->input[10];
|
||||
x11 = x->input[11];
|
||||
x12 = x->input[12];
|
||||
x13 = x->input[13];
|
||||
x14 = x->input[14];
|
||||
x15 = x->input[15];
|
||||
|
||||
for(i = 20; i > 0; i -= 2) {
|
||||
QUARTERROUND(x0, x4, x8, x12)
|
||||
QUARTERROUND(x1, x5, x9, x13)
|
||||
QUARTERROUND(x2, x6, x10, x14)
|
||||
QUARTERROUND(x3, x7, x11, x15)
|
||||
QUARTERROUND(x0, x5, x10, x15)
|
||||
QUARTERROUND(x1, x6, x11, x12)
|
||||
QUARTERROUND(x2, x7, x8, x13)
|
||||
QUARTERROUND(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
U32TO8_LITTLE(c + 0, x0);
|
||||
U32TO8_LITTLE(c + 4, x1);
|
||||
U32TO8_LITTLE(c + 8, x2);
|
||||
U32TO8_LITTLE(c + 12, x3);
|
||||
U32TO8_LITTLE(c + 16, x12);
|
||||
U32TO8_LITTLE(c + 20, x13);
|
||||
U32TO8_LITTLE(c + 24, x14);
|
||||
U32TO8_LITTLE(c + 28, x15);
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
/* ecrypt_config.h */
|
||||
|
||||
/* *** Normally, it should not be necessary to edit this file. *** */
|
||||
|
||||
#ifndef ECRYPT_CONFIG
|
||||
#define ECRYPT_CONFIG
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Guess the endianness of the target architecture. */
|
||||
|
||||
/*
|
||||
* The LITTLE endian machines:
|
||||
*/
|
||||
#if defined(__ultrix) /* Older MIPS */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(__alpha) /* Alpha */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(i386) /* x86 (gcc) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(__i386) /* x86 (gcc) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(__x86_64) /* x86_64 (gcc) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(_M_IX86) /* x86 (MSC, Borland) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(_MSC_VER) /* x86 (surely MSC) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
|
||||
/*
|
||||
* The BIG endian machines:
|
||||
*/
|
||||
#elif defined(__sparc) /* Newer Sparc's */
|
||||
#define ECRYPT_BIG_ENDIAN
|
||||
#elif defined(__powerpc__) /* PowerPC */
|
||||
#define ECRYPT_BIG_ENDIAN
|
||||
#elif defined(__ppc__) /* PowerPC */
|
||||
#define ECRYPT_BIG_ENDIAN
|
||||
#elif defined(__hppa) /* HP-PA */
|
||||
#define ECRYPT_BIG_ENDIAN
|
||||
|
||||
/*
|
||||
* Finally machines with UNKNOWN endianness:
|
||||
*/
|
||||
#elif defined(_AIX) /* RS6000 */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#elif defined(__aux) /* 68K */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#elif defined(__dgux) /* 88K (but P6 in latest boxes) */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#elif defined(__sgi) /* Newer MIPS */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#else /* Any other processor */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit
|
||||
* integers.
|
||||
*
|
||||
* Note: to enable 64-bit types on 32-bit compilers, it might be
|
||||
* necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc
|
||||
* -std=c99), or to allow compiler-specific extensions.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* --- check char --- */
|
||||
|
||||
#if(UCHAR_MAX / 0xFU > 0xFU)
|
||||
#ifndef I8T
|
||||
#define I8T char
|
||||
#define U8C(v) (v##U)
|
||||
|
||||
#if(UCHAR_MAX == 0xFFU)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if(UCHAR_MAX / 0xFFU > 0xFFU)
|
||||
#ifndef I16T
|
||||
#define I16T char
|
||||
#define U16C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if(UCHAR_MAX / 0xFFFFU > 0xFFFFU)
|
||||
#ifndef I32T
|
||||
#define I32T char
|
||||
#define U32C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if(UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
|
||||
#ifndef I64T
|
||||
#define I64T char
|
||||
#define U64C(v) (v##U)
|
||||
#define ECRYPT_NATIVE64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* --- check short --- */
|
||||
|
||||
#if(USHRT_MAX / 0xFU > 0xFU)
|
||||
#ifndef I8T
|
||||
#define I8T short
|
||||
#define U8C(v) (v##U)
|
||||
|
||||
#if(USHRT_MAX == 0xFFU)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if(USHRT_MAX / 0xFFU > 0xFFU)
|
||||
#ifndef I16T
|
||||
#define I16T short
|
||||
#define U16C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if(USHRT_MAX / 0xFFFFU > 0xFFFFU)
|
||||
#ifndef I32T
|
||||
#define I32T short
|
||||
#define U32C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if(USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
|
||||
#ifndef I64T
|
||||
#define I64T short
|
||||
#define U64C(v) (v##U)
|
||||
#define ECRYPT_NATIVE64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* --- check int --- */
|
||||
|
||||
#if(UINT_MAX / 0xFU > 0xFU)
|
||||
#ifndef I8T
|
||||
#define I8T int
|
||||
#define U8C(v) (v##U)
|
||||
|
||||
#if(ULONG_MAX == 0xFFU)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if(UINT_MAX / 0xFFU > 0xFFU)
|
||||
#ifndef I16T
|
||||
#define I16T int
|
||||
#define U16C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if(UINT_MAX / 0xFFFFU > 0xFFFFU)
|
||||
#ifndef I32T
|
||||
#define I32T int
|
||||
#define U32C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if(UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
|
||||
#ifndef I64T
|
||||
#define I64T int
|
||||
#define U64C(v) (v##U)
|
||||
#define ECRYPT_NATIVE64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* --- check long --- */
|
||||
|
||||
#if(ULONG_MAX / 0xFUL > 0xFUL)
|
||||
#ifndef I8T
|
||||
#define I8T long
|
||||
#define U8C(v) (v##UL)
|
||||
|
||||
#if(ULONG_MAX == 0xFFUL)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if(ULONG_MAX / 0xFFUL > 0xFFUL)
|
||||
#ifndef I16T
|
||||
#define I16T long
|
||||
#define U16C(v) (v##UL)
|
||||
#endif
|
||||
|
||||
#if(ULONG_MAX / 0xFFFFUL > 0xFFFFUL)
|
||||
#ifndef I32T
|
||||
#define I32T long
|
||||
#define U32C(v) (v##UL)
|
||||
#endif
|
||||
|
||||
#if(ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL)
|
||||
#ifndef I64T
|
||||
#define I64T long
|
||||
#define U64C(v) (v##UL)
|
||||
#define ECRYPT_NATIVE64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* --- check long long --- */
|
||||
|
||||
#ifdef ULLONG_MAX
|
||||
|
||||
#if(ULLONG_MAX / 0xFULL > 0xFULL)
|
||||
#ifndef I8T
|
||||
#define I8T long long
|
||||
#define U8C(v) (v##ULL)
|
||||
|
||||
#if(ULLONG_MAX == 0xFFULL)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if(ULLONG_MAX / 0xFFULL > 0xFFULL)
|
||||
#ifndef I16T
|
||||
#define I16T long long
|
||||
#define U16C(v) (v##ULL)
|
||||
#endif
|
||||
|
||||
#if(ULLONG_MAX / 0xFFFFULL > 0xFFFFULL)
|
||||
#ifndef I32T
|
||||
#define I32T long long
|
||||
#define U32C(v) (v##ULL)
|
||||
#endif
|
||||
|
||||
#if(ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL)
|
||||
#ifndef I64T
|
||||
#define I64T long long
|
||||
#define U64C(v) (v##ULL)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* --- check __int64 --- */
|
||||
|
||||
#if !defined(__STDC__) && defined(_UI64_MAX)
|
||||
|
||||
#ifndef I64T
|
||||
#define I64T __int64
|
||||
#define U64C(v) (v##ui64)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* --- if platform doesn't announce anything, use most common choices --- */
|
||||
|
||||
#ifndef I8T
|
||||
#define I8T char
|
||||
#define U8C(v) (v##U)
|
||||
#endif
|
||||
#ifndef I16T
|
||||
#define I16T short
|
||||
#define U16C(v) (v##U)
|
||||
#endif
|
||||
#ifndef I32T
|
||||
#define I32T int
|
||||
#define U32C(v) (v##U)
|
||||
#endif
|
||||
#ifndef I64T
|
||||
#define I64T long long
|
||||
#define U64C(v) (v##ULL)
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* find the largest type on this platform (used for alignment) */
|
||||
|
||||
#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300))
|
||||
|
||||
#include <xmmintrin.h>
|
||||
#define MAXT __m128
|
||||
|
||||
#elif defined(__MMX__)
|
||||
|
||||
#include <mmintrin.h>
|
||||
#define MAXT __m64
|
||||
|
||||
#elif defined(__ALTIVEC__)
|
||||
|
||||
#define MAXT __vector int
|
||||
|
||||
#else
|
||||
|
||||
#define MAXT long
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/* ecrypt_machine.h */
|
||||
|
||||
/*
|
||||
* This file is included by 'ecrypt_portable.h'. It allows to override
|
||||
* the default macros for specific platforms. Please carefully check
|
||||
* the machine code generated by your compiler (with optimisations
|
||||
* turned on) before deciding to edit this file.
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#if(defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT))
|
||||
|
||||
#define ECRYPT_MACHINE_ROT
|
||||
|
||||
#if(defined(WIN32) && defined(_MSC_VER))
|
||||
|
||||
#undef ROTL32
|
||||
#undef ROTR32
|
||||
#undef ROTL64
|
||||
#undef ROTR64
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#pragma intrinsic(_lrotl) /* compile rotations "inline" */
|
||||
#pragma intrinsic(_lrotr)
|
||||
|
||||
#define ROTL32(v, n) _lrotl(v, n)
|
||||
#define ROTR32(v, n) _lrotr(v, n)
|
||||
#define ROTL64(v, n) _rotl64(v, n)
|
||||
#define ROTR64(v, n) _rotr64(v, n)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#if(defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP))
|
||||
|
||||
#define ECRYPT_MACHINE_SWAP
|
||||
|
||||
/*
|
||||
* If you want to overwrite the default swap macros, put it here. And so on.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@@ -0,0 +1,246 @@
|
||||
/* ecrypt_portable.h */
|
||||
|
||||
/*
|
||||
* WARNING: the conversions defined below are implemented as macros,
|
||||
* and should be used carefully. They should NOT be used with
|
||||
* parameters which perform some action. E.g., the following two lines
|
||||
* are not equivalent:
|
||||
*
|
||||
* 1) ++x; y = ROTL32(x, n);
|
||||
* 2) y = ROTL32(++x, n);
|
||||
*/
|
||||
|
||||
/*
|
||||
* *** Please do not edit this file. ***
|
||||
*
|
||||
* The default macros can be overridden for specific architectures by
|
||||
* editing 'ecrypt_machine.h'.
|
||||
*/
|
||||
|
||||
#ifndef ECRYPT_PORTABLE
|
||||
#define ECRYPT_PORTABLE
|
||||
|
||||
#include "ecrypt_config.h"
|
||||
#include "ecrypt_types.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* The following macros are used to obtain exact-width results.
|
||||
*/
|
||||
|
||||
#define U8V(v) ((u8)(v)&U8C(0xFF))
|
||||
#define U16V(v) ((u16)(v)&U16C(0xFFFF))
|
||||
#define U32V(v) ((u32)(v)&U32C(0xFFFFFFFF))
|
||||
#define U64V(v) ((u64)(v)&U64C(0xFFFFFFFFFFFFFFFF))
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* The following macros return words with their bits rotated over n
|
||||
* positions to the left/right.
|
||||
*/
|
||||
|
||||
#define ECRYPT_DEFAULT_ROT
|
||||
|
||||
#define ROTL8(v, n) (U8V((v) << (n)) | ((v) >> (8 - (n))))
|
||||
|
||||
#define ROTL16(v, n) (U16V((v) << (n)) | ((v) >> (16 - (n))))
|
||||
|
||||
#define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n))))
|
||||
|
||||
#define ROTL64(v, n) (U64V((v) << (n)) | ((v) >> (64 - (n))))
|
||||
|
||||
#define ROTR8(v, n) ROTL8(v, 8 - (n))
|
||||
#define ROTR16(v, n) ROTL16(v, 16 - (n))
|
||||
#define ROTR32(v, n) ROTL32(v, 32 - (n))
|
||||
#define ROTR64(v, n) ROTL64(v, 64 - (n))
|
||||
|
||||
#include "ecrypt_machine.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* The following macros return a word with bytes in reverse order.
|
||||
*/
|
||||
|
||||
#define ECRYPT_DEFAULT_SWAP
|
||||
|
||||
#define SWAP16(v) ROTL16(v, 8)
|
||||
|
||||
#define SWAP32(v) ((ROTL32(v, 8) & U32C(0x00FF00FF)) | (ROTL32(v, 24) & U32C(0xFF00FF00)))
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define SWAP64(v) \
|
||||
((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | (ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \
|
||||
(ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | (ROTL64(v, 56) & U64C(0xFF000000FF000000)))
|
||||
#else
|
||||
#define SWAP64(v) (((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32)))
|
||||
#endif
|
||||
|
||||
#include "ecrypt_machine.h"
|
||||
|
||||
#define ECRYPT_DEFAULT_WTOW
|
||||
|
||||
#ifdef ECRYPT_LITTLE_ENDIAN
|
||||
#define U16TO16_LITTLE(v) (v)
|
||||
#define U32TO32_LITTLE(v) (v)
|
||||
#define U64TO64_LITTLE(v) (v)
|
||||
|
||||
#define U16TO16_BIG(v) SWAP16(v)
|
||||
#define U32TO32_BIG(v) SWAP32(v)
|
||||
#define U64TO64_BIG(v) SWAP64(v)
|
||||
#endif
|
||||
|
||||
#ifdef ECRYPT_BIG_ENDIAN
|
||||
#define U16TO16_LITTLE(v) SWAP16(v)
|
||||
#define U32TO32_LITTLE(v) SWAP32(v)
|
||||
#define U64TO64_LITTLE(v) SWAP64(v)
|
||||
|
||||
#define U16TO16_BIG(v) (v)
|
||||
#define U32TO32_BIG(v) (v)
|
||||
#define U64TO64_BIG(v) (v)
|
||||
#endif
|
||||
|
||||
#include "ecrypt_machine.h"
|
||||
|
||||
/*
|
||||
* The following macros load words from an array of bytes with
|
||||
* different types of endianness, and vice versa.
|
||||
*/
|
||||
|
||||
#define ECRYPT_DEFAULT_BTOW
|
||||
|
||||
#if(!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE))
|
||||
|
||||
#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0])
|
||||
#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0])
|
||||
#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0])
|
||||
|
||||
#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0])
|
||||
#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0])
|
||||
#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0])
|
||||
|
||||
#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v))
|
||||
#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v))
|
||||
#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v))
|
||||
|
||||
#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v))
|
||||
#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v))
|
||||
#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v))
|
||||
|
||||
#else
|
||||
|
||||
#define U8TO16_LITTLE(p) (((u16)((p)[0])) | ((u16)((p)[1]) << 8))
|
||||
|
||||
#define U8TO32_LITTLE(p) \
|
||||
(((u32)((p)[0])) | ((u32)((p)[1]) << 8) | ((u32)((p)[2]) << 16) | ((u32)((p)[3]) << 24))
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define U8TO64_LITTLE(p) \
|
||||
(((u64)((p)[0])) | ((u64)((p)[1]) << 8) | ((u64)((p)[2]) << 16) | ((u64)((p)[3]) << 24) | \
|
||||
((u64)((p)[4]) << 32) | ((u64)((p)[5]) << 40) | ((u64)((p)[6]) << 48) | \
|
||||
((u64)((p)[7]) << 56))
|
||||
#else
|
||||
#define U8TO64_LITTLE(p) ((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32))
|
||||
#endif
|
||||
|
||||
#define U8TO16_BIG(p) (((u16)((p)[0]) << 8) | ((u16)((p)[1])))
|
||||
|
||||
#define U8TO32_BIG(p) \
|
||||
(((u32)((p)[0]) << 24) | ((u32)((p)[1]) << 16) | ((u32)((p)[2]) << 8) | ((u32)((p)[3])))
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define U8TO64_BIG(p) \
|
||||
(((u64)((p)[0]) << 56) | ((u64)((p)[1]) << 48) | ((u64)((p)[2]) << 40) | \
|
||||
((u64)((p)[3]) << 32) | ((u64)((p)[4]) << 24) | ((u64)((p)[5]) << 16) | \
|
||||
((u64)((p)[6]) << 8) | ((u64)((p)[7])))
|
||||
#else
|
||||
#define U8TO64_BIG(p) (((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4))
|
||||
#endif
|
||||
|
||||
#define U16TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v)); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
} while(0)
|
||||
|
||||
#define U32TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v)); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
(p)[2] = U8V((v) >> 16); \
|
||||
(p)[3] = U8V((v) >> 24); \
|
||||
} while(0)
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define U64TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v)); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
(p)[2] = U8V((v) >> 16); \
|
||||
(p)[3] = U8V((v) >> 24); \
|
||||
(p)[4] = U8V((v) >> 32); \
|
||||
(p)[5] = U8V((v) >> 40); \
|
||||
(p)[6] = U8V((v) >> 48); \
|
||||
(p)[7] = U8V((v) >> 56); \
|
||||
} while(0)
|
||||
#else
|
||||
#define U64TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
U32TO8_LITTLE((p), U32V((v))); \
|
||||
U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#define U16TO8_BIG(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v)); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
} while(0)
|
||||
|
||||
#define U32TO8_BIG(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) >> 24); \
|
||||
(p)[1] = U8V((v) >> 16); \
|
||||
(p)[2] = U8V((v) >> 8); \
|
||||
(p)[3] = U8V((v)); \
|
||||
} while(0)
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define U64TO8_BIG(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) >> 56); \
|
||||
(p)[1] = U8V((v) >> 48); \
|
||||
(p)[2] = U8V((v) >> 40); \
|
||||
(p)[3] = U8V((v) >> 32); \
|
||||
(p)[4] = U8V((v) >> 24); \
|
||||
(p)[5] = U8V((v) >> 16); \
|
||||
(p)[6] = U8V((v) >> 8); \
|
||||
(p)[7] = U8V((v)); \
|
||||
} while(0)
|
||||
#else
|
||||
#define U64TO8_BIG(p, v) \
|
||||
do { \
|
||||
U32TO8_BIG((p), U32V((v) >> 32)); \
|
||||
U32TO8_BIG((p) + 4, U32V((v))); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "ecrypt_machine.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define AT_LEAST_ONE(n) (((n) < 1) ? 1 : (n))
|
||||
|
||||
#define ALIGN(t, v, n) \
|
||||
union { \
|
||||
t b[n]; \
|
||||
MAXT l[AT_LEAST_ONE(n * sizeof(t) / sizeof(MAXT))]; \
|
||||
} v
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,282 @@
|
||||
#define ECRYPT_VARIANT 1
|
||||
#define ECRYPT_API
|
||||
/* ecrypt_sync.h */
|
||||
|
||||
/*
|
||||
* Header file for synchronous stream ciphers without authentication
|
||||
* mechanism.
|
||||
*
|
||||
* *** Please only edit parts marked with "[edit]". ***
|
||||
*/
|
||||
|
||||
#ifndef ECRYPT_SYNC
|
||||
#define ECRYPT_SYNC
|
||||
|
||||
#include "ecrypt_types.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Cipher parameters */
|
||||
|
||||
/*
|
||||
* The name of your cipher.
|
||||
*/
|
||||
#define ECRYPT_NAME "ChaCha20"
|
||||
#define ECRYPT_PROFILE "_____"
|
||||
|
||||
/*
|
||||
* Specify which key and IV sizes are supported by your cipher. A user
|
||||
* should be able to enumerate the supported sizes by running the
|
||||
* following code:
|
||||
*
|
||||
* for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i)
|
||||
* {
|
||||
* keysize = ECRYPT_KEYSIZE(i);
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* All sizes are in bits.
|
||||
*/
|
||||
|
||||
#define ECRYPT_MAXKEYSIZE 256 /* [edit] */
|
||||
#define ECRYPT_KEYSIZE(i) (128 + (i)*128) /* [edit] */
|
||||
|
||||
#define ECRYPT_MAXIVSIZE 64 /* [edit] */
|
||||
#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Data structures */
|
||||
|
||||
/*
|
||||
* ECRYPT_ctx is the structure containing the representation of the
|
||||
* internal state of your cipher.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
u32 input[16]; /* could be compressed */
|
||||
/*
|
||||
* [edit]
|
||||
*
|
||||
* Put here all state variable needed during the encryption process.
|
||||
*/
|
||||
} ECRYPT_ctx;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Mandatory functions */
|
||||
|
||||
/*
|
||||
* Key and message independent initialization. This function will be
|
||||
* called once when the program starts (e.g., to build expanded S-box
|
||||
* tables).
|
||||
*/
|
||||
void ECRYPT_init(void);
|
||||
|
||||
/*
|
||||
* Key setup. It is the user's responsibility to select the values of
|
||||
* keysize and ivsize from the set of supported values specified
|
||||
* above.
|
||||
*/
|
||||
void ECRYPT_keysetup(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* key,
|
||||
u32 keysize, /* Key size in bits. */
|
||||
u32 ivsize); /* IV size in bits. */
|
||||
|
||||
/*
|
||||
* IV setup. After having called ECRYPT_keysetup(), the user is
|
||||
* allowed to call ECRYPT_ivsetup() different times in order to
|
||||
* encrypt/decrypt different messages with the same key but different
|
||||
* IV's. ECRYPT_ivsetup() also sets block counter to zero.
|
||||
*/
|
||||
void ECRYPT_ivsetup(ECRYPT_ctx* ctx, const u8* iv);
|
||||
|
||||
/*
|
||||
* Block counter setup. It is used only for special purposes,
|
||||
* since block counter is usually initialized with ECRYPT_ivsetup.
|
||||
* ECRYPT_ctrsetup has to be called after ECRYPT_ivsetup.
|
||||
*/
|
||||
void ECRYPT_ctrsetup(ECRYPT_ctx* ctx, const u8* ctr);
|
||||
|
||||
/*
|
||||
* Encryption/decryption of arbitrary length messages.
|
||||
*
|
||||
* For efficiency reasons, the API provides two types of
|
||||
* encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function
|
||||
* (declared here) encrypts byte strings of arbitrary length, while
|
||||
* the ECRYPT_encrypt_blocks() function (defined later) only accepts
|
||||
* lengths which are multiples of ECRYPT_BLOCKLENGTH.
|
||||
*
|
||||
* The user is allowed to make multiple calls to
|
||||
* ECRYPT_encrypt_blocks() to incrementally encrypt a long message,
|
||||
* but he is NOT allowed to make additional encryption calls once he
|
||||
* has called ECRYPT_encrypt_bytes() (unless he starts a new message
|
||||
* of course). For example, this sequence of calls is acceptable:
|
||||
*
|
||||
* ECRYPT_keysetup();
|
||||
*
|
||||
* ECRYPT_ivsetup();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
* ECRYPT_encrypt_bytes();
|
||||
*
|
||||
* ECRYPT_ivsetup();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
*
|
||||
* ECRYPT_ivsetup();
|
||||
* ECRYPT_encrypt_bytes();
|
||||
*
|
||||
* The following sequence is not:
|
||||
*
|
||||
* ECRYPT_keysetup();
|
||||
* ECRYPT_ivsetup();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
* ECRYPT_encrypt_bytes();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
*/
|
||||
|
||||
void ECRYPT_encrypt_bytes(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* plaintext,
|
||||
u8* ciphertext,
|
||||
u32 msglen); /* Message length in bytes. */
|
||||
|
||||
void ECRYPT_decrypt_bytes(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* ciphertext,
|
||||
u8* plaintext,
|
||||
u32 msglen); /* Message length in bytes. */
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Optional features */
|
||||
|
||||
/*
|
||||
* For testing purposes it can sometimes be useful to have a function
|
||||
* which immediately generates keystream without having to provide it
|
||||
* with a zero plaintext. If your cipher cannot provide this function
|
||||
* (e.g., because it is not strictly a synchronous cipher), please
|
||||
* reset the ECRYPT_GENERATES_KEYSTREAM flag.
|
||||
*/
|
||||
|
||||
#define ECRYPT_GENERATES_KEYSTREAM
|
||||
#ifdef ECRYPT_GENERATES_KEYSTREAM
|
||||
|
||||
void ECRYPT_keystream_bytes(
|
||||
ECRYPT_ctx* ctx,
|
||||
u8* keystream,
|
||||
u32 length); /* Length of keystream in bytes. */
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Optional optimizations */
|
||||
|
||||
/*
|
||||
* By default, the functions in this section are implemented using
|
||||
* calls to functions declared above. However, you might want to
|
||||
* implement them differently for performance reasons.
|
||||
*/
|
||||
|
||||
/*
|
||||
* All-in-one encryption/decryption of (short) packets.
|
||||
*
|
||||
* The default definitions of these functions can be found in
|
||||
* "ecrypt-sync.c". If you want to implement them differently, please
|
||||
* undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag.
|
||||
*/
|
||||
#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */
|
||||
|
||||
void ECRYPT_encrypt_packet(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* iv,
|
||||
const u8* plaintext,
|
||||
u8* ciphertext,
|
||||
u32 msglen);
|
||||
|
||||
void ECRYPT_decrypt_packet(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* iv,
|
||||
const u8* ciphertext,
|
||||
u8* plaintext,
|
||||
u32 msglen);
|
||||
|
||||
/*
|
||||
* Encryption/decryption of blocks.
|
||||
*
|
||||
* By default, these functions are defined as macros. If you want to
|
||||
* provide a different implementation, please undef the
|
||||
* ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions
|
||||
* declared below.
|
||||
*/
|
||||
|
||||
#define ECRYPT_BLOCKLENGTH 64 /* [edit] */
|
||||
|
||||
#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */
|
||||
#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS
|
||||
|
||||
#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \
|
||||
ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, (blocks)*ECRYPT_BLOCKLENGTH)
|
||||
|
||||
#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \
|
||||
ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, (blocks)*ECRYPT_BLOCKLENGTH)
|
||||
|
||||
#ifdef ECRYPT_GENERATES_KEYSTREAM
|
||||
|
||||
#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \
|
||||
ECRYPT_keystream_bytes(ctx, keystream, (blocks)*ECRYPT_BLOCKLENGTH)
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
void ECRYPT_encrypt_blocks(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* plaintext,
|
||||
u8* ciphertext,
|
||||
u32 blocks); /* Message length in blocks. */
|
||||
|
||||
void ECRYPT_decrypt_blocks(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* ciphertext,
|
||||
u8* plaintext,
|
||||
u32 blocks); /* Message length in blocks. */
|
||||
|
||||
#ifdef ECRYPT_GENERATES_KEYSTREAM
|
||||
|
||||
void ECRYPT_keystream_blocks(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* keystream,
|
||||
u32 blocks); /* Keystream length in blocks. */
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If your cipher can be implemented in different ways, you can use
|
||||
* the ECRYPT_VARIANT parameter to allow the user to choose between
|
||||
* them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please
|
||||
* only use this possibility if you really think it could make a
|
||||
* significant difference and keep the number of variants
|
||||
* (ECRYPT_MAXVARIANT) as small as possible (definitely not more than
|
||||
* 10). Note also that all variants should have exactly the same
|
||||
* external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.).
|
||||
*/
|
||||
#define ECRYPT_MAXVARIANT 1 /* [edit] */
|
||||
|
||||
#ifndef ECRYPT_VARIANT
|
||||
#define ECRYPT_VARIANT 1
|
||||
#endif
|
||||
|
||||
#if(ECRYPT_VARIANT > ECRYPT_MAXVARIANT)
|
||||
#error this variant does not exist
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/* ecrypt_types.h */
|
||||
|
||||
/*
|
||||
* *** Please do not edit this file. ***
|
||||
*
|
||||
* The default macros can be overridden for specific architectures by
|
||||
* editing 'ecrypt_machine.h'.
|
||||
*/
|
||||
|
||||
#ifndef ECRYPT_TYPES
|
||||
#define ECRYPT_TYPES
|
||||
|
||||
#include "ecrypt_config.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* The following types are defined (if available):
|
||||
*
|
||||
* u8: unsigned integer type, at least 8 bits
|
||||
* u16: unsigned integer type, at least 16 bits
|
||||
* u32: unsigned integer type, at least 32 bits
|
||||
* u64: unsigned integer type, at least 64 bits
|
||||
*
|
||||
* s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64
|
||||
*
|
||||
* The selection of minimum-width integer types is taken care of by
|
||||
* 'ecrypt_config.h'. Note: to enable 64-bit types on 32-bit
|
||||
* compilers, it might be necessary to switch from ISO C90 mode to ISO
|
||||
* C99 mode (e.g., gcc -std=c99).
|
||||
*/
|
||||
|
||||
#ifdef I8T
|
||||
typedef signed I8T s8;
|
||||
typedef unsigned I8T u8;
|
||||
#endif
|
||||
|
||||
#ifdef I16T
|
||||
typedef signed I16T s16;
|
||||
typedef unsigned I16T u16;
|
||||
#endif
|
||||
|
||||
#ifdef I32T
|
||||
typedef signed I32T s32;
|
||||
typedef unsigned I32T u32;
|
||||
#endif
|
||||
|
||||
#ifdef I64T
|
||||
typedef signed I64T s64;
|
||||
typedef unsigned I64T u64;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,208 @@
|
||||
#include "poly1305_donna.h"
|
||||
#include "poly1305_donna_32.h"
|
||||
|
||||
void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes) {
|
||||
poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
|
||||
size_t i = 0;
|
||||
|
||||
/* handle leftover */
|
||||
if(st->leftover) {
|
||||
size_t want = (poly1305_block_size - st->leftover);
|
||||
if(want > bytes) want = bytes;
|
||||
for(i = 0; i < want; i++) st->buffer[st->leftover + i] = m[i];
|
||||
bytes -= want;
|
||||
m += want;
|
||||
st->leftover += want;
|
||||
if(st->leftover < poly1305_block_size) return;
|
||||
poly1305_blocks(st, st->buffer, poly1305_block_size);
|
||||
st->leftover = 0;
|
||||
}
|
||||
|
||||
/* process full blocks */
|
||||
if(bytes >= poly1305_block_size) {
|
||||
size_t want = (bytes & ~(poly1305_block_size - 1));
|
||||
poly1305_blocks(st, m, want);
|
||||
m += want;
|
||||
bytes -= want;
|
||||
}
|
||||
|
||||
/* store leftover */
|
||||
if(bytes) {
|
||||
for(i = 0; i < bytes; i++) st->buffer[st->leftover + i] = m[i];
|
||||
st->leftover += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void poly1305_auth(
|
||||
unsigned char mac[16],
|
||||
const unsigned char* m,
|
||||
size_t bytes,
|
||||
const unsigned char key[32]) {
|
||||
poly1305_context ctx = {0};
|
||||
poly1305_init(&ctx, key);
|
||||
poly1305_update(&ctx, m, bytes);
|
||||
poly1305_finish(&ctx, mac);
|
||||
}
|
||||
|
||||
int poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]) {
|
||||
size_t i = 0;
|
||||
unsigned int dif = 0;
|
||||
for(i = 0; i < 16; i++) dif |= (mac1[i] ^ mac2[i]);
|
||||
dif = (dif - 1) >> ((sizeof(unsigned int) * 8) - 1);
|
||||
return (dif & 1);
|
||||
}
|
||||
|
||||
/* test a few basic operations */
|
||||
int poly1305_power_on_self_test(void) {
|
||||
/* example from nacl */
|
||||
static const unsigned char nacl_key[32] = {
|
||||
0xee, 0xa6, 0xa7, 0x25, 0x1c, 0x1e, 0x72, 0x91, 0x6d, 0x11, 0xc2,
|
||||
0xcb, 0x21, 0x4d, 0x3c, 0x25, 0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23,
|
||||
0x4e, 0x65, 0x2d, 0x65, 0x1f, 0xa4, 0xc8, 0xcf, 0xf8, 0x80,
|
||||
};
|
||||
|
||||
static const unsigned char nacl_msg[131] = {
|
||||
0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73, 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76,
|
||||
0xce, 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4, 0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1,
|
||||
0x18, 0x6a, 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, 0x4d, 0xa7, 0xf0, 0x11, 0xec,
|
||||
0x48, 0xc9, 0x72, 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2, 0x27, 0x0d, 0x6f, 0xb8,
|
||||
0x63, 0xd5, 0x17, 0x38, 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a, 0xb9, 0x32, 0x16,
|
||||
0x45, 0x48, 0xe5, 0x26, 0xae, 0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea, 0xbd, 0x6b,
|
||||
0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda, 0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde, 0x56,
|
||||
0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3, 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6,
|
||||
0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74, 0xe3, 0x55, 0xa5};
|
||||
|
||||
static const unsigned char nacl_mac[16] = {
|
||||
0xf3,
|
||||
0xff,
|
||||
0xc7,
|
||||
0x70,
|
||||
0x3f,
|
||||
0x94,
|
||||
0x00,
|
||||
0xe5,
|
||||
0x2a,
|
||||
0x7d,
|
||||
0xfb,
|
||||
0x4b,
|
||||
0x3d,
|
||||
0x33,
|
||||
0x05,
|
||||
0xd9};
|
||||
|
||||
/* generates a final value of (2^130 - 2) == 3 */
|
||||
static const unsigned char wrap_key[32] = {
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const unsigned char wrap_msg[16] = {
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff};
|
||||
|
||||
static const unsigned char wrap_mac[16] = {
|
||||
0x03,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/*
|
||||
mac of the macs of messages of length 0 to 256, where the key and messages
|
||||
have all their values set to the length
|
||||
*/
|
||||
static const unsigned char total_key[32] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
static const unsigned char total_mac[16] = {
|
||||
0x64,
|
||||
0xaf,
|
||||
0xe2,
|
||||
0xe8,
|
||||
0xd6,
|
||||
0xad,
|
||||
0x7b,
|
||||
0xbd,
|
||||
0xd2,
|
||||
0x87,
|
||||
0xf9,
|
||||
0x7c,
|
||||
0x44,
|
||||
0x62,
|
||||
0x3d,
|
||||
0x39};
|
||||
|
||||
poly1305_context ctx = {0};
|
||||
poly1305_context total_ctx = {0};
|
||||
unsigned char all_key[32] = {0};
|
||||
unsigned char all_msg[256] = {0};
|
||||
unsigned char mac[16] = {0};
|
||||
size_t i = 0, j = 0;
|
||||
int result = 1;
|
||||
|
||||
for(i = 0; i < sizeof(mac); i++) mac[i] = 0;
|
||||
poly1305_auth(mac, nacl_msg, sizeof(nacl_msg), nacl_key);
|
||||
result &= poly1305_verify(nacl_mac, mac);
|
||||
|
||||
for(i = 0; i < sizeof(mac); i++) mac[i] = 0;
|
||||
poly1305_init(&ctx, nacl_key);
|
||||
poly1305_update(&ctx, nacl_msg + 0, 32);
|
||||
poly1305_update(&ctx, nacl_msg + 32, 64);
|
||||
poly1305_update(&ctx, nacl_msg + 96, 16);
|
||||
poly1305_update(&ctx, nacl_msg + 112, 8);
|
||||
poly1305_update(&ctx, nacl_msg + 120, 4);
|
||||
poly1305_update(&ctx, nacl_msg + 124, 2);
|
||||
poly1305_update(&ctx, nacl_msg + 126, 1);
|
||||
poly1305_update(&ctx, nacl_msg + 127, 1);
|
||||
poly1305_update(&ctx, nacl_msg + 128, 1);
|
||||
poly1305_update(&ctx, nacl_msg + 129, 1);
|
||||
poly1305_update(&ctx, nacl_msg + 130, 1);
|
||||
poly1305_finish(&ctx, mac);
|
||||
result &= poly1305_verify(nacl_mac, mac);
|
||||
|
||||
for(i = 0; i < sizeof(mac); i++) mac[i] = 0;
|
||||
poly1305_auth(mac, wrap_msg, sizeof(wrap_msg), wrap_key);
|
||||
result &= poly1305_verify(wrap_mac, mac);
|
||||
|
||||
poly1305_init(&total_ctx, total_key);
|
||||
for(i = 0; i < 256; i++) {
|
||||
/* set key and message to 'i,i,i..' */
|
||||
for(j = 0; j < sizeof(all_key); j++) all_key[j] = i;
|
||||
for(j = 0; j < i; j++) all_msg[j] = i;
|
||||
poly1305_auth(mac, all_msg, i, all_key);
|
||||
poly1305_update(&total_ctx, mac, 16);
|
||||
}
|
||||
poly1305_finish(&total_ctx, mac);
|
||||
result &= poly1305_verify(total_mac, mac);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef POLY1305_DONNA_H
|
||||
#define POLY1305_DONNA_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct poly1305_context {
|
||||
size_t aligner;
|
||||
unsigned char opaque[136];
|
||||
} poly1305_context;
|
||||
|
||||
void poly1305_init(poly1305_context* ctx, const unsigned char key[32]);
|
||||
void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes);
|
||||
void poly1305_finish(poly1305_context* ctx, unsigned char mac[16]);
|
||||
void poly1305_auth(
|
||||
unsigned char mac[16],
|
||||
const unsigned char* m,
|
||||
size_t bytes,
|
||||
const unsigned char key[32]);
|
||||
|
||||
int poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]);
|
||||
int poly1305_power_on_self_test(void);
|
||||
|
||||
#endif /* POLY1305_DONNA_H */
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define POLY1305_NOINLINE __declspec(noinline)
|
||||
#elif defined(__GNUC__)
|
||||
#define POLY1305_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
#define POLY1305_NOINLINE
|
||||
#endif
|
||||
|
||||
#define poly1305_block_size 16
|
||||
|
||||
/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */
|
||||
typedef struct poly1305_state_internal_t {
|
||||
unsigned long r[5];
|
||||
unsigned long h[5];
|
||||
unsigned long pad[4];
|
||||
size_t leftover;
|
||||
unsigned char buffer[poly1305_block_size];
|
||||
unsigned char final;
|
||||
} poly1305_state_internal_t;
|
||||
|
||||
/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */
|
||||
static unsigned long U8TO32(const unsigned char* p) {
|
||||
return (
|
||||
((unsigned long)(p[0] & 0xff)) | ((unsigned long)(p[1] & 0xff) << 8) |
|
||||
((unsigned long)(p[2] & 0xff) << 16) | ((unsigned long)(p[3] & 0xff) << 24));
|
||||
}
|
||||
|
||||
/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */
|
||||
static void U32TO8(unsigned char* p, unsigned long v) {
|
||||
p[0] = (v)&0xff;
|
||||
p[1] = (v >> 8) & 0xff;
|
||||
p[2] = (v >> 16) & 0xff;
|
||||
p[3] = (v >> 24) & 0xff;
|
||||
}
|
||||
|
||||
void poly1305_init(poly1305_context* ctx, const unsigned char key[32]) {
|
||||
poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
|
||||
|
||||
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
|
||||
st->r[0] = (U8TO32(&key[0])) & 0x3ffffff;
|
||||
st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03;
|
||||
st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff;
|
||||
st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff;
|
||||
st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
|
||||
|
||||
/* h = 0 */
|
||||
st->h[0] = 0;
|
||||
st->h[1] = 0;
|
||||
st->h[2] = 0;
|
||||
st->h[3] = 0;
|
||||
st->h[4] = 0;
|
||||
|
||||
/* save pad for later */
|
||||
st->pad[0] = U8TO32(&key[16]);
|
||||
st->pad[1] = U8TO32(&key[20]);
|
||||
st->pad[2] = U8TO32(&key[24]);
|
||||
st->pad[3] = U8TO32(&key[28]);
|
||||
|
||||
st->leftover = 0;
|
||||
st->final = 0;
|
||||
}
|
||||
|
||||
static void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes) {
|
||||
const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */
|
||||
unsigned long r0, r1, r2, r3, r4;
|
||||
unsigned long s1, s2, s3, s4;
|
||||
unsigned long h0, h1, h2, h3, h4;
|
||||
unsigned long long d0, d1, d2, d3, d4;
|
||||
unsigned long c;
|
||||
|
||||
r0 = st->r[0];
|
||||
r1 = st->r[1];
|
||||
r2 = st->r[2];
|
||||
r3 = st->r[3];
|
||||
r4 = st->r[4];
|
||||
|
||||
s1 = r1 * 5;
|
||||
s2 = r2 * 5;
|
||||
s3 = r3 * 5;
|
||||
s4 = r4 * 5;
|
||||
|
||||
h0 = st->h[0];
|
||||
h1 = st->h[1];
|
||||
h2 = st->h[2];
|
||||
h3 = st->h[3];
|
||||
h4 = st->h[4];
|
||||
|
||||
while(bytes >= poly1305_block_size) {
|
||||
/* h += m[i] */
|
||||
h0 += (U8TO32(m + 0)) & 0x3ffffff;
|
||||
h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff;
|
||||
h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff;
|
||||
h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff;
|
||||
h4 += (U8TO32(m + 12) >> 8) | hibit;
|
||||
|
||||
/* h *= r */
|
||||
d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) +
|
||||
((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) +
|
||||
((unsigned long long)h4 * s1);
|
||||
d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) +
|
||||
((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) +
|
||||
((unsigned long long)h4 * s2);
|
||||
d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) +
|
||||
((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) +
|
||||
((unsigned long long)h4 * s3);
|
||||
d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) +
|
||||
((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) +
|
||||
((unsigned long long)h4 * s4);
|
||||
d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) +
|
||||
((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) +
|
||||
((unsigned long long)h4 * r0);
|
||||
|
||||
/* (partial) h %= p */
|
||||
c = (unsigned long)(d0 >> 26);
|
||||
h0 = (unsigned long)d0 & 0x3ffffff;
|
||||
d1 += c;
|
||||
c = (unsigned long)(d1 >> 26);
|
||||
h1 = (unsigned long)d1 & 0x3ffffff;
|
||||
d2 += c;
|
||||
c = (unsigned long)(d2 >> 26);
|
||||
h2 = (unsigned long)d2 & 0x3ffffff;
|
||||
d3 += c;
|
||||
c = (unsigned long)(d3 >> 26);
|
||||
h3 = (unsigned long)d3 & 0x3ffffff;
|
||||
d4 += c;
|
||||
c = (unsigned long)(d4 >> 26);
|
||||
h4 = (unsigned long)d4 & 0x3ffffff;
|
||||
h0 += c * 5;
|
||||
c = (h0 >> 26);
|
||||
h0 = h0 & 0x3ffffff;
|
||||
h1 += c;
|
||||
|
||||
m += poly1305_block_size;
|
||||
bytes -= poly1305_block_size;
|
||||
}
|
||||
|
||||
st->h[0] = h0;
|
||||
st->h[1] = h1;
|
||||
st->h[2] = h2;
|
||||
st->h[3] = h3;
|
||||
st->h[4] = h4;
|
||||
}
|
||||
|
||||
POLY1305_NOINLINE void poly1305_finish(poly1305_context* ctx, unsigned char mac[16]) {
|
||||
poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
|
||||
unsigned long h0, h1, h2, h3, h4, c;
|
||||
unsigned long g0, g1, g2, g3, g4;
|
||||
unsigned long long f;
|
||||
unsigned long mask;
|
||||
|
||||
/* process the remaining block */
|
||||
if(st->leftover) {
|
||||
size_t i = st->leftover;
|
||||
st->buffer[i++] = 1;
|
||||
for(; i < poly1305_block_size; i++) st->buffer[i] = 0;
|
||||
st->final = 1;
|
||||
poly1305_blocks(st, st->buffer, poly1305_block_size);
|
||||
}
|
||||
|
||||
/* fully carry h */
|
||||
h0 = st->h[0];
|
||||
h1 = st->h[1];
|
||||
h2 = st->h[2];
|
||||
h3 = st->h[3];
|
||||
h4 = st->h[4];
|
||||
|
||||
c = h1 >> 26;
|
||||
h1 = h1 & 0x3ffffff;
|
||||
h2 += c;
|
||||
c = h2 >> 26;
|
||||
h2 = h2 & 0x3ffffff;
|
||||
h3 += c;
|
||||
c = h3 >> 26;
|
||||
h3 = h3 & 0x3ffffff;
|
||||
h4 += c;
|
||||
c = h4 >> 26;
|
||||
h4 = h4 & 0x3ffffff;
|
||||
h0 += c * 5;
|
||||
c = h0 >> 26;
|
||||
h0 = h0 & 0x3ffffff;
|
||||
h1 += c;
|
||||
|
||||
/* compute h + -p */
|
||||
g0 = h0 + 5;
|
||||
c = g0 >> 26;
|
||||
g0 &= 0x3ffffff;
|
||||
g1 = h1 + c;
|
||||
c = g1 >> 26;
|
||||
g1 &= 0x3ffffff;
|
||||
g2 = h2 + c;
|
||||
c = g2 >> 26;
|
||||
g2 &= 0x3ffffff;
|
||||
g3 = h3 + c;
|
||||
c = g3 >> 26;
|
||||
g3 &= 0x3ffffff;
|
||||
g4 = h4 + c - (1UL << 26);
|
||||
|
||||
/* select h if h < p, or h + -p if h >= p */
|
||||
mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1;
|
||||
g0 &= mask;
|
||||
g1 &= mask;
|
||||
g2 &= mask;
|
||||
g3 &= mask;
|
||||
g4 &= mask;
|
||||
mask = ~mask;
|
||||
h0 = (h0 & mask) | g0;
|
||||
h1 = (h1 & mask) | g1;
|
||||
h2 = (h2 & mask) | g2;
|
||||
h3 = (h3 & mask) | g3;
|
||||
h4 = (h4 & mask) | g4;
|
||||
|
||||
/* h = h % (2^128) */
|
||||
h0 = ((h0) | (h1 << 26)) & 0xffffffff;
|
||||
h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
|
||||
h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
|
||||
h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
|
||||
|
||||
/* mac = (h + pad) % (2^128) */
|
||||
f = (unsigned long long)h0 + st->pad[0];
|
||||
h0 = (unsigned long)f;
|
||||
f = (unsigned long long)h1 + st->pad[1] + (f >> 32);
|
||||
h1 = (unsigned long)f;
|
||||
f = (unsigned long long)h2 + st->pad[2] + (f >> 32);
|
||||
h2 = (unsigned long)f;
|
||||
f = (unsigned long long)h3 + st->pad[3] + (f >> 32);
|
||||
h3 = (unsigned long)f;
|
||||
|
||||
U32TO8(mac + 0, h0);
|
||||
U32TO8(mac + 4, h1);
|
||||
U32TO8(mac + 8, h2);
|
||||
U32TO8(mac + 12, h3);
|
||||
|
||||
/* zero out the state */
|
||||
st->h[0] = 0;
|
||||
st->h[1] = 0;
|
||||
st->h[2] = 0;
|
||||
st->h[3] = 0;
|
||||
st->h[4] = 0;
|
||||
st->r[0] = 0;
|
||||
st->r[1] = 0;
|
||||
st->r[2] = 0;
|
||||
st->r[3] = 0;
|
||||
st->r[4] = 0;
|
||||
st->pad[0] = 0;
|
||||
st->pad[1] = 0;
|
||||
st->pad[2] = 0;
|
||||
st->pad[3] = 0;
|
||||
}
|
||||