package org.jolokia.jvmagent.security;/* * * Copyright 2015 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.*; import java.math.BigInteger; import java.security.spec.RSAPrivateCrtKeySpec; /** * This code is inspired and taken over from net.auth.core:oauth * (albeit in a highly stripped variation): * <p/> * Source is from http://oauth.googlecode.com/svn/code/java/ which is licensed * under the APL (http://oauth.googlecode.com/svn/code/java/LICENSE.txt) * <p/> * All credits go to the original author (zhang) * * @author roland * @since 30/09/15 */ class PKCS1Util { private PKCS1Util() { } public static RSAPrivateCrtKeySpec decodePKCS1(byte[] keyBytes) throws IOException { DerParser parser = new DerParser(keyBytes); Asn1Object sequence = parser.read(); sequence.validateSequence(); parser = new DerParser(sequence.getValue()); parser.read(); return new RSAPrivateCrtKeySpec(next(parser), next(parser), next(parser), next(parser), next(parser), next(parser), next(parser), next(parser)); } // ========================================================================================== private static BigInteger next(DerParser parser) throws IOException { return parser.read().getInteger(); } static class DerParser { private InputStream in; DerParser(byte[] bytes) throws IOException { this.in = new ByteArrayInputStream(bytes); } Asn1Object read() throws IOException { int tag = in.read(); if (tag == -1) { throw new IOException("Invalid DER: stream too short, missing tag"); } int length = getLength(); byte[] value = new byte[length]; if (in.read(value) < length) { throw new IOException("Invalid DER: stream too short, missing value"); } return new Asn1Object(tag, value); } private int getLength() throws IOException { int i = in.read(); if (i == -1) { throw new IOException("Invalid DER: length missing"); } if ((i & ~0x7F) == 0) { return i; } int num = i & 0x7F; if (i >= 0xFF || num > 4) { throw new IOException("Invalid DER: length field too big (" + i + ")"); } byte[] bytes = new byte[num]; if (in.read(bytes) < num) { throw new IOException("Invalid DER: length too short"); } return new BigInteger(1, bytes).intValue(); } } static class Asn1Object { private final int type; private final byte[] value; private final int tag; public Asn1Object(int tag, byte[] value) { this.tag = tag; this.type = tag & 0x1F; this.value = value; } public byte[] getValue() { return value; } BigInteger getInteger() throws IOException { if (type != 0x02) { throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$ } return new BigInteger(value); } void validateSequence() throws IOException { if (type != 0x10) { throw new IOException("Invalid DER: not a sequence"); } if ((tag & 0x20) != 0x20) { throw new IOException("Invalid DER: can't parse primitive entity"); } } } }