简体   繁体   中英

Java BigInteger Out of memory, possibly from long conversion

I'm trying to convert this KeeLoq algorithm from C into Java but my decryption method seems to use too much memory for Java's BigInteger. I was wondering if there was an equivalent operation that would work with Java's BigInteger.

The original calculations for the index and bitVal variables are commented out below.

The original source code I'm using as an example can be found here: https://github.com/franksmicro/Arduino/blob/master/libraries/Keeloq/Keeloq.cpp

Any help would be much appreciated.

package keeloq;

/**
 *
 * @author 
 */
import java.math.BigInteger;

public class KeeLoq {

    BigInteger _keyHigh, _keyLow, keyHigh, keyLow;
    int KeeLoq_code = 0x3A5C742E;
    BigInteger KeeLoq_NLF = new BigInteger(Integer.toString(KeeLoq_code));

    public KeeLoq() {
    }

    public KeeLoq(BigInteger keyHigh, BigInteger keyLow) {
        _keyHigh = keyHigh;
        _keyLow = keyLow;
    }

    public BigInteger bitRead(BigInteger x, int n) {
        BigInteger temp = x.shiftRight(n);
        return temp;
    }

    public BigInteger multiplyBig(BigInteger x, BigInteger n) {
        BigInteger temp = x.multiply(n);
        return temp;
    }

    public BigInteger Encrypt(BigInteger data) {
        BigInteger x = data;
        int keyBitNo;
        long index;
        long position1, position2, position3, position4, position5;
        BigInteger keyBitVal, bitVal;
        BigInteger b1, b2, b3, b4, b5;

        for (int r = 0; r < 528; r++) {
            keyBitNo = r & 63;
            if (keyBitNo < 32) {
                keyBitVal = bitRead(_keyLow, keyBitNo);
            } else {
                keyBitVal = bitRead(_keyHigh, keyBitNo - 32);
            }

            position1 = bitRead(x, 1).longValue() * 1;
            position2 = bitRead(x, 9).longValue() * 2;
            position3 = bitRead(x, 20).longValue() * 4;
            position4 = bitRead(x, 26).longValue() * 8;
            position5 = bitRead(x, 31).longValue() * 16;

            index = position1 + position2 + position3 + position4 + position5;
            System.out.println("the encrypted index is " + index);

            b1 = bitRead(x, 0);
            b2 = bitRead(x, 16);
            int intIndex = (int) index;
            b3 = bitRead(KeeLoq_NLF, intIndex);
            b4 = keyBitVal;

            bitVal = b1.xor(b2).xor(b3).xor(b4);
            BigInteger tempx = x.shiftRight(1);
            x = tempx.xor(bitVal);
                        //bitVal = bitRead(x,0) ^ bitRead(x, 16) ^ bitRead(KeeLoq_NLF,index) ^ keyBitVal;
            //x = (x>>1) ^ bitVal<<31;
        }
        return x;
    }

    BigInteger Decrypt(BigInteger data) {
        BigInteger x = data;
        int keyBitNo;
        long index;
        long position1, position2, position3, position4, position5;
        BigInteger keyBitVal, bitVal;
        BigInteger b1, b2, b3, b4, b5;

        for (int r = 0; r < 528; r++) {
            keyBitNo = (15 - r) & 63;
            if (keyBitNo < 32) {
                keyBitVal = bitRead(_keyLow, keyBitNo);
            } else {
                keyBitVal = bitRead(_keyHigh, keyBitNo - 32);
            }

            position1 = bitRead(x, 0).longValue() * 1;
            position2 = bitRead(x, 8).longValue() * 2;
            position3 = bitRead(x, 19).longValue() * 4;
            position4 = bitRead(x, 25).longValue() * 8;
            position5 = bitRead(x, 30).longValue() * 16;

            index = position1 + position2 + position3 + position4 + position5;

            System.out.println("The Decrypted index is " + index);

            b1 = bitRead(x, 31);
            b2 = bitRead(x, 15);
            int intIndex = (int) index;
            b3 = bitRead(KeeLoq_NLF, intIndex);
            b4 = keyBitVal;

            bitVal = b1.xor(b2).xor(b3).xor(b4);
            BigInteger tempx = x.shiftLeft(1);
            x = tempx.xor(bitVal);


            //index = 1 * bitRead(x,0) + 2 * bitRead(x,8) + 4 * bitRead(x,19) + 8 * bitRead(x,25) + 16 * bitRead(x,30);
            // bitVal = bitRead(x,31) ^ bitRead(x, 15) ^ bitRead(KeeLoq_NLF,index) ^ keyBitVal;
            //   x = (x<<1) ^ bitVal;


        }
        return x;
    }

    public static void main(String[] args) {
        BigInteger highKey = new BigInteger(Integer.toString(66));
        BigInteger lowKey = new BigInteger(Integer.toString(35));
        KeeLoq KeeLoq_file = new KeeLoq(highKey, lowKey);
        System.out.println("The KeeLoq Code is " + KeeLoq_file.KeeLoq_code);
        BigInteger EncryptedBigInt = KeeLoq_file.Encrypt(KeeLoq_file.KeeLoq_NLF);
        System.out.println("The Encrypted BigIntegerValue is " + EncryptedBigInt);
        System.out.println("The Encrypted integer value is " + EncryptedBigInt.intValue());
        BigInteger DecryptedBigInt = KeeLoq_file.Decrypt(EncryptedBigInt);
        System.out.println("The Decrypted BigIntegerValue is " + DecryptedBigInt);
        System.out.println("The Decrypted integer value is " + DecryptedBigInt.intValue());
    }

}

Edit: I think I got it! (or at least part of it)

The issue is at least partially in this line: (got the wrong line at first, sorry)

 int intIndex = (int) index;

When index gets large enough, (int) index will overflow to a large negative value. Guess what happens when you pass that into bitRead() ?

Now, why this overflow happens in Decrypt() and not in Encrypt() , I'm not sure... I'll look later once I get some more rest, but hopefully this is a start.

You can increase the memory space available by running the program with the -Xmx flag. For example, to run with max 4 gigabytes of ram you'd use -Xmx4G

In Eclipse, this can by set by right-clicking on the file, going to Properties --> Run/Debug Settings --> click on the launch configuration --> Edit --> Arguments tab --> VM arguments --> type in the flag.

If you're running out of memory with Java's BigInteger class, I'm not certain that using any other arbitrary-precision library would get you very far if the numbers actually get that large.

You have a bug in the bitRead function: Here is the documentation from arduino:

Syntax bitRead(x, n)

Parameters x: the number from which to read

n: which bit to read, starting at 0 for the least-significant (rightmost) bit

Returns the value of the bit (0 or 1).

Your function returns larger values like 3824712.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM