Encrypt a number to another number of the same length

前端 未结 6 1544
逝去的感伤
逝去的感伤 2021-01-13 03:59

I need a way to take a 12 digit number and encrypt it to a different 12 digit number (no characters other than 0123456789). Then at a later point I need to be able to decryp

6条回答
  •  情歌与酒
    2021-01-13 04:44

    I ended up solving this thanks to you guys using "FPE from a prefix cipher" from the wikipedia page http://en.wikipedia.org/wiki/Format-preserving_encryption. I'll give the basic steps below to hopefully be helpful for someone in the future.

    NOTE - I'm sure any expert will tell you this is a hack. The numbers seemed random and it was secure enough for what I needed, but if security is a big concern use something else. I'm sure experts can point to holes in what I did. My only goal for posting this is because I would have found it useful when doing my search for an answer to the problem. Also only use this in situations where it couldn't be decompiled.

    I was going to post steps, but its too much to explain. I'll just post my code. This is my proof of concept code I still need to clean up, but you'll get the idea. Note my code is specific to a 12 digit number, but adjusting for others should be easy. Max is probably 16 with the way 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 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 prefixCipherResults = new Dictionary();
        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 group = new List();
        foreach (string key in prefixCipherResults.Keys.OrderBy(k => k))
            group.Add(prefixCipherResults[key]);
    
        return group;
    }
    

提交回复
热议问题