How can I encrypt/decrypt 12-digit decimal numbers to other ones, using a password and Java?

后端 未结 12 1110
再見小時候
再見小時候 2020-12-15 15:12

I have already read Using Java to encrypt integers and Encrypting with DES Using a Pass Phrase.

All I need is a simple Encrypter which transforms a 12 digit number t

相关标签:
12条回答
  • 2020-12-15 15:29

    I suggest a very simple algorithm.

    1. Feed the password into a hash function.
    2. Initialize a random number generator with the hash or something you derived from the hash.
    3. Generate a 12 digit random number.
    4. Add this random number to the input digit by digit modulo 10 to encrypt.

    To decrypt subtract the random number modulo 10. This is actually a form of One Time Pad. Because of the comments on this answer I realized that refering to One Time Pad was a bad choice. A better reference is Polyalphabetic cipher - while One Time Pad uses polyalphabetic substitution its main characteristic is not to use any key bit twice.

       Input           1234 1234 1234
       Random number   6710 3987 2154
       Output          7944 4111 3388
    

    There is one remaining problem with that - the algorithm might create leading zeros. To solve this problem one could use XOR instead of addition and substraction. Just transform the digits with XOR. If the first digit turns into a zero, don't encrypt the first digit. When you decrypt with XOR again, the first digit will turn into zero and you know that the first digit was not enrcypted.

    UPDATE

    A simple XOR is not the solution because it will produce to large numbers - 2 XOR 9 = 11 for example. Going to rethinks this...

    UPDATE

    The nice propoerties of XOR are XOR(a, b) = XOR(b, a) and XOR(XOR(a, b), b) = a. This makes encryption and decryption the same and allows to detect the unencrypted leading digit. But it is further required that our function only returns values in the range from 0 to 9 what XOR doesn't do.
    But maybe we can build a custom function with all required properties. So we create an array FUNC with 10 columns and 10 rows and use it as a lookup table for our function. What values to but in? I actually don't know - I am not even sure that it is possible. But if we pick three number from the range 0 to 9 we have to make the following six entries. (It is a symmetric matrix.)

    FUNC[x,y] = z   FUNC[x,z] = y   FUNC[y,z] = x
    FUNC[y,x] = z   FUNC[z,x] = y   FUNC[z,y] = x
    

    So maybe it is possible to create such a function by repeatedly choosing random numbers and filling the six entries if there is no conflict. Maybe it is not. I would like to see the table if one finds a solution.

    0 讨论(0)
  • 2020-12-15 15:31

    This thread is 4 years old, but for those finding the thread in Google: have a look at Format Preserving Ciphers: http://en.wikipedia.org/wiki/Format-preserving_encryption

    0 讨论(0)
  • 2020-12-15 15:32

    If I understand your problem correctly you have a problem with the 16 bytes after decrypting. The trick is to use: Cipher.getInstance("DES/ECB/PKCS5Padding");

    (just in case code is helpful):

    public void mytestSimple(long code, String password) throws Exception 
           { SecretKey key       = new SecretKeySpec (password.getBytes(),"DES");
             Cipher    ecipher   = Cipher.getInstance("DES/ECB/PKCS5Padding");
             byte[]    plaintext = new byte[8];
    
             for (int i=0; i<8; i++)
                 { plaintext[7-i] = (byte) (code & 0x00FF);
                    >>>= 8;
                 }
    
             ecipher.init      (Cipher.ENCRYPT_MODE, key);
             System.out.println(ecipher.getOutputSize(8));
    
             byte[] encrypted = ecipher.doFinal(plaintext);
             System.out.println("--" + encrypted.length);
    
             Cipher dcipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
             dcipher.init(Cipher.DECRYPT_MODE, key);
    
             byte[] crypttext = dcipher.doFinal(encrypted);
             long   decoded    = 0;
    
             for (int i=0; i<8; i++)
                 { decoded <<= 8;
                   decoded  += crypttext[i] & 0x00FF;
                 }
    
             System.out.println(decode + "--" + crypttext.length);
           }
    
    0 讨论(0)
  • 2020-12-15 15:37

    If the strict 1:1 mapping is more important than protecting against cryptanalysis, then you can convert the password to a 12-digit number (via hash or otherwise) and simply add to your original number mod 10^12. If you absolutely must remove leading zeros from the output, you can subtract 10^11, do the math mod (10^12 - 10^11), and then add 10^11 back again. Granted, that's extremely insecure, but it's quite simple. :)

    If the range of inputs is bounded by a prime less than (10^12 - 10^11), you may be able to use message ^ password mod prime to form a ring that will satisfy your requirements and be a little harder to crack. (This is similar to how RSA works.) I think this could work if you don't need to decrypt it.

    I agree with Jon Skeet: requiring a strict 1:1 mapping without the output range being bigger than the input domain is something that most encryption libraries are not going to handle.

    0 讨论(0)
  • 2020-12-15 15:38

    If you're prepared to accept a rather weak solution...

    Treat the 12-digit number as two 6-digit numbers. Then use the hash of the password as a seed to a random number generator which shuffles a table of 999,990 consecutive values. Then use the two 6-digit numbers to look up entries in the table. The concatenation of the two results is your 1:1 mapped 12-digit 'encrypted' input based on a password.

    Let's do an example with 4-digits instead of 12...

    Input: 4852
    Password: passw0rd1 => hashcode = 37592
    

    Now take this array..

    a = [10, 11, 12, 13, .. 98, 99]
    

    And shuffle it with 37592 as the random seed...

    b = [45, 15, 56, 49, .. 33, 88]
    

    Now split the input: 48, 52 and look up those indices in the shuffled array, say...

    b[48] => 23
    b[52] => 96
    

    So our encrypted version of 4852 is 2396

    It really isn't a strong solution but the constraints in your question will not lead to a strong solution. You may need to relax those constraints a bit.

    0 讨论(0)
  • 2020-12-15 15:40

    Rethinking the problem I came up with the following. Basicly you need a symmetric cipher to get a one-to-one mapping. And noting that 10^12 is almost 2^40 (2^39.863) it seems natural to convert your 12 digit number into a 40 bit integer and feed this number into a block cipher with a block length of 40 bits. A good choice might be Blowfish supporting block lengths from 32 to 448 bits in steps of 8 bits - so 40 bits is supported.


    UPDATE

    As Accipitridae pointed out, Blowfish has variable key size but fixed block size hence it is no option. A bit more searching through the web seems to indicate, that there are little or no ciphers with block sizes of 40 bits or less rendering this idea void. A leave the remaining part of the answer - maybe one can find a suitable cipher.


    The remaining problem is that the Blowfish might return a number up to 1,099,511,627,775 with 13 digits and that the returned number might contain leading zeros, but I believe that this can be solved in a second step. My first thought was applying something like a Burrows-Wheeler transform to the string representation of the number in order to get at least one zero to the front of the number eleminating the 13th digit and then modify all remaining digits (for example 0 <-> 9, 1 <-> 8, 2 <-> 7, ...) to turn additional leading zeros into other digits.
    After a few minutes I regonized that this will not work - the input has size 2^40 while the output is only of size 2^39.863. A solution would be to use a 39 bits block cipher and restrict the input to numbers up to 549,755,813,887. I don't know if there is a cipher that can deal with a block length of 39 bits, but this paper on Elastic Block Ciphers describes how to construct a block cipher that can deal with every block size from n up to 2n given a block cipher that can handle block size n. In consequence it is possible to construct a 39 bit block cipher from 32 bit Blowfish.

    0 讨论(0)
提交回复
热议问题