ASecuritySite: When Bob Met Alice

This publication brings together interesting articles related to cyber security.

Living With A Dictator: Anamorphic Cryptography

7 min readApr 19, 2025

--

Last week, I spent an amazing hour speaking with the mighty Moti Yung [here], and who outlined the usage of anamorphic cryptography:

and who, in 2022, published a classic paper of [here]:

With anamorphic images, we can move to a different view and see a different image. For example [here]:

In cybersecurity, we can use anamorphic cryptography to change the viewpoint of a cipher. With this, we assume that we have a dictator who will read all of our encrypted data, and will thus have a secret key of sk. The dictator (Mallory) will arrest anyone who sends secret messages that they cannot read. For this, Bob could create two secret keys: sk0 and sk1. He sends sk0 to Mallory and sk1 to Alice (the person that Bob wants to send a secret message to). As far as Mallory knows, he has the only key for the ciphertext.

We then have a public key of Pk and two private keys of sk0 and sk1. Bob then has two messages:

msg0="I love the Dictator"
msg1="I hate the Dictator"

Bob then encrypts the two messages with the public key:

CT=Enc(pk,msg0, msg1)

The Dictator will then decrypt with sk0 and reveal the first message:

Dec(sk0,CT) -> m0

Alice will decrypt with her key and reveal the second message:

Dec(sk1,CT)-> m1

And, so, the Dictator thinks that they can decrypt the message, and gets, “I love the Dictator”. Alice, though, is able to decrypt the ciphertext to a different message of “I hate the Dictator”.

There are some methods which support the creation of anamorphic encryption, such as RSA-OAEP, Pailler, Goldwasser-Micali, ElGamal schemes, Cramer-Shoup, and Smooth Projective Hash-based systems [here]. In this case, we will use the ElGamal method.

ElGamal

With the ElGamal method, we create a secret key of sk, and then a public key of:

and where g is the base of the discrete logarithm and p is a prime number. For a message of m, the cipher is then:

To decrypt, we perform:

The paper in [2] then defines the ElGamal method for anamorphic cryptography with:

The sample code is [here}:

import random
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

class PublicParams:
def __init__(self, p, q, g):
self.p = p
self.q = q
self.g = g

class AnamParams:
def __init__(self, l, s, t):
self.F = lambda pp, K, x, y: \
int.from_bytes(AES.new(K, AES.MODE_ECB) \
.encrypt(x.to_bytes(8, 'little') \
+ y.to_bytes(8, 'little')), "little") % pp.p
self.d = lambda ap, x: x % ap.t
self.l = l
self.s = s
self.t = t

class KeyPair:
def __init__(self, sk, pk):
self.sk = sk
self.pk = pk

class DoubleKey:
def __init__(self, K, T, pk):
self.K = K
self.T = T
self.pk = pk

def Gen(pp):
sk = random.randint(0, pp.q - 1)
pk = pow(pp.g, sk, pp.p)
return KeyPair(sk, pk)

def Enc(pp, pk, msg):
r = random.randint(0, pp.q - 1)
c0 = (msg * pow(pk, r, pp.p)) % pp.p
c1 = pow(pp.g, r, pp.p)
return c0, c1

def Dec(pp, sk, c):
return (c[0] * pow(c[1], -sk, pp.p)) % pp.p

def aGen(pp, ap, pk):
K = get_random_bytes(16)
T = dict()
for i in range(ap.l):
T[pow(pp.g, i, pp.p)] = i
return DoubleKey(K, T, pk)

def aEncCtr(pp, ap, dk, msg, cm, ctr):
found = False
for x in range(ctr[0], ap.s):
for y in range(ctr[1], ap.t):
t = ap.F(pp, dk.K, x, y)
r = (cm + t) % pp.q
if ap.d(ap, pow(pp.g, r, pp.p)) == y:
found = True
break
if found:
break
ctr[1] = 0
ctr[0] = (x + (1 if y == ap.t - 1 else 0)) % ap.s
ctr[1] = (y + 1) % ap.t
c0 = (msg * pow(dk.pk, r, pp.p)) % pp.p
c1 = pow(pp.g, r, pp.p)
ctx = (c0, c1)
return ctx, ctr

def aEnc(pp, ap, dk, msg, cm):
while True:
x = random.randint(0, ap.s - 1)
y = random.randint(0, ap.t - 1)
t = ap.F(pp, dk.K, x, y)
r = (cm + t) % pp.q
if ap.d(ap, pow(pp.g, r, pp.p)) == y:
break
c0 = (msg * pow(dk.pk, r, pp.p)) % pp.p
c1 = pow(pp.g, r, pp.p)
ctx = (c0, c1)
return ctx

def aDec(pp, ap, dk, ctx):
y = ap.d(ap, ctx[1])
for x in range(ap.s):
t = ap.F(pp, dk.K, x, y)
s = (ctx[1] * pow(pp.g, -t, pp.p)) % pp.p
if s in dk.T:
return dk.T[s]
return -1

# Settings
runs = 1

# Public Parameters (safe prime, pow(g, (p - 1) // 2, p) != 1)
#p, g = int("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1\
#29024E088A67CC74020BBEA63B139B22514A08798E3404DD\
#EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245\
#E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED\
#EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381\
#FFFFFFFFFFFFFFFF", 0), 5 # Oakley group (RFC 2409)
p, g = 1000000007, 5
q = p - 1
pp = PublicParams(p, q, g)
print("p =", pp.p)
print("q =", pp.q)
print("g =", pp.g)

# Anamorphic Parameters
l = 100
s = 100
t = 100
ap = AnamParams(l, s, t)
print("l =", ap.l)
print("s =", ap.t)
print("t =", ap.s)

# Keys Generation
kp = Gen(pp)
dk = aGen(pp, ap, kp.pk)
print("(sk, pk) = (%d, %d)" % (kp.sk, kp.pk))
print("K =", dk.K)
print("T = [", ", ".join(str(a) + "->" + str(b) for (a,b) in \
sorted([((pp.g ** i) % pp.p, i) for i in range(l)])), ']')

# Testing aEnc -> Dec and aEnc -> aDec
msg = random.randint(1, pp.p - 1)
cm = random.randint(0, l - 1)
#ctr = [0, 0]
for i in range(runs):
#c, ctr = aEncCtr(pp, dk, msg, cm, ctr)
ctx = aEnc(pp, ap, dk, msg, cm)
msg_ = Dec(pp, kp.sk, ctx)
cm_ = aDec(pp, ap, dk, ctx)
print("(%d, %d) -> aEnc -> (%d, %d) -> Dec -> %d" \
% (msg, cm, ctx[0], ctx[1], msg_))
print("(%d, %d) -> aEnc -> (%d, %d) -> aDec -> %d" \
% (msg, cm, ctx[0], ctx[1], cm_))

# Testing Enc -> Dec and Enc -> aDec
for i in range(runs):
m = random.randint(1, pp.p - 1)
ctx = Enc(pp, kp.pk, m)
msg_ = Dec(pp, kp.sk, ctx)
cm_ = aDec(pp, ap, dk, ctx)
print("%d -> Enc -> (%d, %d) -> Dec -> %d" \
% (m, ctx[0], ctx[1], msg_))
print("%d -> Enc -> (%d, %d) -> aDec -> %d" \
% (m, ctx[0], ctx[1], cm_), "(!)" if cm_ != -1 else "")

A sample run is:

p = 1000000007
q = 1000000006
g = 5
l = 100
s = 100
t = 100
(sk, pk) = (808381696, 432452453)
K = b'\x8a\x96\xbe\x94:\x1d\x9a\x0e`1|?\x16D]N'
T = [ 1->0, 5->1, 25->2, 125->3, 625->4, 3125->5, 15625->6, 78125->7, 390625->8, 1953125->9, 9765625->10, 18207916->80, 26761407->94, 27912589->38, 48828125->11, 55390767->72, 91039580->81, 96145664->77, 102694758->31, 103515583->14, 110488626->68, 133807035->95, 134200073->44, 139562945->39, 154865266->21, 171376783->64, 184223302->35, 220538953->30, 220703118->13, 226840016->43, 234275358->63, 244107792->29, 244140625->12, 246855073->62, 249371016->61, 275989486->83, 276953835->73, 284419547->66, 335688566->89, 339598996->57, 345175854->97, 355001804->46, 358158117->24, 375225192->49, 379947423->84, 380629737->51, 384769168->74, 392214094->91, 403641586->79, 422097728->67, 430973056->20, 445368006->42, 449874206->60, 455197900->82, 467137716->88, 467919802->56, 480728320->78, 486194614->19, 489073604->41, 489974844->59, 493427546->87, 498685512->86, 513473790->32, 515743362->53, 517577915->15, 552443130->69, 567368936->33, 578716796->54, 587889561->16, 605582522->37, 619229137->76, 629396294->99, 669035175->96, 671000365->45, 678442823->90, 697238927->18, 697814725->40, 697994973->58, 725879263->98, 762215636->70, 769764317->27, 774326330->22, 775009013->47, 790790578->25, 805352287->93, 811078159->71, 836844666->34, 848821564->28, 856883915->65, 871631629->23, 875045044->48, 876125953->50, 893583966->55, 899737108->85, 903148678->52, 921116510->36, 923845833->75, 939447791->17, 953952869->26, 961070463->92 ]
(4, 2) -> aEnc -> (929257589, 695009996) -> Dec -> 4
(4, 2) -> aEnc -> (929257589, 695009996) -> aDec -> 2
451787795 -> Enc -> (749003435, 140907022) -> Dec -> 451787795
451787795 -> Enc -> (749003435, 140907022) -> aDec -> -1

In this case, Message 1 is 4, and Message 2 is 2. When we decrypt, we get 4, but when we anamorphically decrypt, we get 2.

You can run the code here:

Conclusions

If you have time, please go and listen to Moti:

Spotify: https://open.spotify.com/episode/0zsjAewJt8YnlB6g5Q1eZm?si=b6483c6f33df4285

Apple: https://podcasts.apple.com/gb/podcast/asecuritysite-podcast/id1617044319?i=1000703484352

References

[1] Persiano, G., Phan, D. H., & Yung, M. (2022, May). Anamorphic encryption: private communication against a dictator. In Annual International Conference on the Theory and Applications of Cryptographic Techniques (pp. 34–63). Cham: Springer International Publishing.

[2] Banfi, F., Gegier, K., Hirt, M., Maurer, U., & Rito, G. (2024, May). Anamorphic encryption, revisited. In Annual International Conference on the Theory and Applications of Cryptographic Techniques (pp. 3–32). Cham: Springer Nature Switzerland.

--

--

ASecuritySite: When Bob Met Alice
ASecuritySite: When Bob Met Alice

Published in ASecuritySite: When Bob Met Alice

This publication brings together interesting articles related to cyber security.

Prof Bill Buchanan OBE FRSE
Prof Bill Buchanan OBE FRSE

Written by Prof Bill Buchanan OBE FRSE

Professor of Cryptography. Serial innovator. Believer in fairness, justice & freedom. Based in Edinburgh. Old World Breaker. New World Creator. Building trust.

Responses (3)