One time pad, encryption and decryption

2020-04-05 07:36发布

问题:

I am trying to pick up cryptography and had been trying this exercise

Write a program (preferably Java) to generate a one-time pad, which is a relatively large file of all random data (say 1 MB). The program should also be able to encrypt/decrypt files based on the generated one time pad.

Tip: use the following test vector to check if your program does encryption correctly.

Plaintext (ASCII): Every cloud has a silver lining
OTP (HEX): 6dc72fc595e35dcd38c05dca2a0d2dbd8e2df20b129b2cfa29ad17972922a2
ciphertext (HEX): 28b14ab7ecc33ea157b539ea426c5e9def0d81627eed498809c17ef9404cc5

I have tried to generate a one time pad using random number generator as I need to convert them to HEX form. and I am pretty sure I am confused or not tackling it the right way

public static void oneTimePad()
{
    Random ran = new Random();
    String s = "0123456789ABCDEF";
    for(int i = 0; i < 100; i++)
    {   
        System.out.print(s.charAt(ran.nextInt(s.length())));
    }
}

Above would be my one time pad, and I was wondering how any idea how I could implement the encryption using the one time pad and decrypting it.

回答1:

Here you have a full working example:

    // convert secret text to byte array
    final byte[] secret = "secret".getBytes()

    final byte[] encoded = new byte[secret.length];
    final byte[] decoded = new byte[secret.length];

    // Generate random key (has to be exchanged)
    final byte[] key = new byte[secret.length];
    new SecureRandom().nextBytes(key);

    // Encrypt
    for (int i = 0; i < secret.length; i++) {
        encoded[i] = (byte) (secret[i] ^ key[i]);
    }

    // Decrypt
    for (int i = 0; i < encoded.length; i++) {
        decoded[i] = (byte) (encoded[i] ^ key[i]);
    }

    assertTrue(Arrays.equals(secret, decoded));


回答2:

For the one time pad you need a byte array, not hexadecimals. The hexadecimals are only required for displaying data (we tend to have trouble reading bits). You can use the Apache Commons libraries (codec package) to create hexadecimals from byte arrays, or back if you want to decode the test vectors from hexadecimals to bytes.

You should use a secure random number generator, not Random. So use new SecureRandom() instead. To generate random data, first create a byte array, then call nextBytes() on the random number generator. There is not need to generate integers.



回答3:

First here is a OTP algorithm specified called HOTP which is a standard RFC. Almost all other OTP are propriety and we don't know the algorithm for those.

http://tools.ietf.org/html/rfc4226

There is some java code in there you can use to learn how its done. Second if you are going to do encryption don't use Random. Random is nice for psuedo random, but if you really want a good source of random data you need to adopt SecureRandom. That's a much better source of random numbers that are suitable for cryto algorithms.

For converting things to Hex you can easily use

http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigInteger.html#toString(int)

Or any of the varieties Long.toString(value,radix), Integer.toString(value,radix), or Byte.toString(value,radix).

byte[] bytes = ...;
for( int i = 0; i < bytes.length; i++ ) {
    System.out.println( Integer.toString( bytes[i], 16 );
}


回答4:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace one_time_pad
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("                   TRYING\n");

            Console.WriteLine("Enter : ");
            int input= int.Parse( Console.ReadLine());

            //random num generation
            Random rnd = new Random();
            int random = rnd.Next(1,10);

            //binary conversion
            string binary = Convert.ToString(random,2);
            string inbinary = Convert.ToString(input,2);

            Console.WriteLine("Data :   " +input +"   Binary :   " + inbinary);
            Console.WriteLine(" Key :   " +random + "   Binary :    " + binary);    

            // taking xor
            int Ghul = input ^ random;

            //binary conversion
            string intcon = Convert.ToString(Ghul,2);

            Console.WriteLine("Encrypted : " + intcon);

            Console.WriteLine(":)");

            Console.Read();    
        }
    }
}


回答5:

https://en.wikipedia.org/wiki/One-time_pad

public static String crypt(String string, String keyString) {
    // convert secret text to byte array
    byte[] bytes = string != null ? string.getBytes() : new byte[0];
    int size = bytes != null ? bytes.length : 0;
    final byte[] encoded = new byte[size];
    final byte[] key = keyString != null ? keyString.getBytes() : new byte[0];
    // loop on input  bytes
    for (int i = 0; i < size; i++) {
        // shift key index 
        // (we assume key can be smaller or equal if larger then adjust)
        int keyi = i >= keySize ? size % (keySize-1) : i;
        // pad
        encoded[i] = (byte) (bytes[i] ^ key[keyi]);
    }
    return new String(encoded);
}

public static void test(String string, String keyString) {
    String encrypt = crypt(string, keyString);
    String decrypt = crypt(encrypt, keyString);
    assert(string.equals(decrypt));
}
  • test("test","1234");
  • test("test","123");

ps. you can refactor method by pull strings up and replace with bytes

public static byte[] crypt(byte[] bytes, byte[] key) {
    int size = bytes != null ? bytes.length : 0;
    final byte[] encoded = new byte[size];
    int keySize = key != null ? key.length : 0;
    // loop on input bytes 
    for (int i = 0; i < size; i++) {
        // shift key index (assuming key <= bytes)
        int keyi = i >= keySize ? size % (keySize-1) : i;
        // pad 
        encoded[i] = (byte) (bytes[i] ^ key[keyi]);
    }
    return encoded;
}


回答6:

<dependency>
    <groupId>work.eddiejamsession</groupId>
    <artifactId>jam-one-time-pad</artifactId>
    <version>0.67</version>
</dependency>
JamOneTimePad pad = new JamOneTimePad();
String heyEncrypted = pad.encrypt("hey"); //encodes additionally in base64 for url safety
String heyDecrypted = pad.decrypt(heyEncrypted);
System.out.println(heyDecrypted.equals("hey"));
Output: true