Java和子字符串错误

Java和子字符串错误,java,indexing,substring,Java,Indexing,Substring,我正在实现一种用密钥加密的方法,我做了如下调用: Crypto c = new Crypto("mysecretkey"); String enc = c.encrypt("mytext"); 但我有个例外 “加密错误:字符串索引超出范围:-1” 在本部分: String sKeyChar = getKey().substring((i % getKey().length()) - 1, 1); 我不知道我做错了什么,因为我用PHP做了同样的事情,效果很好。也许这很简单,但我被卡住了,这是我

我正在实现一种用密钥加密的方法,我做了如下调用:

Crypto c = new Crypto("mysecretkey");
String enc = c.encrypt("mytext");
但我有个例外

“加密错误:字符串索引超出范围:-1”

在本部分:

String sKeyChar = getKey().substring((i % getKey().length()) - 1, 1);
我不知道我做错了什么,因为我用PHP做了同样的事情,效果很好。也许这很简单,但我被卡住了,这是我的方法:

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;
    }
PHP等效方法:

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); 
} 
函数加密($sData,$sKey='mysecretkey'){
$sResult='';

对于($i=0;$i您的计算是错误的:
(i%getKey().length())-1
将导致
i=0
的-1,即在第一次迭代中正确。因此您尝试将-1传递给
子字符串(…)
方法,这是不允许的

还要注意,如果数据比键长,
i%getKey().length()
将导致键长的每倍数为0

此外,
子字符串(…)
的参数不是
索引
长度
,而是
开始索引
(包含)和
结束索引
(排除)。因此
字符串sChar=sData。子字符串(i,1);
一旦
i
达到2(及以上)就会抛出异常并且不会为
i=1
返回任何内容

您可能希望改用
charAt(i)
(以及
getKey().charAt(i%getKey().length())
,请注意,这将返回单个字符,这将使
ord(…)
方法过时

作为旁注:
String.valueOf(sChar.charAt(0)).codePointAt(0)
相当于
sChar.codePointAt(0)

另一个旁注:

char c = (char) (ord(sChar) - ord(sKeyChar));
String sPart = (new StringBuffer().append(c)).toString();
sResult += sPart; 
可以简化为

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

您可以看到PHP和Java之间的区别,因为PHP的
substr
理解负数,而Java的
substring
不理解负数:它抛出一个异常

在PHP中,将负1传递给
substr
意味着“获取最后一个字符”,但在Java中,需要传递最后一个字符的索引(即
str.length()-1
)才能达到相同的效果

如果这不是一个错误,并且这正是您想要达到的效果,您可以使用
If
条件来解决此问题:

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正如Thomas正确指出的那样,PHP版本的
substr
和Java的
substring
之间的另一个区别在于它们对第二个参数的处理:PHP认为它是长度;Java认为它是最后一个字符加上一个字符的索引。

如前所述,PHP中的substr具有不同的语义在Java中。 在PHP中

string substr(string$string,int$start[,int$length])

它也接受负数(这会改变它的行为)


在java中,它被定义为:

 String     substring(int beginIndex, int endIndex) 
如果
beginIndex
大于
endIndex
,则对负数抛出异常。
总而言之,它们是不同的,你需要对此进行补偿。

你也应该发布
getKey()
方法,因为它在line中使用,但失败了。我认为这不是加密安全的想法是错误的吗?我觉得我应该能够从中猜出密钥和数据,知道该方法(假设短密钥)。这是假设减法运算的结果是一个有效的
char
,不管怎样;
ord()
方法并不总是返回有效的数据,并且不是国际安全的(组合字符)。此外,您正在吞咽
异常,这是不好的,只需打印到
系统。out
(甚至不是
.err
!),而不是正确地记录。并查找
StringBuilder
-您的实现不是最佳的。感谢您的推荐,但这只是一个测试方法和getKey()很好如果有人给我打分,解释一下原因会很好。谢谢你的解释,这真的很有用。如果
pos
不是0或1,就会产生一个异常。@Thomas你完全正确,这是PHP和Java之间的另一个区别。在这一点上,我认为你的解决方案是正确的(使用单个字符而不是一个字符串)更干净,所以我将对其进行升级。感谢您发现此错误!感谢您提供的解决方案:)我在ord()中的“char c=(char)(ord(sChar)-ord(sKeyChar));”这一行仍然遇到错误方法,但我会继续寻找正在发生的事情。但一切都清楚,再次感谢!
 String     substring(int beginIndex, int endIndex)