This is a symmetric encryption method based on an arbitrary hash function h
.
It's not particularly efficient, but easy to remember and implement.
Each character in a plaintext str
is encrypted like so:
cipher[i] = h(str[i] + i + key + nonce)
Each component exists because:
str[i]
is the data to be encryptedi
is relevant so two equal characters at different positions in the ciphertext are not known to be equalkey
can produce and reproduce ciphertextnonce
is relevant so two equal characters at same positions in different ciphertexts are not known to be equal,
it needs to be unique for each ciphertextThe nonce must be extractable out of the ciphertext or communicated through another channel:
cipher[-1] = nonce
Therefore it should probably just be randomly generated and not reveal anything about anything.
(Another option for nonce would be h(str)
,
but that would reveal h(str)
which might be undesirable in certain situations)
But how can I decrypt?
h
is a one-way function.
Yes, but if you have the ciphertext and key:
i
is knownkey
is knownnonce
is knowncipher[i]
is knownAnd while str[i]
is technically unknown,
it can only be one of 256 values
(if the alphabet is bytes).
So, you can just try
h(? + i + key + nonce)
at most 256 times,
until you get cipher[i]
.
And once you get cipher[i]
,
you know what str[i]
is.
Repeat that for each i
and you'll get the plaintext.
h
requirementsI don't think h
needs to be anything special:
If the input changes slightly, the sum should change dramatically, but that's implied by "one-way" anyway, right?
If the output is large, the ciphertext will be very large. The ciphertext will always be quite a bit larger than the plaintext.
Let's say:
# nonce should be larger and doesn't have to be hexadecimal ASCII, this is just an example
nonce=$(</dev/urandom head -c 8 | xxd -p)
# key should also be much more secure
key=password123
# space seperated characters, so we can use shell for loops
plaintext="h e l l o"
The following script prints the ciphertext to stdout.
echo $nonce
i=0
for str_i in $plaintext
do
sha256sum <<<"$str_i $i $key $nonce"
i=$(( $i + 1 ))
done
The ciphertext:
676af7cc8d0c0653
53a05dbfafe643b54e9650e643abb66496edf1ede586663d96e992b6d7d41667 *-
2d4e6396a4767761a204810571c11bb2177ae2f98ca8904674bd90967a80f995 *-
2986ad39d030223b5a0ea61992a62bcc1471fd23568edf6ac9edd4db920def58 *-
aeb25f6df961a4e8b20bfb48071849076a81ed9dae32cf151073a94ec8122331 *-
543fe09195ca4da20b96301b85df8efbde2503f9b58554b6a21fda7a734d6ac2 *-
Now, I won't write a shell script for decrypting - it would be much less tedious in a real programming language.
But just to illustrate, lets attempt to decrypt the fifth character:
$ sha256sum <<<"m 4 password123 676af7cc8d0c0653"
486539f9640623fc6b6e534898da1075d496ac897f25ae50428ce4b682b37e58 *-
$ sha256sum <<<"n 4 password123 676af7cc8d0c0653"
e99154b69ccef255c20c345457cded86066e71049cd912609a80c9ac857437d0 *-
$ sha256sum <<<"o 4 password123 676af7cc8d0c0653"
543fe09195ca4da20b96301b85df8efbde2503f9b58554b6a21fda7a734d6ac2 *-
Oh wow, we've seen 543fe091...
before!
str[4]
must be 'o'.