【发布时间】:2016-03-14 12:24:57
【问题描述】:
在使用AndroidKeyStore 生成 RSA 密钥期间,我在我的应用程序中遇到了以下问题,但我了解到它可以很容易地在 Android SDK 的 BasicAndroidKeyStore 示例应用程序中重现。因此,如果您有 Locale.getDefault() == Locale.US,则此示例运行良好,但如果您将语言环境更改为,例如,"ar_EG",它将崩溃并出现异常:
java.lang.IllegalArgumentException:无效的日期字符串:无法解析 日期:“af`cadaaedcaGMT+00:00”(偏移量 0) 在 com.android.org.bouncycastle.asn1.DERUTCTime.(DERUTCTime.java:98) 在 com.android.org.bouncycastle.asn1.x509.Time.(Time.java:62) 在 com.android.org.bouncycastle.x509.X509V3CertificateGenerator.setNotBefore(X509V3CertificateGenerator.java:112) 在 android.security.AndroidKeyPairGenerator.generateKeyPair(AndroidKeyPairGenerator.java:127) 在 java.security.KeyPairGenerator$KeyPairGeneratorImpl.generateKeyPair(KeyPairGenerator.java:276) 在 com.example.android.basicandroidkeystore.BasicAndroidKeyStoreFragment.createKeys(BasicAndroidKeyStoreFragment.java:237)
因此,问题在于密钥有效时间转换为相对于默认区域设置的字符串。
这是来自ASN1UTCTime 类的代码sn-p,它在KeyPairGenerator.generateKeyPair() 的底层使用以下方法调用:
public ASN1UTCTime(
String time)
{
this.time = Strings.toByteArray(time);
try
{
this.getDate();
}
catch (ParseException e)
{
throw new IllegalArgumentException("invalid date string: " + e.getMessage());
}
}
在调用此方法之前,将 Date 对象传递给以下 Time 构造函数,该构造函数使用默认系统语言环境:
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类还有一个构造函数,似乎更适合国际化工作:
/**
* 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));
}
那么,什么是正确的解决方法或建议如何解决这个问题?
【问题讨论】:
-
1.您看到此内容的 Android 设备的 Android 版本、制造商编号和型号是什么? 2. 如果在生成密钥对和自签名证书之前调用Locale.setDefault(Locale.US),问题会消失吗?
-
1.我在 Lenovo A536 (4.4.2) 和 LG Nexus 4 (5.1.1) 上对此进行了测试。
-
2.是的,在我第一次发现这个问题之后,我试图从代码中更改语言环境。这个修复解决了这个问题,但它看起来很脏,因为我们应用程序的其他部分可能会调用 Locale.getDefault() 并获得错误的值。