# 同态加密 (Homomorphic Encryption)
# 概念
是一种加密方式,用于在不使用密钥的情况下对加密数据进行计算,这种计算的结果仍然是加密的。拥有密钥的用户对经过同态加密处理过的加密数据进行解密后,得到的结果还是正确的原文信息。
# 分类
- 半同态加密 (Partially Homomorphic Encryption(PHE)):只支持加法或乘法中的一种运算
- 部分同态加密 (Somewhat Homomorphic Encryption (SHE)):支持同时进行加法和乘法运算,但运算次数有限制
- 全同态加密 (Fully Homomorphic Encryption (FHE)):支持任意次数的加法和乘法运算
# Paillier 半同态加密方案
# 介绍
Paillier 是一个支持加法同态的公钥密码系统
# Key Generation
- 随机选择两个独立的大素数 和,满足 并且 和 长度相同
- 计算 和
- 选择一个随机的整数,且满足 的阶是 的非零倍数,一般取
- 定义函数,然后计算\mu \equiv (L(g^{\lambda}\mod{n^2}))^{-1}\mod
公钥,私钥
# Encryption
- 假设 是要加密的消息,并且满足
- 选择一个随机的整数,满足
- 计算c\equiv g^mr^n\mod
# Decryption
- 让 是加密后的密文,c\in \mathbb{Z}_{n^2}^
- 计算m\equiv L(c^{\lambda}\mod{n^2})\mu\equiv \frac{L(c^{\lambda}\mod{n^2})}{L(g^{\lambda}\mod{n^2})}\mod
解密具体推导过程
前置知识:
-
,将 用二项式展开即可证明
- 令,可以化简为 $x\equiv \frac {y-1}{n}\mod {n} $
- 令,则
- 因此
-
卡麦尔函数 (函数)
-
定义:使得成立的最小正整数,其中,将记作
-
计算:将 算术分解得到,则
\lambda(n)=\text{lcm}(\lambda(p_1^{r_1}),\lambda(p_2^{r_2}),\cdots,\lambda(p_k^{r_k}))\\ \lambda(p^r)= \begin{cases} \phi(p^r)\quad \ \ \ p^r=2\or p^r=4\or p\gt 2\\ \frac{\phi(p^r)}{2} \quad \ \ \ \ p=2\and r\gt 2 \end{cases} \tag{1} -
令,则
在数域 中,,对于,有
-
-
解密推导
# 同态运算
-
明文同态加
-
明文同态乘
# ByteCTF2022_Compare
# Problem
from Crypto.Util.number import getPrime, getRandomNBitInteger, inverse | |
from fractions import Fraction | |
from gmpy2 import lcm | |
import re | |
N = 512 | |
safe_expr = re.compile(r'^([-+*/0-9.~%^&()=|<>]|and|or|not|MSG)+$') | |
def encode(m, n, g): | |
r = getRandomNBitInteger(N) | |
c = pow(g, m, n*n) * pow(r, n, n*n) % (n*n) | |
return c | |
def decode(c, n, l, u): | |
return int(Fraction(pow(c, l, n * n) - 1, n) * u % n) | |
def round(expr): | |
p = getPrime(N) | |
q = getPrime(N) | |
n = p * q | |
g = getRandomNBitInteger(N) | |
print('n =', n) | |
print('g =', g) | |
a = getRandomNBitInteger(N) | |
b = getRandomNBitInteger(N) | |
print('a =', encode(a, n, g)) | |
print('b =', encode(b, n, g)) | |
msg = int(input("msg = ")) | |
l = int(lcm(p - 1, q - 1)) | |
u = inverse(Fraction(pow(g, l, n * n) - 1, n), n) | |
return (a > b) is bool(eval(expr, None, {'MSG': decode(msg, n, l, u)})) | |
def main(): | |
expr = input('Hello, Give me your expr: ') | |
expr = re.sub(r'\s', '', expr) | |
if safe_expr.match(expr) is None: | |
raise Exception('Hacker?') | |
for i in range(100): | |
print('Round:', i) | |
try: | |
assert round(expr) | |
except: | |
print('You lost.') | |
break | |
else: | |
print('Congratulations!') | |
print(open('/flag').read()) | |
if __name__ == '__main__': | |
main() | |
# ByteCTF{ed4dad6f-45a4-41bf-a538-fd5d0754b3df} |
# Solve
这里讲一下 eval()
的用法, eval(exp,globals,locals)
用来执行一个字符串表达式即 exp
,并返回表达式的值, exp
里面的变量可以在 locals
里面用字典来声明并计算
在本题中, eval
展开就是
eval('MSG < 2**512',None,{'MSG':decode(msg, n, l, u)}) |
先计算出 MSG
的值,然后带入 MSG<2*512
来返回表达式的值
在本题中,可以明显看到就是一个 加密,然而只有见过才知道,然后这里的 就是,题目每次给出 和公钥,需要用户输入一个 msg
,程序对 msg
解密后带回表达式要和 a>b
同真假
根据同态得到D(c_1\cdot c_2^{-1}\mod{n^2})\equiv m_1-m_2\mod
如果,那么,而 和一般很接近,所以可以认为这个差值不会太大
而如果,那么,注意到,而 不会太大,所以 在这种情况下会很大
所以我们可以选择一个数,如果,说明,反之说明
from Crypto.Util.number import * | |
from pwn import * | |
p=remote('e9ce6445e564ac67295cb28d2c5692b2.2022.capturetheflag.fun',1337, ssl=True) | |
context.log_level='debug' | |
p.recvuntil("expr: ") | |
p.sendline("MSG < 2**512") | |
for i in range(100): | |
p.recvuntil("n = ") | |
n=int(p.recvline(False),10) | |
p.recvuntil("a = ") | |
a=int(p.recvline(False),10) | |
p.recvuntil("b = ") | |
b=int(p.recvline(False),10) | |
msg=a*inverse(b,n**2)%(n**2) | |
p.recvuntil("msg = ") | |
p.sendline(str(msg)) | |
p.interactive() | |
#ByteCTF{ed4dad6f-45a4-41bf-a538-fd5d0754b3df} |