我一直在努力为Java中的以下加密方法找出一个简单的解密算法:
/**
* Returns the encryption of the given card number using the given keys.
* Precondition: it can be assumed that cardNum is a valid numeric string,
* k1 is a positive integer at most 9, and
* k2 is a positive integer at most 9.
* Postcondition: the string returned is the encryption of cardNum using keys
* k1 and k2
*/
public static String encrypt (String cardNum, int k1, int k2) {
int currentNum;
long encryptedNum;
String cryptogram = "";
for (int i = 0; i < cardNum.length(); i++) {
currentNum = Character.getNumericValue(cardNum.charAt(i));
encryptedNum = (k1 * currentNum + k2) % 10;//the encryption algorithm
cryptogram += encryptedNum;//add the encrypted number to the cryptogram
}
return cryptogram;
}
以前的加密方法用于加密最多16位数的信用卡号码,目的是创建一种方法来反转算法并检索原始卡号。
我也知道,对于k1
和k2
的某些值,由于在加密结束时使用模10,因此没有可能的解密,因此它也是用于确定k1
和k2
的哪些值可以解密的分配。然后,假设使用cardNum
和k1
的有效值,编写一个解密k2
的方法
以下是我设法使用decrypt方法获得的内容,而且我也无法确定k1
和k2
的有效值是什么。
/**
* Returns the decryption of the given cryptogram using the given keys.
* Precondition: it can be assumed that cryptogram is a valid numeric string,
* k1 is a valid first encryption key,
* k2 is a valid second encryption key.
* Postcondition: the string returned is the decryption of cryptogram
* using keys k1 and k2
*/
public static String decrypt (String cryptogram, int k1, int k2) {
int currentNum;
long decryptedNum;
String cardNum = "";
for (int i = 0; i < cryptogram.length(); i++) {
currentNum = Character.getNumericValue(cryptogram.charAt(i));
decryptedNum = (currentNum - k2)/k1;//the decryption algorithm
cardNum += decryptedNum;//add the decrypted number to the cardNum
}
return cardNum;
}
答案 0 :(得分:1)
让我们从解密可能失败的原因入手。
k1
,k2
理论上可以编写解密算法,但实际上所有已知的算法都会慢下来才有用。 (这种算法的一个例子是&#34;加密&#34;函数e(m,k)=SHA512(k||m)
,它接收任何16字节消息m
,任何16字节密钥k
并输出SHA512哈希值k
和m
的串联。我已经在连字符中加密,作为加密函数的条件是是有效的解密函数。)剧透:你的功能不属于第一类。k1,k2
时,两条消息cardNum1
和cardNum2
获得加密&#34;相同的值cryptogram
。因此,在给定cryptogram
和密钥后,您无法确定哪个值是原始值。这是你面临的问题。你想要达到的财产被称为&#34; injectivity&#34; (没有两个值映射到同一图像)。现在,要实现的下一步是加密在逐个数字的基础上进行细分。因此,如果您对整个信用卡号的加密或解密有问题,那么当且仅当您遇到单个数字时才会显示。
您需要知道的另一个因素是模运算的重要特性。如果对于任何三个整数x,y,z有任何两个基本运算A和B(例如+和*),则以下标识成立:(x A y)B z%10 =((x A y)%10) B z%10。也就是说,您可以在每个步骤后应用模数计算,或者在结束时应用一次,结果将保持不变。例如(5 * 100%10)* 12%10 =(5 * 100)* 12%10。您甚至可以先减少每个模数10:5 * 100%10 = 5 *(100%10)%10 = 0
使用此功能,您可以反转部分加密功能:(k1 * currentNum) % 10 = (k1 * currentNum + k2 - k2) % 10 = (((k1 * currentNum + k2) % 10) - k2) % 10 = (encryptedNum - k2) %10
。
剩下要做的是反转乘法运算。这部分我想留给你。您已经可以猜测,对于k1
的某些值,两个值currentNum1
和currentNum2
将具有相同的结果(k1 * currentNum) % 10
。作为(k1 * currentNum) % 10 = ((k1%10) * currentNum) % 10
,k1
只有10个有趣的值。使用currentNum的每个可能值尝试其中的每一个。使用Java打印,10个数字的10个表应该是一个简单的任务。然后尝试找出那些k1
个currentNum
s导致相同值的{{1}}相互具有共同点和10的内容。一旦你有预感,请查看Extended Euclidean Algorithm ,尤其是关于multiplicative inverses的部分。