Skip to content

Commit

Permalink
feat(app): CTF RSA-crack 支持d c e nbits参数
Browse files Browse the repository at this point in the history
  • Loading branch information
Leon406 committed Dec 16, 2022
1 parent d35c981 commit 13aa2f8
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 15 deletions.
70 changes: 55 additions & 15 deletions app/src/main/kotlin/me/leon/BigInteger.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package me.leon

import java.math.BigInteger
import java.math.BigInteger.ONE
import java.math.BigInteger.TWO
import java.util.*
import me.leon.ctf.rsa.THREE
import me.leon.ext.fromJson
import me.leon.ext.readFromNet

// this = p
fun BigInteger.phi(q: BigInteger) = (this - BigInteger.ONE) * (q - BigInteger.ONE)
fun BigInteger.phi(q: BigInteger) = (this - ONE) * (q - ONE)

fun BigInteger.lcm(other: BigInteger) = this * other / gcd(other)

fun BigInteger.mutualPrime(other: BigInteger) = gcd(other) == BigInteger.ONE
fun BigInteger.mutualPrime(other: BigInteger) = gcd(other) == ONE

// this = e
fun BigInteger.invert(phi: BigInteger): BigInteger = modInverse(phi)
Expand Down Expand Up @@ -45,8 +48,7 @@ fun List<BigInteger>.product(): BigInteger = reduce { acc, int -> acc * int }
fun List<BigInteger>.propN(n: BigInteger) =
filter { it < BigInteger.ZERO }.fold(n) { acc, bigInteger -> acc / bigInteger.abs() }

fun BigInteger.eulerPhi(n: Int) =
if (n == 1) minus(BigInteger.ONE) else minus(BigInteger.ONE) * pow(n - 1)
fun BigInteger.eulerPhi(n: Int) = if (n == 1) minus(ONE) else minus(ONE) * pow(n - 1)

fun getPrimeFromFactorDb(digit: BigInteger) = getPrimeFromFactorDb(digit.toString())

Expand All @@ -68,10 +70,10 @@ fun BigInteger.root(n: Int = 2): Array<BigInteger> {

val sig = this.signum()
val v = this.abs()
var high = BigInteger.ONE
var high = ONE
while (high.pow(n) <= v) high = high.shiftLeft(1)
var low = high.shiftRight(1)
var mid = BigInteger.ONE
var mid = ONE
var midCount = 0
while (low < high) {
mid = (low + high).shiftRight(1)
Expand All @@ -97,8 +99,8 @@ fun BigInteger.continuedFraction(another: BigInteger): MutableList<BigInteger> {

/** 渐进分数线 */
fun List<BigInteger>.convergent(): MutableList<Pair<BigInteger, BigInteger>> {
var (pbe, paf) = BigInteger.ZERO to BigInteger.ONE
var (qbe, qaf) = BigInteger.ONE to BigInteger.ZERO
var (pbe, paf) = BigInteger.ZERO to ONE
var (qbe, qaf) = ONE to BigInteger.ZERO
val convergent = mutableListOf<Pair<BigInteger, BigInteger>>()
for (int in this) {
pbe = paf.also { paf = int * paf + pbe }
Expand All @@ -117,8 +119,8 @@ fun BigInteger.wiener(n: BigInteger): BigInteger? {
return wienerPQ
}
println("wiener attack slow")
var q0 = BigInteger.ONE
val m = BigInteger.TWO
var q0 = ONE
val m = TWO
val c1 = m.modPow(this, n)
val convergent = this.continuedFraction(n).convergent()
for ((_, q1) in convergent) {
Expand Down Expand Up @@ -153,7 +155,7 @@ fun BigInteger.wienerPQ(n: BigInteger): BigInteger? {
// d[0] = 1
val q0 = x / y
val n0 = q0
val d0 = BigInteger.ONE
val d0 = ONE
var temp = x
x = y
y = temp.add(y.multiply(q0).negate())
Expand All @@ -163,7 +165,7 @@ fun BigInteger.wienerPQ(n: BigInteger): BigInteger? {
// n[1] = q[0] * q[1] + 1
// d[1] = q[1]
var qI = x / y
val n1 = q0 * qI + BigInteger.ONE
val n1 = q0 * qI + ONE
val d1 = qI
// i = 2
var dI2 = d0
Expand Down Expand Up @@ -211,7 +213,7 @@ fun BigInteger.wienerPQ(n: BigInteger): BigInteger? {
// phi(n) = (edg) / k
val phiN = this * guessDg / guessK
// (p+q)/2 = (pq - (p-1)*(q-1) + 1)/2
val pPlusQDiv2 = (n - phiN + BigInteger.ONE) / BigInteger.TWO
val pPlusQDiv2 = (n - phiN + ONE) / TWO
val subtract = pPlusQDiv2.pow(2).subtract(n)
if (subtract < BigInteger.ZERO) break
val root = subtract.root()
Expand All @@ -234,17 +236,55 @@ fun BigInteger.wienerPQ(n: BigInteger): BigInteger? {
/** 乘法逆元 (n * m) % p == 1. m = n^-1 =n % p */
fun BigInteger.multiplyInverse(modular: BigInteger): BigInteger {
val (gcd, x, _) = gcdExt(modular)
require(gcd == BigInteger.ONE) { "has no multiplicative inverse" }
require(gcd == ONE) { "has no multiplicative inverse" }
return x.mod(modular)
}

private val RANDOM = Random()

fun BigInteger.random(from: BigInteger = BigInteger.ONE): BigInteger {
fun BigInteger.random(from: BigInteger = ONE): BigInteger {
val bits = bitLength()
var r = BigInteger(bits, RANDOM)
while (r < from || r > this) {
r = BigInteger(bits, RANDOM)
}
return r
}

val FOUR = 4.toBigInteger()
val FIVE = 5.toBigInteger()
val SIX = 6.toBigInteger()
val SEVEN = 7.toBigInteger()
val EIGHT = 8.toBigInteger()
val MAP =
mapOf(
THREE to TWO,
FOUR to THREE,
FIVE to THREE,
SIX to FIVE,
SEVEN to FIVE,
)

/** todo performance */
fun BigInteger.preProbablePrime(): BigInteger {
if (this < EIGHT) return MAP[this]!!
var pre: BigInteger
val nn = (this / SIX) * SIX
if (this - nn <= ONE) {
pre = nn - ONE
if (pre.isProbablePrime(100)) {
return pre
}
pre -= FOUR
} else {
pre = nn + ONE
}
while (true) {
if (pre.isProbablePrime(100)) break
pre -= TWO
if (pre.isProbablePrime(100)) break
pre -= FOUR
}

return pre
}
29 changes: 29 additions & 0 deletions app/src/main/kotlin/me/leon/ctf/rsa/RsaSolver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package me.leon.ctf.rsa

import java.math.BigInteger
import kotlin.math.ln
import kotlin.math.pow
import me.leon.*
import me.leon.ext.findParallel

object RsaSolver {

private val modeNECP = listOf("n", "e", "c", "p")
private val modeNEC = listOf("n", "e", "c")
private val modeDEC_P_NEXT_Q = listOf("d", "e", "c", "nbits")
private val modeN2EC = listOf("n1", "n2", "e", "c")
private val modeNCD = listOf("n", "c", "d")
private val modePQREC = listOf("p", "q", "r", "e", "c")
Expand Down Expand Up @@ -48,6 +50,7 @@ object RsaSolver {
}
)
params.containKeys(modeDpDq) -> solveDpDq(params)
params.containKeys(modeDEC_P_NEXT_Q) -> solveDEC(params)
params.containKeys(modePQREC) || params.containKeys(modePQRnEC) -> solvePQREC(params)
params.containKeys(modeNCD) -> solveNCD(params)
params.containKeys(modeN2E2C2) -> solveN2E2C2(params)
Expand All @@ -67,6 +70,32 @@ object RsaSolver {
else -> error("wrong parameters!!!")
}

private fun solveDEC(params: MutableMap<String, BigInteger>): String {
println("solve D E C nbits")
val d = requireNotNull(params["d"])
val e = requireNotNull(params["e"])
val nLen = requireNotNull(params["nbits"]).toInt()
val kPhi = e * d - BigInteger.ONE
val kBits = kPhi.bitLength() - nLen

val kStart = 2.0.pow(kBits.toDouble() - 1.0).toInt()
val kEnd = 2.0.pow(kBits.toDouble()).toInt()
for (k in kEnd downTo kStart) {
if (kPhi % k.toBigInteger() == BigInteger.ZERO) {
val phi = kPhi / k.toBigInteger()
val p = phi.root(2).first().preProbablePrime()
val q = p.nextProbablePrime()
if (p.phi(q) == phi) {
println("got p=$p q =$q")
params["p"] = p
params["q"] = q
return solvePQEC(params)
}
}
}
return ""
}

private fun solvePQREC(params: MutableMap<String, BigInteger>): String {
println("solve P Q R E C")
val e = requireNotNull(params["e"])
Expand Down
6 changes: 6 additions & 0 deletions app/src/test/kotlin/me/leon/ctf/RsaTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,10 @@ class RsaTest {
val params = "rsa_amm2.txt".parseRsaParams()
println(solve(params))
}

@Test
fun dec() {
val params = "rsa_dec_p_next_q.txt".parseRsaParams()
assertEquals("NCTF{70u2_nn47h_14_v3ry_gOO0000000d}", solve(params))
}
}
4 changes: 4 additions & 0 deletions testdata/ctf/rsa/rsa_dec_p_next_q.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
d = 19275778946037899718035455438175509175723911466127462154506916564101519923603308900331427601983476886255849200332374081996442976307058597390881168155862238533018621944733299208108185814179466844504468163200369996564265921022888670062554504758512453217434777820468049494313818291727050400752551716550403647148197148884408264686846693842118387217753516963449753809860354047619256787869400297858568139700396567519469825398575103885487624463424429913017729585620877168171603444111464692841379661112075123399343270610272287865200880398193573260848268633461983435015031227070217852728240847398084414687146397303110709214913
c = 5382723168073828110696168558294206681757991149022777821127563301413483223874527233300721180839298617076705685041174247415826157096583055069337393987892262764211225227035880754417457056723909135525244957935906902665679777101130111392780237502928656225705262431431953003520093932924375902111280077255205118217436744112064069429678632923259898627997145803892753989255615273140300021040654505901442787810653626524305706316663169341797205752938755590056568986738227803487467274114398257187962140796551136220532809687606867385639367743705527511680719955380746377631156468689844150878381460560990755652899449340045313521804
e = 0x10001
nBits = 2048

0 comments on commit 13aa2f8

Please sign in to comment.