繁体   English   中英

自Android 6 Marshmallow以来,javax.crypto.Cipher的工作方式不同

[英]javax.crypto.Cipher working differently since Android 6 Marshmallow

我已成功使用javax.crypto.Cipher.getInstance(“DESede / CBC / NoPadding”)在Android上使用DESFire卡进行身份验证(遵循以下示例: https ://stackoverflow.com/a/14160507/2095694)。 它已经在Android 4到5的几个设备上工作,但是我的Nexus 7停止工作,更新到6 Marshmallow(和6.0.1)。 在更新之前,它一直在使用同一设备。

似乎Cipher的工作方式不同,为相同的密钥和数据提供了不同的结果。 运行以下代码......

public static void testCipher() throws Exception
{
    byte[] KEY =
            new byte[]{
                    (byte) 0x0C, (byte) 0x09, (byte) 0x03, (byte) 0x0E,
                    (byte) 0x05, (byte) 0x0A, (byte) 0x0D, (byte) 0x02,
                    (byte) 0x03, (byte) 0x0A, (byte) 0x09, (byte) 0x0B,
                    (byte) 0x06, (byte) 0x10, (byte) 0x04, (byte) 0x10
            };

    byte[] DATA =
            new byte[]{
                    (byte) 0x29, (byte) 0xDA, (byte) 0xC0, (byte) 0xC4,
                    (byte) 0xB8, (byte) 0x47, (byte) 0x13, (byte) 0xA2};

    byte[] newByte8 = new byte[8]; //Zeroes

    android.util.Log.d("TEST", "KEY : " + bin2hex(KEY));
    android.util.Log.d("TEST", "DATA: " + bin2hex(DATA));
    android.util.Log.d("TEST", "IVPS: " + bin2hex(newByte8));
    android.util.Log.d("TEST", "----");

    javax.crypto.Cipher cipher =
            javax.crypto.Cipher.getInstance("DESede/CBC/NoPadding");

    cipher.init(
            Cipher.DECRYPT_MODE,
            new javax.crypto.spec.SecretKeySpec(KEY, "DESede"),
            new javax.crypto.spec.IvParameterSpec(newByte8));

    byte[] result = cipher.doFinal(DATA);

    android.util.Log.d("TEST", "RSLT: " + bin2hex(result));
}

public static String bin2hex(byte[] data) {
    return String.format("%0" + (data.length * 2) + "X", new java.math.BigInteger(1, data));
}

...给我以下输出:

KEY : 0C09030E050A0D02030A090B06100410
DATA: 29DAC0C4B84713A2
IVPS: 0000000000000000
----
RSLT: 47BC415065B8155E

正常值,它应该是什么,总是工作,卡最终正确验证,所以它按照卡的预期方式进行。 如上所述,我尝试了几种设备(Android 4和5)并且它们给出了相同的结果。

但是在我的Nexus 7现在使用Marshmallow,我得到了其他东西(并且身份验证最终失败了)

RSLT: F3ADA5969FA9369C 

图书馆有变化吗?

似乎他们改变了Marshmallow中的默认提供者。

一个简单的:

cipher.getProvider().getName();

为Marshmallow显示“AndroidOpenSSL”,之前它是“BC”(BouncyCastle,我想)。

使用其他getInstance重载...

 javax.crypto.Cipher cipher =
            javax.crypto.Cipher.getInstance("DESede/CBC/NoPadding","BC");

...给我带来了与棉花糖的Nexus的预期结果。

更新:我现在收到此警告:

不推荐使用BC提供程序,当targetSdkVersion移动到P时,此方法将抛出NoSuchAlgorithmException。 要解决此问题,您应该停止指定提供程序并使用默认实现
Cipher#getInstance不应该使用ECB作为密码模式调用,或者不设置密码模式,因为android上的默认模式是ECB,这是不安全的。

所以我最终在这里使用了另一个答案 (希望)适用于所有版本的Android。

发布了一个安卓漏洞: https//code.google.com/p/android/issues/detail?can = 2&start = 0&num = 100&q = tripmedes20des&solpec = ID%20Status%20Priority%20Owner%20Summary%20Stars% 20Reporter %20Opened&GROUPBY =&排序=&ID = 189292

您还可以通过将键更改为24字节len来解决您的问题,如下所示:

    MessageDigest md = MessageDigest.getInstance("MD5");
seed_key = md.digest(new String(key).getBytes());

if (seed_key.length == 16) {
    byte[] tempkey = new byte[24];
    System.arraycopy(seed_key, 0, tempkey, 0, 16);
    System.arraycopy(seed_key, 0, tempkey, 16, 8);

    seed_key = tempkey;
}
SecretKeySpec keySpec = new SecretKeySpec(seed_key, "DESede");
nCipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
byte[] IVector = new byte[] { 27, 9, 45, 27, 0, 72, (byte) 171, 54 };
IvParameterSpec iv = new IvParameterSpec(IVector);
nCipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

byte[] cipherbyte = nCipher.doFinal(data.getBytes());
encodeTxt = new String(Base64.encodeBase64(cipherbyte));

暂无
暂无

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

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