oaep rsa base
This commit is contained in:
parent
6460e939e8
commit
7bcd404185
|
@ -0,0 +1,92 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Perform RSA-OAEP
|
||||||
|
|
||||||
|
@author: Christoph J. Scherr <software@cscherr.de>
|
||||||
|
@license: MIT
|
||||||
|
@source: https://git.cscherr.de/PlexSheep/plexcryptool/src/branch/master/plexcryptool/trash-hash.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
from math import floor
|
||||||
|
|
||||||
|
# the given key in the assignment
|
||||||
|
GIVEN_PUB_KEY = (0xAF5466C26A6B662AC98C06023501C9DF6036B065BD1F6804B1FC86307718DA4048211FD68A06917DE6F81DC018DCAF84B38AB77A6538BA2FE6664D3FB81E4A0886BBCDAB071AD6823FE20DF1CD67D33FB6CC5DA519F69B11F3D48534074A83F03A5A9545427720A30A27432E94970155A026572E358072023061AF65A2A18E85, 0x10001)
|
||||||
|
|
||||||
|
SEED_LENGTH = 8 # bytes
|
||||||
|
|
||||||
|
def mgf1(seed: bytearray, length: int, hash_func=hashlib.sha256) -> bytearray:
|
||||||
|
"""
|
||||||
|
Code stolen from wikipedia
|
||||||
|
"""
|
||||||
|
hLen = hash_func().digest_size
|
||||||
|
# https://www.ietf.org/rfc/rfc2437.txt
|
||||||
|
# 1.If l > 2^32(hLen), output "mask too long" and stop.
|
||||||
|
if length > (hLen << 32):
|
||||||
|
raise ValueError("mask too long")
|
||||||
|
# 2.Let T be the empty octet string.
|
||||||
|
T = b""
|
||||||
|
# 3.For counter from 0 to \lceil{l / hLen}\rceil-1, do the following:
|
||||||
|
# Note: \lceil{l / hLen}\rceil-1 is the number of iterations needed,
|
||||||
|
# but it's easier to check if we have reached the desired length.
|
||||||
|
counter = 0
|
||||||
|
while len(T) < length:
|
||||||
|
# a.Convert counter to an octet string C of length 4 with the primitive I2OSP: C = I2OSP (counter, 4)
|
||||||
|
C = int.to_bytes(counter, 4, 'big')
|
||||||
|
# b.Concatenate the hash of the seed Z and C to the octet string T: T = T || Hash (Z || C)
|
||||||
|
T += hash_func(seed + C).digest()
|
||||||
|
counter += 1
|
||||||
|
# 4.Output the leading l octets of T as the octet string mask.
|
||||||
|
return bytearray(T[:length])
|
||||||
|
|
||||||
|
def byte_xor(ba1: bytearray, ba2: bytearray):
|
||||||
|
a = int(ba1.hex(), 16)
|
||||||
|
b = int(ba2.hex(), 16)
|
||||||
|
c = a^b
|
||||||
|
if c.bit_length() / 8 == floor(c.bit_length() / 8):
|
||||||
|
clen = floor(c.bit_length() / 8)
|
||||||
|
else:
|
||||||
|
clen = floor(c.bit_length() / 8) + 1
|
||||||
|
return bytearray(c.to_bytes(clen, 'big'))
|
||||||
|
|
||||||
|
|
||||||
|
def rsa_oaep_inner(seed: bytearray, datablock: bytearray) -> tuple[bytearray, bytearray, bytearray]:
|
||||||
|
mgf_seed = mgf1(seed, len(seed))
|
||||||
|
masked_db = byte_xor(mgf_seed, datablock)
|
||||||
|
print(masked_db.hex())
|
||||||
|
|
||||||
|
def test_rsa_oaep_inner():
|
||||||
|
seed: bytearray = bytearray.fromhex("aa1122fe0815beef")
|
||||||
|
db: bytearray = bytearray.fromhex("""
|
||||||
|
00000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000001466f6f626172203132
|
||||||
|
33343536373839
|
||||||
|
""")
|
||||||
|
print("seed\t%s" % seed.hex())
|
||||||
|
print("db\t%s" % db.hex())
|
||||||
|
|
||||||
|
result = rsa_oaep_inner(seed, db)
|
||||||
|
|
||||||
|
GIVEN_MASK_FOR_DB = bytearray.fromhex("""
|
||||||
|
ea600669f6f16b3a2ad05d4b6d9b23911c8cc432fddd8d34a68d88af
|
||||||
|
3d787b7eebf6cd1b720812086758ce56e24ab819ccd8fb5eedb1cae9
|
||||||
|
f6f895667d7f89d0454b828777ecabc040a649c8956e78ec1c721370
|
||||||
|
663065cbc343deabad9eb6f2aceab6bfed5beb232cc55413bfffa06e
|
||||||
|
68627d7ec3ded5
|
||||||
|
""")
|
||||||
|
GIVEN_MASKED_DB = bytearray.fromhex("""
|
||||||
|
ea600669f6f16b3a2ad05d4b6d9b23911c8cc432fddd8d34a68d88af
|
||||||
|
3d787b7eebf6cd1b720812086758ce56e24ab819ccd8fb5eedb1cae9
|
||||||
|
f6f895667d7f89d0454b828777ecabc040a649c8956e78ec1c721370
|
||||||
|
663065cbc343deabad9eb6f2aceab6bfed5bea6543aa3672cddf915c
|
||||||
|
5b564848f4e6ec
|
||||||
|
""")
|
||||||
|
GIVEN_MASK_FOR_SEED = bytearray.fromhex("713162084a4e0e6d ")
|
||||||
|
GIVEN_MASKED_SEED = bytearray.fromhex("db2040f6425bb082")
|
||||||
|
assert result[0] == GIVEN_MASKED_SEED, "is %s" % result[0].hex()
|
||||||
|
assert result[1] == GIVEN_MASKED_DB, "is %s" % result[1].hex()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_rsa_oaep_inner()
|
|
@ -68,7 +68,7 @@ impl ElipticCurve {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_point() {
|
fn test_check_point() {
|
||||||
let f = GalloisField::new(1151, true);
|
let f = GalloisField::new(1151, true, None);
|
||||||
let ec = ElipticCurve::new(f, 1, 679, true);
|
let ec = ElipticCurve::new(f, 1, 679, true);
|
||||||
// real points
|
// real points
|
||||||
let p = vec![
|
let p = vec![
|
||||||
|
|
|
@ -25,6 +25,12 @@ use pyo3::{prelude::*, exceptions::PyValueError};
|
||||||
|
|
||||||
use primes::is_prime;
|
use primes::is_prime;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
pub const F_8_DEFAULT_RELATION: u128 = 0xb;
|
||||||
|
pub const F_16_DEFAULT_RELATION: u128 = 0x13;
|
||||||
|
pub const F_256_DEFAULT_RELATION: u128 = 0x11b;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// used when trying to find a root for a number which does not have a root.
|
/// used when trying to find a root for a number which does not have a root.
|
||||||
|
@ -70,11 +76,28 @@ pub struct GalloisField {
|
||||||
/// implementations for the gallois field
|
/// implementations for the gallois field
|
||||||
impl GalloisField {
|
impl GalloisField {
|
||||||
/// make a new gallois field
|
/// make a new gallois field
|
||||||
pub fn new(base: u128, verbose: bool, relation: Option<u128>) -> Self {
|
pub fn new(base: u128, verbose: bool, mut relation: Option<u128>) -> Self {
|
||||||
let prime_base: bool = is_prime(base as u64);
|
let prime_base: bool = is_prime(base as u64);
|
||||||
if !prime_base {
|
if !prime_base {
|
||||||
println!("Non prime bases for a field are currently very experimental.\n
|
println!("Non prime bases for a field are currently very experimental.\nUse them at your own risk! ({} is not a prime.)", base);
|
||||||
Use them at your own risk! ({} is not a prime.)", base);
|
if relation.is_none() {
|
||||||
|
// TODO choose common relations for known fields
|
||||||
|
|
||||||
|
match base {
|
||||||
|
8 => {
|
||||||
|
relation = Some(F_8_DEFAULT_RELATION);
|
||||||
|
}
|
||||||
|
16 => {
|
||||||
|
relation = Some(F_16_DEFAULT_RELATION);
|
||||||
|
}
|
||||||
|
256 => {
|
||||||
|
relation = Some(F_256_DEFAULT_RELATION);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("You did not specify a relation and none could be found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let mut field = GalloisField{
|
let mut field = GalloisField{
|
||||||
base,
|
base,
|
||||||
|
@ -124,7 +147,7 @@ impl GalloisField {
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
panic!("reduction for negative numbers not implemented.");
|
panic!("reduction for negative numbers not implemented.");
|
||||||
}
|
}
|
||||||
modred(n as u128, self.relation.unwrap(), self.verbose).expect("modular reduction didn't work")
|
modred(n as u128, self.relation.unwrap(), false).expect("modular reduction didn't work")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,6 +444,16 @@ fn test_gallois_sqrt() {
|
||||||
assert_eq!(field.sqrt(275).expect("function says there is no root but there is"), (585, 392));
|
assert_eq!(field.sqrt(275).expect("function says there is no root but there is"), (585, 392));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gallois_reduce() {
|
||||||
|
let field = GalloisField::new(977, true, None);
|
||||||
|
for i in 0..976 {
|
||||||
|
assert_eq!(field.reduce(i), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
let field = GalloisField::new(16, true, None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_gallois_inverse() {
|
fn test_gallois_inverse() {
|
||||||
let field = GalloisField::new(31, true, None);
|
let field = GalloisField::new(31, true, None);
|
||||||
|
@ -438,10 +471,10 @@ fn test_gallois_inverse() {
|
||||||
assert_eq!(field.inverse(7).unwrap(), 10);
|
assert_eq!(field.inverse(7).unwrap(), 10);
|
||||||
assert!(field.inverse(0).is_err());
|
assert!(field.inverse(0).is_err());
|
||||||
|
|
||||||
// TODO i think this test does not catch all edge cases. In some cases, something seems to be
|
|
||||||
// wrong.
|
|
||||||
|
|
||||||
// TODO add a test for a field that has a non prime base
|
// TODO add a test for a field that has a non prime base
|
||||||
|
let field = GalloisField::new(16, true, None);
|
||||||
|
assert_eq!(field.inverse(0x130).unwrap(), 0);
|
||||||
|
assert!(field.inverse(0).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -450,8 +483,8 @@ fn test_calc_char() {
|
||||||
assert_eq!(GalloisField::new(1151, true, None).calc_char(), 1151);
|
assert_eq!(GalloisField::new(1151, true, None).calc_char(), 1151);
|
||||||
assert_eq!(GalloisField::new(2, true, None).calc_char(), 2);
|
assert_eq!(GalloisField::new(2, true, None).calc_char(), 2);
|
||||||
|
|
||||||
// only primes are supported right now. TODO
|
// experimental
|
||||||
//assert_eq!(GalloisField::new(8, true).calc_char(), 2);
|
assert_eq!(GalloisField::new(8, true, None).calc_char(), 2);
|
||||||
//assert_eq!(GalloisField::new(64, true).calc_char(), 2);
|
assert_eq!(GalloisField::new(64, true, None).calc_char(), 2);
|
||||||
//assert_eq!(GalloisField::new(2u128.pow(64u32), true).calc_char(), 2);
|
//assert_eq!(GalloisField::new(2u128.pow(64u32), true, None).calc_char(), 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,5 +159,4 @@ fn dump_bin(bytes: &Vec<u8>) {
|
||||||
print!("{:08b}", byte);
|
print!("{:08b}", byte);
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue