• There are lots of bad keys, of the form A^n/B^m, where A, B, n, and m are integers.
  • A known plaintext recovers the keystream. With a little work, it could possibly recover the key, but only for very long plaintexts.
  • The key cannot be re-used. Given 2 ciphertexts encrypted with the same key, add them (mod 6 digitwise). This gives plaintext 1 + plaintext 2. It's pretty easy to recover the texts from this - there aren't that many possibile ways for 2 meaningful English text streams to be combined to form a given stream.
  • Similar (numerically almost equal) keys will give streams with the same set of initial digits. This can be trivially fixed by simply ignoring the first 15 or so digits.

    ERIKO-CHAN is an obscure and weak symmetric stream cipher. The only reason I know of its existence is first through novalis's writeup in this node, and then a handful of messages about it on a cryptography mailing list. Was it created by a paranoid or mathematically-inclined Japanophile fangirl or boy? Did e intend to erode the foundations of our dichotic gender paradigm through eir transgression, following in the tradition of the great Alan Turing? How many vampires still live in Transylvania? This is becoming a digression.

    Operation

    Key: a twenty digit (or more) random number (whose square root is irrational)

    Encipher the message with a standard 6x6 Polybius square (see that node for an example, but in short: A-Z and 0-9, in six lines horizontally) with the rows and columns labelled from 0 to 5.

    Calculate the square root of the key and, beginning at the first digit after the decimal place, copy each digit which is within the range 0-5 until you have the same number of digits as in your message.

    Add (modulo 6) the message and key streams. This is the ciphertext to be sent to your partner in crime.

    Notes

    Layer on a transposition cipher to make it more secure.

    Don't use the same key more than once. Subtracting two ciphertexts encrypted with the same key yields two plaintexts mashed together, which is not difficult to crack.

    I don't know why keys of the form A^n/B^m might be bad, as novalis suggests. As long as their square roots are irrational, they should work fine, right?

    It may be possible to recover the key by knowing a short stretch of the square root stream and then using continued fractions. I have no idea if that's true.

    Conclusion

    This is probably kid sister encryption.

    ERIKO-CHAN in Python

    OldMiner points out that Python has built-in support for taking the square root to arbitrary precision, so here's a full implementation of ERIKO-CHAN. (See also my original sqrt function below.)

    import decimal, re
    
    def encrypt(message, key): return erikochan(message, key, True)
    def decrypt(message, key): return erikochan(message, key, False)
    
    def erikochan(input, key, encrypt):
    	# normalize the input
    	input = re.sub(r'[^0-9a-z]+', '', input.lower())
    	
    	# get the key stream
    	k = 1
    	keystream = []
    	while len(keystream) < len(input) * 2:
    		k += 1
    		decimal.getcontext().prec = len(input) * 2 * k
    		keystream = str(decimal.Decimal(key).sqrt()).split('.')[1]
    		keystream = map(int, re.sub(r'[6-9]+', '', keystream))
    	
    	# encrypt
    	k = 0
    	output = ''
    	for c in input:
    		if c in '0123456789': c = ord(c) - ord('0') + 26
    		else: c = ord(c) - ord('a')
    		a = c / 6
    		b = c % 6
    		if encrypt:
    			a = (a + keystream[k]) % 6
    			b = (b + keystream[k+1]) % 6
    		else:
    			a = (a - keystream[k]) % 6
    			b = (b - keystream[k+1]) % 6
    		k += 2
    		c = a * 6 + b
    		if c < 26: c = chr(c + ord('a'))
    		else: c = chr(c - 26 + ord('0'))
    		output += c
    	return output
    

    Taking the Square Root to Arbitrary Precision in Python (the hard way)

    import re
    
    def sqrt(n):
    	'yields the number before the decimal place,\
    	followed by one yield for each digit afterward'
    	
    	n = str(n)
    	assert re.match(r'[0-9]*(\.[0-9]*)?$', n), 'number too funky---pass it as a string without scientific notation, like "123456789.0123456789"'
    	
    	if '.' in n: a, b = n.split('.')
    	else: a, b = n, ''
    	if len(a) % 2: a = '0' + a
    	if len(b) % 2: b += '0'
    	lst = map(int, re.findall('..', a) + re.findall('..', b))
    	dec = len(a) / 2  # decimal pt is before this element in lst
    	i = 0
    	r = 0
    	p = 0
    	while 1:
    		if i >= len(lst): c = r * 100
    		else: c = r * 100 + lst[i]
    		i += 1
    		
    		y = [(x, (20 * p + x) * x) for x in range(10)]
    		# get largest y not exceeding c
    		x, y = [(x, y) for x, y in y if y <= c][-1]
    		
    		p = 10 * p + x
    		r = c - y
    		
    		if i == dec: yield p
    		elif i > dec: yield x
    		if r == 0 and i >= len(lst): return
    
    def example():
    	import math
    	n = 12345678901234567890
    	g = sqrt(n)
    	print n
    	print math.sqrt(n)
    	for i in range(20): print g.next(),
    	print
    

    See Also

    Log in or register to write something here or to contact authors.