3.3.7
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
# SignedOTA - Secure OTA Updates with Signature Verification
|
||||
|
||||
This example demonstrates how to perform secure OTA updates with cryptographic signature verification using the ArduinoOTA library.
|
||||
|
||||
## Overview
|
||||
|
||||
**SignedOTA** adds an extra layer of security to Arduino OTA updates by requiring all firmware to be cryptographically signed with your private key. This protects against:
|
||||
|
||||
- ✅ Unauthorized firmware updates
|
||||
- ✅ Man-in-the-middle attacks
|
||||
- ✅ Compromised networks
|
||||
- ✅ Firmware tampering
|
||||
- ✅ Supply chain attacks
|
||||
|
||||
Even if an attacker gains access to your network, they **cannot** install unsigned firmware on your devices.
|
||||
|
||||
## Features
|
||||
|
||||
- **RSA & ECDSA Support**: RSA-2048/3072/4096 and ECDSA-P256/P384
|
||||
- **Multiple Hash Algorithms**: SHA-256, SHA-384, SHA-512
|
||||
- **Arduino IDE Compatible**: Works with standard Arduino OTA workflow
|
||||
- **Optional Password Protection**: Add password authentication in addition to signature verification
|
||||
- **Easy Integration**: Just a few lines of code
|
||||
|
||||
## Requirements
|
||||
|
||||
- **ESP32 Arduino Core 3.3.0+**
|
||||
- **Python 3.6+** with `cryptography` library
|
||||
<!-- vale Espressif-latest.Units = NO -->
|
||||
- **OTA-capable partition scheme** (e.g., "Minimal SPIFFS (1.9MB APP with OTA)")
|
||||
<!-- vale Espressif-latest.Units = YES -->
|
||||
|
||||
## Quick Start Guide
|
||||
|
||||
### 1. Generate Cryptographic Keys
|
||||
|
||||
```bash
|
||||
# Navigate to Arduino ESP32 tools directory
|
||||
cd <ARDUINO_ROOT>/tools
|
||||
|
||||
# Install Python dependencies
|
||||
pip install cryptography
|
||||
|
||||
# Generate RSA-2048 key pair (recommended)
|
||||
python bin_signing.py --generate-key rsa-2048 --out private_key.pem
|
||||
|
||||
# Extract public key
|
||||
python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem
|
||||
```
|
||||
|
||||
**⚠️ IMPORTANT: Keep `private_key.pem` secure! Anyone with this key can sign firmware for your devices.**
|
||||
|
||||
### 2. Setup the Example
|
||||
|
||||
1. Copy `public_key.h` (generated in step 1) to this sketch directory
|
||||
2. Open `SignedOTA.ino` in Arduino IDE
|
||||
<!-- vale Espressif-latest.TermsSingleCorrectSpelling = NO -->
|
||||
3. Configure WiFi credentials:
|
||||
```cpp
|
||||
const char *ssid = "YourWiFiSSID";
|
||||
const char *password = "YourWiFiPassword";
|
||||
```
|
||||
<!-- vale Espressif-latest.TermsSingleCorrectSpelling = YES -->
|
||||
<!-- vale Espressif-latest.Units = NO -->
|
||||
4. Select appropriate partition scheme:
|
||||
- **Tools → Partition Scheme → "Minimal SPIFFS (1.9MB APP with OTA)"**
|
||||
<!-- vale Espressif-latest.Units = YES -->
|
||||
|
||||
### 3. Upload Initial Firmware
|
||||
|
||||
1. Connect your ESP32 via USB
|
||||
2. Upload the sketch normally
|
||||
3. Open Serial Monitor (115200 baud)
|
||||
4. Note the device IP address
|
||||
|
||||
### 4. Build & Sign Firmware for OTA Update Example
|
||||
|
||||
**Option A: Using Arduino IDE**
|
||||
|
||||
```bash
|
||||
# Export compiled binary
|
||||
# In Arduino IDE: Sketch → Export Compiled Binary
|
||||
|
||||
# Sign the firmware
|
||||
cd <ARDUINO_ROOT>/tools
|
||||
python bin_signing.py \
|
||||
--bin /path/to/SignedOTA.ino.bin \
|
||||
--key private_key.pem \
|
||||
--out firmware_signed.bin
|
||||
```
|
||||
|
||||
**Option B: Using arduino-cli**
|
||||
|
||||
```bash
|
||||
# Compile and export
|
||||
arduino-cli compile --fqbn esp32:esp32:esp32 --export-binaries SignedOTA
|
||||
|
||||
# Sign the firmware
|
||||
cd <ARDUINO_ROOT>/tools
|
||||
python bin_signing.py \
|
||||
--bin build/esp32.esp32.esp32/SignedOTA.ino.bin \
|
||||
--key private_key.pem \
|
||||
--out firmware_signed.bin
|
||||
```
|
||||
|
||||
### 5. Upload Signed Firmware via OTA
|
||||
|
||||
Upload the signed firmware using `espota.py`:
|
||||
|
||||
```bash
|
||||
python <ARDUINO_ROOT>/tools/espota.py -i <device-ip> -f firmware_signed.bin
|
||||
```
|
||||
|
||||
The device will automatically:
|
||||
1. Receive the signed firmware (firmware + signature)
|
||||
2. Hash only the firmware portion
|
||||
3. Verify the signature
|
||||
4. Install if valid, reject if invalid
|
||||
|
||||
**Note**: You can also use the Update library's `Signed_OTA_Update` example for HTTP-based OTA updates.
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Hash Algorithms
|
||||
|
||||
Choose one in `SignedOTA.ino`:
|
||||
|
||||
```cpp
|
||||
#define USE_SHA256 // Default, fastest
|
||||
// #define USE_SHA384
|
||||
// #define USE_SHA512
|
||||
```
|
||||
|
||||
**Must match** the `--hash` parameter when signing:
|
||||
|
||||
```bash
|
||||
python bin_signing.py --bin firmware.bin --key private.pem --out signed.bin --hash sha256
|
||||
```
|
||||
|
||||
### Signature Algorithms
|
||||
|
||||
Choose one in `SignedOTA.ino`:
|
||||
|
||||
```cpp
|
||||
#define USE_RSA // For RSA keys
|
||||
// #define USE_ECDSA // For ECDSA keys
|
||||
```
|
||||
|
||||
### Optional Password Protection
|
||||
|
||||
Add password authentication **in addition to** signature verification:
|
||||
|
||||
```cpp
|
||||
const char *ota_password = "yourpassword"; // Set password
|
||||
// const char *ota_password = nullptr; // Disable password
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Build Firmware │
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Sign Firmware │ ← Uses your private key
|
||||
│ (bin_signing) │
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────┐
|
||||
│ firmware_signed.bin │
|
||||
│ [firmware][signature] │
|
||||
└────────┬────────────────┘
|
||||
│
|
||||
▼ OTA Upload
|
||||
┌─────────────────────────┐
|
||||
│ ESP32 Device │
|
||||
│ ┌──────────────────┐ │
|
||||
│ │ Verify Signature │ │ ← Uses your public key
|
||||
│ │ ✓ or ✗ │ │
|
||||
│ └──────────────────┘ │
|
||||
│ │ │
|
||||
│ ✓ Valid? │
|
||||
│ ├─ Yes: Install │
|
||||
│ └─ No: Reject │
|
||||
└─────────────────────────┘
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Begin Failed" Error
|
||||
|
||||
**Cause**: Signature verification setup failed, or partition scheme issue
|
||||
|
||||
**Solutions**:
|
||||
<!-- vale Espressif-latest.Units = NO -->
|
||||
1. Check partition scheme (use "Minimal SPIFFS (1.9MB APP with OTA)")
|
||||
2. Verify `public_key.h` is in the sketch directory
|
||||
3. Check hash and signature algorithm match your key type
|
||||
<!-- vale Espressif-latest.Units = YES -->
|
||||
|
||||
### "End Failed" Error
|
||||
|
||||
**Cause**: Signature verification failed
|
||||
|
||||
**Solutions**:
|
||||
1. Ensure firmware was signed with the **correct private key**
|
||||
2. Verify hash algorithm matches (SHA-256, SHA-384, SHA-512)
|
||||
3. Check firmware wasn't corrupted during signing/transfer
|
||||
4. Confirm you signed the **correct** `.bin` file
|
||||
|
||||
### "Receive Failed" Error
|
||||
|
||||
**Cause**: Network timeout or connection issue
|
||||
|
||||
**Solutions**:
|
||||
1. Check Wi-Fi signal strength
|
||||
2. Ensure device is reachable on the network
|
||||
3. Try increasing timeout: `ArduinoOTA.setTimeout(5000)`
|
||||
|
||||
### Upload Fails
|
||||
|
||||
**Issue**: OTA upload fails or times out
|
||||
|
||||
**Solutions**:
|
||||
1. Verify device is on the same network
|
||||
2. Check firewall settings aren't blocking port 3232
|
||||
3. Ensure Wi-Fi signal strength is adequate
|
||||
4. If using password protection, ensure the password is correct
|
||||
5. Try: `python <ARDUINO_ROOT>/tools/espota.py -i <device-ip> -f firmware_signed.bin -d`
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Best Practices
|
||||
|
||||
✅ **Keep private key secure**: Never commit to git, store encrypted
|
||||
✅ **Use strong keys**: RSA-2048+ or ECDSA-P256+
|
||||
✅ **Use HTTPS when possible**: For additional transport security
|
||||
✅ **Add password authentication**: Extra layer of protection
|
||||
✅ **Rotate keys periodically**: Generate new keys every 1-2 years
|
||||
|
||||
### What This Protects Against
|
||||
|
||||
- ✅ Unsigned firmware installation
|
||||
- ✅ Firmware signed with wrong key
|
||||
- ✅ Tampered/corrupted firmware
|
||||
- ✅ Network-based attacks (when combined with password)
|
||||
|
||||
### What This Does NOT Protect Against
|
||||
|
||||
<!-- vale Espressif-latest.Cursing = NO -->
|
||||
- ❌ Physical access (USB flashing still works)
|
||||
- ❌ Downgrade attacks (no version checking by default)
|
||||
- ❌ Replay attacks (no timestamp/nonce by default)
|
||||
- ❌ Key compromise (if private key is stolen)
|
||||
<!-- vale Espressif-latest.Cursing = YES -->
|
||||
|
||||
### Additional Security
|
||||
|
||||
For production deployments, consider:
|
||||
|
||||
1. **Add version checking** to prevent downgrades
|
||||
2. **Add timestamp validation** to prevent replay attacks
|
||||
3. **Use secure boot** for additional protection
|
||||
4. **Store keys in HSM** or secure key management system
|
||||
5. **Implement key rotation** mechanism
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Using ECDSA Instead of RSA
|
||||
|
||||
ECDSA keys are smaller and faster:
|
||||
|
||||
```bash
|
||||
# Generate ECDSA-P256 key
|
||||
python bin_signing.py --generate-key ecdsa-p256 --out private_key.pem
|
||||
python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem
|
||||
```
|
||||
|
||||
In `SignedOTA.ino`:
|
||||
|
||||
```cpp
|
||||
#define USE_SHA256
|
||||
#define USE_ECDSA // Instead of USE_RSA
|
||||
```
|
||||
|
||||
### Using SHA-384 or SHA-512
|
||||
|
||||
For higher security:
|
||||
|
||||
```bash
|
||||
# Sign with SHA-384
|
||||
python bin_signing.py --bin firmware.bin --key private.pem --out signed.bin --hash sha384
|
||||
```
|
||||
|
||||
In `SignedOTA.ino`:
|
||||
|
||||
```cpp
|
||||
#define USE_SHA384 // Instead of USE_SHA256
|
||||
#define USE_RSA
|
||||
```
|
||||
|
||||
### Custom Partition Label
|
||||
|
||||
To update a specific partition:
|
||||
|
||||
```cpp
|
||||
ArduinoOTA.setPartitionLabel("my_partition");
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For issues and questions:
|
||||
|
||||
- Update Library README: `libraries/Update/README.md`
|
||||
- ESP32 Arduino Core: https://github.com/espressif/arduino-esp32
|
||||
- Forum: https://github.com/espressif/arduino-esp32/discussions
|
||||
|
||||
## License
|
||||
|
||||
This library is part of the Arduino-ESP32 project and is licensed under the Apache License 2.0.
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* SignedOTA Example - Secure OTA Updates with Signature Verification
|
||||
*
|
||||
* This example demonstrates how to perform OTA updates with cryptographic
|
||||
* signature verification using ArduinoOTA library.
|
||||
*
|
||||
* IMPORTANT: This example requires firmware to be signed with bin_signing.py
|
||||
*
|
||||
* NOTE: Signature verification support is enabled via the build_opt.h file
|
||||
* in this directory.
|
||||
*
|
||||
* Setup:
|
||||
* 1. Generate keys:
|
||||
* python <ARDUINO_ROOT>/tools/bin_signing.py --generate-key rsa-2048 --out private_key.pem
|
||||
* python <ARDUINO_ROOT>/tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem
|
||||
*
|
||||
* 2. Copy public_key.h to this sketch directory
|
||||
*
|
||||
* 3. Configure WiFi credentials below
|
||||
*
|
||||
* 4. Upload this sketch to your device
|
||||
*
|
||||
* 5. Build your firmware and sign it:
|
||||
* arduino-cli compile --fqbn esp32:esp32:esp32 --export-binaries SignedOTA
|
||||
* python <ARDUINO_ROOT>/tools/bin_signing.py --bin build/<file>.bin --key private_key.pem --out firmware_signed.bin
|
||||
*
|
||||
* 6. Upload signed firmware using espota.py or Arduino IDE (after modifying espota.py to handle signed binaries)
|
||||
* python <ARDUINO_ROOT>/tools/espota.py -i <device-ip> -f firmware_signed.bin
|
||||
*
|
||||
* For more information, see the Update library's Signed_OTA_Update example
|
||||
* and README.md in the Update library folder.
|
||||
*
|
||||
* Created by lucasssvaz
|
||||
*/
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <NetworkUdp.h>
|
||||
#include <ArduinoOTA.h>
|
||||
|
||||
// Include your public key (generated with bin_signing.py)
|
||||
#include "public_key.h"
|
||||
|
||||
// ==================== CONFIGURATION ====================
|
||||
|
||||
// WiFi credentials
|
||||
const char *ssid = "..........";
|
||||
const char *password = "..........";
|
||||
|
||||
// Optional: Set a password for OTA authentication
|
||||
// This is in ADDITION to signature verification
|
||||
// ArduinoOTA password protects the OTA connection
|
||||
// Signature verification ensures firmware authenticity
|
||||
const char *ota_password = nullptr; // Set to nullptr to disable, or "yourpassword" to enable
|
||||
|
||||
// Choose hash algorithm (must match what you use with bin_signing.py --hash)
|
||||
// Uncomment ONE of these:
|
||||
#define USE_SHA256 // Default, recommended
|
||||
// #define USE_SHA384
|
||||
// #define USE_SHA512
|
||||
|
||||
// Choose signature algorithm (must match your key type)
|
||||
// Uncomment ONE of these:
|
||||
#define USE_RSA // Recommended (works with rsa-2048, rsa-3072, rsa-4096)
|
||||
// #define USE_ECDSA // Works with ecdsa-p256, ecdsa-p384
|
||||
|
||||
// =======================================================
|
||||
|
||||
uint32_t last_ota_time = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("\n\n=================================");
|
||||
Serial.println("SignedOTA - Secure OTA Updates");
|
||||
Serial.println("=================================\n");
|
||||
Serial.println("Booting...");
|
||||
|
||||
// Connect to WiFi
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||
Serial.println("Connection Failed! Rebooting...");
|
||||
delay(5000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
Serial.println("WiFi Connected!");
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
// ==================== SIGNATURE VERIFICATION SETUP ====================
|
||||
|
||||
// Select hash algorithm
|
||||
#ifdef USE_SHA256
|
||||
int hashType = HASH_SHA256;
|
||||
Serial.println("Using SHA-256 hash");
|
||||
#elif defined(USE_SHA384)
|
||||
int hashType = HASH_SHA384;
|
||||
Serial.println("Using SHA-384 hash");
|
||||
#elif defined(USE_SHA512)
|
||||
int hashType = HASH_SHA512;
|
||||
Serial.println("Using SHA-512 hash");
|
||||
#else
|
||||
#error "Please define a hash algorithm (USE_SHA256, USE_SHA384, or USE_SHA512)"
|
||||
#endif
|
||||
|
||||
// Create verifier object
|
||||
#ifdef USE_RSA
|
||||
static UpdaterRSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, hashType);
|
||||
Serial.println("Using RSA signature verification");
|
||||
#elif defined(USE_ECDSA)
|
||||
static UpdaterECDSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, hashType);
|
||||
Serial.println("Using ECDSA signature verification");
|
||||
#else
|
||||
#error "Please define a signature type (USE_RSA or USE_ECDSA)"
|
||||
#endif
|
||||
|
||||
// Install signature verification BEFORE ArduinoOTA.begin()
|
||||
ArduinoOTA.setSignature(&sign);
|
||||
Serial.println("✓ Signature verification enabled");
|
||||
|
||||
// =======================================================================
|
||||
|
||||
// Optional: Set hostname
|
||||
// ArduinoOTA.setHostname("myesp32");
|
||||
|
||||
// Optional: Set OTA password (in addition to signature verification)
|
||||
if (ota_password != nullptr) {
|
||||
ArduinoOTA.setPassword(ota_password);
|
||||
Serial.println("✓ OTA password protection enabled");
|
||||
}
|
||||
|
||||
// Configure OTA callbacks
|
||||
ArduinoOTA
|
||||
.onStart([]() {
|
||||
String type;
|
||||
if (ArduinoOTA.getCommand() == U_FLASH) {
|
||||
type = "sketch";
|
||||
} else { // U_SPIFFS
|
||||
type = "filesystem";
|
||||
}
|
||||
Serial.println("\n=================================");
|
||||
Serial.println("OTA Update Starting: " + type);
|
||||
Serial.println("=================================");
|
||||
Serial.println("⚠️ Signature will be verified!");
|
||||
})
|
||||
.onEnd([]() {
|
||||
Serial.println("\n=================================");
|
||||
Serial.println("✅ OTA Update Complete!");
|
||||
Serial.println("✅ Signature Verified!");
|
||||
Serial.println("=================================");
|
||||
Serial.println("Rebooting...");
|
||||
})
|
||||
.onProgress([](unsigned int progress, unsigned int total) {
|
||||
if (millis() - last_ota_time > 500) {
|
||||
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||
last_ota_time = millis();
|
||||
}
|
||||
})
|
||||
.onError([](ota_error_t error) {
|
||||
Serial.println("\n=================================");
|
||||
Serial.println("❌ OTA Update Failed!");
|
||||
Serial.println("=================================");
|
||||
Serial.printf("Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) {
|
||||
Serial.println("Authentication Failed");
|
||||
Serial.println("Check your OTA password");
|
||||
} else if (error == OTA_BEGIN_ERROR) {
|
||||
Serial.println("Begin Failed");
|
||||
Serial.println("This could be:");
|
||||
Serial.println("- Signature verification setup failed");
|
||||
Serial.println("- Not enough space for update");
|
||||
Serial.println("- Invalid partition");
|
||||
} else if (error == OTA_CONNECT_ERROR) {
|
||||
Serial.println("Connect Failed");
|
||||
} else if (error == OTA_RECEIVE_ERROR) {
|
||||
Serial.println("Receive Failed");
|
||||
} else if (error == OTA_END_ERROR) {
|
||||
Serial.println("End Failed");
|
||||
Serial.println("This could be:");
|
||||
Serial.println("- ❌ SIGNATURE VERIFICATION FAILED!");
|
||||
Serial.println("- Firmware not signed with correct key");
|
||||
Serial.println("- Firmware corrupted during transfer");
|
||||
Serial.println("- MD5 checksum mismatch");
|
||||
}
|
||||
Serial.println("=================================");
|
||||
});
|
||||
|
||||
// Start ArduinoOTA service
|
||||
ArduinoOTA.begin();
|
||||
|
||||
Serial.println("\n=================================");
|
||||
Serial.println("✓ OTA Server Ready");
|
||||
Serial.println("=================================");
|
||||
Serial.printf("Hostname: %s.local\n", ArduinoOTA.getHostname().c_str());
|
||||
Serial.printf("IP: %s\n", WiFi.localIP().toString().c_str());
|
||||
Serial.println("Port: 3232");
|
||||
Serial.println("\n⚠️ Only signed firmware will be accepted!");
|
||||
Serial.println("=================================\n");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
ArduinoOTA.handle();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
-DUPDATE_SIGN
|
||||
@@ -0,0 +1,3 @@
|
||||
requires_any:
|
||||
- CONFIG_SOC_WIFI_SUPPORTED=y
|
||||
- CONFIG_ESP_WIFI_REMOTE_ENABLED=y
|
||||
@@ -0,0 +1,30 @@
|
||||
// Public key for OTA signature verification
|
||||
// Include this in your Arduino sketch
|
||||
|
||||
// ⚠️ THIS IS A TEST KEY - DO NOT USE IN PRODUCTION!
|
||||
// Generate your own keys using:
|
||||
// python <ARDUINO_ROOT>/tools/bin_signing.py --generate-key rsa-2048 --out private_key.pem
|
||||
// python <ARDUINO_ROOT>/tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem
|
||||
//
|
||||
// Then replace this file with the generated public_key.h
|
||||
|
||||
// Test RSA-2048 Public Key (PEM format)
|
||||
const uint8_t PUBLIC_KEY[] PROGMEM = {
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x0a, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41,
|
||||
0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x73, 0x35, 0x35, 0x66, 0x4f, 0x74, 0x51,
|
||||
0x64, 0x69, 0x70, 0x39, 0x58, 0x6f, 0x49, 0x61, 0x6c, 0x52, 0x5a, 0x4b, 0x6c, 0x4a, 0x0a, 0x52, 0x62, 0x55, 0x73, 0x49, 0x30, 0x4c, 0x48, 0x5a, 0x74, 0x2b,
|
||||
0x50, 0x58, 0x35, 0x4b, 0x58, 0x43, 0x79, 0x54, 0x64, 0x63, 0x78, 0x71, 0x6c, 0x6f, 0x44, 0x45, 0x2b, 0x63, 0x38, 0x43, 0x6f, 0x32, 0x50, 0x77, 0x37, 0x6f,
|
||||
0x66, 0x63, 0x66, 0x30, 0x47, 0x41, 0x38, 0x4a, 0x55, 0x65, 0x6e, 0x6d, 0x45, 0x46, 0x6b, 0x57, 0x6a, 0x50, 0x53, 0x48, 0x4c, 0x55, 0x55, 0x79, 0x44, 0x0a,
|
||||
0x63, 0x65, 0x4b, 0x63, 0x2b, 0x71, 0x45, 0x47, 0x54, 0x58, 0x72, 0x59, 0x39, 0x56, 0x6f, 0x4d, 0x38, 0x6f, 0x42, 0x58, 0x39, 0x67, 0x48, 0x41, 0x64, 0x4b,
|
||||
0x4f, 0x51, 0x48, 0x33, 0x50, 0x4d, 0x70, 0x4a, 0x69, 0x56, 0x51, 0x71, 0x4e, 0x43, 0x36, 0x37, 0x31, 0x44, 0x37, 0x54, 0x45, 0x76, 0x4e, 0x52, 0x43, 0x67,
|
||||
0x6e, 0x4f, 0x41, 0x37, 0x77, 0x62, 0x77, 0x6f, 0x78, 0x4e, 0x0a, 0x63, 0x75, 0x59, 0x30, 0x49, 0x6e, 0x51, 0x4e, 0x30, 0x64, 0x6b, 0x42, 0x43, 0x4f, 0x63,
|
||||
0x34, 0x4e, 0x66, 0x31, 0x56, 0x42, 0x76, 0x35, 0x64, 0x71, 0x55, 0x57, 0x41, 0x62, 0x66, 0x43, 0x57, 0x68, 0x5a, 0x37, 0x31, 0x72, 0x4a, 0x56, 0x32, 0x53,
|
||||
0x68, 0x79, 0x35, 0x48, 0x42, 0x48, 0x48, 0x52, 0x4e, 0x43, 0x78, 0x4f, 0x67, 0x58, 0x68, 0x4f, 0x6c, 0x66, 0x6c, 0x66, 0x0a, 0x72, 0x49, 0x57, 0x56, 0x71,
|
||||
0x66, 0x51, 0x4b, 0x2b, 0x75, 0x54, 0x4d, 0x62, 0x39, 0x4a, 0x4c, 0x51, 0x67, 0x76, 0x4a, 0x66, 0x70, 0x4c, 0x61, 0x65, 0x35, 0x35, 0x61, 0x61, 0x4e, 0x77,
|
||||
0x63, 0x72, 0x62, 0x59, 0x38, 0x58, 0x67, 0x53, 0x79, 0x31, 0x64, 0x6c, 0x58, 0x76, 0x4e, 0x37, 0x4d, 0x33, 0x75, 0x4c, 0x52, 0x72, 0x4b, 0x79, 0x61, 0x75,
|
||||
0x34, 0x59, 0x0a, 0x39, 0x51, 0x53, 0x71, 0x76, 0x4a, 0x71, 0x67, 0x52, 0x61, 0x36, 0x66, 0x47, 0x51, 0x2f, 0x4d, 0x41, 0x63, 0x6c, 0x48, 0x59, 0x33, 0x6d,
|
||||
0x4b, 0x64, 0x6e, 0x64, 0x68, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4c,
|
||||
0x49, 0x43, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00,
|
||||
};
|
||||
const size_t PUBLIC_KEY_LEN = 451;
|
||||
Reference in New Issue
Block a user