Skip to content

Commit 244ead9

Browse files
committed
refactor: reimplement rsa to be pkcs #1 v2.2 compliant
1 parent c61208c commit 244ead9

File tree

3 files changed

+86
-45
lines changed

3 files changed

+86
-45
lines changed

Diff for: src/rsa.jl

+15-9
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ struct RSAPrivateKey
1818
modulus::BigInt
1919
public_exponent::BigInt
2020
exponent::BigInt
21-
primes::Tuple{BigInt,BigInt}
22-
crt_exponents::Tuple{BigInt,BigInt}
23-
crt_coefficients::Tuple{BigInt,BigInt}
21+
primes::Vector{BigInt}
22+
crt_exponents::Vector{BigInt}
23+
crt_coefficients::Vector{BigInt}
2424
end
2525

2626
"""
@@ -48,19 +48,20 @@ const RSAKey = Union{RSAPrivateKey,RSAPublicKey}
4848
Fast implementation of the RSA exponentiation step when RSAPrivateKey is provided.
4949
It uses [Chinese remainer theorem](https://en.wikipedia.org/wiki/Chinese_remainder_theorem) for very fast `exp() mod n` calculations.
5050
"""
51-
function RSAStep(::pkcs1_v1_5_t, msg::BigInt, key::RSAPrivateKey)
51+
function RSAEP(::pkcs1_v1_5_t, msg::BigInt, key::RSAPrivateKey)
5252
if !(0 <= msg < key.modulus)
5353
error("msg has to be 0 <= msg < n, got: msg = $msg, n = $key.modulus")
5454
end
55-
return power_crt(
55+
ret = power_crt(
5656
msg,
5757
key.primes[1],
5858
key.primes[2],
5959
key.crt_exponents[1],
60-
key.crt_coefficients[1],
6160
key.crt_exponents[2],
6261
key.crt_coefficients[2],
6362
)
63+
ret < 0 && (ret += msg) #???
64+
return ret
6465
end
6566

6667
"""
@@ -70,13 +71,16 @@ RSA exponentiation step when only public key is available.
7071
Uses [repeated squares](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
7172
and other fast modulo exponentiation tricks in its GMP implementation (Base.GMP.MPZ.powm).
7273
"""
73-
function RSAStep(::pkcs1_v1_5_t, msg::BigInt, key::RSAPublicKey)
74+
function RSADP(::pkcs1_v1_5_t, msg::BigInt, key::RSAPublicKey)
7475
if !(0 <= msg < key.modulus)
7576
error("msg has to be 0 <= msg < n, got: msg = $msg, n = $key.modulus")
7677
end
7778
return Base.GMP.MPZ.powm(msg, key.exponent, key.modulus)
7879
end
7980

81+
RSAStep(a::pkcs1_v1_5_t, msg::BigInt, key::RSAPrivateKey) = RSAEP(a, msg, key)
82+
RSAStep(a::pkcs1_v1_5_t, msg::BigInt, key::RSAPublicKey) = RSADP(a, msg, key)
83+
8084
"""
8185
RSAStep(::pkcs1_v1_5_t, msg::AbstractVector{T}, key::RSAKey) where {T<:Base.BitInteger}
8286
@@ -177,9 +181,11 @@ function generate_rsa_key_pair(::pkcs1_v1_5_t, bits::Integer)
177181
end
178182
d = BigInt()
179183
Base.GMP.MPZ.invert!(d, big"65537", carm_tot)
180-
p_pow, q_param_p, q_pow, q_param_q = power_crt_components(d, p, q)
184+
d_p, d_q, q_inv, p_inv = power_crt_components(d, p, q)
181185
return (
182-
RSAPrivateKey(0, m, e, d, (p, q), (p_pow, q_pow), (q_param_p, q_param_q)),
186+
RSAPrivateKey(0, m, e, d, [p, q],
187+
[d_p, d_q],
188+
[q_inv, p_inv]),
183189
RSAPublicKey(0, m, e),
184190
)
185191
end

Diff for: src/utils/number_theory.jl

+30-30
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,26 @@
11
"""
2-
power_crt(
2+
function power_crt(
33
base::BigInt,
44
p::BigInt,
55
q::BigInt,
6-
p_pow::BigInt,
7-
q_param_p::BigInt,
8-
q_pow::BigInt,
9-
q_param_q::BigInt,
6+
d_p::BigInt,
7+
d_q::BigInt,
8+
q_inv::BigInt,
109
)
1110
12-
Core implementation of exponentiation over modulus using [CRT](https://en.wikipedia.org/wiki/Chinese_remainder_theorem).
11+
CRT for PKCS #1 based parameters.
1312
"""
1413
function power_crt(
1514
base::BigInt,
1615
p::BigInt,
1716
q::BigInt,
18-
p_pow::BigInt,
19-
q_param_p::BigInt,
20-
q_pow::BigInt,
21-
q_param_q::BigInt,
17+
d_p::BigInt,
18+
d_q::BigInt,
19+
q_inv::BigInt,
2220
)
23-
p_base = base % p
24-
z_p_result = Base.GMP.MPZ.powm(p_base, p_pow, p)
25-
26-
q_base = base % q
27-
z_q_result = Base.GMP.MPZ.powm(q_base, q_pow, q)
28-
return (z_p_result * q_param_p + z_q_result * q_param_q) % (p * q)
21+
m1 = Base.GMP.MPZ.powm(base, d_p, p)
22+
m2 = Base.GMP.MPZ.powm(base, d_q, q)
23+
return (m2 + ((m1 - m2) * q_inv) * q) % (p*q)
2924
end
3025

3126
"""
@@ -34,25 +29,30 @@ end
3429
Wrapper around core implementation, only for generating the parameters if they are not provided.
3530
"""
3631
function power_crt(base::BigInt, pow::BigInt, p::BigInt, q::BigInt)
37-
p_pow, q_param_p, q_pow, q_param_q = power_crt_components(pow, p, q)
38-
return power_crt(base, p, q, p_pow, q_param_p, q_pow, q_param_q)
32+
d_p, d_q, q_inv, _ = power_crt_components(pow, p, q)
33+
return power_crt(base, p, q, d_p, d_q, q_inv)
3934
end
4035

4136
"""
42-
power_crt_components(pow::BigInt, p::BigInt, q::BigInt)
37+
power_crt_components(d::BigInt, p::BigInt, q::BigInt)
4338
44-
Utility function for calculating the [CRT](https://en.wikipedia.org/wiki/Chinese_remainder_theorem) parameters.
39+
Utility function for calculating dth power in p*q mod [CRT](https://en.wikipedia.org/wiki/Chinese_remainder_theorem) parameters for PKCS #1.
4540
"""
46-
function power_crt_components(pow::BigInt, p::BigInt, q::BigInt)
47-
p_pow = pow % (p - 1) # pow % φ(p)
48-
q_param_p = BigInt()
49-
Base.GMP.MPZ.invert!(q_param_p, q, p)
50-
q_param_p *= q
41+
function power_crt_components(d::BigInt, p::BigInt, q::BigInt)
42+
d_p = d % (p - 1) # e. totient for primes
43+
d_q = d % (q - 1)
44+
q_inv = BigInt()
45+
Base.GMP.MPZ.invert!(q_inv, q, p)
46+
p_inv = BigInt()
47+
Base.GMP.MPZ.invert!(p_inv, p, q)
48+
return (d_p, d_q, q_inv, p_inv)
49+
end
5150

52-
q_pow = pow % (q - 1) # pow % φ(q)
53-
q_param_q = BigInt()
54-
Base.GMP.MPZ.invert!(q_param_q, p, q)
55-
q_param_q *= p
51+
"""
52+
power_crt_components(e::BigInt, d::BigInt, primes::Vector{BigInt})
5653
57-
return (p_pow, q_param_p, q_pow, q_param_q)
54+
Utility function for calculating the [CRT](https://en.wikipedia.org/wiki/Chinese_remainder_theorem) parameters for PKCS #1.
55+
"""
56+
function power_crt_components(pow::BigInt, primes::Vector{BigInt})
57+
error("not implemented") |> throw
5858
end

Diff for: test/rsa.jl

+41-6
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,51 @@
2020
@test pass_trough_GMP(test_str) == "this_is_test_str"
2121
end
2222

23+
@testset "power_crt_components" begin
24+
factor1 = big"9679"
25+
factor2 = big"7883"
26+
pow = big"654321"
27+
d_p, d_q, q_inv, p_inv = ToyPublicKeys.power_crt_components(pow, factor1, factor2)
28+
@test (d_p == 5895)
29+
@test (d_q == 115)
30+
@test (q_inv == 6785)
31+
@test (p_inv == 2357)
32+
end
33+
34+
@testset "power_crt from power_crt_components" begin
35+
base = big"123456"
36+
modul = big"76299557"
37+
factor1 = big"9679"
38+
factor2 = big"7883"
39+
pow = big"654321"
40+
d_p, d_q, q_inv, _ = ToyPublicKeys.power_crt_components(pow, factor1, factor2)
41+
pow_crt = ToyPublicKeys.power_crt(base, factor1, factor2, d_p, d_q, q_inv)
42+
pow_m = Base.GMP.MPZ.powm(base, pow, modul)
43+
@test pow_crt == pow_m
44+
end
45+
2346
@testset "power_crt" begin
2447
base = big"123456"
25-
modul = big"265277633"
26-
f1 = big"38561"
27-
f2 = big"15107"
28-
pow_crt = ToyPublicKeys.power_crt(base, modul, f1, f2)
29-
pow_m = Base.GMP.MPZ.powm(base, modul, f1*f2)
48+
modul = big"76299557"
49+
factor1 = big"9679"
50+
factor2 = big"7883"
51+
pow = big"654321"
52+
pow_crt = ToyPublicKeys.power_crt(base, pow, factor1, factor2)
53+
pow_m = Base.GMP.MPZ.powm(base, pow, modul)
3054
@test pow_crt == pow_m
3155
end
3256

57+
@testset "validate generate_rsa_key_pair" begin
58+
Random.seed!(42)
59+
private_key, public_key = ToyPublicKeys.generate_rsa_key_pair(ToyPublicKeys.pkcs1_v1_5, 2048)
60+
@test try
61+
ToyPublicKeys.validate(private_key)
62+
true
63+
catch
64+
false
65+
end
66+
end
67+
3368
@testset "RSAStep(RSAStep) is identity ~ BigInt" begin
3469
Random.seed!(42)
3570
private_key, public_key = ToyPublicKeys.generate_rsa_key_pair(ToyPublicKeys.pkcs1_v1_5, 2048)
@@ -80,5 +115,5 @@ end
80115
private_key, public_key = ToyPublicKeys.generate_rsa_key_pair(ToyPublicKeys.pkcs1_v1_5, 2048)
81116
msg = "1"
82117
signature = ToyPublicKeys.sign(ToyPublicKeys.pkcs1_v1_5, msg, private_key)
83-
@test ToyPublicKeys.verify_signature(ToyPublicKeys.pkcs1_v1_5, msg, signature, public_key)
118+
@test ToyPublicKeys.verify_signature(ToyPublicKeys.pkcs1_v1_5, msg, signature, public_key) == true
84119
end

0 commit comments

Comments
 (0)