Oscar Jara
Oscar Jara

Reputation: 14187

Java and substring error

I am implementing a method to encrypt with a key and i made a call like this:

Crypto c = new Crypto("mysecretkey");
String enc = c.encrypt("mytext");

But i am getting an exception

"crypto encrypt error: String index out of range: -1"

at this part:

String sKeyChar = getKey().substring((i % getKey().length()) - 1, 1);

And I don't know what I am doing wrong because I made the same thing in PHP and works good. Maybe this is simple but I am stuck, this is my method:

public String encrypt(String sData) {
        String sEncrypted = null;
        try {
            String sResult = null;
            for (int i = 0; i < sData.length(); i++) {
                String sChar = sData.substring(i, 1);
                String sKeyChar = getKey().substring((i % getKey().length()) - 1, 1);
                char c = (char) (ord(sChar) - ord(sKeyChar));
                String sPart = (new StringBuffer().append(c)).toString();
                sResult += sPart;
            }
            byte[] sResultBuff = sResult.getBytes("UTF-8");
            sEncrypted = Base64.encode(sResultBuff);
        } catch (Exception e) {
            System.out.println("crypto encrypt error: " + e.getMessage());
            sEncrypted = null;
        }
        return sEncrypted;
    }

Other method needed:

public int ord(String sChar) {
    int ascii_code = 0;
    try {
        ascii_code = String.valueOf(sChar.charAt(0)).codePointAt(0);
    } catch (Exception e) {
        System.out.println("crypto ord error: " + e.getMessage());
        ascii_code = 0;
    }
    return ascii_code;
}

PHP equivalent method:

function encrypt($sData, $sKey='mysecretkey'){ 
    $sResult = ''; 
    for($i=0;$i<strlen($sData);$i++){ 
        $sChar    = substr($sData, $i, 1); 
        $sKeyChar = substr($sKey, ($i % strlen($sKey)) - 1, 1); 
        $sChar    = chr(ord($sChar) + ord($sKeyChar)); 
        $sResult .= $sChar; 
    } 
    return encode_base64($sResult); 
} 

Thanks!

Upvotes: 1

Views: 868

Answers (3)

wmz
wmz

Reputation: 3685

As already noted, substr in PHP has different semantics that in Java. In PHP its

string substr ( string $string , int $start [, int $length ] )
and it also accepts negative numbers (which alter it's behaviour),


while in java it's defined as:

 String     substring(int beginIndex, int endIndex) 

and throws exception on negative numbers or if beginIndex is greater than endIndex. To summarize, they are different and you need to compensate for that.

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726489

You see the difference between PHP and Java because PHP's substr understands negative numbers, but Java's substring does not: it throws an exception.

In PHP, passing negative 1 to substr means "get me the last character", but in Java you need to pass the index of the last character (i.e. str.length()-1) to achieve the same effect.

If this is not a mistake, and this is precisely the effect that you wanted to achieve, you can address this issue with an if condition:

int pos = (i % getKey().length()) - 1;
if (pos == -1) {
    pos = getKey().length() - 1;
}
// EDIT: Second argument needs to be pos+1, not 1. Thomas pointed out this error
String sKeyChar = getKey().substring(pos, pos+1);

EDIT As Thomas correctly pointed out, the other difference between PHP version of substr and Java's substring is in their treatment of the second argument: PHP thinks it's length; Java thinks it's the index of the last character plus one.

Upvotes: 1

Thomas
Thomas

Reputation: 88707

Your calculation is wrong: (i % getKey().length()) - 1 will result in -1 for i = 0, i.e. right in the first iteration. Thus you try to pass -1 to the substring(...) method, which is not allowed.

Also note that if the data is longer than the key, i % getKey().length() will result in 0 for every multiple of the key length.

Additionally, the parameters to substring(...) are not index and length but startIndex (inclusive) and endIndex (exclusive). Thus String sChar = sData.substring(i, 1); will throw an exception once i reaches 2 (and above) and won't return anything for i = 1.

You might want to use charAt(i) instead (and getKey().charAt(i % getKey().length()) in the following line). Note that this returns a single character, which would make the ord(...) method obsolete.

As a side note: String.valueOf(sChar.charAt(0)).codePointAt(0) is equivalent to sChar.codePointAt(0).

Another side note:

char c = (char) (ord(sChar) - ord(sKeyChar));
String sPart = (new StringBuffer().append(c)).toString();
sResult += sPart; 

can be simplified to

char c = (char) (ord(sChar) - ord(sKeyChar));
sResult += c; //you could also merge those two lines

Upvotes: 2

Related Questions