#![deny(broken_intra_doc_links)]
use generic_array::typenum::Unsigned;
use p256::elliptic_curve;
use std::convert::TryInto;
use tink_core::{subtle::random::get_random_bytes, TinkError};
use tink_proto::{EcdsaSignatureEncoding, EllipticCurveType, HashType, KeyData, Keyset};
mod constant;
pub use constant::*;
mod sharedbuf;
pub use sharedbuf::*;
mod wycheproofutil;
pub use wycheproofutil::*;
pub const UPSTREAM_VERSION: &str = "1.5.0";
#[derive(Debug)]
pub struct DummyAeadKeyManager {
pub type_url: &'static str,
}
impl Default for DummyAeadKeyManager {
fn default() -> Self {
Self {
type_url: AES_GCM_TYPE_URL,
}
}
}
impl tink_core::registry::KeyManager for DummyAeadKeyManager {
fn primitive(&self, _serialized_key: &[u8]) -> Result<tink_core::Primitive, TinkError> {
Ok(tink_core::Primitive::Aead(Box::new(DummyAead)))
}
fn new_key(&self, _serialized_key_format: &[u8]) -> Result<Vec<u8>, TinkError> {
Err("not implemented".into())
}
fn type_url(&self) -> &'static str {
self.type_url
}
fn key_material_type(&self) -> tink_proto::key_data::KeyMaterialType {
tink_proto::key_data::KeyMaterialType::Symmetric
}
fn new_key_data(&self, _serialized_key_format: &[u8]) -> Result<KeyData, TinkError> {
Err("not implemented".into())
}
}
#[derive(Clone, Debug)]
pub struct DummyAead;
impl tink_core::Aead for DummyAead {
fn encrypt(&self, _plaintext: &[u8], _additional_data: &[u8]) -> Result<Vec<u8>, TinkError> {
Err("dummy aead encrypt".into())
}
fn decrypt(&self, _ciphertext: &[u8], _additional_data: &[u8]) -> Result<Vec<u8>, TinkError> {
Err("dummy aead decrypt".into())
}
}
#[derive(Clone, Debug)]
pub struct DummyMac {
pub name: String,
}
impl tink_core::Mac for DummyMac {
fn compute_mac(&self, data: &[u8]) -> Result<Vec<u8>, TinkError> {
let mut m = Vec::new();
m.extend_from_slice(data);
m.extend_from_slice(self.name.as_bytes());
Ok(m)
}
fn verify_mac(&self, _mac: &[u8], _data: &[u8]) -> Result<(), TinkError> {
Ok(())
}
}
pub struct DummyKmsClient;
impl tink_core::registry::KmsClient for DummyKmsClient {
fn supported(&self, key_uri: &str) -> bool {
key_uri == "dummy"
}
fn get_aead(&self, _key_uri: &str) -> Result<Box<dyn tink_core::Aead>, TinkError> {
Ok(Box::new(DummyAead))
}
}
pub fn new_test_aes_gcm_keyset(primary_output_prefix_type: tink_proto::OutputPrefixType) -> Keyset {
new_test_keyset(|| new_aes_gcm_key_data(16), primary_output_prefix_type)
}
pub fn new_test_aes_siv_keyset(primary_output_prefix_type: tink_proto::OutputPrefixType) -> Keyset {
new_test_keyset(new_aes_siv_key_data, primary_output_prefix_type)
}
pub fn new_test_hmac_keyset(
tag_size: u32,
primary_output_prefix_type: tink_proto::OutputPrefixType,
) -> Keyset {
new_test_keyset(
|| new_hmac_key_data(HashType::Sha256, tag_size),
primary_output_prefix_type,
)
}
pub fn new_test_aes_gcm_hkdf_keyset() -> Keyset {
const KEY_SIZE: u32 = 16;
const DERIVED_KEY_SIZE: u32 = 16;
const CIPHERTEXT_SEGMENT_SIZE: u32 = 4096;
new_test_keyset(
|| {
new_aes_gcm_hkdf_key_data(
KEY_SIZE,
DERIVED_KEY_SIZE,
HashType::Sha256,
CIPHERTEXT_SEGMENT_SIZE,
)
},
tink_proto::OutputPrefixType::Raw,
)
}
pub fn new_test_keyset<T>(
key_data_generator: T,
primary_output_prefix_type: tink_proto::OutputPrefixType,
) -> Keyset
where
T: Fn() -> KeyData,
{
let primary_key = new_key(
&key_data_generator(),
tink_proto::KeyStatusType::Enabled,
42,
primary_output_prefix_type,
);
let raw_key = new_key(
&key_data_generator(),
tink_proto::KeyStatusType::Enabled,
43,
tink_proto::OutputPrefixType::Raw,
);
let legacy_key = new_key(
&key_data_generator(),
tink_proto::KeyStatusType::Enabled,
44,
tink_proto::OutputPrefixType::Legacy,
);
let tink_key = new_key(
&key_data_generator(),
tink_proto::KeyStatusType::Enabled,
45,
tink_proto::OutputPrefixType::Tink,
);
let crunchy_key = new_key(
&key_data_generator(),
tink_proto::KeyStatusType::Enabled,
46,
tink_proto::OutputPrefixType::Crunchy,
);
let primary_key_id = primary_key.key_id;
let keys = vec![primary_key, raw_key, legacy_key, tink_key, crunchy_key];
new_keyset(primary_key_id, keys)
}
pub fn new_dummy_key(
key_id: tink_core::KeyId,
status: tink_proto::KeyStatusType,
output_prefix_type: tink_proto::OutputPrefixType,
) -> tink_proto::keyset::Key {
tink_proto::keyset::Key {
key_data: Some(KeyData::default()),
status: status as i32,
key_id,
output_prefix_type: output_prefix_type as i32,
}
}
pub fn new_ecdsa_params(
hash_type: HashType,
curve: EllipticCurveType,
encoding: EcdsaSignatureEncoding,
) -> tink_proto::EcdsaParams {
tink_proto::EcdsaParams {
hash_type: hash_type as i32,
curve: curve as i32,
encoding: encoding as i32,
}
}
pub fn new_ecdsa_key_format(params: &tink_proto::EcdsaParams) -> tink_proto::EcdsaKeyFormat {
tink_proto::EcdsaKeyFormat {
params: Some(params.clone()),
}
}
pub fn new_random_ecdsa_private_key(
hash_type: HashType,
curve: EllipticCurveType,
) -> tink_proto::EcdsaPrivateKey {
let mut csprng = rand::thread_rng();
let (secret_key_data, pub_x, pub_y) = match curve {
EllipticCurveType::NistP256 => {
let sk = p256::ecdsa::SigningKey::random(&mut csprng);
let pk = p256::ecdsa::VerifyingKey::from(&sk);
let point_len = <p256::NistP256 as elliptic_curve::Curve>::FieldSize::to_usize();
let pk_point = pk.to_encoded_point( false);
let pk_data = pk_point.as_bytes();
(
sk.to_bytes().to_vec(),
pk_data[1..point_len + 1].to_vec(),
pk_data[point_len + 1..].to_vec(),
)
}
_ => panic!("unsupported curve {:?}", curve),
};
let params = new_ecdsa_params(hash_type, curve, EcdsaSignatureEncoding::Der);
let pub_key = tink_proto::EcdsaPublicKey {
version: ECDSA_SIGNER_KEY_VERSION,
params: Some(params),
x: pub_x,
y: pub_y,
};
tink_proto::EcdsaPrivateKey {
version: ECDSA_SIGNER_KEY_VERSION,
public_key: Some(pub_key),
key_value: secret_key_data,
}
}
pub fn new_random_ecdsa_public_key(
hash_type: HashType,
curve: EllipticCurveType,
) -> tink_proto::EcdsaPublicKey {
new_random_ecdsa_private_key(hash_type, curve)
.public_key
.unwrap()
}
pub fn get_ecdsa_params(
params: &tink_proto::EcdsaParams,
) -> (HashType, EllipticCurveType, EcdsaSignatureEncoding) {
(
HashType::from_i32(params.hash_type).unwrap(),
EllipticCurveType::from_i32(params.curve).unwrap(),
EcdsaSignatureEncoding::from_i32(params.encoding).unwrap(),
)
}
pub fn new_ed25519_private_key() -> tink_proto::Ed25519PrivateKey {
let mut csprng = rand::thread_rng();
let keypair = ed25519_dalek::Keypair::generate(&mut csprng);
let public_proto = tink_proto::Ed25519PublicKey {
version: ED25519_SIGNER_KEY_VERSION,
key_value: keypair.public.as_bytes().to_vec(),
};
tink_proto::Ed25519PrivateKey {
version: ED25519_SIGNER_KEY_VERSION,
public_key: Some(public_proto),
key_value: keypair.secret.as_bytes().to_vec(),
}
}
pub fn new_ed25519_public_key() -> tink_proto::Ed25519PublicKey {
new_ed25519_private_key().public_key.unwrap()
}
fn new_aes_siv_key_data() -> tink_proto::KeyData {
let key_value = get_random_bytes(tink_daead::subtle::AES_SIV_KEY_SIZE);
let key = &tink_proto::AesSivKey {
version: AES_SIV_KEY_VERSION,
key_value,
};
let serialized_key = proto_encode(key);
new_key_data(
AES_SIV_TYPE_URL,
&serialized_key,
tink_proto::key_data::KeyMaterialType::Symmetric,
)
}
pub fn new_aes_gcm_key(key_version: u32, key_size: u32) -> tink_proto::AesGcmKey {
let key_value = get_random_bytes(key_size.try_into().unwrap());
tink_proto::AesGcmKey {
version: key_version,
key_value,
}
}
pub fn new_aes_gcm_key_data(key_size: u32) -> KeyData {
let key = new_aes_gcm_key(AES_GCM_KEY_VERSION, key_size);
let serialized_key = proto_encode(&key);
new_key_data(
AES_GCM_TYPE_URL,
&serialized_key,
tink_proto::key_data::KeyMaterialType::Symmetric,
)
}
pub fn new_aes_gcm_key_format(key_size: u32) -> tink_proto::AesGcmKeyFormat {
tink_proto::AesGcmKeyFormat {
key_size,
version: AES_GCM_KEY_VERSION,
}
}
pub fn new_aes_gcm_siv_key(key_version: u32, key_size: u32) -> tink_proto::AesGcmSivKey {
let key_value = get_random_bytes(key_size.try_into().unwrap());
tink_proto::AesGcmSivKey {
version: key_version,
key_value,
}
}
pub fn new_aes_gcm_siv_key_data(key_size: u32) -> KeyData {
let key = new_aes_gcm_siv_key(AES_GCM_SIV_KEY_VERSION, key_size);
let serialized_key = proto_encode(&key);
new_key_data(
AES_GCM_SIV_TYPE_URL,
&serialized_key,
tink_proto::key_data::KeyMaterialType::Symmetric,
)
}
pub fn new_serialized_aes_gcm_siv_key(key_size: u32) -> Vec<u8> {
let key = new_aes_gcm_siv_key(AES_GCM_SIV_KEY_VERSION, key_size);
proto_encode(&key)
}
pub fn new_aes_gcm_siv_key_format(key_size: u32) -> tink_proto::AesGcmSivKeyFormat {
tink_proto::AesGcmSivKeyFormat {
key_size,
version: AES_GCM_SIV_KEY_VERSION,
}
}
pub fn new_aes_gcm_hkdf_key(
key_version: u32,
key_size: u32,
derived_key_size: u32,
hkdf_hash_type: i32,
ciphertext_segment_size: u32,
) -> tink_proto::AesGcmHkdfStreamingKey {
let key_value = get_random_bytes(key_size.try_into().unwrap());
tink_proto::AesGcmHkdfStreamingKey {
version: key_version,
key_value,
params: Some(tink_proto::AesGcmHkdfStreamingParams {
ciphertext_segment_size,
derived_key_size,
hkdf_hash_type,
}),
}
}
pub fn new_aes_gcm_hkdf_key_data(
key_size: u32,
derived_key_size: u32,
hkdf_hash_type: HashType,
ciphertext_segment_size: u32,
) -> KeyData {
let key = new_aes_gcm_hkdf_key(
AES_GCM_HKDF_KEY_VERSION,
key_size,
derived_key_size,
hkdf_hash_type as i32,
ciphertext_segment_size,
);
let serialized_key = proto_encode(&key);
new_key_data(
AES_GCM_HKDF_TYPE_URL,
&serialized_key,
tink_proto::key_data::KeyMaterialType::Symmetric,
)
}
pub fn new_aes_gcm_hkdf_key_format(
key_size: u32,
derived_key_size: u32,
hkdf_hash_type: i32,
ciphertext_segment_size: u32,
) -> tink_proto::AesGcmHkdfStreamingKeyFormat {
tink_proto::AesGcmHkdfStreamingKeyFormat {
version: AES_GCM_HKDF_KEY_VERSION,
key_size,
params: Some(tink_proto::AesGcmHkdfStreamingParams {
ciphertext_segment_size,
derived_key_size,
hkdf_hash_type,
}),
}
}
pub fn new_aes_ctr_hmac_key(
key_version: u32,
key_size: u32,
hkdf_hash_type: HashType,
derived_key_size: u32,
hash_type: HashType,
tag_size: u32,
ciphertext_segment_size: u32,
) -> tink_proto::AesCtrHmacStreamingKey {
let key_value = get_random_bytes(key_size.try_into().unwrap());
tink_proto::AesCtrHmacStreamingKey {
version: key_version,
key_value,
params: Some(tink_proto::AesCtrHmacStreamingParams {
ciphertext_segment_size,
derived_key_size,
hkdf_hash_type: hkdf_hash_type as i32,
hmac_params: Some(tink_proto::HmacParams {
hash: hash_type as i32,
tag_size,
}),
}),
}
}
pub fn new_aes_ctr_hmac_key_format(
key_size: u32,
hkdf_hash_type: HashType,
derived_key_size: u32,
hash_type: HashType,
tag_size: u32,
ciphertext_segment_size: u32,
) -> tink_proto::AesCtrHmacStreamingKeyFormat {
tink_proto::AesCtrHmacStreamingKeyFormat {
version: AES_CTR_HMAC_AEAD_KEY_VERSION,
key_size,
params: Some(tink_proto::AesCtrHmacStreamingParams {
ciphertext_segment_size,
derived_key_size,
hkdf_hash_type: hkdf_hash_type as i32,
hmac_params: Some(tink_proto::HmacParams {
hash: hash_type as i32,
tag_size,
}),
}),
}
}
pub fn new_hmac_params(hash_type: HashType, tag_size: u32) -> tink_proto::HmacParams {
tink_proto::HmacParams {
hash: hash_type as i32,
tag_size,
}
}
pub fn new_hmac_key(hash_type: HashType, tag_size: u32) -> tink_proto::HmacKey {
let params = new_hmac_params(hash_type, tag_size);
let key_value = get_random_bytes(20);
tink_proto::HmacKey {
version: HMAC_KEY_VERSION,
params: Some(params),
key_value,
}
}
pub fn new_hmac_key_format(hash_type: HashType, tag_size: u32) -> tink_proto::HmacKeyFormat {
let params = new_hmac_params(hash_type, tag_size);
let key_size = 20u32;
tink_proto::HmacKeyFormat {
params: Some(params),
key_size,
version: HMAC_KEY_VERSION,
}
}
pub fn new_aes_cmac_params(tag_size: u32) -> tink_proto::AesCmacParams {
tink_proto::AesCmacParams { tag_size }
}
pub fn new_aes_cmac_key(tag_size: u32) -> tink_proto::AesCmacKey {
let params = new_aes_cmac_params(tag_size);
let key_value = get_random_bytes(32);
tink_proto::AesCmacKey {
version: AES_CMAC_KEY_VERSION,
params: Some(params),
key_value,
}
}
pub fn new_aes_cmac_key_format(tag_size: u32) -> tink_proto::AesCmacKeyFormat {
let params = new_aes_cmac_params(tag_size);
let key_size = 32u32;
tink_proto::AesCmacKeyFormat {
params: Some(params),
key_size,
}
}
pub fn new_hmac_keyset_manager() -> tink_core::keyset::Manager {
let mut ksm = tink_core::keyset::Manager::new();
let kt = tink_mac::hmac_sha256_tag128_key_template();
ksm.rotate(&kt).expect("cannot rotate keyset manager");
ksm
}
pub fn new_hmac_key_data(hash_type: HashType, tag_size: u32) -> KeyData {
let key = new_hmac_key(hash_type, tag_size);
let serialized_key = proto_encode(&key);
KeyData {
type_url: HMAC_TYPE_URL.to_string(),
value: serialized_key,
key_material_type: tink_proto::key_data::KeyMaterialType::Symmetric as i32,
}
}
pub fn new_hmac_prf_params(hash_type: HashType) -> tink_proto::HmacPrfParams {
tink_proto::HmacPrfParams {
hash: hash_type as i32,
}
}
pub fn new_hmac_prf_key(hash_type: HashType) -> tink_proto::HmacPrfKey {
let params = new_hmac_prf_params(hash_type);
let key_value = get_random_bytes(32);
tink_proto::HmacPrfKey {
version: HMAC_PRF_KEY_VERSION,
params: Some(params),
key_value,
}
}
pub fn new_hmac_prf_key_format(hash_type: HashType) -> tink_proto::HmacPrfKeyFormat {
let params = new_hmac_prf_params(hash_type);
let key_size = 32u32;
tink_proto::HmacPrfKeyFormat {
params: Some(params),
key_size,
version: HMAC_PRF_KEY_VERSION,
}
}
pub fn new_hkdf_prf_params(hash_type: HashType, salt: &[u8]) -> tink_proto::HkdfPrfParams {
tink_proto::HkdfPrfParams {
hash: hash_type as i32,
salt: salt.to_vec(),
}
}
pub fn new_hkdf_prf_key(hash_type: HashType, salt: &[u8]) -> tink_proto::HkdfPrfKey {
let params = new_hkdf_prf_params(hash_type, salt);
let key_value = get_random_bytes(32);
tink_proto::HkdfPrfKey {
version: HKDF_PRF_KEY_VERSION,
params: Some(params),
key_value,
}
}
pub fn new_hkdf_prf_key_format(hash_type: HashType, salt: &[u8]) -> tink_proto::HkdfPrfKeyFormat {
let params = new_hkdf_prf_params(hash_type, salt);
let key_size = 32u32;
tink_proto::HkdfPrfKeyFormat {
params: Some(params),
key_size,
version: HKDF_PRF_KEY_VERSION,
}
}
pub fn new_aes_cmac_prf_key() -> tink_proto::AesCmacPrfKey {
let key_value = get_random_bytes(32);
tink_proto::AesCmacPrfKey {
version: AES_CMAC_PRF_KEY_VERSION,
key_value,
}
}
pub fn new_aes_cmac_prf_key_format() -> tink_proto::AesCmacPrfKeyFormat {
let key_size = 32u32;
tink_proto::AesCmacPrfKeyFormat {
version: AES_CMAC_PRF_KEY_VERSION,
key_size,
}
}
pub fn new_key_data(
type_url: &str,
value: &[u8],
material_type: tink_proto::key_data::KeyMaterialType,
) -> KeyData {
KeyData {
type_url: type_url.to_string(),
value: value.to_vec(),
key_material_type: material_type as i32,
}
}
pub fn new_key(
key_data: &KeyData,
status: tink_proto::KeyStatusType,
key_id: tink_core::KeyId,
prefix_type: tink_proto::OutputPrefixType,
) -> tink_proto::keyset::Key {
tink_proto::keyset::Key {
key_data: Some(key_data.clone()),
status: status as i32,
key_id,
output_prefix_type: prefix_type as i32,
}
}
pub fn new_keyset(primary_key_id: tink_core::KeyId, keys: Vec<tink_proto::keyset::Key>) -> Keyset {
Keyset {
primary_key_id,
key: keys,
}
}
pub fn generate_mutations(src: &[u8]) -> Vec<Vec<u8>> {
let mut all = Vec::new();
for i in 0..src.len() {
for j in 0..8u8 {
let mut n = src.to_vec();
n[i] ^= 1 << j;
all.push(n);
}
}
for i in 0..src.len() {
all.push(src[i..].to_vec());
}
let mut m = src.to_vec();
m.push(0);
all.push(m);
all
}
pub fn z_test_uniform_string(bytes: &[u8]) -> Result<(), tink_core::TinkError> {
let expected = (bytes.len() as f64) * 8.0 / 2.0;
let stddev = ((bytes.len() as f64) * 8.0 / 4.0).sqrt();
let mut num_set_bits: i64 = 0;
for b in bytes {
let mut b = *b;
while b != 0 {
num_set_bits += 1;
b = b & (b - 1);
}
}
if ((num_set_bits as f64) - expected).abs() < 10.0 * stddev {
Ok(())
} else {
Err(format!(
"Z test for uniformly distributed variable out of bounds; Actual number of set bits was {} expected was {}, 10 * standard deviation is 10 * {} = {}",
num_set_bits, expected, stddev, 10.0*stddev).into())
}
}
fn rotate(bytes: &[u8]) -> Vec<u8> {
let mut result = vec![0u8; bytes.len()];
for i in 0..bytes.len() {
let prev = if i == 0 { bytes.len() } else { i };
result[i] = (bytes[i] >> 1) | (bytes[prev - 1] << 7);
}
result
}
pub fn z_test_crosscorrelation_uniform_strings(
bytes1: &[u8],
bytes2: &[u8],
) -> Result<(), TinkError> {
if bytes1.len() != bytes2.len() {
return Err("Strings are not of equal length".into());
}
let mut crossed = vec![0u8; bytes1.len()];
for i in 0..bytes1.len() {
crossed[i] = bytes1[i] ^ bytes2[i]
}
z_test_uniform_string(&crossed)
}
pub fn z_test_autocorrelation_uniform_string(bytes: &[u8]) -> Result<(), TinkError> {
let mut rotated = bytes.to_vec();
let mut violations = Vec::new();
for i in 1..(bytes.len() * 8) {
rotated = rotate(&rotated);
if z_test_crosscorrelation_uniform_strings(bytes, &rotated).is_err() {
violations.push(i.to_string());
}
}
if violations.is_empty() {
Ok(())
} else {
Err(TinkError::new(&format!(
"Autocorrelation exceeded 10 standard deviation at {} indices: {}",
violations.len(),
violations.join(", ")
)))
}
}
pub fn ecies_aead_hkdf_public_key(
c: EllipticCurveType,
ht: HashType,
ptfmt: tink_proto::EcPointFormat,
dek_t: tink_proto::KeyTemplate,
x: &[u8],
y: &[u8],
salt: &[u8],
) -> tink_proto::EciesAeadHkdfPublicKey {
tink_proto::EciesAeadHkdfPublicKey {
version: 0,
params: Some(tink_proto::EciesAeadHkdfParams {
kem_params: Some(tink_proto::EciesHkdfKemParams {
curve_type: c as i32,
hkdf_hash_type: ht as i32,
hkdf_salt: salt.to_vec(),
}),
dem_params: Some(tink_proto::EciesAeadDemParams {
aead_dem: Some(dek_t),
}),
ec_point_format: ptfmt as i32,
}),
x: x.to_vec(),
y: y.to_vec(),
}
}
pub fn ecies_aead_hkdf_private_key(
p: tink_proto::EciesAeadHkdfPublicKey,
d: &[u8],
) -> tink_proto::EciesAeadHkdfPrivateKey {
tink_proto::EciesAeadHkdfPrivateKey {
version: 0,
public_key: Some(p),
key_value: d.to_vec(),
}
}
pub fn generate_ecies_aead_hkdf_private_key(
c: EllipticCurveType,
ht: HashType,
ptfmt: tink_proto::EcPointFormat,
dek_t: tink_proto::KeyTemplate,
salt: &[u8],
) -> Result<tink_proto::EciesAeadHkdfPrivateKey, TinkError> {
Err(format!(
"unimplemented for {:?} {:?} {:?} {:?} {:?}",
c, ht, ptfmt, dek_t, salt
)
.into())
}
pub fn proto_encode<T>(msg: &T) -> Vec<u8>
where
T: prost::Message,
{
let mut data = Vec::new();
msg.encode(&mut data)
.expect("failed to encode proto message");
data
}
pub fn expect_err<T, E: std::fmt::Debug>(result: Result<T, E>, err_msg: &str) {
assert!(result.is_err(), "expected error containing '{}'", err_msg);
let err = result.err();
assert!(
format!("{:?}", err).contains(err_msg),
"unexpected error {:?}, doesn't contain '{}'",
err,
err_msg
);
}
pub fn expect_err_for_case<T, E: std::fmt::Debug>(result: Result<T, E>, err_msg: &str, name: &str) {
assert!(
result.is_err(),
"{}: expected error containing '{}'",
name,
err_msg
);
let err = result.err();
assert!(
format!("{:?}", err).contains(err_msg),
"{}: unexpected error {:?}, doesn't contain '{}'",
name,
err,
err_msg
);
}
pub struct IoFailure {}
impl std::io::Read for IoFailure {
fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"failure object",
))
}
}
impl std::io::Write for IoFailure {
fn write(&mut self, _buf: &[u8]) -> std::io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"failure object",
))
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}