简体   繁体   English

安卓公钥加密

[英]Android public key encryption

My Android app implements RSA encryption, however the backend can not decrypt the token generated by the app.我的 Android 应用程序实现了 RSA 加密,但是后端无法解密应用程序生成的令牌。 Here is the code, the beginning and end lines of the public key have been removed before making the calls, what could be the problem?这是代码,在调用之前已经删除了公钥的开头和结尾行,可能是什么问题?

String encryptedToken = Base64.encodeToString(encrypt(publicKey, "4111111111111111"), Base64.NO_WRAP);

public static byte[] encrypt(String publicKey, String data) {
        if (TextUtils.isEmpty(publicKey) || TextUtils.isEmpty(data)) {
            return null;
        }
        try {
            // Decode the modified public key into a byte[]
            byte[] publicKeyByteArray = Base64.decode(publicKey.getBytes("UTF-8"),Base64.NO_WRAP);

            Cipher mCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyByteArray);
            Key key = keyFactory.generatePublic(x509KeySpec);
            mCipher.init(Cipher.ENCRYPT_MODE, key);
            return mCipher.doFinal(data.getBytes("UTF-8"));
        }
        catch (UnsupportedEncodingException e) {
            Log.e("RSAKEY", e.getMessage());
        }
        catch (NoSuchPaddingException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (InvalidKeyException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (InvalidKeySpecException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (IllegalBlockSizeException e) {
            Log.e("RSAKEY", e.getMessage());
        } catch (BadPaddingException e) {
            Log.e("RSAKEY", e.getMessage());
        }
        return null;
    }

The backend team provided the below sample code that works, but it is for desktop java.后端团队提供了以下有效的示例代码,但它适用于桌面 Java。 Android library does not have the Base64.getEncoder method. Android 库没有 Base64.getEncoder 方法。 it is very similar to what I wrote but mine just does not work.它与我写的非常相似,但我的只是不起作用。

 // Decode the modified public key into a byte[]
            byte[] publicKeyByteArray = Base64.getDecoder().decode(publicKey.getBytes(StandardCharsets.UTF_8));

            // Create a PublicKey from the byte array
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyByteArray);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey pubKey = keyFactory.generatePublic(keySpec);

            // Get an instance of the Cipher and perform the encryption
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] cipherText = cipher.doFinal(ccNum.getBytes(StandardCharsets.UTF_8));

            // Get the encrypted value as a Base64-encoded String
            String encodeToStr = Base64.getEncoder().encodeToString(cipherText);

            // Print out the encoded, encrypted string
            System.out.println("Encrypted and Encoded String: " + encodeToStr);

I compared the byte array values at every step.我在每一步都比较了字节数组值。 The desktop cipher and android cipher got exactly the same inputs.桌面密码和安卓密码得到完全相同的输入。 However the results from the Android code cipher.doFinal can not be decrypted by the backend.然而,Android 代码 cipher.doFinal 的结果无法被后端解密。 If I put the desktop results to the REST call body they work fine, so it is not something caused by REST call.如果我将桌面结果放到 REST 调用正文中,它们就可以正常工作,所以这不是由 REST 调用引起的。

I also tried to create a public/private key pair on Android, and use the generated public key to encrypt instead of using the public key from our backend, and decrypt using the private key and it works.我还尝试在 Android 上创建一个公钥/私钥对,并使用生成的公钥进行加密,而不是使用我们后端的公钥,并使用私钥解密并且它可以工作。 So the cipher is also working, just somehow the backend is expecting something different所以密码也有效,只是后端以某种方式期待不同的东西

Finally someone in the team cracked this.团队中终于有人破解了这个问题。 The reason is because the Android OS uses Bouncy castle, the backend uses Sun as the provider, this caused the backend throwing a BadPaddingException.原因是Android操作系统使用Bouncy Castle,后端使用Sun作为Provider,导致后端抛出BadPaddingException。 To make it work, the cipher needs to be initialized this way on Android:为了使其工作,需要在 Android 上以这种方式初始化密码:

 mCipher.init(Cipher.ENCRYPT_MODE, key, new
                    OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1,
                    PSource.PSpecified.DEFAULT));

Check for more details in this post: http://bouncy-castle.1462172.n4.nabble.com/Problems-with-OAEP-SHA-256-hash-crypto-td1466852.html在这篇文章中查看更多详细信息: http : //bouncy-castle.1462172.n4.nabble.com/Problems-with-OAEP-SHA-256-hash-crypto-td1466852.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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