Encrypt a number to another number of the same length

I need a way to make a 12-digit number and encrypt it to another 12-digit number (without characters other than 0123456789). Then at a later point I will need to decrypt the encrypted number to the original number.

It is important that this is not obvious if 2 encrypted numbers are in order. So, for example, if I encrypt 0000000000001, it should look completely different if it is encrypted than 000000000002. It should not be the most secure in the world, but the safer the better.

I looked around a lot, but did not find anything suitable. From what I saw, some type of XOR might be the easiest way, but I'm not sure how to do it.

Thanks Jim

+4
source share
6 answers

I decided to solve this problem thanks to you guys using "FPE from the Prefix Cipher" from the wikipedia page http://en.wikipedia.org/wiki/Format-preserving_encryption . I will give the basic steps below, I hope it will be useful for someone in the future.

NOTE. I am sure that any expert will tell you that it is a hack. The numbers seemed random, and it was safe enough for what I needed, but if security is very important, use something else. I am sure that experts can point out what I have done. My only goal for posting this is that I would find it useful when doing a search for an answer to a problem. Also use this only in situations where it cannot be decompiled.

I was going to post the steps, but there are too many to explain. I will just send my code. This is my proof of concept code, which I still need to clear, but you get this idea. Please note that my code refers to a 12-digit number, but setting up for others should be simple. Max is probably 16 with how I did it.

public static string DoEncrypt(string unencryptedString) { string encryptedString = ""; unencryptedString = new string(unencryptedString.ToCharArray().Reverse().ToArray()); foreach (char character in unencryptedString.ToCharArray()) { string randomizationSeed = (encryptedString.Length > 0) ? unencryptedString.Substring(0, encryptedString.Length) : ""; encryptedString += GetRandomSubstitutionArray(randomizationSeed)[int.Parse(character.ToString())]; } return Shuffle(encryptedString); } public static string DoDecrypt(string encryptedString) { // Unshuffle the string first to make processing easier. encryptedString = Unshuffle(encryptedString); string unencryptedString = ""; foreach (char character in encryptedString.ToCharArray().ToArray()) unencryptedString += GetRandomSubstitutionArray(unencryptedString).IndexOf(int.Parse(character.ToString())); // Reverse string since encrypted string was reversed while processing. return new string(unencryptedString.ToCharArray().Reverse().ToArray()); } private static string Shuffle(string unshuffled) { char[] unshuffledCharacters = unshuffled.ToCharArray(); char[] shuffledCharacters = new char[12]; shuffledCharacters[0] = unshuffledCharacters[2]; shuffledCharacters[1] = unshuffledCharacters[7]; shuffledCharacters[2] = unshuffledCharacters[10]; shuffledCharacters[3] = unshuffledCharacters[5]; shuffledCharacters[4] = unshuffledCharacters[3]; shuffledCharacters[5] = unshuffledCharacters[1]; shuffledCharacters[6] = unshuffledCharacters[0]; shuffledCharacters[7] = unshuffledCharacters[4]; shuffledCharacters[8] = unshuffledCharacters[8]; shuffledCharacters[9] = unshuffledCharacters[11]; shuffledCharacters[10] = unshuffledCharacters[6]; shuffledCharacters[11] = unshuffledCharacters[9]; return new string(shuffledCharacters); } private static string Unshuffle(string shuffled) { char[] shuffledCharacters = shuffled.ToCharArray(); char[] unshuffledCharacters = new char[12]; unshuffledCharacters[0] = shuffledCharacters[6]; unshuffledCharacters[1] = shuffledCharacters[5]; unshuffledCharacters[2] = shuffledCharacters[0]; unshuffledCharacters[3] = shuffledCharacters[4]; unshuffledCharacters[4] = shuffledCharacters[7]; unshuffledCharacters[5] = shuffledCharacters[3]; unshuffledCharacters[6] = shuffledCharacters[10]; unshuffledCharacters[7] = shuffledCharacters[1]; unshuffledCharacters[8] = shuffledCharacters[8]; unshuffledCharacters[9] = shuffledCharacters[11]; unshuffledCharacters[10] = shuffledCharacters[2]; unshuffledCharacters[11] = shuffledCharacters[9]; return new string(unshuffledCharacters); } public static string DoPrefixCipherEncrypt(string strIn, byte[] btKey) { if (strIn.Length < 1) return strIn; // Convert the input string to a byte array byte[] btToEncrypt = System.Text.Encoding.Unicode.GetBytes(strIn); RijndaelManaged cryptoRijndael = new RijndaelManaged(); cryptoRijndael.Mode = CipherMode.ECB;//Doesn't require Initialization Vector cryptoRijndael.Padding = PaddingMode.PKCS7; // Create a key (No IV needed because we are using ECB mode) ASCIIEncoding textConverter = new ASCIIEncoding(); // Get an encryptor ICryptoTransform ictEncryptor = cryptoRijndael.CreateEncryptor(btKey, null); // Encrypt the data... MemoryStream msEncrypt = new MemoryStream(); CryptoStream csEncrypt = new CryptoStream(msEncrypt, ictEncryptor, CryptoStreamMode.Write); // Write all data to the crypto stream to encrypt it csEncrypt.Write(btToEncrypt, 0, btToEncrypt.Length); csEncrypt.Close(); //flush, close, dispose // Get the encrypted array of bytes byte[] btEncrypted = msEncrypt.ToArray(); // Convert the resulting encrypted byte array to string for return return (Convert.ToBase64String(btEncrypted)); } private static List<int> GetRandomSubstitutionArray(string number) { // Pad number as needed to achieve longer key length and seed more randomly. // NOTE I didn't want to make the code here available and it would take too longer to clean, so I'll tell you what I did. I basically took every number seed that was passed in and prefixed it and postfixed it with some values to make it 16 characters long and to get a more unique result. For example: // if (number.Length = 15) // number = "Y" + number; // if (number.Length = 14) // number = "7" + number + "z"; // etc - hey I already said this is a hack ;) // We pass in the current number as the password to an AES encryption of each of the // digits 0 - 9. This returns us a set of values that we can then sort and get a // random order for the digits based on the current state of the number. Dictionary<string, int> prefixCipherResults = new Dictionary<string, int>(); for (int ndx = 0; ndx < 10; ndx++) prefixCipherResults.Add(DoPrefixCipherEncrypt(ndx.ToString(), Encoding.UTF8.GetBytes(number)), ndx); // Order the results and loop through to build your int array. List<int> group = new List<int>(); foreach (string key in prefixCipherResults.Keys.OrderBy(k => k)) group.Add(prefixCipherResults[key]); return group; } 
+5
source

What you are talking about looks like a one-time pad. The key is the same length as the plaintext, and then does some modulo math for each individual character.

 A xor B = C C xor B = A 

or in other words

 A xor B xor B = A 

Until you use the same key B on several different inputs (for example, B must be unique every time you encrypt), then theoretically you can never restore the original A without knowing what B . If you use the same B several times, then all bets are disabled.

a comment:

You should not finish more bits than you started. xor just flushes bits, it does not have carry functionality. The completion with 6 digits is just weird ... As for the code:

 $plaintext = array(digit1, digit2, digit3, digit4, digit5, digit6); $key = array(key1, key2, key3, key4, key5, key6); $ciphertext = array() # encryption foreach($plaintext as $idx => $char) { $ciphertext[$idx] = $char xor $key[$idx]; } # decryption foreach($ciphertext as $idx => $char) { $decrypted[$idx] = $char xor $key[$idx]; } 

Just do it like an array for simplicity. For actual data, you should work on the basis of each byte or each word and simply sequentially in each block. You can use a key string shorter than input, but it makes reverse key development easier. Theoretically, you can use one byte to do xor'ing, but then you basically only reached the rot-13 bit level level.

+2
source

Another way to easily encrypt, you can just fine-tune each number in 10.

For example, source numbers: 123456

10-1 = 9 10-2 = 8 10-3 = 7, etc.

and you get 987654

You can combine it with XOR for more secure encryption.

+1
source

For example, you can add the digits of your number with the digits some const (214354178963 ... whatever) and use the β€œ~” operator (cancel all bits), this is not safe, but you can always decrypt your number.

0
source

anyone with a reflector or ildasm can crack such an encryption algorithm.

I do not know what your business requirement is, but you must know this.

0
source

If the requirements that you can accept 16 hexadecimal digits as the encrypted side have enough space for folding, just interpret the decimal decimal number as 64-bit plaintext and use a 64-bit block cipher like Blowfish, Triple-DES or IDEA .

0
source

Source: https://habr.com/ru/post/1337196/


All Articles