在AndroidKeyStore密钥生成期间出现IllegalArgumentException(Unparseable date) [英] IllegalArgumentException (Unparseable date) during AndroidKeyStore key generation

查看:236
本文介绍了在AndroidKeyStore密钥生成期间出现IllegalArgumentException(Unparseable date)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用 AndroidKeyStore ,而不是理解它可以在Android SDK的BasicAndroidKeyStore示例应用程序中轻松复制。因此,如果您的 Locale.getDefault()== Locale.US 比此示例效果正常,但是如果您将语言环境更改为,例如, ar_EG,它会因异常而崩溃:

I have faced the following problem in my application during RSA key generation using AndroidKeyStore, than understood that it could be easily reproduced in the BasicAndroidKeyStore sample app from the Android SDK. So, if your have Locale.getDefault() == Locale.US than this sample works well, but if you change locale to, for instance, "ar_EG", it would crash with exception:


java.lang.IllegalArgumentException:无效的日期字符串:Unparseable
日期:af`cadaaedcaGMT + 00:00(偏移0)
at
com.android.org.bouncycastle.asn1.DERUTCTime。(DERUTCTime.java:98)
at com.android.org.bouncycastle.asn1.x509.Time。(Time.java:62)
at
com.android.org.bouncycastle.x509.X509V3CertificateGenerator.setNotBefore(X509V3CertificateGenerator.java :112)
at
android.security.AndroidKeyPairGenerator.generateKeyPair(AndroidKeyPairGenerator.java:127)
at
java.security.KeyPairGenerator $ KeyPairGeneratorImpl.generateKeyPair(KeyPairGenerator.java:276)
at
com.example.android.basicandroidkeystore.BasicAndroidKeyStoreFragment.createKeys(BasicAndroidKeyStoreFragment.java:237)

java.lang.IllegalArgumentException: invalid date string: Unparseable date: "af`cadaaedcaGMT+00:00" (at offset 0) at com.android.org.bouncycastle.asn1.DERUTCTime.(DERUTCTime.java:98) at com.android.org.bouncycastle.asn1.x509.Time.(Time.java:62) at com.android.org.bouncycastle.x509.X509V3CertificateGenerator.setNotBefore(X509V3CertificateGenerator.java:112) at android.security.AndroidKeyPairGenerator.generateKeyPair(AndroidKeyPairGenerator.java:127) at java.security.KeyPairGenerator$KeyPairGeneratorImpl.generateKeyPair(KeyPairGenerator.java:276) at com.example.android.basicandroidkeystore.BasicAndroidKeyStoreFragment.createKeys(BasicAndroidKeyStoreFragment.java:237)

所以问题出在转换为String的密钥有效时间是针对默认语言环境进行的。
以下是
ASN1UTCTime 类,在 KeyPairGenerator.generateKeyPair()的引擎下使用以下方法调用:

So, the problem is in the key validity time converting to String which is made with respect to a default locale. Here is code snippet from ASN1UTCTime class, which is used under the hood of KeyPairGenerator.generateKeyPair() following method call:

public ASN1UTCTime(
    String time)
{
    this.time = Strings.toByteArray(time);
    try
    {
        this.getDate();
    }
    catch (ParseException e)
    {
        throw new IllegalArgumentException("invalid date string: " + e.getMessage());
    }
}

在调用此方法之前,Date对象正在传递给以下时间构造函数,它使用默认系统区域设置:

Before calling to this method Date object is being passed to the following Time constructor, which uses default system locale:

public Time(
        Date    time)
    {
        SimpleTimeZone      tz = new SimpleTimeZone(0, "Z");
        SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss");
        dateF.setTimeZone(tz);
        String  d = dateF.format(time) + "Z";
        int     year = Integer.parseInt(d.substring(0, 4));
        if (year < 1950 || year > 2049)
        {
            this.time = new DERGeneralizedTime(d);
        }
        else
        {
            this.time = new DERUTCTime(d.substring(2));
        }
    } 

这很奇怪,因为 ASN1UTCTime 类有另一个构造函数,它似乎更适合国际工作:

This is very strange, because ASN1UTCTime class has another constructor, which is seems to be more suitable for international work:

/**
     * Base constructor from a java.util.date and Locale - you may need to use this if the default locale
     * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations.
     *
     * @param time a date object representing the time of interest.
     * @param locale an appropriate Locale for producing an ASN.1 UTCTime value.
     */
    public ASN1UTCTime(
        Date time,
        Locale locale)
    {
        SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", locale);
        dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
        this.time = Strings.toByteArray(dateF.format(time));
    } 

那么,什么是正确的解决方案或建议如何解决这个问题?

So, what is the correct fix or advise how to solve this problem?

推荐答案

这是 AndroidKeyStore的已知问题

Android KeyStore没有正确接受语言环境,导致设备语言环境的失败,语言从右到左。示例堆栈跟踪:

Android KeyStore doesn't correctly take in the locale and it causes the failures for device locale with language from right to left. Sample stack trace:

Caused by: java.lang.IllegalArgumentException: invalid date string: Unparseable date: "aga``eaeeb`eGMT+00:00" (at offset 0)
    at com.android.org.bouncycastle.asn1.DERUTCTime.<init>(DERUTCTime.java:98)
    at com.android.org.bouncycastle.asn1.x509.Time.<init>(Time.java:62)
    at com.android.org.bouncycastle.x509.X509V3CertificateGenerator.setNotBefore(X509V3CertificateGenerator.java:112)
    at android.security.AndroidKeyPairGenerator.generateKeyPair(AndroidKeyPairGenerator.java:128)
    at java.security.KeyPairGenerator$KeyPairGeneratorImpl.generateKeyPair(KeyPairGenerator.java:275)

一种解决方法是在生成密钥对之前设置英语区域设置,然后再将其更改回来:

A workaround is setting English locale before generating a key pair and changing it back after all:

/**
 * Generates RSA keys.
 */
private void generateRsaKeys(Context context, String rsaAlias) {
    try {
        // Set English locale as default (workaround)
        Locale initialLocale = Locale.getDefault();
        setLocale(Locale.ENGLISH);
        // Generate the RSA key pairs
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        end.add(Calendar.YEAR, 30); // 30 years
        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
                .setAlias(rsaAlias)
                .setSubject(new X500Principal("CN=" + rsaAlias + ", O=Organization"))
                .setSerialNumber(BigInteger.TEN)
                .setStartDate(start.getTime())
                .setEndDate(end.getTime())
                .build();
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA, ANDROID_KEY_STORE);
        kpg.initialize(spec);
        kpg.generateKeyPair();
        // Reset default locale
        setLocale(initialLocale);
    } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
        Log.e(e, "generateRsaKeys: ");
    }
}

/**
 * Sets default locale.
 */
private void setLocale(Locale locale) {
    Locale.setDefault(locale);
    Resources resources = context.getResources();
    Configuration config = resources.getConfiguration();
    config.locale = locale;
    resources.updateConfiguration(config, resources.getDisplayMetrics());
}

这篇关于在AndroidKeyStore密钥生成期间出现IllegalArgumentException(Unparseable date)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆