public static ECDSASignature decodeFromDER(byte[] bytes) { ASN1InputStream decoder = null; try { decoder = new ASN1InputStream(bytes); DLSequence seq = (DLSequence) decoder.readObject(); if (seq == null) throw new RuntimeException("Reached past end of ASN.1 stream."); ASN1Integer r, s; try { r = (ASN1Integer) seq.getObjectAt(0); s = (ASN1Integer) seq.getObjectAt(1); } catch (ClassCastException e) { throw new IllegalArgumentException(e); } // OpenSSL deviates from the DER spec by interpreting these values as unsigned, though they // should not be // Thus, we always use the positive versions. See: http://r6.ca/blog/20111119T211504Z.html return new ECDSASignature(r.getPositiveValue(), s.getPositiveValue()); } catch (IOException e) { throw new RuntimeException(e); } finally { if (decoder != null) try { decoder.close(); } catch (IOException x) { } } }
/** * Convert an inline encoded hex string rendition of an ASN.1 object back into its corresponding * ASN.1 object. * * @param str the hex encoded object * @param off the index at which the encoding starts * @return the decoded object */ protected ASN1Primitive convertHexEncoded(String str, int off) throws IOException { str = Strings.toLowerCase(str); byte[] data = new byte[(str.length() - off) / 2]; for (int index = 0; index != data.length; index++) { char left = str.charAt((index * 2) + off); char right = str.charAt((index * 2) + off + 1); if (left < 'a') { data[index] = (byte) ((left - '0') << 4); } else { data[index] = (byte) ((left - 'a' + 10) << 4); } if (right < 'a') { data[index] |= (byte) (right - '0'); } else { data[index] |= (byte) (right - 'a' + 10); } } ASN1InputStream aIn = new ASN1InputStream(data); return aIn.readObject(); }