Skip to content

Instantly share code, notes, and snippets.

@luatnd
Last active April 7, 2024 10:37
Show Gist options
  • Save luatnd/1adec00e1c5086ff6767ae681be20c47 to your computer and use it in GitHub Desktop.
Save luatnd/1adec00e1c5086ff6767ae681be20c47 to your computer and use it in GitHub Desktop.
Caesar cypher with password - simple method for storing password, private key, mnemonic

mxn0 encrypt with password

Note: This was deprecated, please use this instead: https://luatnd.github.io/caesar-password/

The simple encrypt by combining simple encoding + password method:

  • phrase was split into words by space seperator: "hello world this is an example" => ['hello', 'world', 'this', 'is', 'an', 'example']

  • words will be encoded by a customized caesar cypher encoding:

    supported_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

    password = "your free password"

  • encode by base64: '.....'

  • finish => Save this info into your cloud file for safety.

Security: Caesar can be bruteforce, but with your strong password, it's hard to be brute force

// TODO: Make a public website to host this
(function main() {
	plain_text = "this is your mnemonic word phrases"
	password = 'TestMyP@ss_complex'

	const encoded_text = encode_all(plain_text, password)
	const decoded_text = decode_all(encoded_text, password)
	console.log('plain_text, decoded_text, encoded_text: ', "\n", plain_text, "\n", decoded_text, "\n", encoded_text)
	console.assert(plain_text === decoded_text, {plain_text, decoded_text, encoded_text})
	console.log("This is your encoded phrases, please save it to your cloud file, should not share it for everyone else: ", encoded_text)
	console.log("Must not and never share this password for anyone, you're the only one who know this: ", password)
	console.log("If you need the plain mnemonic phrase to import it to another wallet, use this function to show your mnemonic: decode_all(your_encoded_phrases, your_password)")
})()

(function test() {
	test_special_chars = '_+--=~!@#$%^&* ()__â ơ ê ỉ ắ á';
	plain_text = "Hello world w3 @re the best of gen Y abcdefghijklmnopqrstuvwxyz1234567890"
	plain_text += test_special_chars;
	password = 'TestMyP@ss_complex'

	const encoded_text = encode_all(plain_text, password)
	const decoded_text = decode_all(encoded_text, password)
	console.log('plain_text, decoded_text, encoded_text: ', "\n", plain_text, "\n", decoded_text, "\n", encoded_text)
	console.assert(plain_text === decoded_text, {plain_text, decoded_text, encoded_text})
})()


function encode_all(all_word_string, password) {
	plains = all_word_string.split(' ')
	encodes = []
	plains.forEach(plain => {
		let encoded, decoded;
		
		// Encode latin word only
		if (isLatinOnly(plain)) {
			encoded = pass_encode(plain, password);
		    decoded = pass_decode(encoded, password);
		} else {
			encoded = plain
			decoded = plain
		}
	    
	    encodes.push(encoded)
	    const fn = plain === decoded ? console.info : console.error;
		fn(`"${plain}", "${encoded}", "${decoded}"`)	   
	})
	return encodes.join(' ')
}

function decode_all(all_decoded_string, password) {
	decoded_words = all_decoded_string.split(' ')
	plains = []
	decoded_words.forEach(encoded => {
		let plain;
		if (isLatinOnly(encoded)) {
		    plain = pass_decode(encoded, password);
		}
		else {
			plain = encoded
		}
	    plains.push(plain)
	    console.log(`"${encoded}", "${plain}"`)
	})

	return plains.join(' ')
}


// only supported_chars was encoded
function pass_encode(plain_text, password) {
	return base64_encode(caesar_cypher_with_password(plain_text, password))
}
function pass_decode(encoded_text, password) {
	return caesar_cypher_with_password(base64_decode(encoded_text), password, true)
}

function caesar_cypher_with_password(plain_text, password, decoding = false) {
	const supported_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
	const supported_chars_indexes = toReverseDict(supported_chars);
	/**
    * encode/decode a single char
    * shift can be negative
    */
	function caesar_cypher(char, shift) {
		const prev_idx = supported_chars_indexes[char]
	    const new_idx = (prev_idx + shift + supported_chars.length) % supported_chars.length;
	    return supported_chars[new_idx];
	}
	function makeShiftValues(password) {
	    const shifts = [];
	    for(let i = 0, c = password.length; i < c; i++) {
	        const charCode = supported_chars_indexes[password[i]];
	        const shift = (charCode ?? 0) % supported_chars.length;
	        shifts.push(shift);
	    }
	    return shifts;
	}
	// console.log('makeShiftValues', makeShiftValues(supported_chars + est_special_chars))
	
	/*
	* encode plain text with multiple shift values
	* In case of single shift: shifts = [shift_value]
	*/
	function caesar_cypher_with_shifts(plain_text, shifts) {
		let encoded = '';
	    if (!shifts.length) shifts.push(0); // no password mean not shifting
		
		for(let i =  0, c = plain_text.length; i < c; i++) {  
			const char = plain_text[i];
			if (char in supported_chars_indexes) {
				const shift = shifts[i % shifts.length]
				encoded += caesar_cypher(char, shift)
			} else {
	            // console.log('skip')
				encoded += char;
			}
		}

		return encoded;
	}

    let shifts = makeShiftValues(password);

    // shift of decoding is reversed compared to encoding
    if (decoding) {
		shifts = shifts.map(i => -i);
	}
	
    return caesar_cypher_with_shifts(plain_text, shifts)
}


function toReverseDict(arr) {
    const dict = {}
    for(let i = 0, c = arr.length; i < c; i++) dict[arr[i]] = i;
    return dict;
}
function base64_encode(plain) {
	return btoa(plain)
}
function base64_decode(encoded) {
	return atob(encoded)
}
function isLatinOnly(s) {
	for(let i = 0, c = s.length; i < c; i++) {
		if (s.charCodeAt(i) > 255) return false;
	}
	return true;
}
@luatnd
Copy link
Author

luatnd commented Mar 4, 2023

Why using this:

  • It's simple and can be encoded/decoded with your pen and paper, so you don't need to remember the web page / online tool you used to encode/decode
  • Large entropy because of using your password, no one can decode it except you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment