Vigenere Cipher
From PostgreSQL wiki
Jump to navigationJump to search
This is a simple implementation of an extended multialphabetic substitution Cipher leaned on the Vigenere Cipher. Plain text and key are transformed to base64 before encrypting, making it suitable for all encodings. The Vigenere Cipher is not suitable for usage as alternative to modern cryptographic algorithms. It is purely for fun.
CREATE OR REPLACE FUNCTION public.vigenere_encrypt (
p_plain_text TEXT,
p_key TEXT
)
RETURNS TEXT
AS $$
DECLARE
v_alphabet TEXT := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
v_tab TEXT[] := regexp_split_to_array(v_alphabet,'');
v_mod INTEGER := length(v_alphabet);
v_key TEXT[];
v_plain_text TEXT[];
v_enc TEXT := '';
v_i INTEGER;
t_i INTEGER;
e_i INTEGER;
k_i INTEGER;
v_dec TEXT := '';
BEGIN
IF length(p_plain_text) = 0 THEN RETURN '';
END IF;
-- Text to base 64 without padding
v_plain_text := regexp_split_to_array(replace(replace(encode(convert_to(p_plain_text,'utf8')::BYTEA, 'base64'::TEXT),E'\n',''),'=',''), '');
-- Key to base 64 without padding
v_key := regexp_split_to_array(replace(replace(encode(convert_to(p_key,'utf8')::BYTEA, 'base64'::TEXT),E'\n',''),'=',''),'');
FOR v_i IN 0..(array_length(v_plain_text,1) - 1)
LOOP
t_i := position(v_plain_text[1 + v_i] IN v_alphabet) - 1;
k_i := position(v_key[1 + v_i % array_length(v_key, 1)] IN v_alphabet) - 1;
e_i := (t_i + k_i) % v_mod;
v_enc := v_enc || v_tab[1 + (t_i + k_i) % v_mod];
v_i := v_i + 1;
END LOOP;
RETURN v_enc;
END;
$$ LANGUAGE plpgsql
IMMUTABLE;
CREATE OR REPLACE FUNCTION public.vigenere_decrypt(
p_enc_text TEXT,
p_key TEXT
)
RETURNS TEXT
AS $$
DECLARE
v_alphabet TEXT := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
v_tab TEXT[] := regexp_split_to_array(v_alphabet,'');
v_mod INTEGER := length(v_alphabet);
v_key TEXT[];
v_enc_text TEXT[];
v_i INTEGER;
t_i INTEGER;
k_i INTEGER;
v_dec TEXT := '';
BEGIN
IF length(p_enc_text) = 0 THEN RETURN '';
END IF;
v_enc_text := regexp_split_to_array(p_enc_text, '');
-- Key to base 64 without padding
v_key := regexp_split_to_array(replace(replace(encode(convert_to(p_key,'utf8')::BYTEA, 'base64'::TEXT),E'\n',''),'=',''),'');
FOR v_i IN 0..(array_length(v_enc_text,1) - 1)
LOOP
t_i := position(v_enc_text[1 + v_i] IN v_alphabet) - 1;
k_i := position(v_key[1 + v_i % array_length(v_key, 1)] IN v_alphabet) - 1;
v_dec := v_dec || v_tab[1 + ((t_i - k_i + CASE WHEN t_i < k_i THEN v_mod ELSE 0 END) % v_mod)];
v_i := v_i + 1;
END LOOP;
RETURN convert_from(decode(rpad(v_dec, (4 * ceiling(length(v_dec)::NUMERIC / 4.0))::INTEGER, '=')::TEXT,'base64'::TEXT),'utf8');
END;
$$ LANGUAGE plpgsql
IMMUTABLE;
Usage
db=> select * from public.vigenere_encrypt('Non parlo italiano. Я не говорю по-русски. Γνῶθι σεαυτόν.','terra γαμμαβετα Россия');
vigenere_encrypt
----------------------------------------------------------------------------------------------------------------------
wsSgktFBPRA90ifwLBk3Eyzh+NafM+9B3qEV8Y9EUoBRg4lPXIgX4Uf2zd1parycuUC8Trydu9e7FRZstaXbx+6Ko9aV5sYrWJy+KiPjPebvU3NafHuq
(1 row)
db=> select * from public.vigenere_decrypt('wsSgktFBPRA90ifwLBk3Eyzh+NafM+9B3qEV8Y9EUoBRg4lPXIgX4Uf2zd1parycuUC8Trydu9e7FRZstaXbx+6Ko9aV5sYrWJy+KiPjPebvU3NafHuq','terra γαμμαβετα Россия');
vigenere_decrypt
-----------------------------------------------------------
Non parlo italiano. Я не говорю по-русски. Γνῶθι σεαυτόν.
(1 row)
Caution
This kind of cipher is not secure enough to be used in a critical situation. Use it only for fun.