mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 14:01:06 +00:00
[offchain] Support for sign & verify for crypto keys (#3023)
* Implement sign & verify. * Use phrases and password. * Sign & verify with authority keys. * Fix tests. * WiP * WiP * Allow the caller to decide on 'CryptoKind'. * Remove TODO. * Make seed private back. * Fix non-std build and bump version. * Use Into<u32> instead of asses. * Add missing typedef.
This commit is contained in:
committed by
Gavin Wood
parent
ed630e5eda
commit
e729dbabbe
@@ -28,6 +28,7 @@ use regex::Regex;
|
||||
use base58::{FromBase58, ToBase58};
|
||||
#[cfg(feature = "std")]
|
||||
use std::hash::Hash;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
/// The root phrase for our publicly known keys.
|
||||
pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
|
||||
@@ -66,6 +67,43 @@ impl<S, T: UncheckedFrom<S>> UncheckedInto<T> for S {
|
||||
}
|
||||
}
|
||||
|
||||
/// A store for sensitive data.
|
||||
///
|
||||
/// Calls `Zeroize::zeroize` upon `Drop`.
|
||||
#[derive(Clone)]
|
||||
pub struct Protected<T: Zeroize>(T);
|
||||
|
||||
impl<T: Zeroize> AsRef<T> for Protected<T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Zeroize> std::fmt::Debug for Protected<T> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(fmt, "<protected>")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zeroize> From<T> for Protected<T> {
|
||||
fn from(t: T) -> Self {
|
||||
Protected(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zeroize> Zeroize for Protected<T> {
|
||||
fn zeroize(&mut self) {
|
||||
self.0.zeroize()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zeroize> Drop for Protected<T> {
|
||||
fn drop(&mut self) {
|
||||
self.zeroize()
|
||||
}
|
||||
}
|
||||
|
||||
/// An error with the interpretation of a secret.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg(feature = "std")]
|
||||
@@ -289,7 +327,7 @@ impl<T: AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
|
||||
}
|
||||
|
||||
/// Trait suitable for typical cryptographic PKI key public type.
|
||||
pub trait Public: PartialEq + Eq {
|
||||
pub trait Public: TypedKey + PartialEq + Eq {
|
||||
/// A new instance from the given slice that should be 32 bytes long.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
@@ -308,9 +346,8 @@ pub trait Public: PartialEq + Eq {
|
||||
///
|
||||
/// For now it just specifies how to create a key from a phrase and derivation path.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait Pair: Sized + 'static
|
||||
{
|
||||
/// TThe type which is used to encode a public key.
|
||||
pub trait Pair: TypedKey + Sized + 'static {
|
||||
/// The type which is used to encode a public key.
|
||||
type Public: Public + Hash;
|
||||
|
||||
/// The type used to (minimally) encode the data required to securely create
|
||||
@@ -319,7 +356,7 @@ pub trait Pair: Sized + 'static
|
||||
|
||||
/// The type used to represent a signature. Can be created from a key pair and a message
|
||||
/// and verified with the message and a public key.
|
||||
type Signature;
|
||||
type Signature: AsRef<[u8]>;
|
||||
|
||||
/// Error returned from the `derive` function.
|
||||
type DeriveError;
|
||||
@@ -476,7 +513,7 @@ mod tests {
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
struct TestPublic;
|
||||
impl Public for TestPublic {
|
||||
fn from_slice(bytes: &[u8]) -> Self {
|
||||
fn from_slice(_bytes: &[u8]) -> Self {
|
||||
Self
|
||||
}
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
@@ -486,10 +523,13 @@ mod tests {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
impl TypedKey for TestPublic {
|
||||
const KEY_TYPE: u32 = 4242;
|
||||
}
|
||||
impl Pair for TestPair {
|
||||
type Public = TestPublic;
|
||||
type Seed = [u8; 0];
|
||||
type Signature = ();
|
||||
type Signature = [u8; 0];
|
||||
type DeriveError = ();
|
||||
|
||||
fn generate() -> (Self, <Self as Pair>::Seed) { (TestPair::Generated, []) }
|
||||
@@ -510,7 +550,7 @@ mod tests {
|
||||
Err(())
|
||||
}
|
||||
fn from_seed(_seed: &<TestPair as Pair>::Seed) -> Self { TestPair::Seed(vec![]) }
|
||||
fn sign(&self, _message: &[u8]) -> Self::Signature { () }
|
||||
fn sign(&self, _message: &[u8]) -> Self::Signature { [] }
|
||||
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(
|
||||
_sig: &Self::Signature,
|
||||
_message: M,
|
||||
@@ -542,6 +582,9 @@ mod tests {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
impl TypedKey for TestPair {
|
||||
const KEY_TYPE: u32 = 4242;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interpret_std_seed_should_work() {
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
//! Offchain workers types
|
||||
|
||||
use crate::crypto;
|
||||
use parity_codec::{Encode, Decode};
|
||||
use rstd::prelude::{Vec, Box};
|
||||
use rstd::convert::TryFrom;
|
||||
|
||||
/// A type of supported crypto.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
#[repr(C)]
|
||||
pub enum StorageKind {
|
||||
@@ -50,15 +52,21 @@ impl TryFrom<u32> for StorageKind {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StorageKind> for u32 {
|
||||
fn from(c: StorageKind) -> Self {
|
||||
c as u8 as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// A type of supported crypto.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
#[repr(C)]
|
||||
pub enum CryptoKind {
|
||||
/// SR25519 crypto (Schnorrkel)
|
||||
Sr25519 = 1,
|
||||
Sr25519 = crypto::key_types::SR25519 as isize,
|
||||
/// ED25519 crypto (Edwards)
|
||||
Ed25519 = 2,
|
||||
Ed25519 = crypto::key_types::ED25519 as isize,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for CryptoKind {
|
||||
@@ -66,23 +74,41 @@ impl TryFrom<u32> for CryptoKind {
|
||||
|
||||
fn try_from(kind: u32) -> Result<Self, Self::Error> {
|
||||
match kind {
|
||||
e if e == u32::from(CryptoKind::Sr25519 as u8) => Ok(CryptoKind::Sr25519),
|
||||
e if e == u32::from(CryptoKind::Ed25519 as u8) => Ok(CryptoKind::Ed25519),
|
||||
e if e == CryptoKind::Sr25519 as isize as u32 => Ok(CryptoKind::Sr25519),
|
||||
e if e == CryptoKind::Ed25519 as isize as u32 => Ok(CryptoKind::Ed25519),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CryptoKind> for u32 {
|
||||
fn from(c: CryptoKind) -> Self {
|
||||
c as isize as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Opaque type for created crypto keys.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub struct CryptoKeyId(pub u16);
|
||||
|
||||
impl From<CryptoKeyId> for u32 {
|
||||
fn from(c: CryptoKeyId) -> Self {
|
||||
c.0 as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Opaque type for offchain http requests.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub struct HttpRequestId(pub u16);
|
||||
|
||||
impl From<HttpRequestId> for u32 {
|
||||
fn from(c: HttpRequestId) -> Self {
|
||||
c.0 as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// An error enum returned by some http methods.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
@@ -106,6 +132,12 @@ impl TryFrom<u32> for HttpError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HttpError> for u32 {
|
||||
fn from(c: HttpError) -> Self {
|
||||
c as u8 as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Status of the HTTP request
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
@@ -216,31 +248,34 @@ pub trait Externalities {
|
||||
|
||||
/// Encrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key.
|
||||
/// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist.
|
||||
fn encrypt(&mut self, key: Option<CryptoKeyId>, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
/// Returns an error if `key` is not available or does not exist,
|
||||
/// or the expected `CryptoKind` does not match.
|
||||
fn encrypt(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Decrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key.
|
||||
/// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`.
|
||||
///
|
||||
/// Returns an error if data cannot be decrypted or the `key` is not available or does not exist.
|
||||
fn decrypt(&mut self, key: Option<CryptoKeyId>, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
/// Returns an error if data cannot be decrypted or the `key` is not available or does not exist,
|
||||
/// or the expected `CryptoKind` does not match.
|
||||
fn decrypt(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Sign a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key.
|
||||
/// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist.
|
||||
fn sign(&mut self, key: Option<CryptoKeyId>, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
/// Returns an error if `key` is not available or does not exist,
|
||||
/// or the expected `CryptoKind` does not match.
|
||||
fn sign(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Verifies that `signature` for `msg` matches given `key`.
|
||||
///
|
||||
/// Returns an `Ok` with `true` in case it does, `false` in case it doesn't.
|
||||
/// Returns an error in case the key is not available or does not exist or the parameters
|
||||
/// lengths are incorrect.
|
||||
fn verify(&mut self, key: Option<CryptoKeyId>, msg: &[u8], signature: &[u8]) -> Result<bool, ()>;
|
||||
/// lengths are incorrect or `CryptoKind` does not match.
|
||||
fn verify(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result<bool, ()>;
|
||||
|
||||
/// Returns current UNIX timestamp (in millis)
|
||||
fn timestamp(&mut self) -> Timestamp;
|
||||
@@ -359,20 +394,20 @@ impl<T: Externalities + ?Sized> Externalities for Box<T> {
|
||||
(&mut **self).new_crypto_key(crypto)
|
||||
}
|
||||
|
||||
fn encrypt(&mut self, key: Option<CryptoKeyId>, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).encrypt(key, data)
|
||||
fn encrypt(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).encrypt(key, kind, data)
|
||||
}
|
||||
|
||||
fn decrypt(&mut self, key: Option<CryptoKeyId>, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).decrypt(key, data)
|
||||
fn decrypt(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).decrypt(key, kind, data)
|
||||
}
|
||||
|
||||
fn sign(&mut self, key: Option<CryptoKeyId>, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).sign(key, data)
|
||||
fn sign(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).sign(key, kind, data)
|
||||
}
|
||||
|
||||
fn verify(&mut self, key: Option<CryptoKeyId>, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
(&mut **self).verify(key, msg, signature)
|
||||
fn verify(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
(&mut **self).verify(key, kind, msg, signature)
|
||||
}
|
||||
|
||||
fn timestamp(&mut self) -> Timestamp {
|
||||
|
||||
@@ -379,6 +379,7 @@ fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> Sec
|
||||
secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0.expand()
|
||||
}
|
||||
|
||||
/// The raw secret seed, which can be used to recreate the `Pair`.
|
||||
#[cfg(feature = "std")]
|
||||
type Seed = [u8; MINI_SECRET_KEY_LENGTH];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user