Remove spongycastle, use maven repos in zipsigner
This commit is contained in:
parent
51676bf255
commit
4e81aba841
22
extern/spongycastle/LICENSE.html
vendored
22
extern/spongycastle/LICENSE.html
vendored
@ -1,22 +0,0 @@
|
|||||||
<html>
|
|
||||||
<body bgcolor=#ffffff>
|
|
||||||
|
|
||||||
Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org)
|
|
||||||
<p>
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
||||||
and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
||||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
<p>
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
||||||
portions of the Software.
|
|
||||||
<p>
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
||||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
</body>
|
|
||||||
</html>
|
|
13
extern/spongycastle/build.gradle
vendored
13
extern/spongycastle/build.gradle
vendored
@ -1,13 +0,0 @@
|
|||||||
subprojects {
|
|
||||||
apply plugin: 'java'
|
|
||||||
|
|
||||||
group = 'com.madgag.spongycastle'
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceCompatibility = 1.5
|
|
||||||
targetCompatibility = 1.5
|
|
||||||
version = '1.51.0.0'
|
|
||||||
}
|
|
5
extern/spongycastle/core/build.gradle
vendored
5
extern/spongycastle/core/build.gradle
vendored
@ -1,5 +0,0 @@
|
|||||||
apply plugin: 'java'
|
|
||||||
|
|
||||||
sourceCompatibility = 1.5
|
|
||||||
targetCompatibility = 1.5
|
|
||||||
version = '1.51.0.0'
|
|
@ -1,56 +0,0 @@
|
|||||||
package java.io;
|
|
||||||
|
|
||||||
public class FilterInputStream extends InputStream
|
|
||||||
{
|
|
||||||
protected InputStream in;
|
|
||||||
|
|
||||||
protected FilterInputStream(InputStream underlying)
|
|
||||||
{
|
|
||||||
in = underlying;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read() throws IOException
|
|
||||||
{
|
|
||||||
return in.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read(byte[] b) throws IOException
|
|
||||||
{
|
|
||||||
return read(b, 0, b.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read(byte[] b, int offset, int length) throws IOException
|
|
||||||
{
|
|
||||||
return in.read(b, offset, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long skip(long n) throws IOException
|
|
||||||
{
|
|
||||||
return in.skip(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int available() throws IOException
|
|
||||||
{
|
|
||||||
return in.available();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException
|
|
||||||
{
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mark(int readlimit)
|
|
||||||
{
|
|
||||||
in.mark(readlimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() throws IOException
|
|
||||||
{
|
|
||||||
in.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean markSupported()
|
|
||||||
{
|
|
||||||
return in.markSupported();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package java.io;
|
|
||||||
|
|
||||||
public class FilterOutputStream extends OutputStream
|
|
||||||
{
|
|
||||||
protected OutputStream out;
|
|
||||||
|
|
||||||
protected FilterOutputStream(OutputStream underlying)
|
|
||||||
{
|
|
||||||
out = underlying;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(int b) throws IOException
|
|
||||||
{
|
|
||||||
out.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b) throws IOException
|
|
||||||
{
|
|
||||||
write(b, 0, b.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b, int offset, int length) throws IOException
|
|
||||||
{
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
write(b[offset + i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() throws IOException
|
|
||||||
{
|
|
||||||
out.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException
|
|
||||||
{
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,141 +0,0 @@
|
|||||||
package java.security;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.spongycastle.crypto.digests.SHA1Digest;
|
|
||||||
import org.spongycastle.crypto.digests.SHA256Digest;
|
|
||||||
import org.spongycastle.crypto.prng.RandomGenerator;
|
|
||||||
import org.spongycastle.crypto.prng.DigestRandomGenerator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of SecureRandom specifically for the light-weight API, JDK
|
|
||||||
* 1.0, and the J2ME. Random generation is based on the traditional SHA1 with
|
|
||||||
* counter. Calling setSeed will always increase the entropy of the hash.
|
|
||||||
* <p>
|
|
||||||
* <b>Do not use this class without calling setSeed at least once</b>! There
|
|
||||||
* are some example seed generators in the org.spongycastle.prng package.
|
|
||||||
*/
|
|
||||||
public class SecureRandom extends java.util.Random
|
|
||||||
{
|
|
||||||
// Note: all objects of this class should be deriving their random data from
|
|
||||||
// a single generator appropriate to the digest being used.
|
|
||||||
private static final RandomGenerator sha1Generator = new DigestRandomGenerator(new SHA1Digest());
|
|
||||||
private static final RandomGenerator sha256Generator = new DigestRandomGenerator(new SHA256Digest());
|
|
||||||
|
|
||||||
protected RandomGenerator generator;
|
|
||||||
|
|
||||||
// public constructors
|
|
||||||
public SecureRandom()
|
|
||||||
{
|
|
||||||
this(sha1Generator);
|
|
||||||
setSeed(System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
public SecureRandom(byte[] inSeed)
|
|
||||||
{
|
|
||||||
this(sha1Generator);
|
|
||||||
setSeed(inSeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SecureRandom(
|
|
||||||
RandomGenerator generator)
|
|
||||||
{
|
|
||||||
super(0);
|
|
||||||
this.generator = generator;
|
|
||||||
}
|
|
||||||
|
|
||||||
// protected constructors
|
|
||||||
// protected SecureRandom(SecureRandomSpi srs, Provider provider);
|
|
||||||
|
|
||||||
// public class methods
|
|
||||||
public static SecureRandom getInstance(String algorithm)
|
|
||||||
{
|
|
||||||
if (algorithm.equals("SHA1PRNG"))
|
|
||||||
{
|
|
||||||
return new SecureRandom(sha1Generator);
|
|
||||||
}
|
|
||||||
if (algorithm.equals("SHA256PRNG"))
|
|
||||||
{
|
|
||||||
return new SecureRandom(sha256Generator);
|
|
||||||
}
|
|
||||||
return new SecureRandom(); // follow old behaviour
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SecureRandom getInstance(String algorithm, String provider)
|
|
||||||
{
|
|
||||||
return getInstance(algorithm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] getSeed(int numBytes)
|
|
||||||
{
|
|
||||||
byte[] rv = new byte[numBytes];
|
|
||||||
|
|
||||||
sha1Generator.addSeedMaterial(System.currentTimeMillis());
|
|
||||||
sha1Generator.nextBytes(rv);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// public instance methods
|
|
||||||
public byte[] generateSeed(int numBytes)
|
|
||||||
{
|
|
||||||
byte[] rv = new byte[numBytes];
|
|
||||||
|
|
||||||
nextBytes(rv);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// public final Provider getProvider();
|
|
||||||
public void setSeed(byte[] inSeed)
|
|
||||||
{
|
|
||||||
generator.addSeedMaterial(inSeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// public methods overriding random
|
|
||||||
public void nextBytes(byte[] bytes)
|
|
||||||
{
|
|
||||||
generator.nextBytes(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSeed(long rSeed)
|
|
||||||
{
|
|
||||||
if (rSeed != 0) // to avoid problems with Random calling setSeed in construction
|
|
||||||
{
|
|
||||||
generator.addSeedMaterial(rSeed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int nextInt()
|
|
||||||
{
|
|
||||||
byte[] intBytes = new byte[4];
|
|
||||||
|
|
||||||
nextBytes(intBytes);
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
result = (result << 8) + (intBytes[i] & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final int next(int numBits)
|
|
||||||
{
|
|
||||||
int size = (numBits + 7) / 8;
|
|
||||||
byte[] bytes = new byte[size];
|
|
||||||
|
|
||||||
nextBytes(bytes);
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
result = (result << 8) + (bytes[i] & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result & ((1 << numBits) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,261 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public abstract class AbstractCollection
|
|
||||||
implements Collection
|
|
||||||
{
|
|
||||||
protected AbstractCollection()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Iterator iterator();
|
|
||||||
|
|
||||||
public abstract int size();
|
|
||||||
|
|
||||||
public boolean isEmpty()
|
|
||||||
{
|
|
||||||
return size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Object o)
|
|
||||||
{
|
|
||||||
Iterator it = iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Object e = it.next();
|
|
||||||
if (o == null)
|
|
||||||
{
|
|
||||||
if (e == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (o.equals(e))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] toArray()
|
|
||||||
{
|
|
||||||
Object[] arObjects = new Object[size()];
|
|
||||||
Iterator it = iterator();
|
|
||||||
int i = 0;
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
arObjects[i++] = it.next();
|
|
||||||
}
|
|
||||||
return arObjects;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] toArray(Object[] a)
|
|
||||||
throws NullPointerException, ArrayStoreException
|
|
||||||
//TODO: Check if this is realy compatible to SUN!!!
|
|
||||||
{
|
|
||||||
if (a == null)
|
|
||||||
{
|
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isEmpty())
|
|
||||||
{
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
Object[] arObjects = null;
|
|
||||||
int size = size();
|
|
||||||
if (a.length < size)
|
|
||||||
{
|
|
||||||
Iterator it = iterator();
|
|
||||||
Object o = it.next();
|
|
||||||
if (o == null) //no object or object is null
|
|
||||||
{
|
|
||||||
throw new ArrayStoreException(); //correct ?
|
|
||||||
}
|
|
||||||
throw new ArrayStoreException("please pass array of correct size");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arObjects = a;
|
|
||||||
if (a.length > size)
|
|
||||||
{
|
|
||||||
arObjects[size] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator it = iterator();
|
|
||||||
int i = 0;
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Object o = it.next();
|
|
||||||
arObjects[i++] = o;
|
|
||||||
}
|
|
||||||
return arObjects;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(Object o)
|
|
||||||
throws RuntimeException, NullPointerException, ClassCastException, IllegalArgumentException
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(Object o)
|
|
||||||
throws RuntimeException
|
|
||||||
{
|
|
||||||
Iterator it = iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Object e = it.next();
|
|
||||||
if (o == null)
|
|
||||||
{
|
|
||||||
if (e == null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
catch (RuntimeException ue)
|
|
||||||
{
|
|
||||||
throw ue;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (o.equals(e))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
catch (RuntimeException ue)
|
|
||||||
{
|
|
||||||
throw ue;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsAll(Collection c)
|
|
||||||
{
|
|
||||||
Iterator it = c.iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
if (!contains(it.next()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addAll(Collection c)
|
|
||||||
throws RuntimeException
|
|
||||||
{
|
|
||||||
Iterator it = c.iterator();
|
|
||||||
boolean ret = false;
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ret |= add(it.next());
|
|
||||||
}
|
|
||||||
catch (RuntimeException ue)
|
|
||||||
{
|
|
||||||
throw ue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeAll(Collection c)
|
|
||||||
throws RuntimeException
|
|
||||||
{
|
|
||||||
Iterator it = iterator();
|
|
||||||
boolean ret = false;
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
if (c.contains(it.next()))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
it.remove();
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
catch (RuntimeException ue)
|
|
||||||
{
|
|
||||||
throw ue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean retainAll(Collection c)
|
|
||||||
throws RuntimeException
|
|
||||||
{
|
|
||||||
Iterator it = iterator();
|
|
||||||
boolean ret = false;
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
if (!c.contains(it.next()))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
it.remove();
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
catch (RuntimeException ue)
|
|
||||||
{
|
|
||||||
throw ue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear()
|
|
||||||
throws RuntimeException
|
|
||||||
{
|
|
||||||
Iterator it = iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
it.next();
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
catch (RuntimeException ue)
|
|
||||||
{
|
|
||||||
throw ue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
StringBuffer ret = new StringBuffer("[");
|
|
||||||
Iterator it = iterator();
|
|
||||||
if (it.hasNext())
|
|
||||||
{
|
|
||||||
ret.append(String.valueOf(it.next()));
|
|
||||||
}
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
ret.append(", ");
|
|
||||||
ret.append(String.valueOf(it.next()));
|
|
||||||
|
|
||||||
}
|
|
||||||
ret.append("]");
|
|
||||||
return ret.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,304 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public abstract class AbstractList
|
|
||||||
extends AbstractCollection
|
|
||||||
implements List
|
|
||||||
{
|
|
||||||
protected AbstractList al = this;
|
|
||||||
|
|
||||||
|
|
||||||
protected AbstractList()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(Object o)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
add(size(), o);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (RuntimeException ue)
|
|
||||||
{
|
|
||||||
throw ue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Object get(int index)
|
|
||||||
throws IndexOutOfBoundsException;
|
|
||||||
|
|
||||||
public Object set(int index, Object element)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(int index, Object element)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object remove(int index)
|
|
||||||
throws RuntimeException, IndexOutOfBoundsException
|
|
||||||
{
|
|
||||||
Object o = get(index);
|
|
||||||
|
|
||||||
removeRange(index, index + 1);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int indexOf(Object o)
|
|
||||||
{
|
|
||||||
ListIterator li = listIterator();
|
|
||||||
Object e;
|
|
||||||
while (li.hasNext())
|
|
||||||
{
|
|
||||||
int index = li.nextIndex();
|
|
||||||
e = li.next();
|
|
||||||
|
|
||||||
if (o == null)
|
|
||||||
{
|
|
||||||
if (e == null)
|
|
||||||
{
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (o.equals(e))
|
|
||||||
{
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int lastIndexOf(Object o)
|
|
||||||
{
|
|
||||||
ListIterator li = listIterator(size());
|
|
||||||
while (li.hasPrevious())
|
|
||||||
{
|
|
||||||
int index = li.previousIndex();
|
|
||||||
Object e = li.previous();
|
|
||||||
if (o == null)
|
|
||||||
{
|
|
||||||
if (e == null)
|
|
||||||
{
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (o.equals(e))
|
|
||||||
{
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear()
|
|
||||||
throws RuntimeException
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
removeRange(0, size());
|
|
||||||
}
|
|
||||||
catch (RuntimeException ue)
|
|
||||||
{
|
|
||||||
throw ue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addAll(int index, Collection c)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException
|
|
||||||
{
|
|
||||||
Iterator it = c.iterator();
|
|
||||||
boolean ret = false;
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
add(index++, it.next());
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
catch (RuntimeException ue)
|
|
||||||
{
|
|
||||||
throw ue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator iterator()
|
|
||||||
{
|
|
||||||
return new AbstractListIterator(this, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ListIterator listIterator()
|
|
||||||
{
|
|
||||||
return listIterator(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ListIterator listIterator(int index)
|
|
||||||
throws IndexOutOfBoundsException
|
|
||||||
{
|
|
||||||
if (index < 0 || index > size())
|
|
||||||
{
|
|
||||||
throw new IndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
return new AbstractListListIterator(this, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List subList(int fromIndex, int toIndex)
|
|
||||||
throws IndexOutOfBoundsException, IllegalArgumentException
|
|
||||||
{
|
|
||||||
if (fromIndex < 0 || toIndex > size())
|
|
||||||
{
|
|
||||||
throw new IndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
if (fromIndex > toIndex)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
return (List)new Sublist(this, fromIndex, toIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
if (o == this)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(o instanceof List))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Iterator it1 = iterator();
|
|
||||||
Iterator it2 = ((List)o).iterator();
|
|
||||||
while (it1.hasNext())
|
|
||||||
{
|
|
||||||
if (!it2.hasNext())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Object e1 = it1.next();
|
|
||||||
Object e2 = it2.next();
|
|
||||||
if (e1 == null)
|
|
||||||
{
|
|
||||||
if (e2 != null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!e1.equals(e2))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
int hashCode = 1;
|
|
||||||
Iterator it = iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Object o = it.next();
|
|
||||||
hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
|
|
||||||
}
|
|
||||||
return hashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void removeRange(int fromIndex, int toIndex)
|
|
||||||
{
|
|
||||||
if (fromIndex == toIndex)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ListIterator li = listIterator(fromIndex);
|
|
||||||
|
|
||||||
int i = fromIndex;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
li.next();
|
|
||||||
li.remove();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
while (li.hasNext() && i < toIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AbstractListIterator
|
|
||||||
implements Iterator
|
|
||||||
{
|
|
||||||
AbstractList m_al = null;
|
|
||||||
int m_nextIndex = 0;
|
|
||||||
|
|
||||||
public AbstractListIterator(AbstractList al, int index)
|
|
||||||
{
|
|
||||||
m_al = al;
|
|
||||||
m_nextIndex = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNext()
|
|
||||||
{
|
|
||||||
return m_nextIndex < m_al.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object next()
|
|
||||||
{
|
|
||||||
return m_al.get(m_nextIndex++);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove()
|
|
||||||
{
|
|
||||||
m_al.remove(m_nextIndex - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AbstractListListIterator
|
|
||||||
extends AbstractListIterator
|
|
||||||
implements ListIterator
|
|
||||||
{
|
|
||||||
public AbstractListListIterator(AbstractList al, int index)
|
|
||||||
{
|
|
||||||
super(al, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPrevious()
|
|
||||||
{
|
|
||||||
return m_nextIndex > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object previous()// throws NoSuchElementException;
|
|
||||||
{
|
|
||||||
return m_al.get(--m_nextIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int nextIndex()
|
|
||||||
{
|
|
||||||
return m_nextIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int previousIndex()
|
|
||||||
{
|
|
||||||
return m_nextIndex - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(Object o) //throws RuntimeException, ClassCastException, IllegalArgumentException,IllegalStateException;
|
|
||||||
{
|
|
||||||
m_al.set(m_nextIndex - 1, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(Object o)// throws RuntimeException, ClassCastException, IllegalArgumentException;
|
|
||||||
{
|
|
||||||
m_al.add(m_nextIndex - 1, o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,173 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public abstract class AbstractMap
|
|
||||||
implements Map
|
|
||||||
{
|
|
||||||
|
|
||||||
protected AbstractMap()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return entrySet().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty()
|
|
||||||
{
|
|
||||||
return size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsValue(Object value)
|
|
||||||
{
|
|
||||||
Iterator it = entrySet().iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Map.Entry v = (Map.Entry)it.next();
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
if (v.getValue() == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (value.equals(v.getValue()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsKey(Object key)
|
|
||||||
throws ClassCastException, NullPointerException
|
|
||||||
{
|
|
||||||
Iterator it = entrySet().iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Map.Entry v = (Map.Entry)it.next();
|
|
||||||
if (key == null)
|
|
||||||
{
|
|
||||||
if (v.getKey() == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (key.equals(v.getKey()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(Object key)
|
|
||||||
throws ClassCastException, NullPointerException
|
|
||||||
{
|
|
||||||
Iterator it = entrySet().iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Map.Entry v = (Map.Entry)it.next();
|
|
||||||
if (key == null)
|
|
||||||
{
|
|
||||||
if (v.getKey() == null)
|
|
||||||
{
|
|
||||||
return v.getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (key.equals(v.getKey()))
|
|
||||||
{
|
|
||||||
return v.getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object put(Object key, Object value)
|
|
||||||
throws RuntimeException
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object remove(Object key)
|
|
||||||
{
|
|
||||||
Iterator it = entrySet().iterator();
|
|
||||||
Object o = null;
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Map.Entry v = (Map.Entry)it.next();
|
|
||||||
if (key == null)
|
|
||||||
{
|
|
||||||
if (v.getKey() == null)
|
|
||||||
{
|
|
||||||
o = v.getValue();
|
|
||||||
it.remove();
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (key.equals(v.getKey()))
|
|
||||||
{
|
|
||||||
o = v.getValue();
|
|
||||||
it.remove();
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll(Map t)
|
|
||||||
{
|
|
||||||
Iterator it = t.entrySet().iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Map.Entry v = (Map.Entry)it.next();
|
|
||||||
put(v.getKey(), v.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
entrySet().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set keySet()
|
|
||||||
{
|
|
||||||
throw new RuntimeException("no keySet in AbstractMap()");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection values()
|
|
||||||
{
|
|
||||||
throw new RuntimeException("no values in AbstractMap()");
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Set entrySet();
|
|
||||||
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("no equals in AbstractMap()");
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
throw new RuntimeException("no hashCode in AbstractMap()");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
throw new RuntimeException("no toString in AbstractMap()");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public abstract class AbstractSet
|
|
||||||
extends AbstractCollection
|
|
||||||
implements Set
|
|
||||||
{
|
|
||||||
protected AbstractSet()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
if (this == o)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (o == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(o instanceof Set))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (((Set)o).size() != size())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return containsAll((Collection)o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
int hashCode = 0;
|
|
||||||
Iterator it = iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Object o = it.next();
|
|
||||||
if (o != null)
|
|
||||||
{
|
|
||||||
hashCode += o.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hashCode;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public class ArrayList extends AbstractList
|
|
||||||
implements List
|
|
||||||
{
|
|
||||||
Vector m_Vector=null;
|
|
||||||
|
|
||||||
public ArrayList()
|
|
||||||
{
|
|
||||||
m_Vector=new Vector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList(Collection c)
|
|
||||||
{
|
|
||||||
m_Vector=new Vector((int)(c.size()*1.1));
|
|
||||||
addAll(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList(int initialCapacity)
|
|
||||||
{
|
|
||||||
m_Vector=new Vector(initialCapacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void trimToSize()
|
|
||||||
{
|
|
||||||
m_Vector.trimToSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ensureCapacity(int minCapacity)
|
|
||||||
{
|
|
||||||
m_Vector.ensureCapacity(minCapacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return m_Vector.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Object elem)
|
|
||||||
{
|
|
||||||
return m_Vector.contains(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int indexOf(Object elem)
|
|
||||||
{
|
|
||||||
return m_Vector.indexOf(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int lastIndexOf(Object elem)
|
|
||||||
{
|
|
||||||
return m_Vector.lastIndexOf(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object clone()
|
|
||||||
{
|
|
||||||
ArrayList al=new ArrayList(this);
|
|
||||||
|
|
||||||
return al;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] toArray()
|
|
||||||
{
|
|
||||||
Object[] o=new Object[m_Vector.size()];
|
|
||||||
m_Vector.copyInto(o);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(int index)
|
|
||||||
{
|
|
||||||
return m_Vector.elementAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object set(int index,Object elem)
|
|
||||||
{
|
|
||||||
Object o=m_Vector.elementAt(index);
|
|
||||||
m_Vector.setElementAt(elem,index);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(Object o)
|
|
||||||
{
|
|
||||||
m_Vector.addElement(o);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(int index,Object elem)
|
|
||||||
{
|
|
||||||
m_Vector.insertElementAt(elem,index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object remove(int index)
|
|
||||||
{
|
|
||||||
Object o=m_Vector.elementAt(index);
|
|
||||||
m_Vector.removeElementAt(index);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
m_Vector.removeAllElements();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public class Arrays
|
|
||||||
{
|
|
||||||
|
|
||||||
private Arrays()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void fill(byte[] ret, byte v)
|
|
||||||
{
|
|
||||||
for (int i = 0; i != ret.length; i++)
|
|
||||||
{
|
|
||||||
ret[i] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean equals(byte[] a, byte[] a2)
|
|
||||||
{
|
|
||||||
if (a == a2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (a == null || a2 == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int length = a.length;
|
|
||||||
if (a2.length != length)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
if (a[i] != a2[i])
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List asList(Object[] a)
|
|
||||||
{
|
|
||||||
return new ArrayList(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ArrayList
|
|
||||||
extends AbstractList
|
|
||||||
{
|
|
||||||
private Object[] a;
|
|
||||||
|
|
||||||
ArrayList(Object[] array)
|
|
||||||
{
|
|
||||||
a = array;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return a.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] toArray()
|
|
||||||
{
|
|
||||||
Object[] tmp = new Object[a.length];
|
|
||||||
|
|
||||||
System.arraycopy(a, 0, tmp, 0, tmp.length);
|
|
||||||
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(int index)
|
|
||||||
{
|
|
||||||
return a[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object set(int index, Object element)
|
|
||||||
{
|
|
||||||
Object oldValue = a[index];
|
|
||||||
a[index] = element;
|
|
||||||
return oldValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int indexOf(Object o)
|
|
||||||
{
|
|
||||||
if (o == null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < a.length; i++)
|
|
||||||
{
|
|
||||||
if (a[i] == null)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < a.length; i++)
|
|
||||||
{
|
|
||||||
if (o.equals(a[i]))
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Object o)
|
|
||||||
{
|
|
||||||
return indexOf(o) != -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
|
|
||||||
package java.util;
|
|
||||||
|
|
||||||
public interface Collection
|
|
||||||
{
|
|
||||||
public boolean add(Object o) throws RuntimeException,ClassCastException,IllegalArgumentException;
|
|
||||||
public boolean addAll(Collection c) throws RuntimeException,ClassCastException,IllegalArgumentException;
|
|
||||||
public void clear() throws RuntimeException;
|
|
||||||
public boolean contains(Object o);
|
|
||||||
public boolean containsAll(Collection c);
|
|
||||||
public boolean equals(Object o);
|
|
||||||
public int hashCode();
|
|
||||||
public boolean isEmpty();
|
|
||||||
public Iterator iterator();
|
|
||||||
public /*SK13*/boolean remove(Object o) throws RuntimeException;
|
|
||||||
public boolean removeAll(Collection c) throws RuntimeException;
|
|
||||||
public boolean retainAll(Collection c) throws RuntimeException;
|
|
||||||
public int size();
|
|
||||||
public Object[] toArray();
|
|
||||||
public Object[] toArray(Object[] a) throws ArrayStoreException;
|
|
||||||
}
|
|
@ -1,365 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public class Collections
|
|
||||||
{
|
|
||||||
public static List EMPTY_LIST = new ArrayList();
|
|
||||||
|
|
||||||
private Collections()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Collection unmodifiableCollection(Collection c)
|
|
||||||
{
|
|
||||||
return new UnmodifiableCollection(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UnmodifiableCollection
|
|
||||||
implements Collection
|
|
||||||
{
|
|
||||||
Collection c;
|
|
||||||
|
|
||||||
UnmodifiableCollection(Collection c)
|
|
||||||
{
|
|
||||||
this.c = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return c.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty()
|
|
||||||
{
|
|
||||||
return c.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Object o)
|
|
||||||
{
|
|
||||||
return c.contains(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] toArray()
|
|
||||||
{
|
|
||||||
return c.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] toArray(Object[] a)
|
|
||||||
{
|
|
||||||
return c.toArray(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator iterator()
|
|
||||||
{
|
|
||||||
return new Iterator()
|
|
||||||
{
|
|
||||||
Iterator i = c.iterator();
|
|
||||||
|
|
||||||
public boolean hasNext()
|
|
||||||
{
|
|
||||||
return i.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object next()
|
|
||||||
{
|
|
||||||
return i.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove()
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(Object o)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(Object o)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsAll(Collection coll)
|
|
||||||
{
|
|
||||||
return c.containsAll(coll);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addAll(Collection coll)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeAll(Collection coll)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean retainAll(Collection coll)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return c.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Set unmodifiableSet(Set s)
|
|
||||||
{
|
|
||||||
return new UnmodifiableSet(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UnmodifiableSet
|
|
||||||
extends UnmodifiableCollection
|
|
||||||
implements Set
|
|
||||||
{
|
|
||||||
UnmodifiableSet(Set s)
|
|
||||||
{
|
|
||||||
super(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
return c.equals(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return c.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map unmodifiableMap(Map map)
|
|
||||||
{
|
|
||||||
return new UnmodifiableMap(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UnmodifiableMap
|
|
||||||
implements Map
|
|
||||||
{
|
|
||||||
private Map map;
|
|
||||||
|
|
||||||
UnmodifiableMap(Map map)
|
|
||||||
{
|
|
||||||
this.map = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return map.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty()
|
|
||||||
{
|
|
||||||
return map.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsKey(Object key)
|
|
||||||
throws ClassCastException, NullPointerException
|
|
||||||
{
|
|
||||||
return map.containsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsValue(Object value)
|
|
||||||
{
|
|
||||||
return map.containsValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(Object key)
|
|
||||||
throws ClassCastException, NullPointerException
|
|
||||||
{
|
|
||||||
return map.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object put(Object key, Object value)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, NullPointerException
|
|
||||||
{
|
|
||||||
throw new RuntimeException("unsupported operation - map unmodifiable");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object remove(Object key)
|
|
||||||
throws RuntimeException
|
|
||||||
{
|
|
||||||
throw new RuntimeException("unsupported operation - map unmodifiable");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll(Map t)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, NullPointerException
|
|
||||||
{
|
|
||||||
throw new RuntimeException("unsupported operation - map unmodifiable");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear()
|
|
||||||
throws RuntimeException
|
|
||||||
{
|
|
||||||
throw new RuntimeException("unsupported operation - map unmodifiable");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set keySet()
|
|
||||||
{
|
|
||||||
return map.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection values()
|
|
||||||
{
|
|
||||||
return map.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set entrySet()
|
|
||||||
{
|
|
||||||
return map.entrySet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List unmodifiableList(List list)
|
|
||||||
{
|
|
||||||
return new UnmodifiableList(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UnmodifiableList
|
|
||||||
extends UnmodifiableCollection
|
|
||||||
implements List
|
|
||||||
{
|
|
||||||
private List list;
|
|
||||||
|
|
||||||
UnmodifiableList(List list)
|
|
||||||
{
|
|
||||||
super(list);
|
|
||||||
this.list = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
return list.equals(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return list.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(int index)
|
|
||||||
{
|
|
||||||
return list.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object set(int index, Object element)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(int index, Object element)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object remove(int index)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int indexOf(Object o)
|
|
||||||
{
|
|
||||||
return list.indexOf(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int lastIndexOf(Object o)
|
|
||||||
{
|
|
||||||
return list.lastIndexOf(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addAll(int index, Collection c)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ListIterator listIterator()
|
|
||||||
{
|
|
||||||
return listIterator(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ListIterator listIterator(final int index)
|
|
||||||
{
|
|
||||||
return new ListIterator()
|
|
||||||
{
|
|
||||||
ListIterator i = list.listIterator(index);
|
|
||||||
|
|
||||||
public boolean hasNext()
|
|
||||||
{
|
|
||||||
return i.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object next()
|
|
||||||
{
|
|
||||||
return i.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPrevious()
|
|
||||||
{
|
|
||||||
return i.hasPrevious();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object previous()
|
|
||||||
{
|
|
||||||
return i.previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int nextIndex()
|
|
||||||
{
|
|
||||||
return i.nextIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int previousIndex()
|
|
||||||
{
|
|
||||||
return i.previousIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove()
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(Object o)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(Object o)
|
|
||||||
{
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public List subList(int fromIndex, int toIndex)
|
|
||||||
{
|
|
||||||
return new UnmodifiableList(list.subList(fromIndex, toIndex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Enumeration enumeration(final Collection c)
|
|
||||||
{
|
|
||||||
return new Enumeration()
|
|
||||||
{
|
|
||||||
Iterator i = c.iterator();
|
|
||||||
|
|
||||||
public boolean hasMoreElements()
|
|
||||||
{
|
|
||||||
return i.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object nextElement()
|
|
||||||
{
|
|
||||||
return i.next();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,279 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
|
|
||||||
public class HashMap extends AbstractMap{
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
///// innere Klasse Null ////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
public class Null extends Object
|
|
||||||
{
|
|
||||||
public Null()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return "Nullobject";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
///// innere Klasse innerSet ////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class ISet extends AbstractSet implements java.util.Set
|
|
||||||
{
|
|
||||||
|
|
||||||
Vector vec = null;
|
|
||||||
|
|
||||||
public ISet()
|
|
||||||
{
|
|
||||||
|
|
||||||
vec = new Vector();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(Object o)
|
|
||||||
{
|
|
||||||
vec.addElement(o);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return vec.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator iterator()
|
|
||||||
{
|
|
||||||
return new IIterator(vec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
///// innere Klasse Iterator ////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
class IIterator implements java.util.Iterator
|
|
||||||
{
|
|
||||||
int index = 0;
|
|
||||||
Vector vec = null;
|
|
||||||
public IIterator(Vector ve)
|
|
||||||
{
|
|
||||||
vec = ve;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNext()
|
|
||||||
{
|
|
||||||
if (vec.size() > index) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object next()
|
|
||||||
{
|
|
||||||
Object o = vec.elementAt(index);
|
|
||||||
if (o==Nullobject) o=null;
|
|
||||||
index++;
|
|
||||||
return o;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove()
|
|
||||||
{
|
|
||||||
index--;
|
|
||||||
vec.removeElementAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
///// innere Klasse Entry ////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
class Entry implements Map.Entry
|
|
||||||
{
|
|
||||||
public Object key=null;
|
|
||||||
public Object value=null;
|
|
||||||
|
|
||||||
public Entry(Object ke,Object valu)
|
|
||||||
{
|
|
||||||
key = ke;
|
|
||||||
value = valu;
|
|
||||||
}
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
if (value == ((Entry)o).value && key == ((Entry)o).key ) return true;
|
|
||||||
else return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getValue()
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getKey()
|
|
||||||
{
|
|
||||||
return (Object)key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return value.hashCode() + key.hashCode();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object setValue(Object valu)
|
|
||||||
{
|
|
||||||
value = (String)valu;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private Hashtable m_HashTable=null;
|
|
||||||
private Null Nullobject = null;
|
|
||||||
|
|
||||||
public HashMap()
|
|
||||||
{
|
|
||||||
Nullobject = new Null();
|
|
||||||
m_HashTable=new Hashtable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap(int initialCapacity)
|
|
||||||
{
|
|
||||||
Nullobject = new Null();
|
|
||||||
m_HashTable=new Hashtable(initialCapacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap(Map t)
|
|
||||||
{
|
|
||||||
Nullobject = new Null();
|
|
||||||
m_HashTable=new Hashtable();
|
|
||||||
this.putAll(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
m_HashTable.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object clone()
|
|
||||||
{
|
|
||||||
HashMap hm=new HashMap(this);
|
|
||||||
|
|
||||||
return hm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsKey(Object key)
|
|
||||||
{
|
|
||||||
if (key == null) key = Nullobject;
|
|
||||||
boolean b = m_HashTable.containsKey(key);
|
|
||||||
return b;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsValue(Object value)
|
|
||||||
{
|
|
||||||
if (value == null ) value = Nullobject;
|
|
||||||
boolean b = m_HashTable.contains(value);
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set entrySet()
|
|
||||||
{
|
|
||||||
|
|
||||||
Object Key = null;
|
|
||||||
ISet s = new ISet();
|
|
||||||
Enumeration en = m_HashTable.keys();
|
|
||||||
while (en.hasMoreElements())
|
|
||||||
{
|
|
||||||
Key = en.nextElement();
|
|
||||||
s.add(new Entry(Key,m_HashTable.get(Key)));
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(Object key)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (key==null) key= Nullobject;
|
|
||||||
|
|
||||||
Object o = m_HashTable.get(key);
|
|
||||||
|
|
||||||
if (o == Nullobject) o=null;
|
|
||||||
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty()
|
|
||||||
{
|
|
||||||
return m_HashTable.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set keySet()
|
|
||||||
{
|
|
||||||
ISet s=new ISet();
|
|
||||||
Enumeration en = m_HashTable.keys();
|
|
||||||
|
|
||||||
while (en.hasMoreElements())
|
|
||||||
{
|
|
||||||
s.add(en.nextElement());
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object put(Object key, Object value)
|
|
||||||
{
|
|
||||||
if (key==null) key=Nullobject;
|
|
||||||
if (value==null) value = Nullobject;
|
|
||||||
return m_HashTable.put(key,value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll(Map m)
|
|
||||||
{
|
|
||||||
Iterator it = m.entrySet().iterator();
|
|
||||||
Object key=null;
|
|
||||||
Object value=null;
|
|
||||||
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Map.Entry me = (Map.Entry)it.next();
|
|
||||||
if (me.getKey() == null) key = Nullobject;
|
|
||||||
else key= me.getKey();
|
|
||||||
if (me.getValue()==null) value = Nullobject;
|
|
||||||
else value = me.getValue();
|
|
||||||
m_HashTable.put(key,value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object remove(Object key)
|
|
||||||
{
|
|
||||||
return m_HashTable.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return m_HashTable.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection values()
|
|
||||||
{
|
|
||||||
|
|
||||||
ISet s=new ISet();
|
|
||||||
Enumeration en = m_HashTable.keys();
|
|
||||||
|
|
||||||
while (en.hasMoreElements())
|
|
||||||
{
|
|
||||||
Object Key = en.nextElement();
|
|
||||||
//s.add(((Map.Entry)m_HashTable.get(Key)).getValue());
|
|
||||||
s.add(m_HashTable.get(Key));
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public class HashSet
|
|
||||||
extends AbstractSet
|
|
||||||
{
|
|
||||||
private HashMap m_HashMap = null;
|
|
||||||
|
|
||||||
public HashSet()
|
|
||||||
{
|
|
||||||
m_HashMap = new HashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashSet(Collection c)
|
|
||||||
{
|
|
||||||
m_HashMap = new HashMap(Math.max(11, c.size() * 2));
|
|
||||||
addAll(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashSet(int initialCapacity)
|
|
||||||
{
|
|
||||||
m_HashMap = new HashMap(initialCapacity);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator iterator()
|
|
||||||
{
|
|
||||||
return (m_HashMap.keySet()).iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return m_HashMap.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Object o)
|
|
||||||
{
|
|
||||||
return m_HashMap.containsKey(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(Object o)
|
|
||||||
{
|
|
||||||
if (!m_HashMap.containsValue(o))
|
|
||||||
{
|
|
||||||
m_HashMap.put((Object)o, (Object)o);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(Object o)
|
|
||||||
{
|
|
||||||
return (m_HashMap.remove(o) != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
m_HashMap.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Object clone()
|
|
||||||
{
|
|
||||||
HashSet hs = new HashSet();
|
|
||||||
hs.m_HashMap = (HashMap)m_HashMap.clone();
|
|
||||||
return hs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
package java.util;
|
|
||||||
|
|
||||||
public interface Iterator
|
|
||||||
{
|
|
||||||
public abstract boolean hasNext();
|
|
||||||
public abstract Object next() throws NoSuchElementException;
|
|
||||||
public abstract void remove() throws RuntimeException,IllegalStateException;
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public interface List
|
|
||||||
extends Collection
|
|
||||||
{
|
|
||||||
void add(int index, Object element)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException;
|
|
||||||
|
|
||||||
boolean addAll(int index, Collection c)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException;
|
|
||||||
|
|
||||||
Object get(int index)
|
|
||||||
throws IndexOutOfBoundsException;
|
|
||||||
|
|
||||||
int indexOf(Object o);
|
|
||||||
|
|
||||||
int lastIndexOf(Object o);
|
|
||||||
|
|
||||||
ListIterator listIterator();
|
|
||||||
|
|
||||||
ListIterator listIterator(int index)
|
|
||||||
throws IndexOutOfBoundsException;
|
|
||||||
|
|
||||||
Object remove(int index)
|
|
||||||
throws RuntimeException, IndexOutOfBoundsException;
|
|
||||||
|
|
||||||
Object set(int index, Object element)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException;
|
|
||||||
|
|
||||||
List subList(int fromIndex, int toIndex)
|
|
||||||
throws IndexOutOfBoundsException;
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public interface ListIterator
|
|
||||||
extends Iterator
|
|
||||||
{
|
|
||||||
public boolean hasPrevious();
|
|
||||||
|
|
||||||
public Object previous()
|
|
||||||
throws NoSuchElementException;
|
|
||||||
|
|
||||||
public int nextIndex();
|
|
||||||
|
|
||||||
public int previousIndex();
|
|
||||||
|
|
||||||
public void set(Object o)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, IllegalStateException;
|
|
||||||
|
|
||||||
public void add(Object o)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException;
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public interface Map
|
|
||||||
{
|
|
||||||
|
|
||||||
public static interface Entry
|
|
||||||
{
|
|
||||||
public Object getKey();
|
|
||||||
|
|
||||||
public Object getValue();
|
|
||||||
|
|
||||||
public Object setValue(Object value)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, NullPointerException;
|
|
||||||
|
|
||||||
public boolean equals(Object o);
|
|
||||||
|
|
||||||
public int hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size();
|
|
||||||
|
|
||||||
public boolean isEmpty();
|
|
||||||
|
|
||||||
public boolean containsKey(Object Key)
|
|
||||||
throws ClassCastException, NullPointerException;
|
|
||||||
|
|
||||||
public boolean containsValue(Object value);
|
|
||||||
|
|
||||||
public Object get(Object key)
|
|
||||||
throws ClassCastException, NullPointerException;
|
|
||||||
|
|
||||||
public Object put(Object key, Object value)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, NullPointerException;
|
|
||||||
|
|
||||||
public Object remove(Object key)
|
|
||||||
throws RuntimeException;
|
|
||||||
|
|
||||||
public void putAll(Map t)
|
|
||||||
throws RuntimeException, ClassCastException, IllegalArgumentException, NullPointerException;
|
|
||||||
|
|
||||||
public void clear()
|
|
||||||
throws RuntimeException;
|
|
||||||
|
|
||||||
public Set keySet();
|
|
||||||
|
|
||||||
public Collection values();
|
|
||||||
|
|
||||||
public Set entrySet();
|
|
||||||
|
|
||||||
public boolean equals(Object o);
|
|
||||||
|
|
||||||
public int hashCode();
|
|
||||||
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public interface Set
|
|
||||||
extends Collection
|
|
||||||
{
|
|
||||||
|
|
||||||
public int size();
|
|
||||||
|
|
||||||
public boolean isEmpty();
|
|
||||||
|
|
||||||
public boolean contains(Object o);
|
|
||||||
|
|
||||||
public Iterator iterator();
|
|
||||||
|
|
||||||
public Object[] toArray();
|
|
||||||
|
|
||||||
public Object[] toArray(Object[] a);
|
|
||||||
|
|
||||||
public boolean add(Object o);
|
|
||||||
|
|
||||||
public boolean remove(Object o);
|
|
||||||
|
|
||||||
public boolean containsAll(Collection c);
|
|
||||||
|
|
||||||
public boolean addAll(Collection c);
|
|
||||||
|
|
||||||
public boolean retainAll(Collection c);
|
|
||||||
|
|
||||||
public boolean removeAll(Collection c);
|
|
||||||
|
|
||||||
public void clear();
|
|
||||||
|
|
||||||
public boolean equals(Object o);
|
|
||||||
|
|
||||||
public int hashCode();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
public class StringTokenizer
|
|
||||||
implements Enumeration
|
|
||||||
{
|
|
||||||
private String s;
|
|
||||||
private String delims;
|
|
||||||
private boolean retDelims;
|
|
||||||
private int maxPos;
|
|
||||||
|
|
||||||
private int pos;
|
|
||||||
|
|
||||||
public StringTokenizer(String s, String delims)
|
|
||||||
{
|
|
||||||
this(s, delims, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringTokenizer(String s, String delims, boolean retDelims)
|
|
||||||
{
|
|
||||||
this.s = s;
|
|
||||||
this.delims = delims;
|
|
||||||
this.retDelims = retDelims;
|
|
||||||
this.maxPos = s.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMoreTokens()
|
|
||||||
{
|
|
||||||
if (retDelims)
|
|
||||||
{
|
|
||||||
return pos < maxPos;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int next = pos;
|
|
||||||
while (next < maxPos && isDelim(next))
|
|
||||||
{
|
|
||||||
next++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return next < maxPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String nextToken()
|
|
||||||
{
|
|
||||||
String tok;
|
|
||||||
|
|
||||||
if (pos == maxPos)
|
|
||||||
{
|
|
||||||
throw new NoSuchElementException("no more tokens");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retDelims)
|
|
||||||
{
|
|
||||||
if (isDelim(pos))
|
|
||||||
{
|
|
||||||
tok = s.substring(pos, pos + 1);
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (pos < maxPos && isDelim(pos))
|
|
||||||
{
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int start = pos;
|
|
||||||
|
|
||||||
while (pos < maxPos && !isDelim(pos))
|
|
||||||
{
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos < maxPos)
|
|
||||||
{
|
|
||||||
tok = s.substring(start, pos);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tok = s.substring(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMoreElements()
|
|
||||||
{
|
|
||||||
return hasMoreTokens();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object nextElement()
|
|
||||||
{
|
|
||||||
return nextToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isDelim(int index)
|
|
||||||
{
|
|
||||||
char c = s.charAt(index);
|
|
||||||
|
|
||||||
for (int i = 0; i != delims.length(); i++)
|
|
||||||
{
|
|
||||||
if (delims.charAt(i) == c)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
package java.util;
|
|
||||||
|
|
||||||
public class Sublist
|
|
||||||
extends AbstractList
|
|
||||||
{
|
|
||||||
AbstractList m_al = null;
|
|
||||||
int m_fromIndex = 0;
|
|
||||||
int m_toIndex = 0;
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
public Sublist(AbstractList ali, int fromIndex, int toIndex)
|
|
||||||
{
|
|
||||||
m_al = ali;
|
|
||||||
m_toIndex = toIndex;
|
|
||||||
m_fromIndex = fromIndex;
|
|
||||||
size = size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object set(int index, Object o)
|
|
||||||
{
|
|
||||||
if (index < size)
|
|
||||||
{
|
|
||||||
o = m_al.set(index + m_fromIndex, o);
|
|
||||||
if (o != null)
|
|
||||||
{
|
|
||||||
size++;
|
|
||||||
m_toIndex++;
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(int index)
|
|
||||||
throws IndexOutOfBoundsException
|
|
||||||
{
|
|
||||||
if (index < size)
|
|
||||||
{
|
|
||||||
return m_al.get(index + m_fromIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(int index, Object o)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (index <= size)
|
|
||||||
{
|
|
||||||
m_al.add(index + m_fromIndex, o);
|
|
||||||
m_toIndex++;
|
|
||||||
size++;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object remove(int index, Object o)
|
|
||||||
{
|
|
||||||
if (index < size)
|
|
||||||
{
|
|
||||||
Object ob = m_al.remove(index + m_fromIndex);
|
|
||||||
if (ob != null)
|
|
||||||
{
|
|
||||||
m_toIndex--;
|
|
||||||
size--;
|
|
||||||
}
|
|
||||||
return ob;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addAll(int index, Collection c)
|
|
||||||
{
|
|
||||||
if (index < size)
|
|
||||||
{
|
|
||||||
boolean bool = m_al.addAll(index + m_fromIndex, c);
|
|
||||||
if (bool)
|
|
||||||
{
|
|
||||||
int lange = c.size();
|
|
||||||
m_toIndex = m_toIndex + lange;
|
|
||||||
size = size + lange;
|
|
||||||
}
|
|
||||||
return bool;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addAll(Collection c)
|
|
||||||
{
|
|
||||||
boolean bool = m_al.addAll(m_toIndex, c);
|
|
||||||
if (bool)
|
|
||||||
{
|
|
||||||
int lange = c.size();
|
|
||||||
m_toIndex = m_toIndex + lange;
|
|
||||||
size = size + lange;
|
|
||||||
}
|
|
||||||
return bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeRange(int from, int to)
|
|
||||||
{
|
|
||||||
if ((from <= to) && (from <= size) && (to <= size))
|
|
||||||
{
|
|
||||||
m_al.removeRange(from, to);
|
|
||||||
int lange = to - from;
|
|
||||||
m_toIndex = m_toIndex - lange;
|
|
||||||
size = size - lange;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (from > to)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return (m_toIndex - m_fromIndex);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,260 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
import org.spongycastle.util.Strings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generalized time object.
|
|
||||||
*/
|
|
||||||
public class ASN1GeneralizedTime
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
private byte[] time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a generalized time from the passed in object
|
|
||||||
*
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
*/
|
|
||||||
public static ASN1GeneralizedTime getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1GeneralizedTime)
|
|
||||||
{
|
|
||||||
return (ASN1GeneralizedTime)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof ASN1GeneralizedTime)
|
|
||||||
{
|
|
||||||
return new ASN1GeneralizedTime(((ASN1GeneralizedTime)obj).time);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a Generalized Time object from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
*/
|
|
||||||
public static ASN1GeneralizedTime getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Primitive o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof ASN1GeneralizedTime)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
|
|
||||||
* for local time, or Z|[+|-]HHMM on the end, for difference between local
|
|
||||||
* time and UTC time. The fractional second amount f must consist of at
|
|
||||||
* least one number with trailing zeroes removed.
|
|
||||||
*
|
|
||||||
* @param time the time string.
|
|
||||||
* @exception IllegalArgumentException if String is an illegal format.
|
|
||||||
*/
|
|
||||||
public ASN1GeneralizedTime(
|
|
||||||
String time)
|
|
||||||
{
|
|
||||||
char last = time.charAt(time.length() - 1);
|
|
||||||
if (last != 'Z' && !(last >= 0 && last <= '9'))
|
|
||||||
{
|
|
||||||
if (time.indexOf('-') < 0 && time.indexOf('+') < 0)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("time needs to be in format YYYYMMDDHHMMSS[.f]Z or YYYYMMDDHHMMSS[.f][+-]HHMM");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.time = Strings.toByteArray(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* base constructer from a java.util.date object
|
|
||||||
*/
|
|
||||||
public ASN1GeneralizedTime(
|
|
||||||
Date time)
|
|
||||||
{
|
|
||||||
this.time = Strings.toByteArray(DateFormatter.getGeneralizedTimeDateString(time, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ASN1GeneralizedTime(Date date, boolean includeMillis)
|
|
||||||
{
|
|
||||||
this.time = Strings.toByteArray(DateFormatter.getGeneralizedTimeDateString(date, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1GeneralizedTime(
|
|
||||||
byte[] bytes)
|
|
||||||
{
|
|
||||||
this.time = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the time.
|
|
||||||
* @return The time string as it appeared in the encoded object.
|
|
||||||
*/
|
|
||||||
public String getTimeString()
|
|
||||||
{
|
|
||||||
return Strings.fromByteArray(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the time - always in the form of
|
|
||||||
* YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
|
|
||||||
* <p>
|
|
||||||
* Normally in a certificate we would expect "Z" rather than "GMT",
|
|
||||||
* however adding the "GMT" means we can just use:
|
|
||||||
* <pre>
|
|
||||||
* dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
|
||||||
* </pre>
|
|
||||||
* To read in the time and get a date which is compatible with our local
|
|
||||||
* time zone.
|
|
||||||
*/
|
|
||||||
public String getTime()
|
|
||||||
{
|
|
||||||
String stime = Strings.fromByteArray(time);
|
|
||||||
|
|
||||||
//
|
|
||||||
// standardise the format.
|
|
||||||
//
|
|
||||||
if (stime.charAt(stime.length() - 1) == 'Z')
|
|
||||||
{
|
|
||||||
return stime.substring(0, stime.length() - 1) + "GMT+00:00";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int signPos = stime.length() - 5;
|
|
||||||
char sign = stime.charAt(signPos);
|
|
||||||
if (sign == '-' || sign == '+')
|
|
||||||
{
|
|
||||||
return stime.substring(0, signPos)
|
|
||||||
+ "GMT"
|
|
||||||
+ stime.substring(signPos, signPos + 3)
|
|
||||||
+ ":"
|
|
||||||
+ stime.substring(signPos + 3);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
signPos = stime.length() - 3;
|
|
||||||
sign = stime.charAt(signPos);
|
|
||||||
if (sign == '-' || sign == '+')
|
|
||||||
{
|
|
||||||
return stime.substring(0, signPos)
|
|
||||||
+ "GMT"
|
|
||||||
+ stime.substring(signPos)
|
|
||||||
+ ":00";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stime + calculateGMTOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String calculateGMTOffset()
|
|
||||||
{
|
|
||||||
String sign = "+";
|
|
||||||
TimeZone timeZone = TimeZone.getDefault();
|
|
||||||
int offset = timeZone.getRawOffset();
|
|
||||||
if (offset < 0)
|
|
||||||
{
|
|
||||||
sign = "-";
|
|
||||||
offset = -offset;
|
|
||||||
}
|
|
||||||
int hours = offset / (60 * 60 * 1000);
|
|
||||||
int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000);
|
|
||||||
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate()))
|
|
||||||
// {
|
|
||||||
// hours += sign.equals("+") ? 1 : -1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// catch (ParseException e)
|
|
||||||
// {
|
|
||||||
// // we'll do our best and ignore daylight savings
|
|
||||||
// }
|
|
||||||
|
|
||||||
return "GMT" + sign + convert(hours) + ":" + convert(minutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String convert(int time)
|
|
||||||
{
|
|
||||||
if (time < 10)
|
|
||||||
{
|
|
||||||
return "0" + time;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Integer.toString(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getDate()
|
|
||||||
{
|
|
||||||
return DateFormatter.fromGeneralizedTimeString(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasFractionalSeconds()
|
|
||||||
{
|
|
||||||
for (int i = 0; i != time.length; i++)
|
|
||||||
{
|
|
||||||
if (time[i] == '.')
|
|
||||||
{
|
|
||||||
if (i == 14)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
{
|
|
||||||
int length = time.length;
|
|
||||||
|
|
||||||
return 1 + StreamUtil.calculateBodyLength(length) + length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.writeEncoded(BERTags.GENERALIZED_TIME, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1GeneralizedTime))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Arrays.areEqual(time, ((ASN1GeneralizedTime)o).time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Arrays.hashCode(time);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,259 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
import org.spongycastle.util.Strings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UTC time object.
|
|
||||||
*/
|
|
||||||
public class ASN1UTCTime
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
private byte[] time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an UTC Time from the passed in object.
|
|
||||||
*
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
*/
|
|
||||||
public static ASN1UTCTime getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return (ASN1UTCTime)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return new ASN1UTCTime(((ASN1UTCTime)obj).time);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an UTC Time from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
*/
|
|
||||||
public static ASN1UTCTime getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Object o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new ASN1UTCTime(((ASN1OctetString)o).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
|
|
||||||
* never encoded. When you're creating one of these objects from scratch, that's
|
|
||||||
* what you want to use, otherwise we'll try to deal with whatever gets read from
|
|
||||||
* the input stream... (this is why the input format is different from the getTime()
|
|
||||||
* method output).
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @param time the time string.
|
|
||||||
*/
|
|
||||||
public ASN1UTCTime(
|
|
||||||
String time)
|
|
||||||
{
|
|
||||||
if (time.charAt(time.length() - 1) != 'Z')
|
|
||||||
{
|
|
||||||
// we accept this as a variation
|
|
||||||
if (time.indexOf('-') < 0 && time.indexOf('+') < 0)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("time needs to be in format YYMMDDHHMMSSZ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.time = Strings.toByteArray(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* base constructor from a java.util.date object
|
|
||||||
*/
|
|
||||||
public ASN1UTCTime(
|
|
||||||
Date time)
|
|
||||||
{
|
|
||||||
this.time = Strings.toByteArray(DateFormatter.toUTCDateString(time));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1UTCTime(
|
|
||||||
byte[] time)
|
|
||||||
{
|
|
||||||
this.time = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the time as a date based on whatever a 2 digit year will return. For
|
|
||||||
* standardised processing use getAdjustedDate().
|
|
||||||
*
|
|
||||||
* @return the resulting date
|
|
||||||
*/
|
|
||||||
public Date getDate()
|
|
||||||
{
|
|
||||||
return DateFormatter.adjustedFromUTCDateString(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the time as an adjusted date
|
|
||||||
* in the range of 1950 - 2049.
|
|
||||||
*
|
|
||||||
* @return a date in the range of 1950 to 2049.
|
|
||||||
*/
|
|
||||||
public Date getAdjustedDate()
|
|
||||||
{
|
|
||||||
return DateFormatter.adjustedFromUTCDateString(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the time - always in the form of
|
|
||||||
* YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
|
|
||||||
* <p>
|
|
||||||
* Normally in a certificate we would expect "Z" rather than "GMT",
|
|
||||||
* however adding the "GMT" means we can just use:
|
|
||||||
* <pre>
|
|
||||||
* dateF = new SimpleDateFormat("yyMMddHHmmssz");
|
|
||||||
* </pre>
|
|
||||||
* To read in the time and get a date which is compatible with our local
|
|
||||||
* time zone.
|
|
||||||
* <p>
|
|
||||||
* <b>Note:</b> In some cases, due to the local date processing, this
|
|
||||||
* may lead to unexpected results. If you want to stick the normal
|
|
||||||
* convention of 1950 to 2049 use the getAdjustedTime() method.
|
|
||||||
*/
|
|
||||||
public String getTime()
|
|
||||||
{
|
|
||||||
String stime = Strings.fromByteArray(time);
|
|
||||||
|
|
||||||
//
|
|
||||||
// standardise the format.
|
|
||||||
//
|
|
||||||
if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0)
|
|
||||||
{
|
|
||||||
if (stime.length() == 11)
|
|
||||||
{
|
|
||||||
return stime.substring(0, 10) + "00GMT+00:00";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return stime.substring(0, 12) + "GMT+00:00";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int index = stime.indexOf('-');
|
|
||||||
if (index < 0)
|
|
||||||
{
|
|
||||||
index = stime.indexOf('+');
|
|
||||||
}
|
|
||||||
String d = stime;
|
|
||||||
|
|
||||||
if (index == stime.length() - 3)
|
|
||||||
{
|
|
||||||
d += "00";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == 10)
|
|
||||||
{
|
|
||||||
return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a time string as an adjusted date with a 4 digit year. This goes
|
|
||||||
* in the range of 1950 - 2049.
|
|
||||||
*/
|
|
||||||
public String getAdjustedTime()
|
|
||||||
{
|
|
||||||
String d = this.getTime();
|
|
||||||
|
|
||||||
if (d.charAt(0) < '5')
|
|
||||||
{
|
|
||||||
return "20" + d;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return "19" + d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the time.
|
|
||||||
* @return The time string as it appeared in the encoded object.
|
|
||||||
*/
|
|
||||||
public String getTimeString()
|
|
||||||
{
|
|
||||||
return Strings.fromByteArray(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
{
|
|
||||||
int length = time.length;
|
|
||||||
|
|
||||||
return 1 + StreamUtil.calculateBodyLength(length) + length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.write(BERTags.UTC_TIME);
|
|
||||||
|
|
||||||
int length = time.length;
|
|
||||||
|
|
||||||
out.writeLength(length);
|
|
||||||
|
|
||||||
for (int i = 0; i != length; i++)
|
|
||||||
{
|
|
||||||
out.write((byte)time[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1UTCTime))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Arrays.areEqual(time, ((ASN1UTCTime)o).time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Arrays.hashCode(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return Strings.fromByteArray(time);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
class DERFactory
|
|
||||||
{
|
|
||||||
static final ASN1Sequence EMPTY_SEQUENCE = new DERSequence();
|
|
||||||
static final ASN1Set EMPTY_SET = new DERSet();
|
|
||||||
|
|
||||||
static ASN1Sequence createSequence(ASN1EncodableVector v)
|
|
||||||
{
|
|
||||||
if (v.size() < 1)
|
|
||||||
{
|
|
||||||
return EMPTY_SEQUENCE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new DLSequence(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ASN1Set createSet(ASN1EncodableVector v)
|
|
||||||
{
|
|
||||||
if (v.size() < 1)
|
|
||||||
{
|
|
||||||
return EMPTY_SET;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new DLSet(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
public class DERGeneralizedTime
|
|
||||||
extends ASN1GeneralizedTime
|
|
||||||
{
|
|
||||||
DERGeneralizedTime(byte[] bytes)
|
|
||||||
{
|
|
||||||
super(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERGeneralizedTime(Date date)
|
|
||||||
{
|
|
||||||
super(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERGeneralizedTime(Date date, boolean includeMillis)
|
|
||||||
{
|
|
||||||
super(date, includeMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERGeneralizedTime(String time)
|
|
||||||
{
|
|
||||||
super(time);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
public class DERUTCTime
|
|
||||||
extends ASN1UTCTime
|
|
||||||
{
|
|
||||||
DERUTCTime(byte[] bytes)
|
|
||||||
{
|
|
||||||
super(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERUTCTime(Date date)
|
|
||||||
{
|
|
||||||
super(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERUTCTime(String time)
|
|
||||||
{
|
|
||||||
super(time);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,272 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
class DateFormatter
|
|
||||||
{
|
|
||||||
// YYMMDDHHMMSSZ
|
|
||||||
static String toUTCDateString(Date date)
|
|
||||||
{
|
|
||||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
|
||||||
|
|
||||||
calendar.setTime(date);
|
|
||||||
|
|
||||||
return format2Year(calendar.get(Calendar.YEAR)) + format2(calendar.get(Calendar.MONTH) + 1) + format2(calendar.get(Calendar.DAY_OF_MONTH))
|
|
||||||
+ format2(calendar.get(Calendar.HOUR_OF_DAY)) + format2(calendar.get(Calendar.MINUTE)) + format2(calendar.get(Calendar.SECOND)) + "Z";
|
|
||||||
}
|
|
||||||
|
|
||||||
static Date adjustedFromUTCDateString(byte[] date)
|
|
||||||
{
|
|
||||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
|
||||||
|
|
||||||
int year = toInt2(date, 0);
|
|
||||||
|
|
||||||
if (year < 50)
|
|
||||||
{
|
|
||||||
year += 2000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
year += 1900;
|
|
||||||
}
|
|
||||||
|
|
||||||
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
||||||
|
|
||||||
calendar.set(Calendar.YEAR, year);
|
|
||||||
calendar.set(Calendar.MONTH, toInt2(date, 2) - 1);
|
|
||||||
calendar.set(Calendar.DAY_OF_MONTH, toInt2(date, 4));
|
|
||||||
calendar.set(Calendar.HOUR_OF_DAY, toInt2(date, 6));
|
|
||||||
calendar.set(Calendar.MINUTE, toInt2(date, 8));
|
|
||||||
|
|
||||||
int tzChar = 10;
|
|
||||||
|
|
||||||
if (isNumber(date, tzChar))
|
|
||||||
{
|
|
||||||
calendar.set(Calendar.SECOND, toInt2(date, 10));
|
|
||||||
tzChar = 12;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
calendar.set(Calendar.SECOND, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
calendar.set(Calendar.MILLISECOND, 0);
|
|
||||||
|
|
||||||
if (date[tzChar] != 'Z')
|
|
||||||
{
|
|
||||||
int hoursOff = 0;
|
|
||||||
int minutesOff = 0;
|
|
||||||
|
|
||||||
hoursOff = toInt2(date, tzChar + 1) * 60 * 60 * 1000;
|
|
||||||
|
|
||||||
if (date.length > tzChar + 3)
|
|
||||||
{
|
|
||||||
minutesOff = toInt2(date, tzChar + 3) * 60 * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (date[tzChar] == '-')
|
|
||||||
{
|
|
||||||
return new Date(calendar.getTime().getTime() + hoursOff + minutesOff);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new Date(calendar.getTime().getTime() - (hoursOff + minutesOff));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return calendar.getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getGeneralizedTimeDateString(Date date, boolean includeMillis)
|
|
||||||
{
|
|
||||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
|
||||||
|
|
||||||
calendar.setTime(date);
|
|
||||||
|
|
||||||
String time = format4Year(calendar.get(Calendar.YEAR)) + format2(calendar.get(Calendar.MONTH) + 1) + format2(calendar.get(Calendar.DAY_OF_MONTH))
|
|
||||||
+ format2(calendar.get(Calendar.HOUR_OF_DAY)) + format2(calendar.get(Calendar.MINUTE)) + format2(calendar.get(Calendar.SECOND));
|
|
||||||
|
|
||||||
if (includeMillis)
|
|
||||||
{
|
|
||||||
time += "." + format3(calendar.get(Calendar.MILLISECOND));
|
|
||||||
}
|
|
||||||
|
|
||||||
return time + "Z";
|
|
||||||
}
|
|
||||||
|
|
||||||
static Date fromGeneralizedTimeString(byte[] date)
|
|
||||||
{
|
|
||||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
|
||||||
|
|
||||||
int year = toInt4(date, 0);
|
|
||||||
|
|
||||||
if (isLocalTime(date))
|
|
||||||
{
|
|
||||||
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
||||||
}
|
|
||||||
|
|
||||||
calendar.set(Calendar.YEAR, year);
|
|
||||||
calendar.set(Calendar.MONTH, toInt2(date, 4) - 1);
|
|
||||||
calendar.set(Calendar.DAY_OF_MONTH, toInt2(date, 6));
|
|
||||||
calendar.set(Calendar.HOUR_OF_DAY, toInt2(date, 8));
|
|
||||||
calendar.set(Calendar.MINUTE, toInt2(date, 10));
|
|
||||||
|
|
||||||
int tzChar = 12;
|
|
||||||
|
|
||||||
if (isNumber(date, tzChar))
|
|
||||||
{
|
|
||||||
calendar.set(Calendar.SECOND, toInt2(date, 12));
|
|
||||||
tzChar = 14;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
calendar.set(Calendar.SECOND, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tzChar != date.length && date[tzChar] == '.')
|
|
||||||
{
|
|
||||||
int millis = 0;
|
|
||||||
tzChar++;
|
|
||||||
if (isNumber(date, tzChar))
|
|
||||||
{
|
|
||||||
millis = (date[tzChar] - '0') * 100;
|
|
||||||
tzChar++;
|
|
||||||
}
|
|
||||||
if (tzChar != date.length && isNumber(date, tzChar))
|
|
||||||
{
|
|
||||||
millis += (date[tzChar] - '0') * 10;
|
|
||||||
tzChar++;
|
|
||||||
}
|
|
||||||
if (tzChar != date.length && isNumber(date, tzChar))
|
|
||||||
{
|
|
||||||
millis += (date[tzChar] - '0');
|
|
||||||
tzChar++;
|
|
||||||
}
|
|
||||||
calendar.set(Calendar.MILLISECOND, millis);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
calendar.set(Calendar.MILLISECOND, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip nano-seconds
|
|
||||||
while (tzChar != date.length && isNumber(date, tzChar))
|
|
||||||
{
|
|
||||||
tzChar++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tzChar != date.length && date[tzChar] != 'Z')
|
|
||||||
{
|
|
||||||
int hoursOff = 0;
|
|
||||||
int minutesOff = 0;
|
|
||||||
|
|
||||||
hoursOff = toInt2(date, tzChar + 1) * 60 * 60 * 1000;
|
|
||||||
|
|
||||||
if (date.length > tzChar + 3)
|
|
||||||
{
|
|
||||||
minutesOff = toInt2(date, tzChar + 3) * 60 * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (date[tzChar] == '-')
|
|
||||||
{
|
|
||||||
return new Date(calendar.getTime().getTime() + hoursOff + minutesOff);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new Date(calendar.getTime().getTime() - (hoursOff + minutesOff));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return calendar.getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String format2(int v)
|
|
||||||
{
|
|
||||||
if (v < 10)
|
|
||||||
{
|
|
||||||
return "0" + v;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Integer.toString(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String format2Year(int v)
|
|
||||||
{
|
|
||||||
if (v > 2000)
|
|
||||||
{
|
|
||||||
v = v - 2000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v = v - 1900;
|
|
||||||
}
|
|
||||||
|
|
||||||
return format2(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String format3(int v)
|
|
||||||
{
|
|
||||||
if (v < 10)
|
|
||||||
{
|
|
||||||
return "00" + v;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v < 100)
|
|
||||||
{
|
|
||||||
return "0" + v;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Integer.toString(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String format4Year(int v)
|
|
||||||
{
|
|
||||||
if (v < 10)
|
|
||||||
{
|
|
||||||
return "000" + v;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v < 100)
|
|
||||||
{
|
|
||||||
return "00" + v;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v < 1000)
|
|
||||||
{
|
|
||||||
return "0" + v;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Integer.toString(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isNumber(byte[] input, int off)
|
|
||||||
{
|
|
||||||
byte b = input[off];
|
|
||||||
return (b >= '0') && (b <= '9');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isLocalTime(byte[] date)
|
|
||||||
{
|
|
||||||
for (int i = date.length - 1; i > date.length - 6; i--)
|
|
||||||
{
|
|
||||||
if (date[i] == 'Z' || date[i] == '-' || date[i] == '+')
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int toInt2(byte[] input, int off)
|
|
||||||
{
|
|
||||||
return (input[off] - '0') * 10 + (input[off + 1] - '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int toInt4(byte[] input, int off)
|
|
||||||
{
|
|
||||||
return toInt2(input, off) * 100 + toInt2(input, off + 2) ;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
class StreamUtil
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Find out possible longest length...
|
|
||||||
*
|
|
||||||
* @param in input stream of interest
|
|
||||||
* @return length calculation or MAX_VALUE.
|
|
||||||
*/
|
|
||||||
static int findLimit(InputStream in)
|
|
||||||
{
|
|
||||||
if (in instanceof LimitedInputStream)
|
|
||||||
{
|
|
||||||
return ((LimitedInputStream)in).getRemaining();
|
|
||||||
}
|
|
||||||
else if (in instanceof ASN1InputStream)
|
|
||||||
{
|
|
||||||
return ((ASN1InputStream)in).getLimit();
|
|
||||||
}
|
|
||||||
else if (in instanceof ByteArrayInputStream)
|
|
||||||
{
|
|
||||||
return ((ByteArrayInputStream)in).available();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Integer.MAX_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int calculateBodyLength(
|
|
||||||
int length)
|
|
||||||
{
|
|
||||||
int count = 1;
|
|
||||||
|
|
||||||
if (length > 127)
|
|
||||||
{
|
|
||||||
int size = 1;
|
|
||||||
int val = length;
|
|
||||||
|
|
||||||
while ((val >>>= 8) != 0)
|
|
||||||
{
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = (size - 1) * 8; i >= 0; i -= 8)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int calculateTagLength(int tagNo)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int length = 1;
|
|
||||||
|
|
||||||
if (tagNo >= 31)
|
|
||||||
{
|
|
||||||
if (tagNo < 128)
|
|
||||||
{
|
|
||||||
length++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte[] stack = new byte[5];
|
|
||||||
int pos = stack.length;
|
|
||||||
|
|
||||||
stack[--pos] = (byte)(tagNo & 0x7F);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
tagNo >>= 7;
|
|
||||||
stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
|
|
||||||
}
|
|
||||||
while (tagNo > 127);
|
|
||||||
|
|
||||||
length += stack.length - pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
package org.spongycastle.asn1.cms;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.spongycastle.asn1.ASN1Choice;
|
|
||||||
import org.spongycastle.asn1.ASN1Object;
|
|
||||||
import org.spongycastle.asn1.ASN1Primitive;
|
|
||||||
import org.spongycastle.asn1.ASN1TaggedObject;
|
|
||||||
import org.spongycastle.asn1.ASN1GeneralizedTime;
|
|
||||||
import org.spongycastle.asn1.ASN1UTCTime;
|
|
||||||
|
|
||||||
public class Time
|
|
||||||
extends ASN1Object
|
|
||||||
implements ASN1Choice
|
|
||||||
{
|
|
||||||
ASN1Primitive time;
|
|
||||||
|
|
||||||
public static Time getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
return getInstance(obj.getObject()); // must be explicitly tagged
|
|
||||||
}
|
|
||||||
|
|
||||||
public Time(
|
|
||||||
ASN1Primitive time)
|
|
||||||
{
|
|
||||||
if (!(time instanceof ASN1UTCTime)
|
|
||||||
&& !(time instanceof ASN1GeneralizedTime))
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("unknown object passed to Time");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.time = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates a time object from a given date - if the date is between 1950
|
|
||||||
* and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
|
|
||||||
* is used.
|
|
||||||
*/
|
|
||||||
public Time(
|
|
||||||
Date date)
|
|
||||||
{
|
|
||||||
Calendar calendar = Calendar.getInstance();
|
|
||||||
|
|
||||||
calendar.setTime(date);
|
|
||||||
|
|
||||||
int year = calendar.get(Calendar.YEAR);
|
|
||||||
|
|
||||||
if (year < 1950 || year > 2049)
|
|
||||||
{
|
|
||||||
time = new ASN1GeneralizedTime(date);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
time = new ASN1UTCTime(date);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Time getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof Time)
|
|
||||||
{
|
|
||||||
return (Time)obj;
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return new Time((ASN1UTCTime)obj);
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1GeneralizedTime)
|
|
||||||
{
|
|
||||||
return new Time((ASN1GeneralizedTime)obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTime()
|
|
||||||
{
|
|
||||||
if (time instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return ((ASN1UTCTime)time).getAdjustedTime();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ((ASN1GeneralizedTime)time).getTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getDate()
|
|
||||||
{
|
|
||||||
if (time instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return ((ASN1UTCTime)time).getAdjustedDate();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ((ASN1GeneralizedTime)time).getDate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Produce an object suitable for an ASN1OutputStream.
|
|
||||||
* <pre>
|
|
||||||
* Time ::= CHOICE {
|
|
||||||
* utcTime UTCTime,
|
|
||||||
* generalTime GeneralizedTime }
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return getTime();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
package org.spongycastle.asn1.eac;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EAC encoding date object
|
|
||||||
*/
|
|
||||||
public class PackedDate
|
|
||||||
{
|
|
||||||
private byte[] time;
|
|
||||||
|
|
||||||
public PackedDate(
|
|
||||||
String time)
|
|
||||||
{
|
|
||||||
this.time = convert(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] convert(String sTime)
|
|
||||||
{
|
|
||||||
char[] digs = sTime.toCharArray();
|
|
||||||
byte[] date = new byte[6];
|
|
||||||
|
|
||||||
for (int i = 0; i != 6; i++)
|
|
||||||
{
|
|
||||||
date[i] = (byte)(digs[i] - '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
|
|
||||||
PackedDate(
|
|
||||||
byte[] bytes)
|
|
||||||
{
|
|
||||||
this.time = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Arrays.hashCode(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof PackedDate))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PackedDate other = (PackedDate)o;
|
|
||||||
|
|
||||||
return Arrays.areEqual(time, other.time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
char[] dateC = new char[time.length];
|
|
||||||
|
|
||||||
for (int i = 0; i != dateC.length; i++)
|
|
||||||
{
|
|
||||||
dateC[i] = (char)((time[i] & 0xff) + '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new String(dateC);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getEncoding()
|
|
||||||
{
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
package org.spongycastle.asn1.x509;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.spongycastle.asn1.ASN1Choice;
|
|
||||||
import org.spongycastle.asn1.ASN1Object;
|
|
||||||
import org.spongycastle.asn1.ASN1Primitive;
|
|
||||||
import org.spongycastle.asn1.ASN1TaggedObject;
|
|
||||||
import org.spongycastle.asn1.ASN1GeneralizedTime;
|
|
||||||
import org.spongycastle.asn1.ASN1UTCTime;
|
|
||||||
|
|
||||||
public class Time
|
|
||||||
extends ASN1Object
|
|
||||||
implements ASN1Choice
|
|
||||||
{
|
|
||||||
ASN1Primitive time;
|
|
||||||
|
|
||||||
public static Time getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
return getInstance(obj.getObject()); // must be explicitly tagged
|
|
||||||
}
|
|
||||||
|
|
||||||
public Time(
|
|
||||||
ASN1Primitive time)
|
|
||||||
{
|
|
||||||
if (!(time instanceof ASN1UTCTime)
|
|
||||||
&& !(time instanceof ASN1GeneralizedTime))
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("unknown object passed to Time");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.time = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates a time object from a given date - if the date is between 1950
|
|
||||||
* and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
|
|
||||||
* is used.
|
|
||||||
*/
|
|
||||||
public Time(
|
|
||||||
Date date)
|
|
||||||
{
|
|
||||||
Calendar calendar = Calendar.getInstance();
|
|
||||||
|
|
||||||
calendar.setTime(date);
|
|
||||||
|
|
||||||
int year = calendar.get(Calendar.YEAR);
|
|
||||||
|
|
||||||
if (year < 1950 || year > 2049)
|
|
||||||
{
|
|
||||||
time = new ASN1GeneralizedTime(date);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
time = new ASN1UTCTime(date);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Time getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof Time)
|
|
||||||
{
|
|
||||||
return (Time)obj;
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return new Time((ASN1UTCTime)obj);
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1GeneralizedTime)
|
|
||||||
{
|
|
||||||
return new Time((ASN1GeneralizedTime)obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTime()
|
|
||||||
{
|
|
||||||
if (time instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return ((ASN1UTCTime)time).getAdjustedTime();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ((ASN1GeneralizedTime)time).getTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getDate()
|
|
||||||
{
|
|
||||||
if (time instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return ((ASN1UTCTime)time).getAdjustedDate();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ((ASN1GeneralizedTime)time).getDate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Produce an object suitable for an ASN1OutputStream.
|
|
||||||
* <pre>
|
|
||||||
* Time ::= CHOICE {
|
|
||||||
* utcTime UTCTime,
|
|
||||||
* generalTime GeneralizedTime }
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return getTime();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,410 +0,0 @@
|
|||||||
package org.spongycastle.crypto.encodings;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
|
|
||||||
import org.spongycastle.crypto.AsymmetricBlockCipher;
|
|
||||||
import org.spongycastle.crypto.CipherParameters;
|
|
||||||
import org.spongycastle.crypto.InvalidCipherTextException;
|
|
||||||
import org.spongycastle.crypto.params.AsymmetricKeyParameter;
|
|
||||||
import org.spongycastle.crypto.params.ParametersWithRandom;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this does your basic PKCS 1 v1.5 padding - whether or not you should be using this
|
|
||||||
* depends on your application - see PKCS1 Version 2 for details.
|
|
||||||
*/
|
|
||||||
public class PKCS1Encoding
|
|
||||||
implements AsymmetricBlockCipher
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to
|
|
||||||
* work with one of these set the system property org.spongycastle.pkcs1.strict to false.
|
|
||||||
* <p>
|
|
||||||
* The system property is checked during construction of the encoding object, it is set to
|
|
||||||
* true by default.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public static final String STRICT_LENGTH_ENABLED_PROPERTY = "org.spongycastle.pkcs1.strict";
|
|
||||||
|
|
||||||
private static final int HEADER_LENGTH = 10;
|
|
||||||
|
|
||||||
private SecureRandom random;
|
|
||||||
private AsymmetricBlockCipher engine;
|
|
||||||
private boolean forEncryption;
|
|
||||||
private boolean forPrivateKey;
|
|
||||||
private boolean useStrictLength;
|
|
||||||
private int pLen = -1;
|
|
||||||
private byte[] fallback = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic constructor.
|
|
||||||
* @param cipher
|
|
||||||
*/
|
|
||||||
public PKCS1Encoding(
|
|
||||||
AsymmetricBlockCipher cipher)
|
|
||||||
{
|
|
||||||
this.engine = cipher;
|
|
||||||
this.useStrictLength = useStrict();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for decryption with a fixed plaintext length.
|
|
||||||
*
|
|
||||||
* @param cipher The cipher to use for cryptographic operation.
|
|
||||||
* @param pLen Length of the expected plaintext.
|
|
||||||
*/
|
|
||||||
public PKCS1Encoding(
|
|
||||||
AsymmetricBlockCipher cipher,
|
|
||||||
int pLen)
|
|
||||||
{
|
|
||||||
this.engine = cipher;
|
|
||||||
this.useStrictLength = useStrict();
|
|
||||||
this.pLen = pLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for decryption with a fixed plaintext length and a fallback
|
|
||||||
* value that is returned, if the padding is incorrect.
|
|
||||||
*
|
|
||||||
* @param cipher
|
|
||||||
* The cipher to use for cryptographic operation.
|
|
||||||
* @param fallback
|
|
||||||
* The fallback value, we don't to a arraycopy here.
|
|
||||||
*/
|
|
||||||
public PKCS1Encoding(
|
|
||||||
AsymmetricBlockCipher cipher,
|
|
||||||
byte[] fallback)
|
|
||||||
{
|
|
||||||
this.engine = cipher;
|
|
||||||
this.useStrictLength = useStrict();
|
|
||||||
this.fallback = fallback;
|
|
||||||
this.pLen = fallback.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// for J2ME compatibility
|
|
||||||
//
|
|
||||||
private boolean useStrict()
|
|
||||||
{
|
|
||||||
// required if security manager has been installed.
|
|
||||||
String strict = System.getProperty(STRICT_LENGTH_ENABLED_PROPERTY);
|
|
||||||
|
|
||||||
return strict == null || strict.equals("true");
|
|
||||||
}
|
|
||||||
|
|
||||||
public AsymmetricBlockCipher getUnderlyingCipher()
|
|
||||||
{
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(
|
|
||||||
boolean forEncryption,
|
|
||||||
CipherParameters param)
|
|
||||||
{
|
|
||||||
AsymmetricKeyParameter kParam;
|
|
||||||
|
|
||||||
if (param instanceof ParametersWithRandom)
|
|
||||||
{
|
|
||||||
ParametersWithRandom rParam = (ParametersWithRandom)param;
|
|
||||||
|
|
||||||
this.random = rParam.getRandom();
|
|
||||||
kParam = (AsymmetricKeyParameter)rParam.getParameters();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.random = new SecureRandom();
|
|
||||||
kParam = (AsymmetricKeyParameter)param;
|
|
||||||
}
|
|
||||||
|
|
||||||
engine.init(forEncryption, param);
|
|
||||||
|
|
||||||
this.forPrivateKey = kParam.isPrivate();
|
|
||||||
this.forEncryption = forEncryption;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getInputBlockSize()
|
|
||||||
{
|
|
||||||
int baseBlockSize = engine.getInputBlockSize();
|
|
||||||
|
|
||||||
if (forEncryption)
|
|
||||||
{
|
|
||||||
return baseBlockSize - HEADER_LENGTH;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return baseBlockSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOutputBlockSize()
|
|
||||||
{
|
|
||||||
int baseBlockSize = engine.getOutputBlockSize();
|
|
||||||
|
|
||||||
if (forEncryption)
|
|
||||||
{
|
|
||||||
return baseBlockSize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return baseBlockSize - HEADER_LENGTH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] processBlock(
|
|
||||||
byte[] in,
|
|
||||||
int inOff,
|
|
||||||
int inLen)
|
|
||||||
throws InvalidCipherTextException
|
|
||||||
{
|
|
||||||
if (forEncryption)
|
|
||||||
{
|
|
||||||
return encodeBlock(in, inOff, inLen);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return decodeBlock(in, inOff, inLen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] encodeBlock(
|
|
||||||
byte[] in,
|
|
||||||
int inOff,
|
|
||||||
int inLen)
|
|
||||||
throws InvalidCipherTextException
|
|
||||||
{
|
|
||||||
if (inLen > getInputBlockSize())
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("input data too large");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] block = new byte[engine.getInputBlockSize()];
|
|
||||||
|
|
||||||
if (forPrivateKey)
|
|
||||||
{
|
|
||||||
block[0] = 0x01; // type code 1
|
|
||||||
|
|
||||||
for (int i = 1; i != block.length - inLen - 1; i++)
|
|
||||||
{
|
|
||||||
block[i] = (byte)0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
random.nextBytes(block); // random fill
|
|
||||||
|
|
||||||
block[0] = 0x02; // type code 2
|
|
||||||
|
|
||||||
//
|
|
||||||
// a zero byte marks the end of the padding, so all
|
|
||||||
// the pad bytes must be non-zero.
|
|
||||||
//
|
|
||||||
for (int i = 1; i != block.length - inLen - 1; i++)
|
|
||||||
{
|
|
||||||
while (block[i] == 0)
|
|
||||||
{
|
|
||||||
block[i] = (byte)random.nextInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
block[block.length - inLen - 1] = 0x00; // mark the end of the padding
|
|
||||||
System.arraycopy(in, inOff, block, block.length - inLen, inLen);
|
|
||||||
|
|
||||||
return engine.processBlock(block, 0, block.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the argument is a correctly PKCS#1.5 encoded Plaintext
|
|
||||||
* for encryption.
|
|
||||||
*
|
|
||||||
* @param encoded The Plaintext.
|
|
||||||
* @param pLen Expected length of the plaintext.
|
|
||||||
* @return Either 0, if the encoding is correct, or -1, if it is incorrect.
|
|
||||||
*/
|
|
||||||
private static int checkPkcs1Encoding(byte[] encoded, int pLen) {
|
|
||||||
int correct = 0;
|
|
||||||
/*
|
|
||||||
* Check if the first two bytes are 0 2
|
|
||||||
*/
|
|
||||||
correct |= (encoded[0] ^ 2);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now the padding check, check for no 0 byte in the padding
|
|
||||||
*/
|
|
||||||
int plen = encoded.length - (
|
|
||||||
pLen /* Lenght of the PMS */
|
|
||||||
+ 1 /* Final 0-byte before PMS */
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 1; i < plen; i++) {
|
|
||||||
int tmp = encoded[i];
|
|
||||||
tmp |= tmp >> 1;
|
|
||||||
tmp |= tmp >> 2;
|
|
||||||
tmp |= tmp >> 4;
|
|
||||||
correct |= (tmp & 1) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure the padding ends with a 0 byte.
|
|
||||||
*/
|
|
||||||
correct |= encoded[encoded.length - (pLen +1)];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return 0 or 1, depending on the result.
|
|
||||||
*/
|
|
||||||
correct |= correct >> 1;
|
|
||||||
correct |= correct >> 2;
|
|
||||||
correct |= correct >> 4;
|
|
||||||
return ~((correct & 1) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode PKCS#1.5 encoding, and return a random value if the padding is not correct.
|
|
||||||
*
|
|
||||||
* @param in The encrypted block.
|
|
||||||
* @param inOff Offset in the encrypted block.
|
|
||||||
* @param inLen Length of the encrypted block.
|
|
||||||
* //@param pLen Length of the desired output.
|
|
||||||
* @return The plaintext without padding, or a random value if the padding was incorrect.
|
|
||||||
*
|
|
||||||
* @throws InvalidCipherTextException
|
|
||||||
*/
|
|
||||||
private byte[] decodeBlockOrRandom(byte[] in, int inOff, int inLen)
|
|
||||||
throws InvalidCipherTextException
|
|
||||||
{
|
|
||||||
if (!forPrivateKey)
|
|
||||||
{
|
|
||||||
throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] block = engine.processBlock(in, inOff, inLen);
|
|
||||||
byte[] random = null;
|
|
||||||
if (this.fallback == null)
|
|
||||||
{
|
|
||||||
random = new byte[this.pLen];
|
|
||||||
this.random.nextBytes(random);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
random = fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: This is a potential dangerous side channel. However, you can
|
|
||||||
* fix this by changing the RSA engine in a way, that it will always
|
|
||||||
* return blocks of the same length and prepend them with 0 bytes if
|
|
||||||
* needed.
|
|
||||||
*/
|
|
||||||
if (block.length < getOutputBlockSize())
|
|
||||||
{
|
|
||||||
throw new InvalidCipherTextException("block truncated");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: Potential side channel. Fix it by making the engine always
|
|
||||||
* return blocks of the correct length.
|
|
||||||
*/
|
|
||||||
if (useStrictLength && block.length != engine.getOutputBlockSize())
|
|
||||||
{
|
|
||||||
throw new InvalidCipherTextException("block incorrect size");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the padding.
|
|
||||||
*/
|
|
||||||
int correct = PKCS1Encoding.checkPkcs1Encoding(block, this.pLen);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now, to a constant time constant memory copy of the decrypted value
|
|
||||||
* or the random value, depending on the validity of the padding.
|
|
||||||
*/
|
|
||||||
byte[] result = new byte[this.pLen];
|
|
||||||
for (int i = 0; i < this.pLen; i++)
|
|
||||||
{
|
|
||||||
result[i] = (byte)((block[i + (block.length - pLen)] & (~correct)) | (random[i] & correct));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format.
|
|
||||||
*/
|
|
||||||
private byte[] decodeBlock(
|
|
||||||
byte[] in,
|
|
||||||
int inOff,
|
|
||||||
int inLen)
|
|
||||||
throws InvalidCipherTextException
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If the length of the expected plaintext is known, we use a constant-time decryption.
|
|
||||||
* If the decryption fails, we return a random value.
|
|
||||||
*/
|
|
||||||
if (this.pLen != -1) {
|
|
||||||
return this.decodeBlockOrRandom(in, inOff, inLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] block = engine.processBlock(in, inOff, inLen);
|
|
||||||
|
|
||||||
if (block.length < getOutputBlockSize())
|
|
||||||
{
|
|
||||||
throw new InvalidCipherTextException("block truncated");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte type = block[0];
|
|
||||||
|
|
||||||
if (forPrivateKey)
|
|
||||||
{
|
|
||||||
if (type != 2)
|
|
||||||
{
|
|
||||||
throw new InvalidCipherTextException("unknown block type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (type != 1)
|
|
||||||
{
|
|
||||||
throw new InvalidCipherTextException("unknown block type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useStrictLength && block.length != engine.getOutputBlockSize())
|
|
||||||
{
|
|
||||||
throw new InvalidCipherTextException("block incorrect size");
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// find and extract the message block.
|
|
||||||
//
|
|
||||||
int start;
|
|
||||||
|
|
||||||
for (start = 1; start != block.length; start++)
|
|
||||||
{
|
|
||||||
byte pad = block[start];
|
|
||||||
|
|
||||||
if (pad == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (type == 1 && pad != (byte)0xff)
|
|
||||||
{
|
|
||||||
throw new InvalidCipherTextException("block padding incorrect");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
start++; // data should start at the next byte
|
|
||||||
|
|
||||||
if (start > block.length || start < HEADER_LENGTH)
|
|
||||||
{
|
|
||||||
throw new InvalidCipherTextException("no data in block");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] result = new byte[block.length - start];
|
|
||||||
|
|
||||||
System.arraycopy(block, start, result, 0, result.length);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,177 +0,0 @@
|
|||||||
package org.spongycastle.crypto.examples;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.lang.*;
|
|
||||||
|
|
||||||
import javax.microedition.midlet.MIDlet;
|
|
||||||
import javax.microedition.lcdui.*;
|
|
||||||
|
|
||||||
import org.spongycastle.util.test.*;
|
|
||||||
import org.spongycastle.util.encoders.*;
|
|
||||||
|
|
||||||
import org.spongycastle.crypto.*;
|
|
||||||
import org.spongycastle.crypto.paddings.*;
|
|
||||||
import org.spongycastle.crypto.engines.*;
|
|
||||||
import org.spongycastle.crypto.modes.*;
|
|
||||||
import org.spongycastle.crypto.params.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MIDP is a simple graphics application for the J2ME CLDC/MIDP.
|
|
||||||
*
|
|
||||||
* It has hardcoded values for the key and plain text. It also performs the
|
|
||||||
* standard testing for the chosen cipher, and displays the results.
|
|
||||||
*
|
|
||||||
* This example shows how to use the light-weight API and a symmetric cipher.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class MIDPTest extends MIDlet
|
|
||||||
{
|
|
||||||
private Display d = null;
|
|
||||||
|
|
||||||
private boolean doneEncrypt = false;
|
|
||||||
|
|
||||||
private String key = "0123456789abcdef0123456789abcdef";
|
|
||||||
private String plainText = "www.bouncycastle.org";
|
|
||||||
private byte[] keyBytes = null;
|
|
||||||
private byte[] cipherText = null;
|
|
||||||
private BufferedBlockCipher cipher = null;
|
|
||||||
|
|
||||||
private String[] cipherNames = {"DES", "DESede", "IDEA", "Rijndael", "Twofish"};
|
|
||||||
|
|
||||||
private Form output = null;
|
|
||||||
|
|
||||||
public void startApp()
|
|
||||||
{
|
|
||||||
Display.getDisplay(this).setCurrent(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void pauseApp()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroyApp(boolean unconditional)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public MIDPTest()
|
|
||||||
{
|
|
||||||
output = new Form("BouncyCastle");
|
|
||||||
output.append("Key: " + key.substring(0, 7) + "...\n");
|
|
||||||
output.append("In : " + plainText.substring(0, 7) + "...\n");
|
|
||||||
|
|
||||||
cipherText = performEncrypt(Hex.decode(key.getBytes()), plainText);
|
|
||||||
String ctS = new String(Hex.encode(cipherText));
|
|
||||||
|
|
||||||
output.append("\nCT : " + ctS.substring(0, 7) + "...\n");
|
|
||||||
|
|
||||||
String decryptText = performDecrypt(Hex.decode(key.getBytes()), cipherText);
|
|
||||||
|
|
||||||
output.append("PT : " + decryptText.substring(0, 7) + "...\n");
|
|
||||||
|
|
||||||
if (decryptText.compareTo(plainText) == 0)
|
|
||||||
{
|
|
||||||
output.append("Success");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
output.append("Failure");
|
|
||||||
message("[" + plainText + "]");
|
|
||||||
message("[" + decryptText + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] performEncrypt(byte[] key, String plainText)
|
|
||||||
{
|
|
||||||
byte[] ptBytes = plainText.getBytes();
|
|
||||||
|
|
||||||
cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(getEngineInstance()));
|
|
||||||
|
|
||||||
String name = cipher.getUnderlyingCipher().getAlgorithmName();
|
|
||||||
message("Using " + name);
|
|
||||||
|
|
||||||
cipher.init(true, new KeyParameter(key));
|
|
||||||
|
|
||||||
byte[] rv = new byte[cipher.getOutputSize(ptBytes.length)];
|
|
||||||
|
|
||||||
int oLen = cipher.processBytes(ptBytes, 0, ptBytes.length, rv, 0);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cipher.doFinal(rv, oLen);
|
|
||||||
}
|
|
||||||
catch (CryptoException ce)
|
|
||||||
{
|
|
||||||
message("Ooops, encrypt exception");
|
|
||||||
status(ce.toString());
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String performDecrypt(byte[] key, byte[] cipherText)
|
|
||||||
{
|
|
||||||
cipher.init(false, new KeyParameter(key));
|
|
||||||
|
|
||||||
byte[] rv = new byte[cipher.getOutputSize(cipherText.length)];
|
|
||||||
|
|
||||||
int oLen = cipher.processBytes(cipherText, 0, cipherText.length, rv, 0);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cipher.doFinal(rv, oLen);
|
|
||||||
}
|
|
||||||
catch (CryptoException ce)
|
|
||||||
{
|
|
||||||
message("Ooops, decrypt exception");
|
|
||||||
status(ce.toString());
|
|
||||||
}
|
|
||||||
return new String(rv).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int whichCipher()
|
|
||||||
{
|
|
||||||
return 4; // DES
|
|
||||||
}
|
|
||||||
|
|
||||||
private BlockCipher getEngineInstance()
|
|
||||||
{
|
|
||||||
// returns a block cipher according to the current
|
|
||||||
// state of the radio button lists. This is only
|
|
||||||
// done prior to encryption.
|
|
||||||
BlockCipher rv = null;
|
|
||||||
|
|
||||||
switch (whichCipher())
|
|
||||||
{
|
|
||||||
case 0 :
|
|
||||||
rv = new DESEngine();
|
|
||||||
break;
|
|
||||||
case 1 :
|
|
||||||
rv = new DESedeEngine();
|
|
||||||
break;
|
|
||||||
case 2 :
|
|
||||||
rv = new IDEAEngine();
|
|
||||||
break;
|
|
||||||
case 3 :
|
|
||||||
rv = new RijndaelEngine();
|
|
||||||
break;
|
|
||||||
case 4 :
|
|
||||||
rv = new TwofishEngine();
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
rv = new DESEngine();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void message(String s)
|
|
||||||
{
|
|
||||||
System.out.println("M:" + s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void status(String s)
|
|
||||||
{
|
|
||||||
System.out.println("S:" + s);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
MIDlet-1: MIDPTest, , org.spongycastle.crypto.examples.MIDPTest
|
|
||||||
MIDlet-Name: MIDPTest
|
|
||||||
MIDlet-Jar-Size: 300000
|
|
||||||
MIDlet-Jar-URL: midp_test.jar
|
|
||||||
MIDlet-Vendor: The Legion of the Bouncy Castle
|
|
||||||
MIDlet-Version: 1.0.0
|
|
@ -1,7 +0,0 @@
|
|||||||
MIDlet-1: MIDPTTest, , org.spongycastle.crypto.examples.MIDPTest
|
|
||||||
MIDlet-Name: MIDPTest
|
|
||||||
MIDlet-Version: 1.0.0
|
|
||||||
MIDlet-Vendor: Jon Eaves
|
|
||||||
Created-By: 1.3.1 (Sun Microsystems Inc.)
|
|
||||||
MicroEdition-Configuration: CLDC-1.0
|
|
||||||
MicroEdition-Profile: MIDP-1.0
|
|
@ -1,258 +0,0 @@
|
|||||||
package org.spongycastle.crypto.params;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
|
|
||||||
import org.spongycastle.crypto.CipherParameters;
|
|
||||||
import org.spongycastle.crypto.digests.SkeinDigest;
|
|
||||||
import org.spongycastle.crypto.digests.SkeinEngine;
|
|
||||||
import org.spongycastle.crypto.macs.SkeinMac;
|
|
||||||
import org.spongycastle.util.Integers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters for the Skein hash function - a series of byte[] strings identified by integer tags.
|
|
||||||
* <p/>
|
|
||||||
* Parameterised Skein can be used for:
|
|
||||||
* <ul>
|
|
||||||
* <li>MAC generation, by providing a {@link SkeinParameters.Builder#setKey(byte[]) key}.</li>
|
|
||||||
* <li>Randomised hashing, by providing a {@link SkeinParameters.Builder#setNonce(byte[]) nonce}.</li>
|
|
||||||
* <li>A hash function for digital signatures, associating a
|
|
||||||
* {@link SkeinParameters.Builder#setPublicKey(byte[]) public key} with the message digest.</li>
|
|
||||||
* <li>A key derivation function, by providing a
|
|
||||||
* {@link SkeinParameters.Builder#setKeyIdentifier(byte[]) key identifier}.</li>
|
|
||||||
* <li>Personalised hashing, by providing a
|
|
||||||
* {@link SkeinParameters.Builder#setPersonalisation(Date, String, String) recommended format} or
|
|
||||||
* {@link SkeinParameters.Builder#setPersonalisation(byte[]) arbitrary} personalisation string.</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @see SkeinEngine
|
|
||||||
* @see SkeinDigest
|
|
||||||
* @see SkeinMac
|
|
||||||
*/
|
|
||||||
public class SkeinParameters
|
|
||||||
implements CipherParameters
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The parameter type for a secret key, supporting MAC or KDF functions: {@value
|
|
||||||
* #PARAM_TYPE_KEY}.
|
|
||||||
*/
|
|
||||||
public static final int PARAM_TYPE_KEY = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameter type for the Skein configuration block: {@value #PARAM_TYPE_CONFIG}.
|
|
||||||
*/
|
|
||||||
public static final int PARAM_TYPE_CONFIG = 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameter type for a personalisation string: {@value #PARAM_TYPE_PERSONALISATION}.
|
|
||||||
*/
|
|
||||||
public static final int PARAM_TYPE_PERSONALISATION = 8;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameter type for a public key: {@value #PARAM_TYPE_PUBLIC_KEY}.
|
|
||||||
*/
|
|
||||||
public static final int PARAM_TYPE_PUBLIC_KEY = 12;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameter type for a key identifier string: {@value #PARAM_TYPE_KEY_IDENTIFIER}.
|
|
||||||
*/
|
|
||||||
public static final int PARAM_TYPE_KEY_IDENTIFIER = 16;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameter type for a nonce: {@value #PARAM_TYPE_NONCE}.
|
|
||||||
*/
|
|
||||||
public static final int PARAM_TYPE_NONCE = 20;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameter type for the message: {@value #PARAM_TYPE_MESSAGE}.
|
|
||||||
*/
|
|
||||||
public static final int PARAM_TYPE_MESSAGE = 48;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameter type for the output transformation: {@value #PARAM_TYPE_OUTPUT}.
|
|
||||||
*/
|
|
||||||
public static final int PARAM_TYPE_OUTPUT = 63;
|
|
||||||
|
|
||||||
private Hashtable parameters;
|
|
||||||
|
|
||||||
public SkeinParameters()
|
|
||||||
{
|
|
||||||
this(new Hashtable());
|
|
||||||
}
|
|
||||||
|
|
||||||
private SkeinParameters(final Hashtable parameters)
|
|
||||||
{
|
|
||||||
this.parameters = parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains a map of type (Integer) to value (byte[]) for the parameters tracked in this object.
|
|
||||||
*/
|
|
||||||
public Hashtable getParameters()
|
|
||||||
{
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains the value of the {@link #PARAM_TYPE_KEY key parameter}, or <code>null</code> if not
|
|
||||||
* set.
|
|
||||||
*/
|
|
||||||
public byte[] getKey()
|
|
||||||
{
|
|
||||||
return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_KEY));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains the value of the {@link #PARAM_TYPE_PERSONALISATION personalisation parameter}, or
|
|
||||||
* <code>null</code> if not set.
|
|
||||||
*/
|
|
||||||
public byte[] getPersonalisation()
|
|
||||||
{
|
|
||||||
return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_PERSONALISATION));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains the value of the {@link #PARAM_TYPE_PUBLIC_KEY public key parameter}, or
|
|
||||||
* <code>null</code> if not set.
|
|
||||||
*/
|
|
||||||
public byte[] getPublicKey()
|
|
||||||
{
|
|
||||||
return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_PUBLIC_KEY));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains the value of the {@link #PARAM_TYPE_KEY_IDENTIFIER key identifier parameter}, or
|
|
||||||
* <code>null</code> if not set.
|
|
||||||
*/
|
|
||||||
public byte[] getKeyIdentifier()
|
|
||||||
{
|
|
||||||
return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_KEY_IDENTIFIER));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains the value of the {@link #PARAM_TYPE_NONCE nonce parameter}, or <code>null</code> if
|
|
||||||
* not set.
|
|
||||||
*/
|
|
||||||
public byte[] getNonce()
|
|
||||||
{
|
|
||||||
return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_NONCE));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A builder for {@link SkeinParameters}.
|
|
||||||
*/
|
|
||||||
public static class Builder
|
|
||||||
{
|
|
||||||
private Hashtable parameters = new Hashtable();
|
|
||||||
|
|
||||||
public Builder()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder(Hashtable paramsMap)
|
|
||||||
{
|
|
||||||
Enumeration keys = paramsMap.keys();
|
|
||||||
while (keys.hasMoreElements())
|
|
||||||
{
|
|
||||||
Integer key = (Integer)keys.nextElement();
|
|
||||||
parameters.put(key, paramsMap.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder(SkeinParameters params)
|
|
||||||
{
|
|
||||||
Enumeration keys = params.parameters.keys();
|
|
||||||
while (keys.hasMoreElements())
|
|
||||||
{
|
|
||||||
Integer key = (Integer)keys.nextElement();
|
|
||||||
parameters.put(key, params.parameters.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a parameters to apply to the Skein hash function.<br>
|
|
||||||
* Parameter types must be in the range 0,5..62, and cannot use the value {@value
|
|
||||||
* SkeinParameters#PARAM_TYPE_MESSAGE} (reserved for message body).
|
|
||||||
* <p/>
|
|
||||||
* Parameters with type < {@value SkeinParameters#PARAM_TYPE_MESSAGE} are processed before
|
|
||||||
* the message content, parameters with type > {@value SkeinParameters#PARAM_TYPE_MESSAGE}
|
|
||||||
* are processed after the message and prior to output.
|
|
||||||
*
|
|
||||||
* @param type the type of the parameter, in the range 5..62.
|
|
||||||
* @param value the byte sequence of the parameter.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Builder set(int type, byte[] value)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Parameter value must not be null.");
|
|
||||||
}
|
|
||||||
if ((type != PARAM_TYPE_KEY)
|
|
||||||
&& (type <= PARAM_TYPE_CONFIG || type >= PARAM_TYPE_OUTPUT || type == PARAM_TYPE_MESSAGE))
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Parameter types must be in the range 0,5..47,49..62.");
|
|
||||||
}
|
|
||||||
if (type == PARAM_TYPE_CONFIG)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Parameter type " + PARAM_TYPE_CONFIG
|
|
||||||
+ " is reserved for internal use.");
|
|
||||||
}
|
|
||||||
this.parameters.put(Integers.valueOf(type), value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link SkeinParameters#PARAM_TYPE_KEY} parameter.
|
|
||||||
*/
|
|
||||||
public Builder setKey(byte[] key)
|
|
||||||
{
|
|
||||||
return set(PARAM_TYPE_KEY, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link SkeinParameters#PARAM_TYPE_PERSONALISATION} parameter.
|
|
||||||
*/
|
|
||||||
public Builder setPersonalisation(byte[] personalisation)
|
|
||||||
{
|
|
||||||
return set(PARAM_TYPE_PERSONALISATION, personalisation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link SkeinParameters#PARAM_TYPE_KEY_IDENTIFIER} parameter.
|
|
||||||
*/
|
|
||||||
public Builder setPublicKey(byte[] publicKey)
|
|
||||||
{
|
|
||||||
return set(PARAM_TYPE_PUBLIC_KEY, publicKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link SkeinParameters#PARAM_TYPE_KEY_IDENTIFIER} parameter.
|
|
||||||
*/
|
|
||||||
public Builder setKeyIdentifier(byte[] keyIdentifier)
|
|
||||||
{
|
|
||||||
return set(PARAM_TYPE_KEY_IDENTIFIER, keyIdentifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link SkeinParameters#PARAM_TYPE_NONCE} parameter.
|
|
||||||
*/
|
|
||||||
public Builder setNonce(byte[] nonce)
|
|
||||||
{
|
|
||||||
return set(PARAM_TYPE_NONCE, nonce);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new {@link SkeinParameters} instance with the parameters provided to this
|
|
||||||
* builder.
|
|
||||||
*/
|
|
||||||
public SkeinParameters build()
|
|
||||||
{
|
|
||||||
return new SkeinParameters(parameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,131 +0,0 @@
|
|||||||
package org.spongycastle.crypto.tls;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import org.spongycastle.asn1.ASN1Encoding;
|
|
||||||
import org.spongycastle.asn1.ocsp.ResponderID;
|
|
||||||
import org.spongycastle.asn1.x509.Extensions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RFC 3546 3.6
|
|
||||||
*/
|
|
||||||
public class OCSPStatusRequest
|
|
||||||
{
|
|
||||||
protected Vector responderIDList;
|
|
||||||
protected Extensions requestExtensions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param responderIDList
|
|
||||||
* a {@link Vector} of {@link ResponderID}, specifying the list of trusted OCSP
|
|
||||||
* responders. An empty list has the special meaning that the responders are
|
|
||||||
* implicitly known to the server - e.g., by prior arrangement.
|
|
||||||
* @param requestExtensions
|
|
||||||
* OCSP request extensions. A null value means that there are no extensions.
|
|
||||||
*/
|
|
||||||
public OCSPStatusRequest(Vector responderIDList, Extensions requestExtensions)
|
|
||||||
{
|
|
||||||
this.responderIDList = responderIDList;
|
|
||||||
this.requestExtensions = requestExtensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a {@link Vector} of {@link ResponderID}
|
|
||||||
*/
|
|
||||||
public Vector getResponderIDList()
|
|
||||||
{
|
|
||||||
return responderIDList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return OCSP request extensions
|
|
||||||
*/
|
|
||||||
public Extensions getRequestExtensions()
|
|
||||||
{
|
|
||||||
return requestExtensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode this {@link OCSPStatusRequest} to an {@link OutputStream}.
|
|
||||||
*
|
|
||||||
* @param output
|
|
||||||
* the {@link OutputStream} to encode to.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public void encode(OutputStream output) throws IOException
|
|
||||||
{
|
|
||||||
if (responderIDList == null || responderIDList.isEmpty())
|
|
||||||
{
|
|
||||||
TlsUtils.writeUint16(0, output);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
|
||||||
for (int i = 0; i < responderIDList.size(); ++i)
|
|
||||||
{
|
|
||||||
ResponderID responderID = (ResponderID) responderIDList.elementAt(i);
|
|
||||||
byte[] derEncoding = responderID.getEncoded(ASN1Encoding.DER);
|
|
||||||
TlsUtils.writeOpaque16(derEncoding, buf);
|
|
||||||
}
|
|
||||||
TlsUtils.checkUint16(buf.size());
|
|
||||||
TlsUtils.writeUint16(buf.size(), output);
|
|
||||||
output.write(buf.toByteArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestExtensions == null)
|
|
||||||
{
|
|
||||||
TlsUtils.writeUint16(0, output);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte[] derEncoding = requestExtensions.getEncoded(ASN1Encoding.DER);
|
|
||||||
TlsUtils.checkUint16(derEncoding.length);
|
|
||||||
TlsUtils.writeUint16(derEncoding.length, output);
|
|
||||||
output.write(derEncoding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse an {@link OCSPStatusRequest} from an {@link InputStream}.
|
|
||||||
*
|
|
||||||
* @param input
|
|
||||||
* the {@link InputStream} to parse from.
|
|
||||||
* @return an {@link OCSPStatusRequest} object.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static OCSPStatusRequest parse(InputStream input) throws IOException
|
|
||||||
{
|
|
||||||
Vector responderIDList = new Vector();
|
|
||||||
{
|
|
||||||
int length = TlsUtils.readUint16(input);
|
|
||||||
if (length > 0)
|
|
||||||
{
|
|
||||||
byte[] data = TlsUtils.readFully(length, input);
|
|
||||||
ByteArrayInputStream buf = new ByteArrayInputStream(data);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
byte[] derEncoding = TlsUtils.readOpaque16(buf);
|
|
||||||
ResponderID responderID = ResponderID.getInstance(TlsUtils.readDERObject(derEncoding));
|
|
||||||
responderIDList.addElement(responderID);
|
|
||||||
}
|
|
||||||
while (buf.available() > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Extensions requestExtensions = null;
|
|
||||||
{
|
|
||||||
int length = TlsUtils.readUint16(input);
|
|
||||||
if (length > 0)
|
|
||||||
{
|
|
||||||
byte[] derEncoding = TlsUtils.readFully(length, input);
|
|
||||||
requestExtensions = Extensions.getInstance(TlsUtils.readDERObject(derEncoding));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new OCSPStatusRequest(responderIDList, requestExtensions);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
package org.spongycastle.crypto.tls;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
public class ServerNameList
|
|
||||||
{
|
|
||||||
protected Vector serverNameList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param serverNameList a {@link Vector} of {@link ServerName}.
|
|
||||||
*/
|
|
||||||
public ServerNameList(Vector serverNameList)
|
|
||||||
{
|
|
||||||
if (serverNameList == null || serverNameList.isEmpty())
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("'serverNameList' must not be null or empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.serverNameList = serverNameList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a {@link Vector} of {@link ServerName}.
|
|
||||||
*/
|
|
||||||
public Vector getServerNameList()
|
|
||||||
{
|
|
||||||
return serverNameList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode this {@link ServerNameList} to an {@link OutputStream}.
|
|
||||||
*
|
|
||||||
* @param output
|
|
||||||
* the {@link OutputStream} to encode to.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public void encode(OutputStream output) throws IOException
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
for (int i = 0; i < serverNameList.size(); ++i)
|
|
||||||
{
|
|
||||||
ServerName entry = (ServerName)serverNameList.elementAt(i);
|
|
||||||
entry.encode(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
TlsUtils.checkUint16(buf.size());
|
|
||||||
TlsUtils.writeUint16(buf.size(), output);
|
|
||||||
output.write(buf.toByteArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a {@link ServerNameList} from an {@link InputStream}.
|
|
||||||
*
|
|
||||||
* @param input
|
|
||||||
* the {@link InputStream} to parse from.
|
|
||||||
* @return a {@link ServerNameList} object.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static ServerNameList parse(InputStream input) throws IOException
|
|
||||||
{
|
|
||||||
int length = TlsUtils.readUint16(input);
|
|
||||||
if (length < 1)
|
|
||||||
{
|
|
||||||
throw new TlsFatalAlert(AlertDescription.decode_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] data = TlsUtils.readFully(length, input);
|
|
||||||
|
|
||||||
ByteArrayInputStream buf = new ByteArrayInputStream(data);
|
|
||||||
|
|
||||||
Vector server_name_list = new Vector();
|
|
||||||
while (buf.available() > 0)
|
|
||||||
{
|
|
||||||
ServerName entry = ServerName.parse(buf);
|
|
||||||
server_name_list.addElement(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ServerNameList(server_name_list);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
package org.spongycastle.crypto.tls;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import javax.microedition.io.DatagramConnection;
|
|
||||||
import javax.microedition.io.Datagram;
|
|
||||||
|
|
||||||
public class UDPTransport
|
|
||||||
implements DatagramTransport
|
|
||||||
{
|
|
||||||
|
|
||||||
protected final static int MIN_IP_OVERHEAD = 20;
|
|
||||||
protected final static int MAX_IP_OVERHEAD = MIN_IP_OVERHEAD + 64;
|
|
||||||
protected final static int UDP_OVERHEAD = 8;
|
|
||||||
|
|
||||||
protected final DatagramConnection socket;
|
|
||||||
protected final int receiveLimit, sendLimit;
|
|
||||||
|
|
||||||
public UDPTransport(DatagramConnection socket, int mtu)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// In 1.3 and earlier sockets were bound and connected during creation
|
|
||||||
//
|
|
||||||
//if (!socket.isBound() || !socket.isConnected())
|
|
||||||
//{
|
|
||||||
// throw new IllegalArgumentException("'socket' must be bound and connected");
|
|
||||||
//}
|
|
||||||
|
|
||||||
this.socket = socket;
|
|
||||||
|
|
||||||
// NOTE: As of JDK 1.6, can use NetworkInterface.getMTU
|
|
||||||
|
|
||||||
this.receiveLimit = mtu - MIN_IP_OVERHEAD - UDP_OVERHEAD;
|
|
||||||
this.sendLimit = mtu - MAX_IP_OVERHEAD - UDP_OVERHEAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getReceiveLimit()
|
|
||||||
{
|
|
||||||
return receiveLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSendLimit()
|
|
||||||
{
|
|
||||||
// TODO[DTLS] Implement Path-MTU discovery?
|
|
||||||
return sendLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int receive(byte[] buf, int off, int len, int waitMillis)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
//socket.setSoTimeout(waitMillis); -- not applicable
|
|
||||||
|
|
||||||
if (off == 0)
|
|
||||||
{
|
|
||||||
Datagram packet = socket.newDatagram(buf, len);
|
|
||||||
socket.receive(packet);
|
|
||||||
|
|
||||||
return packet.getLength();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte[] rv = new byte[len];
|
|
||||||
|
|
||||||
Datagram packet = socket.newDatagram(rv, len);
|
|
||||||
socket.receive(packet);
|
|
||||||
|
|
||||||
System.arraycopy(rv, 0, buf, off, packet.getLength());
|
|
||||||
|
|
||||||
return packet.getLength();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void send(byte[] buf, int off, int len)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (len > getSendLimit())
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* RFC 4347 4.1.1. "If the application attempts to send a record larger than the MTU,
|
|
||||||
* the DTLS implementation SHOULD generate an error, thus avoiding sending a packet
|
|
||||||
* which will be fragmented."
|
|
||||||
*/
|
|
||||||
// TODO Exception
|
|
||||||
}
|
|
||||||
|
|
||||||
if (off == 0)
|
|
||||||
{
|
|
||||||
Datagram packet = socket.newDatagram(buf, len);
|
|
||||||
socket.send(packet);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte[] data = new byte[len];
|
|
||||||
|
|
||||||
System.arraycopy(buf, off, data, 0, len);
|
|
||||||
|
|
||||||
Datagram packet = socket.newDatagram(data, len);
|
|
||||||
socket.send(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,19 +0,0 @@
|
|||||||
package org.spongycastle.util;
|
|
||||||
|
|
||||||
public class Integers
|
|
||||||
{
|
|
||||||
public static int rotateLeft(int i, int distance)
|
|
||||||
{
|
|
||||||
return (i << distance) ^ (i >>> -distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int rotateRight(int i, int distance)
|
|
||||||
{
|
|
||||||
return (i >>> distance) ^ (i << -distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Integer valueOf(int value)
|
|
||||||
{
|
|
||||||
return new Integer(value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package org.spongycastle.util;
|
|
||||||
|
|
||||||
public interface Selector
|
|
||||||
{
|
|
||||||
boolean match(Object obj);
|
|
||||||
|
|
||||||
Object clone();
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package org.spongycastle.util;
|
|
||||||
|
|
||||||
public class Shorts
|
|
||||||
{
|
|
||||||
public static Short valueOf(short value)
|
|
||||||
{
|
|
||||||
return new Short(value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package org.spongycastle.util;
|
|
||||||
|
|
||||||
public final class Times
|
|
||||||
{
|
|
||||||
private static long NANOS_PER_MILLI = 1000000L;
|
|
||||||
|
|
||||||
public static long nanoTime()
|
|
||||||
{
|
|
||||||
return NANOS_PER_MILLI * System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
package org.spongycastle.util.test;
|
|
||||||
|
|
||||||
import java.io.PrintStream;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
|
|
||||||
public abstract class SimpleTest
|
|
||||||
implements Test
|
|
||||||
{
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
private TestResult success()
|
|
||||||
{
|
|
||||||
return SimpleTestResult.successful(this, "Okay");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void fail(
|
|
||||||
String message)
|
|
||||||
{
|
|
||||||
throw new TestFailedException(SimpleTestResult.failed(this, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void fail(
|
|
||||||
String message,
|
|
||||||
Throwable throwable)
|
|
||||||
{
|
|
||||||
throw new TestFailedException(SimpleTestResult.failed(this, message, throwable));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void fail(
|
|
||||||
String message,
|
|
||||||
Object expected,
|
|
||||||
Object found)
|
|
||||||
{
|
|
||||||
throw new TestFailedException(SimpleTestResult.failed(this, message, expected, found));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean areEqual(
|
|
||||||
byte[] a,
|
|
||||||
byte[] b)
|
|
||||||
{
|
|
||||||
return Arrays.areEqual(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TestResult perform()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
performTest();
|
|
||||||
|
|
||||||
return success();
|
|
||||||
}
|
|
||||||
catch (TestFailedException e)
|
|
||||||
{
|
|
||||||
return e.getResult();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return SimpleTestResult.failed(this, "Exception: " + e, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void runTest(
|
|
||||||
Test test)
|
|
||||||
{
|
|
||||||
runTest(test, System.out);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void runTest(
|
|
||||||
Test test,
|
|
||||||
PrintStream out)
|
|
||||||
{
|
|
||||||
TestResult result = test.perform();
|
|
||||||
|
|
||||||
out.println(result.toString());
|
|
||||||
if (result.getException() != null)
|
|
||||||
{
|
|
||||||
result.getException().printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void performTest()
|
|
||||||
throws Exception;
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
package org.spongycastle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Bouncy Castle License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2000-2014 The Legion Of The Bouncy Castle Inc. (http://www.bouncycastle.org)
|
|
||||||
* <p>
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
||||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
||||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
* subject to the following conditions:
|
|
||||||
* <p>
|
|
||||||
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
||||||
* portions of the Software.
|
|
||||||
* <p>
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
||||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
* DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
public class LICENSE
|
|
||||||
{
|
|
||||||
public static String licenseText =
|
|
||||||
"Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) "
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "Permission is hereby granted, free of charge, to any person obtaining a copy of this software "
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "and associated documentation files (the \"Software\"), to deal in the Software without restriction, "
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, "
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,"
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "subject to the following conditions:"
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "The above copyright notice and this permission notice shall be included in all copies or substantial"
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "portions of the Software."
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,"
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR"
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE"
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR"
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER"
|
|
||||||
+ System.getProperty("line.separator")
|
|
||||||
+ "DEALINGS IN THE SOFTWARE.";
|
|
||||||
|
|
||||||
public static void main(
|
|
||||||
String[] args)
|
|
||||||
{
|
|
||||||
System.out.println(licenseText);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface to parse ASN.1 application specific objects.
|
|
||||||
*/
|
|
||||||
public interface ASN1ApplicationSpecificParser
|
|
||||||
extends ASN1Encodable, InMemoryRepresentable
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Read the next object in the parser.
|
|
||||||
*
|
|
||||||
* @return an ASN1Encodable
|
|
||||||
* @throws IOException on a parsing or decoding error.
|
|
||||||
*/
|
|
||||||
ASN1Encodable readObject()
|
|
||||||
throws IOException;
|
|
||||||
}
|
|
@ -1,204 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Public facade of ASN.1 Boolean data.
|
|
||||||
* <p>
|
|
||||||
* Use following to place a new instance of ASN.1 Boolean in your dataset:
|
|
||||||
* </p>
|
|
||||||
* <ul>
|
|
||||||
* <li> ASN1Boolean.TRUE literal</li>
|
|
||||||
* <li> ASN1Boolean.FALSE literal</li>
|
|
||||||
* <li> {@link ASN1Boolean#getInstance(boolean) ASN1Boolean.getInstance(boolean)}</li>
|
|
||||||
* <li> {@link ASN1Boolean#getInstance(int) ASN1Boolean.getInstance(int)}</li>
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public class ASN1Boolean
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
|
|
||||||
private static final byte[] FALSE_VALUE = new byte[] { 0 };
|
|
||||||
|
|
||||||
private byte[] value;
|
|
||||||
|
|
||||||
public static final ASN1Boolean FALSE = new ASN1Boolean(false);
|
|
||||||
public static final ASN1Boolean TRUE = new ASN1Boolean(true);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a boolean from the passed in object.
|
|
||||||
*
|
|
||||||
* @param obj an ASN1Boolean or an object that can be converted into one.
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
* @return an ASN1Boolean instance.
|
|
||||||
*/
|
|
||||||
public static ASN1Boolean getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1Boolean)
|
|
||||||
{
|
|
||||||
return (ASN1Boolean)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
byte[] enc = (byte[])obj;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (ASN1Boolean)fromByteArray(enc);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("failed to construct boolean from byte[]: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an ASN1Boolean from the passed in boolean.
|
|
||||||
* @return an ASN1Boolean instance.
|
|
||||||
*/
|
|
||||||
public static ASN1Boolean getInstance(
|
|
||||||
boolean value)
|
|
||||||
{
|
|
||||||
return (value ? TRUE : FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an ASN1Boolean from the passed in value.
|
|
||||||
* @return an ASN1Boolean instance.
|
|
||||||
*/
|
|
||||||
public static ASN1Boolean getInstance(
|
|
||||||
int value)
|
|
||||||
{
|
|
||||||
return (value != 0 ? TRUE : FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a Boolean from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
* @return an ASN1Boolean instance.
|
|
||||||
*/
|
|
||||||
public static ASN1Boolean getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Primitive o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof ASN1Boolean)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Boolean(
|
|
||||||
byte[] value)
|
|
||||||
{
|
|
||||||
if (value.length != 1)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("byte value should have 1 byte in it");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value[0] == 0)
|
|
||||||
{
|
|
||||||
this.value = FALSE_VALUE;
|
|
||||||
}
|
|
||||||
else if ((value[0] & 0xff) == 0xff)
|
|
||||||
{
|
|
||||||
this.value = TRUE_VALUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.value = Arrays.clone(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use getInstance(boolean) method.
|
|
||||||
* @param value true or false.
|
|
||||||
*/
|
|
||||||
public ASN1Boolean(
|
|
||||||
boolean value)
|
|
||||||
{
|
|
||||||
this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTrue()
|
|
||||||
{
|
|
||||||
return (value[0] != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
{
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.writeEncoded(BERTags.BOOLEAN, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (o instanceof ASN1Boolean)
|
|
||||||
{
|
|
||||||
return (value[0] == ((ASN1Boolean)o).value[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return value[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return (value[0] != 0) ? "TRUE" : "FALSE";
|
|
||||||
}
|
|
||||||
|
|
||||||
static ASN1Boolean fromOctetString(byte[] value)
|
|
||||||
{
|
|
||||||
if (value.length != 1)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value[0] == 0)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else if ((value[0] & 0xff) == 0xff)
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new ASN1Boolean(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker interface for CHOICE objects - if you implement this in a role your
|
|
||||||
* own object any attempt to tag the object implicitly will convert the tag to
|
|
||||||
* an explicit one as the encoding rules require.
|
|
||||||
* <p>
|
|
||||||
* If you use this interface your class should also implement the getInstance()
|
|
||||||
* pattern which takes a tag object and the tagging mode used.
|
|
||||||
* <p>
|
|
||||||
* <hr>
|
|
||||||
* <p><b>X.690</b></p>
|
|
||||||
* <p><b>8: Basic encoding rules</b></p>
|
|
||||||
* <p><b>8.13 Encoding of a choice value </b></p>
|
|
||||||
* <p>
|
|
||||||
* The encoding of a choice value shall be the same as the encoding of a value of the chosen type.
|
|
||||||
* <blockquote>
|
|
||||||
* NOTE 1 — The encoding may be primitive or constructed depending on the chosen type.
|
|
||||||
* <p>
|
|
||||||
* NOTE 2 — The tag used in the identifier octets is the tag of the chosen type,
|
|
||||||
* as specified in the ASN.1 definition of the choice type.
|
|
||||||
* </blockquote>
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public interface ASN1Choice
|
|
||||||
{
|
|
||||||
// marker interface
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic interface to produce serialisers for ASN.1 encodings.
|
|
||||||
*/
|
|
||||||
public interface ASN1Encodable
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Return an object, possibly constructed, of ASN.1 primitives
|
|
||||||
* @return an ASN.1 primitive.
|
|
||||||
*/
|
|
||||||
ASN1Primitive toASN1Primitive();
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mutable class for building ASN.1 constructed objects.
|
|
||||||
*/
|
|
||||||
public class ASN1EncodableVector
|
|
||||||
{
|
|
||||||
Vector v = new Vector();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base constructor.
|
|
||||||
*/
|
|
||||||
public ASN1EncodableVector()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an encodable to the vector.
|
|
||||||
*
|
|
||||||
* @param obj the encodable to add.
|
|
||||||
*/
|
|
||||||
public void add(ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
v.addElement(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the contents of another vector.
|
|
||||||
*
|
|
||||||
* @param other the vector to add.
|
|
||||||
*/
|
|
||||||
public void addAll(ASN1EncodableVector other)
|
|
||||||
{
|
|
||||||
for (Enumeration en = other.v.elements(); en.hasMoreElements();)
|
|
||||||
{
|
|
||||||
v.addElement(en.nextElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the object at position i in this vector.
|
|
||||||
*
|
|
||||||
* @param i the index of the object of interest.
|
|
||||||
* @return the object at position i.
|
|
||||||
*/
|
|
||||||
public ASN1Encodable get(int i)
|
|
||||||
{
|
|
||||||
return (ASN1Encodable)v.elementAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the size of the vector.
|
|
||||||
*
|
|
||||||
* @return the object count in the vector.
|
|
||||||
*/
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return v.size();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Supported encoding formats.
|
|
||||||
*/
|
|
||||||
public interface ASN1Encoding
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* DER - distinguished encoding rules.
|
|
||||||
*/
|
|
||||||
static final String DER = "DER";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DL - definite length encoding.
|
|
||||||
*/
|
|
||||||
static final String DL = "DL";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BER - basic encoding rules.
|
|
||||||
*/
|
|
||||||
static final String BER = "BER";
|
|
||||||
}
|
|
@ -1,174 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class representing the ASN.1 ENUMERATED type.
|
|
||||||
*/
|
|
||||||
public class ASN1Enumerated
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
byte[] bytes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an enumerated from the passed in object
|
|
||||||
*
|
|
||||||
* @param obj an ASN1Enumerated or an object that can be converted into one.
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
* @return an ASN1Enumerated instance, or null.
|
|
||||||
*/
|
|
||||||
public static ASN1Enumerated getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1Enumerated)
|
|
||||||
{
|
|
||||||
return (ASN1Enumerated)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (ASN1Enumerated)fromByteArray((byte[])obj);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an Enumerated from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
* @return an ASN1Enumerated instance, or null.
|
|
||||||
*/
|
|
||||||
public static ASN1Enumerated getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Primitive o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof ASN1Enumerated)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return fromOctetString(((ASN1OctetString)o).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor from int.
|
|
||||||
*
|
|
||||||
* @param value the value of this enumerated.
|
|
||||||
*/
|
|
||||||
public ASN1Enumerated(
|
|
||||||
int value)
|
|
||||||
{
|
|
||||||
bytes = BigInteger.valueOf(value).toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor from BigInteger
|
|
||||||
*
|
|
||||||
* @param value the value of this enumerated.
|
|
||||||
*/
|
|
||||||
public ASN1Enumerated(
|
|
||||||
BigInteger value)
|
|
||||||
{
|
|
||||||
bytes = value.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor from encoded BigInteger.
|
|
||||||
*
|
|
||||||
* @param bytes the value of this enumerated as an encoded BigInteger (signed).
|
|
||||||
*/
|
|
||||||
public ASN1Enumerated(
|
|
||||||
byte[] bytes)
|
|
||||||
{
|
|
||||||
this.bytes = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getValue()
|
|
||||||
{
|
|
||||||
return new BigInteger(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
{
|
|
||||||
return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.writeEncoded(BERTags.ENUMERATED, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1Enumerated))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Enumerated other = (ASN1Enumerated)o;
|
|
||||||
|
|
||||||
return Arrays.areEqual(this.bytes, other.bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Arrays.hashCode(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
|
|
||||||
|
|
||||||
static ASN1Enumerated fromOctetString(byte[] enc)
|
|
||||||
{
|
|
||||||
if (enc.length > 1)
|
|
||||||
{
|
|
||||||
return new ASN1Enumerated(Arrays.clone(enc));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enc.length == 0)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("ENUMERATED has zero length");
|
|
||||||
}
|
|
||||||
int value = enc[0] & 0xff;
|
|
||||||
|
|
||||||
if (value >= cache.length)
|
|
||||||
{
|
|
||||||
return new ASN1Enumerated(Arrays.clone(enc));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Enumerated possibleMatch = cache[value];
|
|
||||||
|
|
||||||
if (possibleMatch == null)
|
|
||||||
{
|
|
||||||
possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
|
|
||||||
}
|
|
||||||
|
|
||||||
return possibleMatch;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ASN1Exception
|
|
||||||
extends IOException
|
|
||||||
{
|
|
||||||
private Throwable cause;
|
|
||||||
|
|
||||||
ASN1Exception(String message)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Exception(String message, Throwable cause)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
this.cause = cause;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Throwable getCause()
|
|
||||||
{
|
|
||||||
return cause;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,373 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.SimpleTimeZone;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
import org.spongycastle.util.Strings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class representing the ASN.1 GeneralizedTime type.
|
|
||||||
* <p>
|
|
||||||
* The main difference between these and UTC time is a 4 digit year.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public class ASN1GeneralizedTime
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
private byte[] time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a generalized time from the passed in object
|
|
||||||
*
|
|
||||||
* @param obj an ASN1GeneralizedTime or an object that can be converted into one.
|
|
||||||
* @return an ASN1GeneralizedTime instance, or null.
|
|
||||||
* @throws IllegalArgumentException if the object cannot be converted.
|
|
||||||
*/
|
|
||||||
public static ASN1GeneralizedTime getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1GeneralizedTime)
|
|
||||||
{
|
|
||||||
return (ASN1GeneralizedTime)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (ASN1GeneralizedTime)fromByteArray((byte[])obj);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a Generalized Time object from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @return an ASN1GeneralizedTime instance.
|
|
||||||
* @throws IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
*/
|
|
||||||
public static ASN1GeneralizedTime getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Primitive o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof ASN1GeneralizedTime)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
|
|
||||||
* for local time, or Z+-HHMM on the end, for difference between local
|
|
||||||
* time and UTC time. The fractional second amount f must consist of at
|
|
||||||
* least one number with trailing zeroes removed.
|
|
||||||
*
|
|
||||||
* @param time the time string.
|
|
||||||
* @throws IllegalArgumentException if String is an illegal format.
|
|
||||||
*/
|
|
||||||
public ASN1GeneralizedTime(
|
|
||||||
String time)
|
|
||||||
{
|
|
||||||
this.time = Strings.toByteArray(time);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this.getDate();
|
|
||||||
}
|
|
||||||
catch (ParseException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("invalid date string: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base constructor from a java.util.date object
|
|
||||||
*
|
|
||||||
* @param time a date object representing the time of interest.
|
|
||||||
*/
|
|
||||||
public ASN1GeneralizedTime(
|
|
||||||
Date time)
|
|
||||||
{
|
|
||||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
|
|
||||||
|
|
||||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
|
||||||
|
|
||||||
this.time = Strings.toByteArray(dateF.format(time));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 GeneralizedTime value.
|
|
||||||
*/
|
|
||||||
public ASN1GeneralizedTime(
|
|
||||||
Date time,
|
|
||||||
Locale locale)
|
|
||||||
{
|
|
||||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", locale);
|
|
||||||
|
|
||||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
|
||||||
|
|
||||||
this.time = Strings.toByteArray(dateF.format(time));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1GeneralizedTime(
|
|
||||||
byte[] bytes)
|
|
||||||
{
|
|
||||||
this.time = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the time.
|
|
||||||
*
|
|
||||||
* @return The time string as it appeared in the encoded object.
|
|
||||||
*/
|
|
||||||
public String getTimeString()
|
|
||||||
{
|
|
||||||
return Strings.fromByteArray(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the time - always in the form of
|
|
||||||
* YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
|
|
||||||
* <p/>
|
|
||||||
* Normally in a certificate we would expect "Z" rather than "GMT",
|
|
||||||
* however adding the "GMT" means we can just use:
|
|
||||||
* <pre>
|
|
||||||
* dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
|
||||||
* </pre>
|
|
||||||
* To read in the time and get a date which is compatible with our local
|
|
||||||
* time zone.
|
|
||||||
*/
|
|
||||||
public String getTime()
|
|
||||||
{
|
|
||||||
String stime = Strings.fromByteArray(time);
|
|
||||||
|
|
||||||
//
|
|
||||||
// standardise the format.
|
|
||||||
//
|
|
||||||
if (stime.charAt(stime.length() - 1) == 'Z')
|
|
||||||
{
|
|
||||||
return stime.substring(0, stime.length() - 1) + "GMT+00:00";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int signPos = stime.length() - 5;
|
|
||||||
char sign = stime.charAt(signPos);
|
|
||||||
if (sign == '-' || sign == '+')
|
|
||||||
{
|
|
||||||
return stime.substring(0, signPos)
|
|
||||||
+ "GMT"
|
|
||||||
+ stime.substring(signPos, signPos + 3)
|
|
||||||
+ ":"
|
|
||||||
+ stime.substring(signPos + 3);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
signPos = stime.length() - 3;
|
|
||||||
sign = stime.charAt(signPos);
|
|
||||||
if (sign == '-' || sign == '+')
|
|
||||||
{
|
|
||||||
return stime.substring(0, signPos)
|
|
||||||
+ "GMT"
|
|
||||||
+ stime.substring(signPos)
|
|
||||||
+ ":00";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stime + calculateGMTOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String calculateGMTOffset()
|
|
||||||
{
|
|
||||||
String sign = "+";
|
|
||||||
TimeZone timeZone = TimeZone.getDefault();
|
|
||||||
int offset = timeZone.getRawOffset();
|
|
||||||
if (offset < 0)
|
|
||||||
{
|
|
||||||
sign = "-";
|
|
||||||
offset = -offset;
|
|
||||||
}
|
|
||||||
int hours = offset / (60 * 60 * 1000);
|
|
||||||
int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate()))
|
|
||||||
{
|
|
||||||
hours += sign.equals("+") ? 1 : -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ParseException e)
|
|
||||||
{
|
|
||||||
// we'll do our best and ignore daylight savings
|
|
||||||
}
|
|
||||||
|
|
||||||
return "GMT" + sign + convert(hours) + ":" + convert(minutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String convert(int time)
|
|
||||||
{
|
|
||||||
if (time < 10)
|
|
||||||
{
|
|
||||||
return "0" + time;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Integer.toString(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getDate()
|
|
||||||
throws ParseException
|
|
||||||
{
|
|
||||||
SimpleDateFormat dateF;
|
|
||||||
String stime = Strings.fromByteArray(time);
|
|
||||||
String d = stime;
|
|
||||||
|
|
||||||
if (stime.endsWith("Z"))
|
|
||||||
{
|
|
||||||
if (hasFractionalSeconds())
|
|
||||||
{
|
|
||||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
|
|
||||||
}
|
|
||||||
|
|
||||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
|
||||||
}
|
|
||||||
else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0)
|
|
||||||
{
|
|
||||||
d = this.getTime();
|
|
||||||
if (hasFractionalSeconds())
|
|
||||||
{
|
|
||||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
|
||||||
}
|
|
||||||
|
|
||||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (hasFractionalSeconds())
|
|
||||||
{
|
|
||||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss");
|
|
||||||
}
|
|
||||||
|
|
||||||
dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasFractionalSeconds())
|
|
||||||
{
|
|
||||||
// java misinterprets extra digits as being milliseconds...
|
|
||||||
String frac = d.substring(14);
|
|
||||||
int index;
|
|
||||||
for (index = 1; index < frac.length(); index++)
|
|
||||||
{
|
|
||||||
char ch = frac.charAt(index);
|
|
||||||
if (!('0' <= ch && ch <= '9'))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index - 1 > 3)
|
|
||||||
{
|
|
||||||
frac = frac.substring(0, 4) + frac.substring(index);
|
|
||||||
d = d.substring(0, 14) + frac;
|
|
||||||
}
|
|
||||||
else if (index - 1 == 1)
|
|
||||||
{
|
|
||||||
frac = frac.substring(0, index) + "00" + frac.substring(index);
|
|
||||||
d = d.substring(0, 14) + frac;
|
|
||||||
}
|
|
||||||
else if (index - 1 == 2)
|
|
||||||
{
|
|
||||||
frac = frac.substring(0, index) + "0" + frac.substring(index);
|
|
||||||
d = d.substring(0, 14) + frac;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dateF.parse(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasFractionalSeconds()
|
|
||||||
{
|
|
||||||
for (int i = 0; i != time.length; i++)
|
|
||||||
{
|
|
||||||
if (time[i] == '.')
|
|
||||||
{
|
|
||||||
if (i == 14)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
{
|
|
||||||
int length = time.length;
|
|
||||||
|
|
||||||
return 1 + StreamUtil.calculateBodyLength(length) + length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.writeEncoded(BERTags.GENERALIZED_TIME, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1GeneralizedTime))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Arrays.areEqual(time, ((ASN1GeneralizedTime)o).time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Arrays.hashCode(time);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public abstract class ASN1Generator
|
|
||||||
{
|
|
||||||
protected OutputStream _out;
|
|
||||||
|
|
||||||
public ASN1Generator(OutputStream out)
|
|
||||||
{
|
|
||||||
_out = out;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract OutputStream getRawOutputStream();
|
|
||||||
}
|
|
@ -1,472 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.FilterInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.spongycastle.util.io.Streams;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* a general purpose ASN.1 decoder - note: this class differs from the
|
|
||||||
* others in that it returns null after it has read the last object in
|
|
||||||
* the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
|
|
||||||
* returned.
|
|
||||||
*/
|
|
||||||
public class ASN1InputStream
|
|
||||||
extends FilterInputStream
|
|
||||||
implements BERTags
|
|
||||||
{
|
|
||||||
private final int limit;
|
|
||||||
private final boolean lazyEvaluate;
|
|
||||||
|
|
||||||
private final byte[][] tmpBuffers;
|
|
||||||
|
|
||||||
public ASN1InputStream(
|
|
||||||
InputStream is)
|
|
||||||
{
|
|
||||||
this(is, StreamUtil.findLimit(is));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an ASN1InputStream based on the input byte array. The length of DER objects in
|
|
||||||
* the stream is automatically limited to the length of the input array.
|
|
||||||
*
|
|
||||||
* @param input array containing ASN.1 encoded data.
|
|
||||||
*/
|
|
||||||
public ASN1InputStream(
|
|
||||||
byte[] input)
|
|
||||||
{
|
|
||||||
this(new ByteArrayInputStream(input), input.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an ASN1InputStream based on the input byte array. The length of DER objects in
|
|
||||||
* the stream is automatically limited to the length of the input array.
|
|
||||||
*
|
|
||||||
* @param input array containing ASN.1 encoded data.
|
|
||||||
* @param lazyEvaluate true if parsing inside constructed objects can be delayed.
|
|
||||||
*/
|
|
||||||
public ASN1InputStream(
|
|
||||||
byte[] input,
|
|
||||||
boolean lazyEvaluate)
|
|
||||||
{
|
|
||||||
this(new ByteArrayInputStream(input), input.length, lazyEvaluate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an ASN1InputStream where no DER object will be longer than limit.
|
|
||||||
*
|
|
||||||
* @param input stream containing ASN.1 encoded data.
|
|
||||||
* @param limit maximum size of a DER encoded object.
|
|
||||||
*/
|
|
||||||
public ASN1InputStream(
|
|
||||||
InputStream input,
|
|
||||||
int limit)
|
|
||||||
{
|
|
||||||
this(input, limit, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an ASN1InputStream where no DER object will be longer than limit, and constructed
|
|
||||||
* objects such as sequences will be parsed lazily.
|
|
||||||
*
|
|
||||||
* @param input stream containing ASN.1 encoded data.
|
|
||||||
* @param lazyEvaluate true if parsing inside constructed objects can be delayed.
|
|
||||||
*/
|
|
||||||
public ASN1InputStream(
|
|
||||||
InputStream input,
|
|
||||||
boolean lazyEvaluate)
|
|
||||||
{
|
|
||||||
this(input, StreamUtil.findLimit(input), lazyEvaluate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an ASN1InputStream where no DER object will be longer than limit, and constructed
|
|
||||||
* objects such as sequences will be parsed lazily.
|
|
||||||
*
|
|
||||||
* @param input stream containing ASN.1 encoded data.
|
|
||||||
* @param limit maximum size of a DER encoded object.
|
|
||||||
* @param lazyEvaluate true if parsing inside constructed objects can be delayed.
|
|
||||||
*/
|
|
||||||
public ASN1InputStream(
|
|
||||||
InputStream input,
|
|
||||||
int limit,
|
|
||||||
boolean lazyEvaluate)
|
|
||||||
{
|
|
||||||
super(input);
|
|
||||||
this.limit = limit;
|
|
||||||
this.lazyEvaluate = lazyEvaluate;
|
|
||||||
this.tmpBuffers = new byte[11][];
|
|
||||||
}
|
|
||||||
|
|
||||||
int getLimit()
|
|
||||||
{
|
|
||||||
return limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int readLength()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return readLength(this, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void readFully(
|
|
||||||
byte[] bytes)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (Streams.readFully(this, bytes) != bytes.length)
|
|
||||||
{
|
|
||||||
throw new EOFException("EOF encountered in middle of object");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* build an object given its tag and the number of bytes to construct it from.
|
|
||||||
*
|
|
||||||
* @param tag the full tag details.
|
|
||||||
* @param tagNo the tagNo defined.
|
|
||||||
* @param length the length of the object.
|
|
||||||
* @return the resulting primitive.
|
|
||||||
* @throws java.io.IOException on processing exception.
|
|
||||||
*/
|
|
||||||
protected ASN1Primitive buildObject(
|
|
||||||
int tag,
|
|
||||||
int tagNo,
|
|
||||||
int length)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
boolean isConstructed = (tag & CONSTRUCTED) != 0;
|
|
||||||
|
|
||||||
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length);
|
|
||||||
|
|
||||||
if ((tag & APPLICATION) != 0)
|
|
||||||
{
|
|
||||||
return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tag & TAGGED) != 0)
|
|
||||||
{
|
|
||||||
return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isConstructed)
|
|
||||||
{
|
|
||||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
|
||||||
switch (tagNo)
|
|
||||||
{
|
|
||||||
case OCTET_STRING:
|
|
||||||
//
|
|
||||||
// yes, people actually do this...
|
|
||||||
//
|
|
||||||
ASN1EncodableVector v = buildDEREncodableVector(defIn);
|
|
||||||
ASN1OctetString[] strings = new ASN1OctetString[v.size()];
|
|
||||||
|
|
||||||
for (int i = 0; i != strings.length; i++)
|
|
||||||
{
|
|
||||||
strings[i] = (ASN1OctetString)v.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BEROctetString(strings);
|
|
||||||
case SEQUENCE:
|
|
||||||
if (lazyEvaluate)
|
|
||||||
{
|
|
||||||
return new LazyEncodedSequence(defIn.toByteArray());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return DERFactory.createSequence(buildDEREncodableVector(defIn));
|
|
||||||
}
|
|
||||||
case SET:
|
|
||||||
return DERFactory.createSet(buildDEREncodableVector(defIn));
|
|
||||||
case EXTERNAL:
|
|
||||||
return new DERExternal(buildDEREncodableVector(defIn));
|
|
||||||
default:
|
|
||||||
throw new IOException("unknown tag " + tagNo + " encountered");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1EncodableVector buildEncodableVector()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
|
||||||
ASN1Primitive o;
|
|
||||||
|
|
||||||
while ((o = readObject()) != null)
|
|
||||||
{
|
|
||||||
v.add(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1EncodableVector buildDEREncodableVector(
|
|
||||||
DefiniteLengthInputStream dIn) throws IOException
|
|
||||||
{
|
|
||||||
return new ASN1InputStream(dIn).buildEncodableVector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive readObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int tag = read();
|
|
||||||
if (tag <= 0)
|
|
||||||
{
|
|
||||||
if (tag == 0)
|
|
||||||
{
|
|
||||||
throw new IOException("unexpected end-of-contents marker");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// calculate tag number
|
|
||||||
//
|
|
||||||
int tagNo = readTagNumber(this, tag);
|
|
||||||
|
|
||||||
boolean isConstructed = (tag & CONSTRUCTED) != 0;
|
|
||||||
|
|
||||||
//
|
|
||||||
// calculate length
|
|
||||||
//
|
|
||||||
int length = readLength();
|
|
||||||
|
|
||||||
if (length < 0) // indefinite length method
|
|
||||||
{
|
|
||||||
if (!isConstructed)
|
|
||||||
{
|
|
||||||
throw new IOException("indefinite length primitive encoding encountered");
|
|
||||||
}
|
|
||||||
|
|
||||||
IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit);
|
|
||||||
ASN1StreamParser sp = new ASN1StreamParser(indIn, limit);
|
|
||||||
|
|
||||||
if ((tag & APPLICATION) != 0)
|
|
||||||
{
|
|
||||||
return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tag & TAGGED) != 0)
|
|
||||||
{
|
|
||||||
return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
|
||||||
switch (tagNo)
|
|
||||||
{
|
|
||||||
case OCTET_STRING:
|
|
||||||
return new BEROctetStringParser(sp).getLoadedObject();
|
|
||||||
case SEQUENCE:
|
|
||||||
return new BERSequenceParser(sp).getLoadedObject();
|
|
||||||
case SET:
|
|
||||||
return new BERSetParser(sp).getLoadedObject();
|
|
||||||
case EXTERNAL:
|
|
||||||
return new DERExternalParser(sp).getLoadedObject();
|
|
||||||
default:
|
|
||||||
throw new IOException("unknown BER object encountered");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return buildObject(tag, tagNo, length);
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e)
|
|
||||||
{
|
|
||||||
throw new ASN1Exception("corrupted stream detected", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int readTagNumber(InputStream s, int tag)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int tagNo = tag & 0x1f;
|
|
||||||
|
|
||||||
//
|
|
||||||
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
|
|
||||||
//
|
|
||||||
if (tagNo == 0x1f)
|
|
||||||
{
|
|
||||||
tagNo = 0;
|
|
||||||
|
|
||||||
int b = s.read();
|
|
||||||
|
|
||||||
// X.690-0207 8.1.2.4.2
|
|
||||||
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
|
|
||||||
if ((b & 0x7f) == 0) // Note: -1 will pass
|
|
||||||
{
|
|
||||||
throw new IOException("corrupted stream - invalid high tag number found");
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((b >= 0) && ((b & 0x80) != 0))
|
|
||||||
{
|
|
||||||
tagNo |= (b & 0x7f);
|
|
||||||
tagNo <<= 7;
|
|
||||||
b = s.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b < 0)
|
|
||||||
{
|
|
||||||
throw new EOFException("EOF found inside tag value.");
|
|
||||||
}
|
|
||||||
|
|
||||||
tagNo |= (b & 0x7f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tagNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int readLength(InputStream s, int limit)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int length = s.read();
|
|
||||||
if (length < 0)
|
|
||||||
{
|
|
||||||
throw new EOFException("EOF found when length expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length == 0x80)
|
|
||||||
{
|
|
||||||
return -1; // indefinite-length encoding
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length > 127)
|
|
||||||
{
|
|
||||||
int size = length & 0x7f;
|
|
||||||
|
|
||||||
// Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
|
|
||||||
if (size > 4)
|
|
||||||
{
|
|
||||||
throw new IOException("DER length more than 4 bytes: " + size);
|
|
||||||
}
|
|
||||||
|
|
||||||
length = 0;
|
|
||||||
for (int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
int next = s.read();
|
|
||||||
|
|
||||||
if (next < 0)
|
|
||||||
{
|
|
||||||
throw new EOFException("EOF found reading length");
|
|
||||||
}
|
|
||||||
|
|
||||||
length = (length << 8) + next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length < 0)
|
|
||||||
{
|
|
||||||
throw new IOException("corrupted stream - negative length found");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length >= limit) // after all we must have read at least 1 byte
|
|
||||||
{
|
|
||||||
throw new IOException("corrupted stream - out of bounds length found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int len = defIn.getRemaining();
|
|
||||||
if (defIn.getRemaining() < tmpBuffers.length)
|
|
||||||
{
|
|
||||||
byte[] buf = tmpBuffers[len];
|
|
||||||
|
|
||||||
if (buf == null)
|
|
||||||
{
|
|
||||||
buf = tmpBuffers[len] = new byte[len];
|
|
||||||
}
|
|
||||||
|
|
||||||
Streams.readFully(defIn, buf);
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return defIn.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int len = defIn.getRemaining() / 2;
|
|
||||||
char[] buf = new char[len];
|
|
||||||
int totalRead = 0;
|
|
||||||
while (totalRead < len)
|
|
||||||
{
|
|
||||||
int ch1 = defIn.read();
|
|
||||||
if (ch1 < 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int ch2 = defIn.read();
|
|
||||||
if (ch2 < 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff));
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ASN1Primitive createPrimitiveDERObject(
|
|
||||||
int tagNo,
|
|
||||||
DefiniteLengthInputStream defIn,
|
|
||||||
byte[][] tmpBuffers)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
switch (tagNo)
|
|
||||||
{
|
|
||||||
case BIT_STRING:
|
|
||||||
return DERBitString.fromInputStream(defIn.getRemaining(), defIn);
|
|
||||||
case BMP_STRING:
|
|
||||||
return new DERBMPString(getBMPCharBuffer(defIn));
|
|
||||||
case BOOLEAN:
|
|
||||||
return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers));
|
|
||||||
case ENUMERATED:
|
|
||||||
return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers));
|
|
||||||
case GENERALIZED_TIME:
|
|
||||||
return new ASN1GeneralizedTime(defIn.toByteArray());
|
|
||||||
case GENERAL_STRING:
|
|
||||||
return new DERGeneralString(defIn.toByteArray());
|
|
||||||
case IA5_STRING:
|
|
||||||
return new DERIA5String(defIn.toByteArray());
|
|
||||||
case INTEGER:
|
|
||||||
return new ASN1Integer(defIn.toByteArray(), false);
|
|
||||||
case NULL:
|
|
||||||
return DERNull.INSTANCE; // actual content is ignored (enforce 0 length?)
|
|
||||||
case NUMERIC_STRING:
|
|
||||||
return new DERNumericString(defIn.toByteArray());
|
|
||||||
case OBJECT_IDENTIFIER:
|
|
||||||
return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers));
|
|
||||||
case OCTET_STRING:
|
|
||||||
return new DEROctetString(defIn.toByteArray());
|
|
||||||
case PRINTABLE_STRING:
|
|
||||||
return new DERPrintableString(defIn.toByteArray());
|
|
||||||
case T61_STRING:
|
|
||||||
return new DERT61String(defIn.toByteArray());
|
|
||||||
case UNIVERSAL_STRING:
|
|
||||||
return new DERUniversalString(defIn.toByteArray());
|
|
||||||
case UTC_TIME:
|
|
||||||
return new ASN1UTCTime(defIn.toByteArray());
|
|
||||||
case UTF8_STRING:
|
|
||||||
return new DERUTF8String(defIn.toByteArray());
|
|
||||||
case VISIBLE_STRING:
|
|
||||||
return new DERVisibleString(defIn.toByteArray());
|
|
||||||
default:
|
|
||||||
throw new IOException("unknown tag " + tagNo + " encountered");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,157 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class representing the ASN.1 INTEGER type.
|
|
||||||
*/
|
|
||||||
public class ASN1Integer
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
byte[] bytes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an integer from the passed in object
|
|
||||||
*
|
|
||||||
* @param obj an ASN1Integer or an object that can be converted into one.
|
|
||||||
* @throws IllegalArgumentException if the object cannot be converted.
|
|
||||||
* @return an ASN1Integer instance.
|
|
||||||
*/
|
|
||||||
public static ASN1Integer getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1Integer)
|
|
||||||
{
|
|
||||||
return (ASN1Integer)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (ASN1Integer)fromByteArray((byte[])obj);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an Integer from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @throws IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
* @return an ASN1Integer instance.
|
|
||||||
*/
|
|
||||||
public static ASN1Integer getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Primitive o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof ASN1Integer)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Integer(
|
|
||||||
long value)
|
|
||||||
{
|
|
||||||
bytes = BigInteger.valueOf(value).toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Integer(
|
|
||||||
BigInteger value)
|
|
||||||
{
|
|
||||||
bytes = value.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Integer(
|
|
||||||
byte[] bytes)
|
|
||||||
{
|
|
||||||
this(bytes, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Integer(byte[] bytes, boolean clone)
|
|
||||||
{
|
|
||||||
this.bytes = (clone) ? Arrays.clone(bytes) : bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getValue()
|
|
||||||
{
|
|
||||||
return new BigInteger(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* in some cases positive values get crammed into a space,
|
|
||||||
* that's not quite big enough...
|
|
||||||
* @return the BigInteger that results from treating this ASN.1 INTEGER as unsigned.
|
|
||||||
*/
|
|
||||||
public BigInteger getPositiveValue()
|
|
||||||
{
|
|
||||||
return new BigInteger(1, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
{
|
|
||||||
return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.writeEncoded(BERTags.INTEGER, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
int value = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i != bytes.length; i++)
|
|
||||||
{
|
|
||||||
value ^= (bytes[i] & 0xff) << (i % 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1Integer))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Integer other = (ASN1Integer)o;
|
|
||||||
|
|
||||||
return Arrays.areEqual(bytes, other.bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return getValue().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A NULL object - use DERNull.INSTANCE for populating structures.
|
|
||||||
*/
|
|
||||||
public abstract class ASN1Null
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Return an instance of ASN.1 NULL from the passed in object.
|
|
||||||
* <p>
|
|
||||||
* Accepted inputs:
|
|
||||||
* <ul>
|
|
||||||
* <li> null → null
|
|
||||||
* <li> {@link ASN1Null} object
|
|
||||||
* <li> a byte[] containing ASN.1 NULL object
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param o object to be converted.
|
|
||||||
* @return an instance of ASN1Null, or null.
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
*/
|
|
||||||
public static ASN1Null getInstance(Object o)
|
|
||||||
{
|
|
||||||
if (o instanceof ASN1Null)
|
|
||||||
{
|
|
||||||
return (ASN1Null)o;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (o != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ASN1Null.getInstance(ASN1Primitive.fromByteArray((byte[])o));
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("failed to construct NULL from byte[]: " + e.getMessage());
|
|
||||||
}
|
|
||||||
catch (ClassCastException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("unknown object in getInstance(): " + o.getClass().getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1Null))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void encode(ASN1OutputStream out)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return "NULL";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for defining an ASN.1 object.
|
|
||||||
*/
|
|
||||||
public abstract class ASN1Object
|
|
||||||
implements ASN1Encodable
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Return the default BER or DER encoding for this object.
|
|
||||||
*
|
|
||||||
* @return BER/DER byte encoded object.
|
|
||||||
* @throws java.io.IOException on encoding error.
|
|
||||||
*/
|
|
||||||
public byte[] getEncoded()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
||||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
|
|
||||||
|
|
||||||
aOut.writeObject(this);
|
|
||||||
|
|
||||||
return bOut.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return either the default for "BER" or a DER encoding if "DER" is specified.
|
|
||||||
*
|
|
||||||
* @param encoding name of encoding to use.
|
|
||||||
* @return byte encoded object.
|
|
||||||
* @throws IOException on encoding error.
|
|
||||||
*/
|
|
||||||
public byte[] getEncoded(
|
|
||||||
String encoding)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (encoding.equals(ASN1Encoding.DER))
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
||||||
DEROutputStream dOut = new DEROutputStream(bOut);
|
|
||||||
|
|
||||||
dOut.writeObject(this);
|
|
||||||
|
|
||||||
return bOut.toByteArray();
|
|
||||||
}
|
|
||||||
else if (encoding.equals(ASN1Encoding.DL))
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
||||||
DLOutputStream dOut = new DLOutputStream(bOut);
|
|
||||||
|
|
||||||
dOut.writeObject(this);
|
|
||||||
|
|
||||||
return bOut.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.getEncoded();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return this.toASN1Primitive().hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(
|
|
||||||
Object o)
|
|
||||||
{
|
|
||||||
if (this == o)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(o instanceof ASN1Encodable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Encodable other = (ASN1Encodable)o;
|
|
||||||
|
|
||||||
return this.toASN1Primitive().equals(other.toASN1Primitive());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use toASN1Primitive()
|
|
||||||
* @return the underlying primitive type.
|
|
||||||
*/
|
|
||||||
public ASN1Primitive toASN1Object()
|
|
||||||
{
|
|
||||||
return this.toASN1Primitive();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if obj is a byte array and represents an object with the given tag value.
|
|
||||||
*
|
|
||||||
* @param obj object of interest.
|
|
||||||
* @param tagValue tag value to check for.
|
|
||||||
* @return true if obj is a byte encoding starting with the given tag value, false otherwise.
|
|
||||||
*/
|
|
||||||
protected static boolean hasEncodedTagValue(Object obj, int tagValue)
|
|
||||||
{
|
|
||||||
return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method providing a primitive representation of this object suitable for encoding.
|
|
||||||
* @return a primitive representation of this object.
|
|
||||||
*/
|
|
||||||
public abstract ASN1Primitive toASN1Primitive();
|
|
||||||
}
|
|
@ -1,472 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class representing the ASN.1 OBJECT IDENTIFIER type.
|
|
||||||
*/
|
|
||||||
public class ASN1ObjectIdentifier
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
String identifier;
|
|
||||||
|
|
||||||
private byte[] body;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an OID from the passed in object
|
|
||||||
* @param obj an ASN1ObjectIdentifier or an object that can be converted into one.
|
|
||||||
* @throws IllegalArgumentException if the object cannot be converted.
|
|
||||||
* @return an ASN1ObjectIdentifier instance, or null.
|
|
||||||
*/
|
|
||||||
public static ASN1ObjectIdentifier getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1ObjectIdentifier)
|
|
||||||
{
|
|
||||||
return (ASN1ObjectIdentifier)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier)
|
|
||||||
{
|
|
||||||
return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
byte[] enc = (byte[])obj;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (ASN1ObjectIdentifier)fromByteArray(enc);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("failed to construct object identifier from byte[]: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an Object Identifier from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @throws IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
* @return an ASN1ObjectIdentifier instance, or null.
|
|
||||||
*/
|
|
||||||
public static ASN1ObjectIdentifier getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Primitive o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof ASN1ObjectIdentifier)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;
|
|
||||||
|
|
||||||
ASN1ObjectIdentifier(
|
|
||||||
byte[] bytes)
|
|
||||||
{
|
|
||||||
StringBuffer objId = new StringBuffer();
|
|
||||||
long value = 0;
|
|
||||||
BigInteger bigValue = null;
|
|
||||||
boolean first = true;
|
|
||||||
|
|
||||||
for (int i = 0; i != bytes.length; i++)
|
|
||||||
{
|
|
||||||
int b = bytes[i] & 0xff;
|
|
||||||
|
|
||||||
if (value <= LONG_LIMIT)
|
|
||||||
{
|
|
||||||
value += (b & 0x7f);
|
|
||||||
if ((b & 0x80) == 0) // end of number reached
|
|
||||||
{
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
if (value < 40)
|
|
||||||
{
|
|
||||||
objId.append('0');
|
|
||||||
}
|
|
||||||
else if (value < 80)
|
|
||||||
{
|
|
||||||
objId.append('1');
|
|
||||||
value -= 40;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
objId.append('2');
|
|
||||||
value -= 80;
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
objId.append('.');
|
|
||||||
objId.append(value);
|
|
||||||
value = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
value <<= 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (bigValue == null)
|
|
||||||
{
|
|
||||||
bigValue = BigInteger.valueOf(value);
|
|
||||||
}
|
|
||||||
bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
|
|
||||||
if ((b & 0x80) == 0)
|
|
||||||
{
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
objId.append('2');
|
|
||||||
bigValue = bigValue.subtract(BigInteger.valueOf(80));
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
objId.append('.');
|
|
||||||
objId.append(bigValue);
|
|
||||||
bigValue = null;
|
|
||||||
value = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bigValue = bigValue.shiftLeft(7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.identifier = objId.toString();
|
|
||||||
this.body = Arrays.clone(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an OID based on the passed in String.
|
|
||||||
*
|
|
||||||
* @param identifier a string representation of an OID.
|
|
||||||
*/
|
|
||||||
public ASN1ObjectIdentifier(
|
|
||||||
String identifier)
|
|
||||||
{
|
|
||||||
if (identifier == null)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("'identifier' cannot be null");
|
|
||||||
}
|
|
||||||
if (!isValidIdentifier(identifier))
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("string " + identifier + " not an OID");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.identifier = identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an OID that creates a branch under the current one.
|
|
||||||
*
|
|
||||||
* @param branchID node numbers for the new branch.
|
|
||||||
* @return the OID for the new created branch.
|
|
||||||
*/
|
|
||||||
ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branchID)
|
|
||||||
{
|
|
||||||
if (!isValidBranchID(branchID, 0))
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.identifier = oid.getId() + "." + branchID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the OID as a string.
|
|
||||||
*
|
|
||||||
* @return the string representation of the OID carried by this object.
|
|
||||||
*/
|
|
||||||
public String getId()
|
|
||||||
{
|
|
||||||
return identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an OID that creates a branch under the current one.
|
|
||||||
*
|
|
||||||
* @param branchID node numbers for the new branch.
|
|
||||||
* @return the OID for the new created branch.
|
|
||||||
*/
|
|
||||||
public ASN1ObjectIdentifier branch(String branchID)
|
|
||||||
{
|
|
||||||
return new ASN1ObjectIdentifier(this, branchID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if this oid is an extension of the passed in branch, stem.
|
|
||||||
*
|
|
||||||
* @param stem the arc or branch that is a possible parent.
|
|
||||||
* @return true if the branch is on the passed in stem, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean on(ASN1ObjectIdentifier stem)
|
|
||||||
{
|
|
||||||
String id = getId(), stemId = stem.getId();
|
|
||||||
return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeField(
|
|
||||||
ByteArrayOutputStream out,
|
|
||||||
long fieldValue)
|
|
||||||
{
|
|
||||||
byte[] result = new byte[9];
|
|
||||||
int pos = 8;
|
|
||||||
result[pos] = (byte)((int)fieldValue & 0x7f);
|
|
||||||
while (fieldValue >= (1L << 7))
|
|
||||||
{
|
|
||||||
fieldValue >>= 7;
|
|
||||||
result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
|
|
||||||
}
|
|
||||||
out.write(result, pos, 9 - pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeField(
|
|
||||||
ByteArrayOutputStream out,
|
|
||||||
BigInteger fieldValue)
|
|
||||||
{
|
|
||||||
int byteCount = (fieldValue.bitLength() + 6) / 7;
|
|
||||||
if (byteCount == 0)
|
|
||||||
{
|
|
||||||
out.write(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BigInteger tmpValue = fieldValue;
|
|
||||||
byte[] tmp = new byte[byteCount];
|
|
||||||
for (int i = byteCount - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80);
|
|
||||||
tmpValue = tmpValue.shiftRight(7);
|
|
||||||
}
|
|
||||||
tmp[byteCount - 1] &= 0x7f;
|
|
||||||
out.write(tmp, 0, tmp.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doOutput(ByteArrayOutputStream aOut)
|
|
||||||
{
|
|
||||||
OIDTokenizer tok = new OIDTokenizer(identifier);
|
|
||||||
int first = Integer.parseInt(tok.nextToken()) * 40;
|
|
||||||
|
|
||||||
String secondToken = tok.nextToken();
|
|
||||||
if (secondToken.length() <= 18)
|
|
||||||
{
|
|
||||||
writeField(aOut, first + Long.parseLong(secondToken));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));
|
|
||||||
}
|
|
||||||
|
|
||||||
while (tok.hasMoreTokens())
|
|
||||||
{
|
|
||||||
String token = tok.nextToken();
|
|
||||||
if (token.length() <= 18)
|
|
||||||
{
|
|
||||||
writeField(aOut, Long.parseLong(token));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writeField(aOut, new BigInteger(token));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected synchronized byte[] getBody()
|
|
||||||
{
|
|
||||||
if (body == null)
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
doOutput(bOut);
|
|
||||||
|
|
||||||
body = bOut.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int length = getBody().length;
|
|
||||||
|
|
||||||
return 1 + StreamUtil.calculateBodyLength(length) + length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
byte[] enc = getBody();
|
|
||||||
|
|
||||||
out.write(BERTags.OBJECT_IDENTIFIER);
|
|
||||||
out.writeLength(enc.length);
|
|
||||||
out.write(enc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return identifier.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1ObjectIdentifier))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return identifier.equals(((ASN1ObjectIdentifier)o).identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isValidBranchID(
|
|
||||||
String branchID, int start)
|
|
||||||
{
|
|
||||||
boolean periodAllowed = false;
|
|
||||||
|
|
||||||
int pos = branchID.length();
|
|
||||||
while (--pos >= start)
|
|
||||||
{
|
|
||||||
char ch = branchID.charAt(pos);
|
|
||||||
|
|
||||||
// TODO Leading zeroes?
|
|
||||||
if ('0' <= ch && ch <= '9')
|
|
||||||
{
|
|
||||||
periodAllowed = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == '.')
|
|
||||||
{
|
|
||||||
if (!periodAllowed)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
periodAllowed = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return periodAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isValidIdentifier(
|
|
||||||
String identifier)
|
|
||||||
{
|
|
||||||
if (identifier.length() < 3 || identifier.charAt(1) != '.')
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char first = identifier.charAt(0);
|
|
||||||
if (first < '0' || first > '2')
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isValidBranchID(identifier, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][];
|
|
||||||
|
|
||||||
static ASN1ObjectIdentifier fromOctetString(byte[] enc)
|
|
||||||
{
|
|
||||||
if (enc.length < 3)
|
|
||||||
{
|
|
||||||
return new ASN1ObjectIdentifier(enc);
|
|
||||||
}
|
|
||||||
|
|
||||||
int idx1 = enc[enc.length - 2] & 0xff;
|
|
||||||
// in this case top bit is always zero
|
|
||||||
int idx2 = enc[enc.length - 1] & 0x7f;
|
|
||||||
|
|
||||||
ASN1ObjectIdentifier possibleMatch;
|
|
||||||
|
|
||||||
synchronized (cache)
|
|
||||||
{
|
|
||||||
ASN1ObjectIdentifier[] first = cache[idx1];
|
|
||||||
if (first == null)
|
|
||||||
{
|
|
||||||
first = cache[idx1] = new ASN1ObjectIdentifier[128];
|
|
||||||
}
|
|
||||||
|
|
||||||
possibleMatch = first[idx2];
|
|
||||||
if (possibleMatch == null)
|
|
||||||
{
|
|
||||||
return first[idx2] = new ASN1ObjectIdentifier(enc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Arrays.areEqual(enc, possibleMatch.getBody()))
|
|
||||||
{
|
|
||||||
return possibleMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
idx1 = (idx1 + 1) & 0xff;
|
|
||||||
first = cache[idx1];
|
|
||||||
if (first == null)
|
|
||||||
{
|
|
||||||
first = cache[idx1] = new ASN1ObjectIdentifier[128];
|
|
||||||
}
|
|
||||||
|
|
||||||
possibleMatch = first[idx2];
|
|
||||||
if (possibleMatch == null)
|
|
||||||
{
|
|
||||||
return first[idx2] = new ASN1ObjectIdentifier(enc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Arrays.areEqual(enc, possibleMatch.getBody()))
|
|
||||||
{
|
|
||||||
return possibleMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
idx2 = (idx2 + 1) & 0x7f;
|
|
||||||
possibleMatch = first[idx2];
|
|
||||||
if (possibleMatch == null)
|
|
||||||
{
|
|
||||||
return first[idx2] = new ASN1ObjectIdentifier(enc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Arrays.areEqual(enc, possibleMatch.getBody()))
|
|
||||||
{
|
|
||||||
return possibleMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ASN1ObjectIdentifier(enc);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,251 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
import org.spongycastle.util.encoders.Hex;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract base for the ASN.1 OCTET STRING data type
|
|
||||||
* <p>
|
|
||||||
* This supports BER, and DER forms of the data.
|
|
||||||
* </p><p>
|
|
||||||
* DER form is always primitive single OCTET STRING, while
|
|
||||||
* BER support includes the constructed forms.
|
|
||||||
* </p>
|
|
||||||
* <hr>
|
|
||||||
* <p><b>X.690</b></p>
|
|
||||||
* <p><b>8: Basic encoding rules</b></p>
|
|
||||||
* <p><b>8.7 Encoding of an octetstring value</b></p>
|
|
||||||
* <p>
|
|
||||||
* <b>8.7.1</b> The encoding of an octetstring value shall be
|
|
||||||
* either primitive or constructed at the option of the sender.
|
|
||||||
* <blockquote>
|
|
||||||
* NOTE — Where it is necessary to transfer part of an octet string
|
|
||||||
* before the entire OCTET STRING is available, the constructed encoding
|
|
||||||
* is used.
|
|
||||||
* </blockquote>
|
|
||||||
* <p>
|
|
||||||
* <b>8.7.2</b> The primitive encoding contains zero,
|
|
||||||
* one or more contents octets equal in value to the octets
|
|
||||||
* in the data value, in the order they appear in the data value,
|
|
||||||
* and with the most significant bit of an octet of the data value
|
|
||||||
* aligned with the most significant bit of an octet of the contents octets.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <b>8.7.3</b> The contents octets for the constructed encoding shall consist
|
|
||||||
* of zero, one, or more encodings.
|
|
||||||
* <blockquote>
|
|
||||||
* NOTE — Each such encoding includes identifier, length, and contents octets,
|
|
||||||
* and may include end-of-contents octets if it is constructed.
|
|
||||||
* </blockquote>
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <b>8.7.3.1</b> To encode an octetstring value in this way,
|
|
||||||
* it is segmented. Each segment shall consist of a series of
|
|
||||||
* consecutive octets of the value. There shall be no significance
|
|
||||||
* placed on the segment boundaries.
|
|
||||||
* <blockquote>
|
|
||||||
* NOTE — A segment may be of size zero, i.e. contain no octets.
|
|
||||||
* </blockquote>
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <b>8.7.3.2</b> Each encoding in the contents octets shall represent
|
|
||||||
* a segment of the overall octetstring, the encoding arising from
|
|
||||||
* a recursive application of this subclause.
|
|
||||||
* In this recursive application, each segment is treated as if it were
|
|
||||||
* a octetstring value. The encodings of the segments shall appear in the contents
|
|
||||||
* octets in the order in which their octets appear in the overall value.
|
|
||||||
* <blockquote>
|
|
||||||
* NOTE 1 — As a consequence of this recursion,
|
|
||||||
* each encoding in the contents octets may itself
|
|
||||||
* be primitive or constructed.
|
|
||||||
* However, such encodings will usually be primitive.
|
|
||||||
* </p><p>
|
|
||||||
* NOTE 2 — In particular, the tags in the contents octets are always universal class, number 4.
|
|
||||||
* </blockquote>
|
|
||||||
* </p>
|
|
||||||
* <p><b>9: Canonical encoding rules</b></p>
|
|
||||||
* <p><b>9.1 Length forms</b></p>
|
|
||||||
* <p>
|
|
||||||
* If the encoding is constructed, it shall employ the indefinite length form.
|
|
||||||
* If the encoding is primitive, it shall include the fewest length octets necessary.
|
|
||||||
* [Contrast with 8.1.3.2 b).]
|
|
||||||
* </p>
|
|
||||||
* <p><b>9.2 String encoding forms</b></p>
|
|
||||||
* <p>
|
|
||||||
* BIT STRING, OCTET STRING,and restricted character string
|
|
||||||
* values shall be encoded with a primitive encoding if they would
|
|
||||||
* require no more than 1000 contents octets, and as a constructed
|
|
||||||
* encoding otherwise. The string fragments contained in
|
|
||||||
* the constructed encoding shall be encoded with a primitive encoding.
|
|
||||||
* The encoding of each fragment, except possibly
|
|
||||||
* the last, shall have 1000 contents octets. (Contrast with 8.21.6.)
|
|
||||||
* </p>
|
|
||||||
* <b>10: Distinguished encoding rules</b>
|
|
||||||
* </p><p>
|
|
||||||
* <b>10.1 Length forms</b>
|
|
||||||
* The definite form of length encoding shall be used,
|
|
||||||
* encoded in the minimum number of octets.
|
|
||||||
* [Contrast with 8.1.3.2 b).]
|
|
||||||
* </p><p>
|
|
||||||
* <b>10.2 String encoding forms</b>
|
|
||||||
* For BIT STRING, OCTET STRING and restricted character string types,
|
|
||||||
* the constructed form of encoding shall not be used.
|
|
||||||
* (Contrast with 8.21.6.)
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public abstract class ASN1OctetString
|
|
||||||
extends ASN1Primitive
|
|
||||||
implements ASN1OctetStringParser
|
|
||||||
{
|
|
||||||
byte[] string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an Octet String from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want.
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
*/
|
|
||||||
public static ASN1OctetString getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Primitive o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof ASN1OctetString)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return BEROctetString.fromSequence(ASN1Sequence.getInstance(o));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an Octet String from the given object.
|
|
||||||
*
|
|
||||||
* @param obj the object we want converted.
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
*/
|
|
||||||
public static ASN1OctetString getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1OctetString)
|
|
||||||
{
|
|
||||||
return (ASN1OctetString)obj;
|
|
||||||
}
|
|
||||||
else if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ASN1OctetString.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("failed to construct OCTET STRING from byte[]: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1Encodable)
|
|
||||||
{
|
|
||||||
ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
|
|
||||||
|
|
||||||
if (primitive instanceof ASN1OctetString)
|
|
||||||
{
|
|
||||||
return (ASN1OctetString)primitive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string the octets making up the octet string.
|
|
||||||
*/
|
|
||||||
public ASN1OctetString(
|
|
||||||
byte[] string)
|
|
||||||
{
|
|
||||||
if (string == null)
|
|
||||||
{
|
|
||||||
throw new NullPointerException("string cannot be null");
|
|
||||||
}
|
|
||||||
this.string = string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the content of the OCTET STRING as an InputStream.
|
|
||||||
*
|
|
||||||
* @return an InputStream representing the OCTET STRING's content.
|
|
||||||
*/
|
|
||||||
public InputStream getOctetStream()
|
|
||||||
{
|
|
||||||
return new ByteArrayInputStream(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the parser associated with this object.
|
|
||||||
*
|
|
||||||
* @return a parser based on this OCTET STRING
|
|
||||||
*/
|
|
||||||
public ASN1OctetStringParser parser()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the content of the OCTET STRING as a byte array.
|
|
||||||
*
|
|
||||||
* @return the byte[] representing the OCTET STRING's content.
|
|
||||||
*/
|
|
||||||
public byte[] getOctets()
|
|
||||||
{
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Arrays.hashCode(this.getOctets());
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1OctetString))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1OctetString other = (ASN1OctetString)o;
|
|
||||||
|
|
||||||
return Arrays.areEqual(string, other.string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive getLoadedObject()
|
|
||||||
{
|
|
||||||
return this.toASN1Primitive();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Primitive toDERObject()
|
|
||||||
{
|
|
||||||
return new DEROctetString(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Primitive toDLObject()
|
|
||||||
{
|
|
||||||
return new DEROctetString(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void encode(ASN1OutputStream out)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return "#"+new String(Hex.encode(string));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A basic parser for an OCTET STRING object
|
|
||||||
*/
|
|
||||||
public interface ASN1OctetStringParser
|
|
||||||
extends ASN1Encodable, InMemoryRepresentable
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Return the content of the OCTET STRING as an InputStream.
|
|
||||||
*
|
|
||||||
* @return an InputStream representing the OCTET STRING's content.
|
|
||||||
*/
|
|
||||||
public InputStream getOctetStream();
|
|
||||||
}
|
|
@ -1,194 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stream that produces output based on the default encoding for the passed in objects.
|
|
||||||
*/
|
|
||||||
public class ASN1OutputStream
|
|
||||||
{
|
|
||||||
private OutputStream os;
|
|
||||||
|
|
||||||
public ASN1OutputStream(
|
|
||||||
OutputStream os)
|
|
||||||
{
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeLength(
|
|
||||||
int length)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (length > 127)
|
|
||||||
{
|
|
||||||
int size = 1;
|
|
||||||
int val = length;
|
|
||||||
|
|
||||||
while ((val >>>= 8) != 0)
|
|
||||||
{
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
write((byte)(size | 0x80));
|
|
||||||
|
|
||||||
for (int i = (size - 1) * 8; i >= 0; i -= 8)
|
|
||||||
{
|
|
||||||
write((byte)(length >> i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
write((byte)length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(int b)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
os.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(byte[] bytes)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
os.write(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(byte[] bytes, int off, int len)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
os.write(bytes, off, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeEncoded(
|
|
||||||
int tag,
|
|
||||||
byte[] bytes)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
write(tag);
|
|
||||||
writeLength(bytes.length);
|
|
||||||
write(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeTag(int flags, int tagNo)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (tagNo < 31)
|
|
||||||
{
|
|
||||||
write(flags | tagNo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
write(flags | 0x1f);
|
|
||||||
if (tagNo < 128)
|
|
||||||
{
|
|
||||||
write(tagNo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte[] stack = new byte[5];
|
|
||||||
int pos = stack.length;
|
|
||||||
|
|
||||||
stack[--pos] = (byte)(tagNo & 0x7F);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
tagNo >>= 7;
|
|
||||||
stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
|
|
||||||
}
|
|
||||||
while (tagNo > 127);
|
|
||||||
|
|
||||||
write(stack, pos, stack.length - pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeEncoded(int flags, int tagNo, byte[] bytes)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
writeTag(flags, tagNo);
|
|
||||||
writeLength(bytes.length);
|
|
||||||
write(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeNull()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
os.write(BERTags.NULL);
|
|
||||||
os.write(0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeObject(
|
|
||||||
ASN1Encodable obj)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (obj != null)
|
|
||||||
{
|
|
||||||
obj.toASN1Primitive().encode(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IOException("null object detected");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeImplicitObject(ASN1Primitive obj)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (obj != null)
|
|
||||||
{
|
|
||||||
obj.encode(new ImplicitOutputStream(os));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IOException("null object detected");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
os.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
os.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1OutputStream getDERSubStream()
|
|
||||||
{
|
|
||||||
return new DEROutputStream(os);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1OutputStream getDLSubStream()
|
|
||||||
{
|
|
||||||
return new DLOutputStream(os);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ImplicitOutputStream
|
|
||||||
extends ASN1OutputStream
|
|
||||||
{
|
|
||||||
private boolean first = true;
|
|
||||||
|
|
||||||
public ImplicitOutputStream(OutputStream os)
|
|
||||||
{
|
|
||||||
super(os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(int b)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
super.write(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
public class ASN1ParsingException
|
|
||||||
extends IllegalStateException
|
|
||||||
{
|
|
||||||
private Throwable cause;
|
|
||||||
|
|
||||||
public ASN1ParsingException(String message)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1ParsingException(String message, Throwable cause)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
this.cause = cause;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Throwable getCause()
|
|
||||||
{
|
|
||||||
return cause;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for ASN.1 primitive objects. These are the actual objects used to generate byte encodings.
|
|
||||||
*/
|
|
||||||
public abstract class ASN1Primitive
|
|
||||||
extends ASN1Object
|
|
||||||
{
|
|
||||||
ASN1Primitive()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a base ASN.1 object from a byte stream.
|
|
||||||
*
|
|
||||||
* @param data the byte stream to parse.
|
|
||||||
* @return the base ASN.1 object represented by the byte stream.
|
|
||||||
* @exception IOException if there is a problem parsing the data.
|
|
||||||
*/
|
|
||||||
public static ASN1Primitive fromByteArray(byte[] data)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
ASN1InputStream aIn = new ASN1InputStream(data);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return aIn.readObject();
|
|
||||||
}
|
|
||||||
catch (ClassCastException e)
|
|
||||||
{
|
|
||||||
throw new IOException("cannot recognise object in stream");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean equals(Object o)
|
|
||||||
{
|
|
||||||
if (this == o)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (o instanceof ASN1Encodable) && asn1Equals(((ASN1Encodable)o).toASN1Primitive());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the current object as one which encodes using Distinguished Encoding Rules.
|
|
||||||
*
|
|
||||||
* @return a DER version of this.
|
|
||||||
*/
|
|
||||||
ASN1Primitive toDERObject()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the current object as one which encodes using Definite Length encoding.
|
|
||||||
*
|
|
||||||
* @return a DL version of this.
|
|
||||||
*/
|
|
||||||
ASN1Primitive toDLObject()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract int hashCode();
|
|
||||||
|
|
||||||
abstract boolean isConstructed();
|
|
||||||
|
|
||||||
abstract int encodedLength() throws IOException;
|
|
||||||
|
|
||||||
abstract void encode(ASN1OutputStream out) throws IOException;
|
|
||||||
|
|
||||||
abstract boolean asn1Equals(ASN1Primitive o);
|
|
||||||
}
|
|
@ -1,382 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ASN.1 <code>SEQUENCE</code> and <code>SEQUENCE OF</code> constructs.
|
|
||||||
* <p>
|
|
||||||
* DER form is always definite form length fields, while
|
|
||||||
* BER support uses indefinite form.
|
|
||||||
* <hr>
|
|
||||||
* <p><b>X.690</b></p>
|
|
||||||
* <p><b>8: Basic encoding rules</b></p>
|
|
||||||
* <p><b>8.9 Encoding of a sequence value </b></p>
|
|
||||||
* 8.9.1 The encoding of a sequence value shall be constructed.
|
|
||||||
* <p>
|
|
||||||
* <b>8.9.2</b> The contents octets shall consist of the complete
|
|
||||||
* encoding of one data value from each of the types listed in
|
|
||||||
* the ASN.1 definition of the sequence type, in the order of
|
|
||||||
* their appearance in the definition, unless the type was referenced
|
|
||||||
* with the keyword <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
|
|
||||||
* </p><p>
|
|
||||||
* <b>8.9.3</b> The encoding of a data value may, but need not,
|
|
||||||
* be present for a type which was referenced with the keyword
|
|
||||||
* <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
|
|
||||||
* If present, it shall appear in the encoding at the point
|
|
||||||
* corresponding to the appearance of the type in the ASN.1 definition.
|
|
||||||
* </p><p>
|
|
||||||
* <b>8.10 Encoding of a sequence-of value </b>
|
|
||||||
* </p><p>
|
|
||||||
* <b>8.10.1</b> The encoding of a sequence-of value shall be constructed.
|
|
||||||
* <p>
|
|
||||||
* <b>8.10.2</b> The contents octets shall consist of zero,
|
|
||||||
* one or more complete encodings of data values from the type listed in
|
|
||||||
* the ASN.1 definition.
|
|
||||||
* <p>
|
|
||||||
* <b>8.10.3</b> The order of the encodings of the data values shall be
|
|
||||||
* the same as the order of the data values in the sequence-of value to
|
|
||||||
* be encoded.
|
|
||||||
* </p>
|
|
||||||
* <p><b>9: Canonical encoding rules</b></p>
|
|
||||||
* <p><b>9.1 Length forms</b></p>
|
|
||||||
* If the encoding is constructed, it shall employ the indefinite length form.
|
|
||||||
* If the encoding is primitive, it shall include the fewest length octets necessary.
|
|
||||||
* [Contrast with 8.1.3.2 b).]
|
|
||||||
*
|
|
||||||
* <p><b>11: Restrictions on BER employed by both CER and DER</b></p>
|
|
||||||
* <p><b>11.5 Set and sequence components with default value</b></p>
|
|
||||||
* The encoding of a set value or sequence value shall not include
|
|
||||||
* an encoding for any component value which is equal to
|
|
||||||
* its default value.
|
|
||||||
*/
|
|
||||||
public abstract class ASN1Sequence
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
protected Vector seq = new Vector();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an ASN1Sequence from the given object.
|
|
||||||
*
|
|
||||||
* @param obj the object we want converted.
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
* @return an ASN1Sequence instance, or null.
|
|
||||||
*/
|
|
||||||
public static ASN1Sequence getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1Sequence)
|
|
||||||
{
|
|
||||||
return (ASN1Sequence)obj;
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1SequenceParser)
|
|
||||||
{
|
|
||||||
return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive());
|
|
||||||
}
|
|
||||||
else if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ASN1Sequence.getInstance(fromByteArray((byte[])obj));
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1Encodable)
|
|
||||||
{
|
|
||||||
ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
|
|
||||||
|
|
||||||
if (primitive instanceof ASN1Sequence)
|
|
||||||
{
|
|
||||||
return (ASN1Sequence)primitive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an ASN1 sequence from a tagged object. There is a special
|
|
||||||
* case here, if an object appears to have been explicitly tagged on
|
|
||||||
* reading but we were expecting it to be implicitly tagged in the
|
|
||||||
* normal course of events it indicates that we lost the surrounding
|
|
||||||
* sequence - so we need to add it back (this will happen if the tagged
|
|
||||||
* object is a sequence that contains other sequences). If you are
|
|
||||||
* dealing with implicitly tagged sequences you really <b>should</b>
|
|
||||||
* be using this method.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object.
|
|
||||||
* @param explicit true if the object is meant to be explicitly tagged,
|
|
||||||
* false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
* @return an ASN1Sequence instance.
|
|
||||||
*/
|
|
||||||
public static ASN1Sequence getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
if (explicit)
|
|
||||||
{
|
|
||||||
if (!obj.isExplicit())
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("object implicit - explicit expected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// constructed object which appears to be explicitly tagged
|
|
||||||
// when it should be implicit means we have to add the
|
|
||||||
// surrounding sequence.
|
|
||||||
//
|
|
||||||
if (obj.isExplicit())
|
|
||||||
{
|
|
||||||
if (obj instanceof BERTaggedObject)
|
|
||||||
{
|
|
||||||
return new BERSequence(obj.getObject());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new DLSequence(obj.getObject());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (obj.getObject() instanceof ASN1Sequence)
|
|
||||||
{
|
|
||||||
return (ASN1Sequence)obj.getObject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an empty sequence
|
|
||||||
*/
|
|
||||||
protected ASN1Sequence()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a sequence containing one object
|
|
||||||
* @param obj the object to be put in the SEQUENCE.
|
|
||||||
*/
|
|
||||||
protected ASN1Sequence(
|
|
||||||
ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
seq.addElement(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a sequence containing a vector of objects.
|
|
||||||
* @param v the vector of objects to be put in the SEQUENCE
|
|
||||||
*/
|
|
||||||
protected ASN1Sequence(
|
|
||||||
ASN1EncodableVector v)
|
|
||||||
{
|
|
||||||
for (int i = 0; i != v.size(); i++)
|
|
||||||
{
|
|
||||||
seq.addElement(v.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a sequence containing a vector of objects.
|
|
||||||
*/
|
|
||||||
protected ASN1Sequence(
|
|
||||||
ASN1Encodable[] array)
|
|
||||||
{
|
|
||||||
for (int i = 0; i != array.length; i++)
|
|
||||||
{
|
|
||||||
seq.addElement(array[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Encodable[] toArray()
|
|
||||||
{
|
|
||||||
ASN1Encodable[] values = new ASN1Encodable[this.size()];
|
|
||||||
|
|
||||||
for (int i = 0; i != this.size(); i++)
|
|
||||||
{
|
|
||||||
values[i] = this.getObjectAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Enumeration getObjects()
|
|
||||||
{
|
|
||||||
return seq.elements();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1SequenceParser parser()
|
|
||||||
{
|
|
||||||
final ASN1Sequence outer = this;
|
|
||||||
|
|
||||||
return new ASN1SequenceParser()
|
|
||||||
{
|
|
||||||
private final int max = size();
|
|
||||||
|
|
||||||
private int index;
|
|
||||||
|
|
||||||
public ASN1Encodable readObject() throws IOException
|
|
||||||
{
|
|
||||||
if (index == max)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Encodable obj = getObjectAt(index++);
|
|
||||||
if (obj instanceof ASN1Sequence)
|
|
||||||
{
|
|
||||||
return ((ASN1Sequence)obj).parser();
|
|
||||||
}
|
|
||||||
if (obj instanceof ASN1Set)
|
|
||||||
{
|
|
||||||
return ((ASN1Set)obj).parser();
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive getLoadedObject()
|
|
||||||
{
|
|
||||||
return outer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
return outer;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the object at the sequence position indicated by index.
|
|
||||||
*
|
|
||||||
* @param index the sequence number (starting at zero) of the object
|
|
||||||
* @return the object at the sequence position indicated by index.
|
|
||||||
*/
|
|
||||||
public ASN1Encodable getObjectAt(
|
|
||||||
int index)
|
|
||||||
{
|
|
||||||
return (ASN1Encodable)seq.elementAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the number of objects in this sequence.
|
|
||||||
*
|
|
||||||
* @return the number of objects in this sequence.
|
|
||||||
*/
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return seq.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
Enumeration e = this.getObjects();
|
|
||||||
int hashCode = size();
|
|
||||||
|
|
||||||
while (e.hasMoreElements())
|
|
||||||
{
|
|
||||||
Object o = getNext(e);
|
|
||||||
hashCode *= 17;
|
|
||||||
|
|
||||||
hashCode ^= o.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
return hashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1Sequence))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Sequence other = (ASN1Sequence)o;
|
|
||||||
|
|
||||||
if (this.size() != other.size())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Enumeration s1 = this.getObjects();
|
|
||||||
Enumeration s2 = other.getObjects();
|
|
||||||
|
|
||||||
while (s1.hasMoreElements())
|
|
||||||
{
|
|
||||||
ASN1Encodable obj1 = getNext(s1);
|
|
||||||
ASN1Encodable obj2 = getNext(s2);
|
|
||||||
|
|
||||||
ASN1Primitive o1 = obj1.toASN1Primitive();
|
|
||||||
ASN1Primitive o2 = obj2.toASN1Primitive();
|
|
||||||
|
|
||||||
if (o1 == o2 || o1.equals(o2))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ASN1Encodable getNext(Enumeration e)
|
|
||||||
{
|
|
||||||
ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
|
|
||||||
|
|
||||||
return encObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change current SEQUENCE object to be encoded as {@link DERSequence}.
|
|
||||||
* This is part of Distinguished Encoding Rules form serialization.
|
|
||||||
*/
|
|
||||||
ASN1Primitive toDERObject()
|
|
||||||
{
|
|
||||||
ASN1Sequence derSeq = new DERSequence();
|
|
||||||
|
|
||||||
derSeq.seq = this.seq;
|
|
||||||
|
|
||||||
return derSeq;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change current SEQUENCE object to be encoded as {@link DLSequence}.
|
|
||||||
* This is part of Direct Length form serialization.
|
|
||||||
*/
|
|
||||||
ASN1Primitive toDLObject()
|
|
||||||
{
|
|
||||||
ASN1Sequence dlSeq = new DLSequence();
|
|
||||||
|
|
||||||
dlSeq.seq = this.seq;
|
|
||||||
|
|
||||||
return dlSeq;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void encode(ASN1OutputStream out)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return seq.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A basic parser for a SEQUENCE object
|
|
||||||
*/
|
|
||||||
public interface ASN1SequenceParser
|
|
||||||
extends ASN1Encodable, InMemoryRepresentable
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Read the next object from the underlying object representing a SEQUENCE.
|
|
||||||
*
|
|
||||||
* @throws IOException for bad input stream.
|
|
||||||
* @return the next object, null if we are at the end.
|
|
||||||
*/
|
|
||||||
ASN1Encodable readObject()
|
|
||||||
throws IOException;
|
|
||||||
}
|
|
@ -1,560 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ASN.1 <code>SET</code> and <code>SET OF</code> constructs.
|
|
||||||
* <p>
|
|
||||||
* Note: This does not know which syntax the set is!
|
|
||||||
* (The difference: ordering of SET elements or not ordering.)
|
|
||||||
* <p>
|
|
||||||
* DER form is always definite form length fields, while
|
|
||||||
* BER support uses indefinite form.
|
|
||||||
* <p>
|
|
||||||
* The CER form support does not exist.
|
|
||||||
* <p>
|
|
||||||
* <hr>
|
|
||||||
* <h2>X.690</h2>
|
|
||||||
* <h3>8: Basic encoding rules</h3>
|
|
||||||
* <h4>8.11 Encoding of a set value </h4>
|
|
||||||
* <b>8.11.1</b> The encoding of a set value shall be constructed
|
|
||||||
* <p>
|
|
||||||
* <b>8.11.2</b> The contents octets shall consist of the complete
|
|
||||||
* encoding of a data value from each of the types listed in the
|
|
||||||
* ASN.1 definition of the set type, in an order chosen by the sender,
|
|
||||||
* unless the type was referenced with the keyword
|
|
||||||
* <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
|
|
||||||
* <p>
|
|
||||||
* <b>8.11.3</b> The encoding of a data value may, but need not,
|
|
||||||
* be present for a type which was referenced with the keyword
|
|
||||||
* <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
|
|
||||||
* <blockquote>
|
|
||||||
* NOTE — The order of data values in a set value is not significant,
|
|
||||||
* and places no constraints on the order during transfer
|
|
||||||
* </blockquote>
|
|
||||||
* <h4>8.12 Encoding of a set-of value</h4>
|
|
||||||
* <b>8.12.1</b> The encoding of a set-of value shall be constructed.
|
|
||||||
* <p>
|
|
||||||
* <b>8.12.2</b> The text of 8.10.2 applies:
|
|
||||||
* <i>The contents octets shall consist of zero,
|
|
||||||
* one or more complete encodings of data values from the type listed in
|
|
||||||
* the ASN.1 definition.</i>
|
|
||||||
* <p>
|
|
||||||
* <b>8.12.3</b> The order of data values need not be preserved by
|
|
||||||
* the encoding and subsequent decoding.
|
|
||||||
*
|
|
||||||
* <h3>9: Canonical encoding rules</h3>
|
|
||||||
* <h4>9.1 Length forms</h4>
|
|
||||||
* If the encoding is constructed, it shall employ the indefinite length form.
|
|
||||||
* If the encoding is primitive, it shall include the fewest length octets necessary.
|
|
||||||
* [Contrast with 8.1.3.2 b).]
|
|
||||||
* <h4>9.3 Set components</h4>
|
|
||||||
* The encodings of the component values of a set value shall
|
|
||||||
* appear in an order determined by their tags as specified
|
|
||||||
* in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
|
|
||||||
* Additionally, for the purposes of determining the order in which
|
|
||||||
* components are encoded when one or more component is an untagged
|
|
||||||
* choice type, each untagged choice type is ordered as though it
|
|
||||||
* has a tag equal to that of the smallest tag in that choice type
|
|
||||||
* or any untagged choice types nested within.
|
|
||||||
*
|
|
||||||
* <h3>10: Distinguished encoding rules</h3>
|
|
||||||
* <h4>10.1 Length forms</h4>
|
|
||||||
* The definite form of length encoding shall be used,
|
|
||||||
* encoded in the minimum number of octets.
|
|
||||||
* [Contrast with 8.1.3.2 b).]
|
|
||||||
* <h4>10.3 Set components</h4>
|
|
||||||
* The encodings of the component values of a set value shall appear
|
|
||||||
* in an order determined by their tags as specified
|
|
||||||
* in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
|
|
||||||
* <blockquote>
|
|
||||||
* NOTE — Where a component of the set is an untagged choice type,
|
|
||||||
* the location of that component in the ordering will depend on
|
|
||||||
* the tag of the choice component being encoded.
|
|
||||||
* </blockquote>
|
|
||||||
*
|
|
||||||
* <h3>11: Restrictions on BER employed by both CER and DER</h3>
|
|
||||||
* <h4>11.5 Set and sequence components with default value </h4>
|
|
||||||
* The encoding of a set value or sequence value shall not include
|
|
||||||
* an encoding for any component value which is equal to
|
|
||||||
* its default value.
|
|
||||||
* <h4>11.6 Set-of components </h4>
|
|
||||||
* <p>
|
|
||||||
* The encodings of the component values of a set-of value
|
|
||||||
* shall appear in ascending order, the encodings being compared
|
|
||||||
* as octet strings with the shorter components being padded at
|
|
||||||
* their trailing end with 0-octets.
|
|
||||||
* <blockquote>
|
|
||||||
* NOTE — The padding octets are for comparison purposes only
|
|
||||||
* and do not appear in the encodings.
|
|
||||||
* </blockquote>
|
|
||||||
*/
|
|
||||||
public abstract class ASN1Set
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
private Vector set = new Vector();
|
|
||||||
private boolean isSorted = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an ASN1Set from the given object.
|
|
||||||
*
|
|
||||||
* @param obj the object we want converted.
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
* @return an ASN1Set instance, or null.
|
|
||||||
*/
|
|
||||||
public static ASN1Set getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1Set)
|
|
||||||
{
|
|
||||||
return (ASN1Set)obj;
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1SetParser)
|
|
||||||
{
|
|
||||||
return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive());
|
|
||||||
}
|
|
||||||
else if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1Encodable)
|
|
||||||
{
|
|
||||||
ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
|
|
||||||
|
|
||||||
if (primitive instanceof ASN1Set)
|
|
||||||
{
|
|
||||||
return (ASN1Set)primitive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an ASN1 set from a tagged object. There is a special
|
|
||||||
* case here, if an object appears to have been explicitly tagged on
|
|
||||||
* reading but we were expecting it to be implicitly tagged in the
|
|
||||||
* normal course of events it indicates that we lost the surrounding
|
|
||||||
* set - so we need to add it back (this will happen if the tagged
|
|
||||||
* object is a sequence that contains other sequences). If you are
|
|
||||||
* dealing with implicitly tagged sets you really <b>should</b>
|
|
||||||
* be using this method.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object.
|
|
||||||
* @param explicit true if the object is meant to be explicitly tagged
|
|
||||||
* false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
* @return an ASN1Set instance.
|
|
||||||
*/
|
|
||||||
public static ASN1Set getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
if (explicit)
|
|
||||||
{
|
|
||||||
if (!obj.isExplicit())
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("object implicit - explicit expected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ASN1Set)obj.getObject();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// constructed object which appears to be explicitly tagged
|
|
||||||
// and it's really implicit means we have to add the
|
|
||||||
// surrounding set.
|
|
||||||
//
|
|
||||||
if (obj.isExplicit())
|
|
||||||
{
|
|
||||||
if (obj instanceof BERTaggedObject)
|
|
||||||
{
|
|
||||||
return new BERSet(obj.getObject());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new DLSet(obj.getObject());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (obj.getObject() instanceof ASN1Set)
|
|
||||||
{
|
|
||||||
return (ASN1Set)obj.getObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// in this case the parser returns a sequence, convert it
|
|
||||||
// into a set.
|
|
||||||
//
|
|
||||||
if (obj.getObject() instanceof ASN1Sequence)
|
|
||||||
{
|
|
||||||
ASN1Sequence s = (ASN1Sequence)obj.getObject();
|
|
||||||
|
|
||||||
if (obj instanceof BERTaggedObject)
|
|
||||||
{
|
|
||||||
return new BERSet(s.toArray());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new DLSet(s.toArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ASN1Set()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a sequence containing one object
|
|
||||||
* @param obj object to be added to the SET.
|
|
||||||
*/
|
|
||||||
protected ASN1Set(
|
|
||||||
ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
set.addElement(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a sequence containing a vector of objects.
|
|
||||||
* @param v a vector of objects to make up the SET.
|
|
||||||
* @param doSort true if should be sorted DER style, false otherwise.
|
|
||||||
*/
|
|
||||||
protected ASN1Set(
|
|
||||||
ASN1EncodableVector v,
|
|
||||||
boolean doSort)
|
|
||||||
{
|
|
||||||
for (int i = 0; i != v.size(); i++)
|
|
||||||
{
|
|
||||||
set.addElement(v.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doSort)
|
|
||||||
{
|
|
||||||
this.sort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a sequence containing a vector of objects.
|
|
||||||
*/
|
|
||||||
protected ASN1Set(
|
|
||||||
ASN1Encodable[] array,
|
|
||||||
boolean doSort)
|
|
||||||
{
|
|
||||||
for (int i = 0; i != array.length; i++)
|
|
||||||
{
|
|
||||||
set.addElement(array[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doSort)
|
|
||||||
{
|
|
||||||
this.sort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Enumeration getObjects()
|
|
||||||
{
|
|
||||||
return set.elements();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the object at the set position indicated by index.
|
|
||||||
*
|
|
||||||
* @param index the set number (starting at zero) of the object
|
|
||||||
* @return the object at the set position indicated by index.
|
|
||||||
*/
|
|
||||||
public ASN1Encodable getObjectAt(
|
|
||||||
int index)
|
|
||||||
{
|
|
||||||
return (ASN1Encodable)set.elementAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the number of objects in this set.
|
|
||||||
*
|
|
||||||
* @return the number of objects in this set.
|
|
||||||
*/
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return set.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Encodable[] toArray()
|
|
||||||
{
|
|
||||||
ASN1Encodable[] values = new ASN1Encodable[this.size()];
|
|
||||||
|
|
||||||
for (int i = 0; i != this.size(); i++)
|
|
||||||
{
|
|
||||||
values[i] = this.getObjectAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1SetParser parser()
|
|
||||||
{
|
|
||||||
final ASN1Set outer = this;
|
|
||||||
|
|
||||||
return new ASN1SetParser()
|
|
||||||
{
|
|
||||||
private final int max = size();
|
|
||||||
|
|
||||||
private int index;
|
|
||||||
|
|
||||||
public ASN1Encodable readObject() throws IOException
|
|
||||||
{
|
|
||||||
if (index == max)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Encodable obj = getObjectAt(index++);
|
|
||||||
if (obj instanceof ASN1Sequence)
|
|
||||||
{
|
|
||||||
return ((ASN1Sequence)obj).parser();
|
|
||||||
}
|
|
||||||
if (obj instanceof ASN1Set)
|
|
||||||
{
|
|
||||||
return ((ASN1Set)obj).parser();
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive getLoadedObject()
|
|
||||||
{
|
|
||||||
return outer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
return outer;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
Enumeration e = this.getObjects();
|
|
||||||
int hashCode = size();
|
|
||||||
|
|
||||||
while (e.hasMoreElements())
|
|
||||||
{
|
|
||||||
Object o = getNext(e);
|
|
||||||
hashCode *= 17;
|
|
||||||
|
|
||||||
hashCode ^= o.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
return hashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change current SET object to be encoded as {@link DERSet}.
|
|
||||||
* This is part of Distinguished Encoding Rules form serialization.
|
|
||||||
*/
|
|
||||||
ASN1Primitive toDERObject()
|
|
||||||
{
|
|
||||||
if (isSorted)
|
|
||||||
{
|
|
||||||
ASN1Set derSet = new DERSet();
|
|
||||||
|
|
||||||
derSet.set = this.set;
|
|
||||||
|
|
||||||
return derSet;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Vector v = new Vector();
|
|
||||||
|
|
||||||
for (int i = 0; i != set.size(); i++)
|
|
||||||
{
|
|
||||||
v.addElement(set.elementAt(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Set derSet = new DERSet();
|
|
||||||
|
|
||||||
derSet.set = v;
|
|
||||||
|
|
||||||
derSet.sort();
|
|
||||||
|
|
||||||
return derSet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change current SET object to be encoded as {@link DLSet}.
|
|
||||||
* This is part of Direct Length form serialization.
|
|
||||||
*/
|
|
||||||
ASN1Primitive toDLObject()
|
|
||||||
{
|
|
||||||
ASN1Set derSet = new DLSet();
|
|
||||||
|
|
||||||
derSet.set = this.set;
|
|
||||||
|
|
||||||
return derSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1Set))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Set other = (ASN1Set)o;
|
|
||||||
|
|
||||||
if (this.size() != other.size())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Enumeration s1 = this.getObjects();
|
|
||||||
Enumeration s2 = other.getObjects();
|
|
||||||
|
|
||||||
while (s1.hasMoreElements())
|
|
||||||
{
|
|
||||||
ASN1Encodable obj1 = getNext(s1);
|
|
||||||
ASN1Encodable obj2 = getNext(s2);
|
|
||||||
|
|
||||||
ASN1Primitive o1 = obj1.toASN1Primitive();
|
|
||||||
ASN1Primitive o2 = obj2.toASN1Primitive();
|
|
||||||
|
|
||||||
if (o1 == o2 || o1.equals(o2))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ASN1Encodable getNext(Enumeration e)
|
|
||||||
{
|
|
||||||
ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
|
|
||||||
|
|
||||||
// unfortunately null was allowed as a substitute for DER null
|
|
||||||
if (encObj == null)
|
|
||||||
{
|
|
||||||
return DERNull.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return encObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return true if a <= b (arrays are assumed padded with zeros).
|
|
||||||
*/
|
|
||||||
private boolean lessThanOrEqual(
|
|
||||||
byte[] a,
|
|
||||||
byte[] b)
|
|
||||||
{
|
|
||||||
int len = Math.min(a.length, b.length);
|
|
||||||
for (int i = 0; i != len; ++i)
|
|
||||||
{
|
|
||||||
if (a[i] != b[i])
|
|
||||||
{
|
|
||||||
return (a[i] & 0xff) < (b[i] & 0xff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len == a.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] getEncoded(
|
|
||||||
ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
||||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
aOut.writeObject(obj);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("cannot encode object added to SET");
|
|
||||||
}
|
|
||||||
|
|
||||||
return bOut.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void sort()
|
|
||||||
{
|
|
||||||
if (!isSorted)
|
|
||||||
{
|
|
||||||
isSorted = true;
|
|
||||||
if (set.size() > 1)
|
|
||||||
{
|
|
||||||
boolean swapped = true;
|
|
||||||
int lastSwap = set.size() - 1;
|
|
||||||
|
|
||||||
while (swapped)
|
|
||||||
{
|
|
||||||
int index = 0;
|
|
||||||
int swapIndex = 0;
|
|
||||||
byte[] a = getEncoded((ASN1Encodable)set.elementAt(0));
|
|
||||||
|
|
||||||
swapped = false;
|
|
||||||
|
|
||||||
while (index != lastSwap)
|
|
||||||
{
|
|
||||||
byte[] b = getEncoded((ASN1Encodable)set.elementAt(index + 1));
|
|
||||||
|
|
||||||
if (lessThanOrEqual(a, b))
|
|
||||||
{
|
|
||||||
a = b;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Object o = set.elementAt(index);
|
|
||||||
|
|
||||||
set.setElementAt(set.elementAt(index + 1), index);
|
|
||||||
set.setElementAt(o, index + 1);
|
|
||||||
|
|
||||||
swapped = true;
|
|
||||||
swapIndex = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastSwap = swapIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void encode(ASN1OutputStream out)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return set.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A basic parser for a SET object
|
|
||||||
*/
|
|
||||||
public interface ASN1SetParser
|
|
||||||
extends ASN1Encodable, InMemoryRepresentable
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Read the next object from the underlying object representing a SET.
|
|
||||||
*
|
|
||||||
* @throws IOException for bad input stream.
|
|
||||||
* @return the next object, null if we are at the end.
|
|
||||||
*/
|
|
||||||
public ASN1Encodable readObject()
|
|
||||||
throws IOException;
|
|
||||||
}
|
|
@ -1,250 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A parser for ASN.1 streams which also returns, where possible, parsers for the objects it encounters.
|
|
||||||
*/
|
|
||||||
public class ASN1StreamParser
|
|
||||||
{
|
|
||||||
private final InputStream _in;
|
|
||||||
private final int _limit;
|
|
||||||
private final byte[][] tmpBuffers;
|
|
||||||
|
|
||||||
public ASN1StreamParser(
|
|
||||||
InputStream in)
|
|
||||||
{
|
|
||||||
this(in, StreamUtil.findLimit(in));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1StreamParser(
|
|
||||||
InputStream in,
|
|
||||||
int limit)
|
|
||||||
{
|
|
||||||
this._in = in;
|
|
||||||
this._limit = limit;
|
|
||||||
|
|
||||||
this.tmpBuffers = new byte[11][];
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1StreamParser(
|
|
||||||
byte[] encoding)
|
|
||||||
{
|
|
||||||
this(new ByteArrayInputStream(encoding), encoding.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Encodable readIndef(int tagValue) throws IOException
|
|
||||||
{
|
|
||||||
// Note: INDEF => CONSTRUCTED
|
|
||||||
|
|
||||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
|
||||||
switch (tagValue)
|
|
||||||
{
|
|
||||||
case BERTags.EXTERNAL:
|
|
||||||
return new DERExternalParser(this);
|
|
||||||
case BERTags.OCTET_STRING:
|
|
||||||
return new BEROctetStringParser(this);
|
|
||||||
case BERTags.SEQUENCE:
|
|
||||||
return new BERSequenceParser(this);
|
|
||||||
case BERTags.SET:
|
|
||||||
return new BERSetParser(this);
|
|
||||||
default:
|
|
||||||
throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException
|
|
||||||
{
|
|
||||||
if (_in instanceof IndefiniteLengthInputStream)
|
|
||||||
{
|
|
||||||
if (!constructed)
|
|
||||||
{
|
|
||||||
throw new IOException("indefinite length primitive encoding encountered");
|
|
||||||
}
|
|
||||||
|
|
||||||
return readIndef(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (constructed)
|
|
||||||
{
|
|
||||||
switch (tag)
|
|
||||||
{
|
|
||||||
case BERTags.SET:
|
|
||||||
return new DERSetParser(this);
|
|
||||||
case BERTags.SEQUENCE:
|
|
||||||
return new DERSequenceParser(this);
|
|
||||||
case BERTags.OCTET_STRING:
|
|
||||||
return new BEROctetStringParser(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (tag)
|
|
||||||
{
|
|
||||||
case BERTags.SET:
|
|
||||||
throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
|
|
||||||
case BERTags.SEQUENCE:
|
|
||||||
throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
|
|
||||||
case BERTags.OCTET_STRING:
|
|
||||||
return new DEROctetStringParser((DefiniteLengthInputStream)_in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO ASN1Exception
|
|
||||||
throw new RuntimeException("implicit tagging not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException
|
|
||||||
{
|
|
||||||
if (!constructed)
|
|
||||||
{
|
|
||||||
// Note: !CONSTRUCTED => IMPLICIT
|
|
||||||
DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
|
|
||||||
return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray()));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1EncodableVector v = readVector();
|
|
||||||
|
|
||||||
if (_in instanceof IndefiniteLengthInputStream)
|
|
||||||
{
|
|
||||||
return v.size() == 1
|
|
||||||
? new BERTaggedObject(true, tag, v.get(0))
|
|
||||||
: new BERTaggedObject(false, tag, BERFactory.createSequence(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
return v.size() == 1
|
|
||||||
? new DERTaggedObject(true, tag, v.get(0))
|
|
||||||
: new DERTaggedObject(false, tag, DERFactory.createSequence(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Encodable readObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int tag = _in.read();
|
|
||||||
if (tag == -1)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// turn of looking for "00" while we resolve the tag
|
|
||||||
//
|
|
||||||
set00Check(false);
|
|
||||||
|
|
||||||
//
|
|
||||||
// calculate tag number
|
|
||||||
//
|
|
||||||
int tagNo = ASN1InputStream.readTagNumber(_in, tag);
|
|
||||||
|
|
||||||
boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0;
|
|
||||||
|
|
||||||
//
|
|
||||||
// calculate length
|
|
||||||
//
|
|
||||||
int length = ASN1InputStream.readLength(_in, _limit);
|
|
||||||
|
|
||||||
if (length < 0) // indefinite length method
|
|
||||||
{
|
|
||||||
if (!isConstructed)
|
|
||||||
{
|
|
||||||
throw new IOException("indefinite length primitive encoding encountered");
|
|
||||||
}
|
|
||||||
|
|
||||||
IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
|
|
||||||
ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
|
|
||||||
|
|
||||||
if ((tag & BERTags.APPLICATION) != 0)
|
|
||||||
{
|
|
||||||
return new BERApplicationSpecificParser(tagNo, sp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tag & BERTags.TAGGED) != 0)
|
|
||||||
{
|
|
||||||
return new BERTaggedObjectParser(true, tagNo, sp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sp.readIndef(tagNo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
|
|
||||||
|
|
||||||
if ((tag & BERTags.APPLICATION) != 0)
|
|
||||||
{
|
|
||||||
return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tag & BERTags.TAGGED) != 0)
|
|
||||||
{
|
|
||||||
return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isConstructed)
|
|
||||||
{
|
|
||||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
|
||||||
switch (tagNo)
|
|
||||||
{
|
|
||||||
case BERTags.OCTET_STRING:
|
|
||||||
//
|
|
||||||
// yes, people actually do this...
|
|
||||||
//
|
|
||||||
return new BEROctetStringParser(new ASN1StreamParser(defIn));
|
|
||||||
case BERTags.SEQUENCE:
|
|
||||||
return new DERSequenceParser(new ASN1StreamParser(defIn));
|
|
||||||
case BERTags.SET:
|
|
||||||
return new DERSetParser(new ASN1StreamParser(defIn));
|
|
||||||
case BERTags.EXTERNAL:
|
|
||||||
return new DERExternalParser(new ASN1StreamParser(defIn));
|
|
||||||
default:
|
|
||||||
throw new IOException("unknown tag " + tagNo + " encountered");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some primitive encodings can be handled by parsers too...
|
|
||||||
switch (tagNo)
|
|
||||||
{
|
|
||||||
case BERTags.OCTET_STRING:
|
|
||||||
return new DEROctetStringParser(defIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e)
|
|
||||||
{
|
|
||||||
throw new ASN1Exception("corrupted stream detected", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void set00Check(boolean enabled)
|
|
||||||
{
|
|
||||||
if (_in instanceof IndefiniteLengthInputStream)
|
|
||||||
{
|
|
||||||
((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1EncodableVector readVector() throws IOException
|
|
||||||
{
|
|
||||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
|
||||||
|
|
||||||
ASN1Encodable obj;
|
|
||||||
while ((obj = readObject()) != null)
|
|
||||||
{
|
|
||||||
if (obj instanceof InMemoryRepresentable)
|
|
||||||
{
|
|
||||||
v.add(((InMemoryRepresentable)obj).getLoadedObject());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v.add(obj.toASN1Primitive());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
public interface ASN1String
|
|
||||||
{
|
|
||||||
public String getString();
|
|
||||||
}
|
|
@ -1,236 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by
|
|
||||||
* a [n] where n is some number - these are assumed to follow the construction
|
|
||||||
* rules (as with sequences).
|
|
||||||
*/
|
|
||||||
public abstract class ASN1TaggedObject
|
|
||||||
extends ASN1Primitive
|
|
||||||
implements ASN1TaggedObjectParser
|
|
||||||
{
|
|
||||||
int tagNo;
|
|
||||||
boolean empty = false;
|
|
||||||
boolean explicit = true;
|
|
||||||
ASN1Encodable obj = null;
|
|
||||||
|
|
||||||
static public ASN1TaggedObject getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
if (explicit)
|
|
||||||
{
|
|
||||||
return (ASN1TaggedObject)obj.getObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("implicitly tagged tagged object");
|
|
||||||
}
|
|
||||||
|
|
||||||
static public ASN1TaggedObject getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1TaggedObject)
|
|
||||||
{
|
|
||||||
return (ASN1TaggedObject)obj;
|
|
||||||
}
|
|
||||||
else if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ASN1TaggedObject.getInstance(fromByteArray((byte[])obj));
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("failed to construct tagged object from byte[]: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a tagged object with the style given by the value of explicit.
|
|
||||||
* <p>
|
|
||||||
* If the object implements ASN1Choice the tag style will always be changed
|
|
||||||
* to explicit in accordance with the ASN.1 encoding rules.
|
|
||||||
* </p>
|
|
||||||
* @param explicit true if the object is explicitly tagged.
|
|
||||||
* @param tagNo the tag number for this object.
|
|
||||||
* @param obj the tagged object.
|
|
||||||
*/
|
|
||||||
public ASN1TaggedObject(
|
|
||||||
boolean explicit,
|
|
||||||
int tagNo,
|
|
||||||
ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
if (obj instanceof ASN1Choice)
|
|
||||||
{
|
|
||||||
this.explicit = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.explicit = explicit;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tagNo = tagNo;
|
|
||||||
|
|
||||||
if (this.explicit)
|
|
||||||
{
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASN1Primitive prim = obj.toASN1Primitive();
|
|
||||||
|
|
||||||
if (prim instanceof ASN1Set)
|
|
||||||
{
|
|
||||||
ASN1Set s = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1TaggedObject))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1TaggedObject other = (ASN1TaggedObject)o;
|
|
||||||
|
|
||||||
if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(obj == null)
|
|
||||||
{
|
|
||||||
if (other.obj != null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive())))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
int code = tagNo;
|
|
||||||
|
|
||||||
// TODO: actually this is wrong - the problem is that a re-encoded
|
|
||||||
// object may end up with a different hashCode due to implicit
|
|
||||||
// tagging. As implicit tagging is ambiguous if a sequence is involved
|
|
||||||
// it seems the only correct method for both equals and hashCode is to
|
|
||||||
// compare the encodings...
|
|
||||||
if (obj != null)
|
|
||||||
{
|
|
||||||
code ^= obj.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTagNo()
|
|
||||||
{
|
|
||||||
return tagNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return whether or not the object may be explicitly tagged.
|
|
||||||
* <p>
|
|
||||||
* Note: if the object has been read from an input stream, the only
|
|
||||||
* time you can be sure if isExplicit is returning the true state of
|
|
||||||
* affairs is if it returns false. An implicitly tagged object may appear
|
|
||||||
* to be explicitly tagged, so you need to understand the context under
|
|
||||||
* which the reading was done as well, see getObject below.
|
|
||||||
*/
|
|
||||||
public boolean isExplicit()
|
|
||||||
{
|
|
||||||
return explicit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty()
|
|
||||||
{
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return whatever was following the tag.
|
|
||||||
* <p>
|
|
||||||
* Note: tagged objects are generally context dependent if you're
|
|
||||||
* trying to extract a tagged object you should be going via the
|
|
||||||
* appropriate getInstance method.
|
|
||||||
*/
|
|
||||||
public ASN1Primitive getObject()
|
|
||||||
{
|
|
||||||
if (obj != null)
|
|
||||||
{
|
|
||||||
return obj.toASN1Primitive();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the object held in this tagged object as a parser assuming it has
|
|
||||||
* the type of the passed in tag. If the object doesn't have a parser
|
|
||||||
* associated with it, the base object is returned.
|
|
||||||
*/
|
|
||||||
public ASN1Encodable getObjectParser(
|
|
||||||
int tag,
|
|
||||||
boolean isExplicit)
|
|
||||||
{
|
|
||||||
switch (tag)
|
|
||||||
{
|
|
||||||
case BERTags.SET:
|
|
||||||
return ASN1Set.getInstance(this, isExplicit).parser();
|
|
||||||
case BERTags.SEQUENCE:
|
|
||||||
return ASN1Sequence.getInstance(this, isExplicit).parser();
|
|
||||||
case BERTags.OCTET_STRING:
|
|
||||||
return ASN1OctetString.getInstance(this, isExplicit).parser();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isExplicit)
|
|
||||||
{
|
|
||||||
return getObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new RuntimeException("implicit tagging not implemented for tag: " + tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive getLoadedObject()
|
|
||||||
{
|
|
||||||
return this.toASN1Primitive();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Primitive toDERObject()
|
|
||||||
{
|
|
||||||
return new DERTaggedObject(explicit, tagNo, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1Primitive toDLObject()
|
|
||||||
{
|
|
||||||
return new DLTaggedObject(explicit, tagNo, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void encode(ASN1OutputStream out)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return "[" + tagNo + "]" + obj;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public interface ASN1TaggedObjectParser
|
|
||||||
extends ASN1Encodable, InMemoryRepresentable
|
|
||||||
{
|
|
||||||
public int getTagNo();
|
|
||||||
|
|
||||||
public ASN1Encodable getObjectParser(int tag, boolean isExplicit)
|
|
||||||
throws IOException;
|
|
||||||
}
|
|
@ -1,314 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.SimpleTimeZone;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
import org.spongycastle.util.Strings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
- * UTC time object.
|
|
||||||
* Internal facade of {@link ASN1UTCTime}.
|
|
||||||
* <p>
|
|
||||||
* This datatype is valid only from 1950-01-01 00:00:00 UTC until 2049-12-31 23:59:59 UTC.
|
|
||||||
* <p>
|
|
||||||
* <hr>
|
|
||||||
* <p><b>X.690</b></p>
|
|
||||||
* <p><b>11: Restrictions on BER employed by both CER and DER</b></p>
|
|
||||||
* <p><b>11.8 UTCTime </b></p>
|
|
||||||
* <b>11.8.1</b> The encoding shall terminate with "Z",
|
|
||||||
* as described in the ITU-T X.680 | ISO/IEC 8824-1 clause on UTCTime.
|
|
||||||
* <p>
|
|
||||||
* <b>11.8.2</b> The seconds element shall always be present.
|
|
||||||
* <p>
|
|
||||||
* <b>11.8.3</b> Midnight (GMT) shall be represented in the form:
|
|
||||||
* <blockquote>
|
|
||||||
* "YYMMDD000000Z"
|
|
||||||
* </blockquote>
|
|
||||||
* where "YYMMDD" represents the day following the midnight in question.
|
|
||||||
*/
|
|
||||||
public class ASN1UTCTime
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
private byte[] time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an UTC Time from the passed in object.
|
|
||||||
*
|
|
||||||
* @param obj an ASN1UTCTime or an object that can be converted into one.
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
* @return an ASN1UTCTime instance, or null.
|
|
||||||
*/
|
|
||||||
public static ASN1UTCTime getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return (ASN1UTCTime)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (ASN1UTCTime)fromByteArray((byte[])obj);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return an UTC Time from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
* @return an ASN1UTCTime instance, or null.
|
|
||||||
*/
|
|
||||||
public static ASN1UTCTime getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Object o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof ASN1UTCTime)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new ASN1UTCTime(((ASN1OctetString)o).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
|
|
||||||
* never encoded. When you're creating one of these objects from scratch, that's
|
|
||||||
* what you want to use, otherwise we'll try to deal with whatever gets read from
|
|
||||||
* the input stream... (this is why the input format is different from the getTime()
|
|
||||||
* method output).
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @param time the time string.
|
|
||||||
*/
|
|
||||||
public ASN1UTCTime(
|
|
||||||
String time)
|
|
||||||
{
|
|
||||||
this.time = Strings.toByteArray(time);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this.getDate();
|
|
||||||
}
|
|
||||||
catch (ParseException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("invalid date string: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* base constructor from a java.util.date object
|
|
||||||
* @param time the Date to build the time from.
|
|
||||||
*/
|
|
||||||
public ASN1UTCTime(
|
|
||||||
Date time)
|
|
||||||
{
|
|
||||||
SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'");
|
|
||||||
|
|
||||||
dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
|
|
||||||
|
|
||||||
this.time = Strings.toByteArray(dateF.format(time));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1UTCTime(
|
|
||||||
byte[] time)
|
|
||||||
{
|
|
||||||
this.time = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the time as a date based on whatever a 2 digit year will return. For
|
|
||||||
* standardised processing use getAdjustedDate().
|
|
||||||
*
|
|
||||||
* @return the resulting date
|
|
||||||
* @exception ParseException if the date string cannot be parsed.
|
|
||||||
*/
|
|
||||||
public Date getDate()
|
|
||||||
throws ParseException
|
|
||||||
{
|
|
||||||
SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz");
|
|
||||||
|
|
||||||
return dateF.parse(getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the time as an adjusted date
|
|
||||||
* in the range of 1950 - 2049.
|
|
||||||
*
|
|
||||||
* @return a date in the range of 1950 to 2049.
|
|
||||||
* @exception ParseException if the date string cannot be parsed.
|
|
||||||
*/
|
|
||||||
public Date getAdjustedDate()
|
|
||||||
throws ParseException
|
|
||||||
{
|
|
||||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
|
||||||
|
|
||||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
|
||||||
|
|
||||||
return dateF.parse(getAdjustedTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the time - always in the form of
|
|
||||||
* YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
|
|
||||||
* <p>
|
|
||||||
* Normally in a certificate we would expect "Z" rather than "GMT",
|
|
||||||
* however adding the "GMT" means we can just use:
|
|
||||||
* <pre>
|
|
||||||
* dateF = new SimpleDateFormat("yyMMddHHmmssz");
|
|
||||||
* </pre>
|
|
||||||
* To read in the time and get a date which is compatible with our local
|
|
||||||
* time zone.
|
|
||||||
* <p>
|
|
||||||
* <b>Note:</b> In some cases, due to the local date processing, this
|
|
||||||
* may lead to unexpected results. If you want to stick the normal
|
|
||||||
* convention of 1950 to 2049 use the getAdjustedTime() method.
|
|
||||||
*/
|
|
||||||
public String getTime()
|
|
||||||
{
|
|
||||||
String stime = Strings.fromByteArray(time);
|
|
||||||
|
|
||||||
//
|
|
||||||
// standardise the format.
|
|
||||||
//
|
|
||||||
if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0)
|
|
||||||
{
|
|
||||||
if (stime.length() == 11)
|
|
||||||
{
|
|
||||||
return stime.substring(0, 10) + "00GMT+00:00";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return stime.substring(0, 12) + "GMT+00:00";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int index = stime.indexOf('-');
|
|
||||||
if (index < 0)
|
|
||||||
{
|
|
||||||
index = stime.indexOf('+');
|
|
||||||
}
|
|
||||||
String d = stime;
|
|
||||||
|
|
||||||
if (index == stime.length() - 3)
|
|
||||||
{
|
|
||||||
d += "00";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == 10)
|
|
||||||
{
|
|
||||||
return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a time string as an adjusted date with a 4 digit year. This goes
|
|
||||||
* in the range of 1950 - 2049.
|
|
||||||
*/
|
|
||||||
public String getAdjustedTime()
|
|
||||||
{
|
|
||||||
String d = this.getTime();
|
|
||||||
|
|
||||||
if (d.charAt(0) < '5')
|
|
||||||
{
|
|
||||||
return "20" + d;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return "19" + d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
{
|
|
||||||
int length = time.length;
|
|
||||||
|
|
||||||
return 1 + StreamUtil.calculateBodyLength(length) + length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.write(BERTags.UTC_TIME);
|
|
||||||
|
|
||||||
int length = time.length;
|
|
||||||
|
|
||||||
out.writeLength(length);
|
|
||||||
|
|
||||||
for (int i = 0; i != length; i++)
|
|
||||||
{
|
|
||||||
out.write((byte)time[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof ASN1UTCTime))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Arrays.areEqual(time, ((ASN1UTCTime)o).time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Arrays.hashCode(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return Strings.fromByteArray(time);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
public class BERApplicationSpecific
|
|
||||||
extends DERApplicationSpecific
|
|
||||||
{
|
|
||||||
public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
|
|
||||||
{
|
|
||||||
super(tagNo, vec);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class BERApplicationSpecificParser
|
|
||||||
implements ASN1ApplicationSpecificParser
|
|
||||||
{
|
|
||||||
private final int tag;
|
|
||||||
private final ASN1StreamParser parser;
|
|
||||||
|
|
||||||
BERApplicationSpecificParser(int tag, ASN1StreamParser parser)
|
|
||||||
{
|
|
||||||
this.tag = tag;
|
|
||||||
this.parser = parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Encodable readObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return parser.readObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive getLoadedObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return new BERApplicationSpecific(tag, parser.readVector());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return getLoadedObject();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ASN1ParsingException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use BEROctetString
|
|
||||||
*/
|
|
||||||
public class BERConstructedOctetString
|
|
||||||
extends BEROctetString
|
|
||||||
{
|
|
||||||
private static final int MAX_LENGTH = 1000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convert a vector of octet strings into a single byte string
|
|
||||||
*/
|
|
||||||
static private byte[] toBytes(
|
|
||||||
Vector octs)
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
for (int i = 0; i != octs.size(); i++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DEROctetString o = (DEROctetString)octs.elementAt(i);
|
|
||||||
|
|
||||||
bOut.write(o.getOctets());
|
|
||||||
}
|
|
||||||
catch (ClassCastException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + " found in input should only contain DEROctetString");
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("exception converting octets " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bOut.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vector octs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string the octets making up the octet string.
|
|
||||||
*/
|
|
||||||
public BERConstructedOctetString(
|
|
||||||
byte[] string)
|
|
||||||
{
|
|
||||||
super(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BERConstructedOctetString(
|
|
||||||
Vector octs)
|
|
||||||
{
|
|
||||||
super(toBytes(octs));
|
|
||||||
|
|
||||||
this.octs = octs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BERConstructedOctetString(
|
|
||||||
ASN1Primitive obj)
|
|
||||||
{
|
|
||||||
super(toByteArray(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] toByteArray(ASN1Primitive obj)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return obj.getEncoded();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Unable to encode object");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BERConstructedOctetString(
|
|
||||||
ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
this(obj.toASN1Primitive());
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getOctets()
|
|
||||||
{
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the DER octets that make up this string.
|
|
||||||
*/
|
|
||||||
public Enumeration getObjects()
|
|
||||||
{
|
|
||||||
if (octs == null)
|
|
||||||
{
|
|
||||||
return generateOcts().elements();
|
|
||||||
}
|
|
||||||
|
|
||||||
return octs.elements();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vector generateOcts()
|
|
||||||
{
|
|
||||||
Vector vec = new Vector();
|
|
||||||
for (int i = 0; i < string.length; i += MAX_LENGTH)
|
|
||||||
{
|
|
||||||
int end;
|
|
||||||
|
|
||||||
if (i + MAX_LENGTH > string.length)
|
|
||||||
{
|
|
||||||
end = string.length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
end = i + MAX_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] nStr = new byte[end - i];
|
|
||||||
|
|
||||||
System.arraycopy(string, i, nStr, 0, nStr.length);
|
|
||||||
|
|
||||||
vec.addElement(new DEROctetString(nStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BEROctetString fromSequence(ASN1Sequence seq)
|
|
||||||
{
|
|
||||||
Vector v = new Vector();
|
|
||||||
Enumeration e = seq.getObjects();
|
|
||||||
|
|
||||||
while (e.hasMoreElements())
|
|
||||||
{
|
|
||||||
v.addElement(e.nextElement());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BERConstructedOctetString(v);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
class BERFactory
|
|
||||||
{
|
|
||||||
static final BERSequence EMPTY_SEQUENCE = new BERSequence();
|
|
||||||
static final BERSet EMPTY_SET = new BERSet();
|
|
||||||
|
|
||||||
static BERSequence createSequence(ASN1EncodableVector v)
|
|
||||||
{
|
|
||||||
return v.size() < 1 ? EMPTY_SEQUENCE : new BERSequence(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BERSet createSet(ASN1EncodableVector v)
|
|
||||||
{
|
|
||||||
return v.size() < 1 ? EMPTY_SET : new BERSet(v);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public class BERGenerator
|
|
||||||
extends ASN1Generator
|
|
||||||
{
|
|
||||||
private boolean _tagged = false;
|
|
||||||
private boolean _isExplicit;
|
|
||||||
private int _tagNo;
|
|
||||||
|
|
||||||
protected BERGenerator(
|
|
||||||
OutputStream out)
|
|
||||||
{
|
|
||||||
super(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BERGenerator(
|
|
||||||
OutputStream out,
|
|
||||||
int tagNo,
|
|
||||||
boolean isExplicit)
|
|
||||||
{
|
|
||||||
super(out);
|
|
||||||
|
|
||||||
_tagged = true;
|
|
||||||
_isExplicit = isExplicit;
|
|
||||||
_tagNo = tagNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OutputStream getRawOutputStream()
|
|
||||||
{
|
|
||||||
return _out;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeHdr(
|
|
||||||
int tag)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_out.write(tag);
|
|
||||||
_out.write(0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeBERHeader(
|
|
||||||
int tag)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (_tagged)
|
|
||||||
{
|
|
||||||
int tagNum = _tagNo | BERTags.TAGGED;
|
|
||||||
|
|
||||||
if (_isExplicit)
|
|
||||||
{
|
|
||||||
writeHdr(tagNum | BERTags.CONSTRUCTED);
|
|
||||||
writeHdr(tag);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((tag & BERTags.CONSTRUCTED) != 0)
|
|
||||||
{
|
|
||||||
writeHdr(tagNum | BERTags.CONSTRUCTED);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writeHdr(tagNum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writeHdr(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeBERBody(
|
|
||||||
InputStream contentStream)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int ch;
|
|
||||||
|
|
||||||
while ((ch = contentStream.read()) >= 0)
|
|
||||||
{
|
|
||||||
_out.write(ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeBEREnd()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_out.write(0x00);
|
|
||||||
_out.write(0x00);
|
|
||||||
|
|
||||||
if (_tagged && _isExplicit) // write extra end for tag header
|
|
||||||
{
|
|
||||||
_out.write(0x00);
|
|
||||||
_out.write(0x00);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
public class BEROctetString
|
|
||||||
extends ASN1OctetString
|
|
||||||
{
|
|
||||||
private static final int MAX_LENGTH = 1000;
|
|
||||||
|
|
||||||
private ASN1OctetString[] octs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convert a vector of octet strings into a single byte string
|
|
||||||
*/
|
|
||||||
static private byte[] toBytes(
|
|
||||||
ASN1OctetString[] octs)
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
for (int i = 0; i != octs.length; i++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DEROctetString o = (DEROctetString)octs[i];
|
|
||||||
|
|
||||||
bOut.write(o.getOctets());
|
|
||||||
}
|
|
||||||
catch (ClassCastException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException(octs[i].getClass().getName() + " found in input should only contain DEROctetString");
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("exception converting octets " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bOut.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string the octets making up the octet string.
|
|
||||||
*/
|
|
||||||
public BEROctetString(
|
|
||||||
byte[] string)
|
|
||||||
{
|
|
||||||
super(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BEROctetString(
|
|
||||||
ASN1OctetString[] octs)
|
|
||||||
{
|
|
||||||
super(toBytes(octs));
|
|
||||||
|
|
||||||
this.octs = octs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getOctets()
|
|
||||||
{
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the DER octets that make up this string.
|
|
||||||
*/
|
|
||||||
public Enumeration getObjects()
|
|
||||||
{
|
|
||||||
if (octs == null)
|
|
||||||
{
|
|
||||||
return generateOcts().elements();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Enumeration()
|
|
||||||
{
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
public boolean hasMoreElements()
|
|
||||||
{
|
|
||||||
return counter < octs.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object nextElement()
|
|
||||||
{
|
|
||||||
return octs[counter++];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vector generateOcts()
|
|
||||||
{
|
|
||||||
Vector vec = new Vector();
|
|
||||||
for (int i = 0; i < string.length; i += MAX_LENGTH)
|
|
||||||
{
|
|
||||||
int end;
|
|
||||||
|
|
||||||
if (i + MAX_LENGTH > string.length)
|
|
||||||
{
|
|
||||||
end = string.length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
end = i + MAX_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] nStr = new byte[end - i];
|
|
||||||
|
|
||||||
System.arraycopy(string, i, nStr, 0, nStr.length);
|
|
||||||
|
|
||||||
vec.addElement(new DEROctetString(nStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int length = 0;
|
|
||||||
for (Enumeration e = getObjects(); e.hasMoreElements();)
|
|
||||||
{
|
|
||||||
length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 2 + length + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.write(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
|
|
||||||
|
|
||||||
out.write(0x80);
|
|
||||||
|
|
||||||
//
|
|
||||||
// write out the octet array
|
|
||||||
//
|
|
||||||
for (Enumeration e = getObjects(); e.hasMoreElements();)
|
|
||||||
{
|
|
||||||
out.writeObject((ASN1Encodable)e.nextElement());
|
|
||||||
}
|
|
||||||
|
|
||||||
out.write(0x00);
|
|
||||||
out.write(0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BEROctetString fromSequence(ASN1Sequence seq)
|
|
||||||
{
|
|
||||||
ASN1OctetString[] v = new ASN1OctetString[seq.size()];
|
|
||||||
Enumeration e = seq.getObjects();
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
while (e.hasMoreElements())
|
|
||||||
{
|
|
||||||
v[index++] = (ASN1OctetString)e.nextElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BEROctetString(v);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public class BEROctetStringGenerator
|
|
||||||
extends BERGenerator
|
|
||||||
{
|
|
||||||
public BEROctetStringGenerator(OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
super(out);
|
|
||||||
|
|
||||||
writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BEROctetStringGenerator(
|
|
||||||
OutputStream out,
|
|
||||||
int tagNo,
|
|
||||||
boolean isExplicit)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
super(out, tagNo, isExplicit);
|
|
||||||
|
|
||||||
writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
public OutputStream getOctetOutputStream()
|
|
||||||
{
|
|
||||||
return getOctetOutputStream(new byte[1000]); // limit for CER encoding.
|
|
||||||
}
|
|
||||||
|
|
||||||
public OutputStream getOctetOutputStream(
|
|
||||||
byte[] buf)
|
|
||||||
{
|
|
||||||
return new BufferedBEROctetStream(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BufferedBEROctetStream
|
|
||||||
extends OutputStream
|
|
||||||
{
|
|
||||||
private byte[] _buf;
|
|
||||||
private int _off;
|
|
||||||
private DEROutputStream _derOut;
|
|
||||||
|
|
||||||
BufferedBEROctetStream(
|
|
||||||
byte[] buf)
|
|
||||||
{
|
|
||||||
_buf = buf;
|
|
||||||
_off = 0;
|
|
||||||
_derOut = new DEROutputStream(_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(
|
|
||||||
int b)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_buf[_off++] = (byte)b;
|
|
||||||
|
|
||||||
if (_off == _buf.length)
|
|
||||||
{
|
|
||||||
DEROctetString.encode(_derOut, _buf);
|
|
||||||
_off = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b, int off, int len) throws IOException
|
|
||||||
{
|
|
||||||
while (len > 0)
|
|
||||||
{
|
|
||||||
int numToCopy = Math.min(len, _buf.length - _off);
|
|
||||||
System.arraycopy(b, off, _buf, _off, numToCopy);
|
|
||||||
|
|
||||||
_off += numToCopy;
|
|
||||||
if (_off < _buf.length)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEROctetString.encode(_derOut, _buf);
|
|
||||||
_off = 0;
|
|
||||||
|
|
||||||
off += numToCopy;
|
|
||||||
len -= numToCopy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (_off != 0)
|
|
||||||
{
|
|
||||||
byte[] bytes = new byte[_off];
|
|
||||||
System.arraycopy(_buf, 0, bytes, 0, _off);
|
|
||||||
|
|
||||||
DEROctetString.encode(_derOut, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
writeBEREnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.spongycastle.util.io.Streams;
|
|
||||||
|
|
||||||
public class BEROctetStringParser
|
|
||||||
implements ASN1OctetStringParser
|
|
||||||
{
|
|
||||||
private ASN1StreamParser _parser;
|
|
||||||
|
|
||||||
BEROctetStringParser(
|
|
||||||
ASN1StreamParser parser)
|
|
||||||
{
|
|
||||||
_parser = parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream getOctetStream()
|
|
||||||
{
|
|
||||||
return new ConstructedOctetStream(_parser);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive getLoadedObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return new BEROctetString(Streams.readAll(getOctetStream()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return getLoadedObject();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public class BEROutputStream
|
|
||||||
extends DEROutputStream
|
|
||||||
{
|
|
||||||
public BEROutputStream(
|
|
||||||
OutputStream os)
|
|
||||||
{
|
|
||||||
super(os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeObject(
|
|
||||||
Object obj)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
writeNull();
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1Primitive)
|
|
||||||
{
|
|
||||||
((ASN1Primitive)obj).encode(this);
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1Encodable)
|
|
||||||
{
|
|
||||||
((ASN1Encodable)obj).toASN1Primitive().encode(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IOException("object not BEREncodable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
|
|
||||||
public class BERSequence
|
|
||||||
extends ASN1Sequence
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* create an empty sequence
|
|
||||||
*/
|
|
||||||
public BERSequence()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a sequence containing one object
|
|
||||||
*/
|
|
||||||
public BERSequence(
|
|
||||||
ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
super(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a sequence containing a vector of objects.
|
|
||||||
*/
|
|
||||||
public BERSequence(
|
|
||||||
ASN1EncodableVector v)
|
|
||||||
{
|
|
||||||
super(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a sequence containing an array of objects.
|
|
||||||
*/
|
|
||||||
public BERSequence(
|
|
||||||
ASN1Encodable[] array)
|
|
||||||
{
|
|
||||||
super(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int length = 0;
|
|
||||||
for (Enumeration e = getObjects(); e.hasMoreElements();)
|
|
||||||
{
|
|
||||||
length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 2 + length + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*/
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
|
|
||||||
out.write(0x80);
|
|
||||||
|
|
||||||
Enumeration e = getObjects();
|
|
||||||
while (e.hasMoreElements())
|
|
||||||
{
|
|
||||||
out.writeObject((ASN1Encodable)e.nextElement());
|
|
||||||
}
|
|
||||||
|
|
||||||
out.write(0x00);
|
|
||||||
out.write(0x00);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public class BERSequenceGenerator
|
|
||||||
extends BERGenerator
|
|
||||||
{
|
|
||||||
public BERSequenceGenerator(
|
|
||||||
OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
super(out);
|
|
||||||
|
|
||||||
writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BERSequenceGenerator(
|
|
||||||
OutputStream out,
|
|
||||||
int tagNo,
|
|
||||||
boolean isExplicit)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
super(out, tagNo, isExplicit);
|
|
||||||
|
|
||||||
writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addObject(
|
|
||||||
ASN1Encodable object)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
object.toASN1Primitive().encode(new BEROutputStream(_out));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
writeBEREnd();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class BERSequenceParser
|
|
||||||
implements ASN1SequenceParser
|
|
||||||
{
|
|
||||||
private ASN1StreamParser _parser;
|
|
||||||
|
|
||||||
BERSequenceParser(ASN1StreamParser parser)
|
|
||||||
{
|
|
||||||
this._parser = parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Encodable readObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return _parser.readObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive getLoadedObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return new BERSequence(_parser.readVector());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return getLoadedObject();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalStateException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
|
|
||||||
public class BERSet
|
|
||||||
extends ASN1Set
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* create an empty sequence
|
|
||||||
*/
|
|
||||||
public BERSet()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param obj - a single object that makes up the set.
|
|
||||||
*/
|
|
||||||
public BERSet(
|
|
||||||
ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
super(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param v - a vector of objects making up the set.
|
|
||||||
*/
|
|
||||||
public BERSet(
|
|
||||||
ASN1EncodableVector v)
|
|
||||||
{
|
|
||||||
super(v, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a set from an array of objects.
|
|
||||||
*/
|
|
||||||
public BERSet(
|
|
||||||
ASN1Encodable[] a)
|
|
||||||
{
|
|
||||||
super(a, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int length = 0;
|
|
||||||
for (Enumeration e = getObjects(); e.hasMoreElements();)
|
|
||||||
{
|
|
||||||
length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 2 + length + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*/
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.write(BERTags.SET | BERTags.CONSTRUCTED);
|
|
||||||
out.write(0x80);
|
|
||||||
|
|
||||||
Enumeration e = getObjects();
|
|
||||||
while (e.hasMoreElements())
|
|
||||||
{
|
|
||||||
out.writeObject((ASN1Encodable)e.nextElement());
|
|
||||||
}
|
|
||||||
|
|
||||||
out.write(0x00);
|
|
||||||
out.write(0x00);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class BERSetParser
|
|
||||||
implements ASN1SetParser
|
|
||||||
{
|
|
||||||
private ASN1StreamParser _parser;
|
|
||||||
|
|
||||||
BERSetParser(ASN1StreamParser parser)
|
|
||||||
{
|
|
||||||
this._parser = parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Encodable readObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return _parser.readObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive getLoadedObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return new BERSet(_parser.readVector());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return getLoadedObject();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ASN1ParsingException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,147 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BER TaggedObject - in ASN.1 notation this is any object preceded by
|
|
||||||
* a [n] where n is some number - these are assumed to follow the construction
|
|
||||||
* rules (as with sequences).
|
|
||||||
*/
|
|
||||||
public class BERTaggedObject
|
|
||||||
extends ASN1TaggedObject
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param tagNo the tag number for this object.
|
|
||||||
* @param obj the tagged object.
|
|
||||||
*/
|
|
||||||
public BERTaggedObject(
|
|
||||||
int tagNo,
|
|
||||||
ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
super(true, tagNo, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param explicit true if an explicitly tagged object.
|
|
||||||
* @param tagNo the tag number for this object.
|
|
||||||
* @param obj the tagged object.
|
|
||||||
*/
|
|
||||||
public BERTaggedObject(
|
|
||||||
boolean explicit,
|
|
||||||
int tagNo,
|
|
||||||
ASN1Encodable obj)
|
|
||||||
{
|
|
||||||
super(explicit, tagNo, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an implicitly tagged object that contains a zero
|
|
||||||
* length sequence.
|
|
||||||
*/
|
|
||||||
public BERTaggedObject(
|
|
||||||
int tagNo)
|
|
||||||
{
|
|
||||||
super(false, tagNo, new BERSequence());
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
if (!empty)
|
|
||||||
{
|
|
||||||
if (explicit)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
|
|
||||||
|
|
||||||
return primitive.isConstructed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (!empty)
|
|
||||||
{
|
|
||||||
ASN1Primitive primitive = obj.toASN1Primitive();
|
|
||||||
int length = primitive.encodedLength();
|
|
||||||
|
|
||||||
if (explicit)
|
|
||||||
{
|
|
||||||
return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// header length already in calculation
|
|
||||||
length = length - 1;
|
|
||||||
|
|
||||||
return StreamUtil.calculateTagLength(tagNo) + length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return StreamUtil.calculateTagLength(tagNo) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
|
|
||||||
out.write(0x80);
|
|
||||||
|
|
||||||
if (!empty)
|
|
||||||
{
|
|
||||||
if (!explicit)
|
|
||||||
{
|
|
||||||
Enumeration e;
|
|
||||||
if (obj instanceof ASN1OctetString)
|
|
||||||
{
|
|
||||||
if (obj instanceof BEROctetString)
|
|
||||||
{
|
|
||||||
e = ((BEROctetString)obj).getObjects();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASN1OctetString octs = (ASN1OctetString)obj;
|
|
||||||
BEROctetString berO = new BEROctetString(octs.getOctets());
|
|
||||||
e = berO.getObjects();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1Sequence)
|
|
||||||
{
|
|
||||||
e = ((ASN1Sequence)obj).getObjects();
|
|
||||||
}
|
|
||||||
else if (obj instanceof ASN1Set)
|
|
||||||
{
|
|
||||||
e = ((ASN1Set)obj).getObjects();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new RuntimeException("not implemented: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
while (e.hasMoreElements())
|
|
||||||
{
|
|
||||||
out.writeObject((ASN1Encodable)e.nextElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
out.writeObject(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out.write(0x00);
|
|
||||||
out.write(0x00);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class BERTaggedObjectParser
|
|
||||||
implements ASN1TaggedObjectParser
|
|
||||||
{
|
|
||||||
private boolean _constructed;
|
|
||||||
private int _tagNumber;
|
|
||||||
private ASN1StreamParser _parser;
|
|
||||||
|
|
||||||
BERTaggedObjectParser(
|
|
||||||
boolean constructed,
|
|
||||||
int tagNumber,
|
|
||||||
ASN1StreamParser parser)
|
|
||||||
{
|
|
||||||
_constructed = constructed;
|
|
||||||
_tagNumber = tagNumber;
|
|
||||||
_parser = parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConstructed()
|
|
||||||
{
|
|
||||||
return _constructed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTagNo()
|
|
||||||
{
|
|
||||||
return _tagNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Encodable getObjectParser(
|
|
||||||
int tag,
|
|
||||||
boolean isExplicit)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (isExplicit)
|
|
||||||
{
|
|
||||||
if (!_constructed)
|
|
||||||
{
|
|
||||||
throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
|
|
||||||
}
|
|
||||||
return _parser.readObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _parser.readImplicit(_constructed, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive getLoadedObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return _parser.readTaggedObject(_constructed, _tagNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Primitive toASN1Primitive()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return this.getLoadedObject();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ASN1ParsingException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
public interface BERTags
|
|
||||||
{
|
|
||||||
public static final int BOOLEAN = 0x01;
|
|
||||||
public static final int INTEGER = 0x02;
|
|
||||||
public static final int BIT_STRING = 0x03;
|
|
||||||
public static final int OCTET_STRING = 0x04;
|
|
||||||
public static final int NULL = 0x05;
|
|
||||||
public static final int OBJECT_IDENTIFIER = 0x06;
|
|
||||||
public static final int EXTERNAL = 0x08;
|
|
||||||
public static final int ENUMERATED = 0x0a;
|
|
||||||
public static final int SEQUENCE = 0x10;
|
|
||||||
public static final int SEQUENCE_OF = 0x10; // for completeness - used to model a SEQUENCE of the same type.
|
|
||||||
public static final int SET = 0x11;
|
|
||||||
public static final int SET_OF = 0x11; // for completeness - used to model a SET of the same type.
|
|
||||||
|
|
||||||
|
|
||||||
public static final int NUMERIC_STRING = 0x12;
|
|
||||||
public static final int PRINTABLE_STRING = 0x13;
|
|
||||||
public static final int T61_STRING = 0x14;
|
|
||||||
public static final int VIDEOTEX_STRING = 0x15;
|
|
||||||
public static final int IA5_STRING = 0x16;
|
|
||||||
public static final int UTC_TIME = 0x17;
|
|
||||||
public static final int GENERALIZED_TIME = 0x18;
|
|
||||||
public static final int GRAPHIC_STRING = 0x19;
|
|
||||||
public static final int VISIBLE_STRING = 0x1a;
|
|
||||||
public static final int GENERAL_STRING = 0x1b;
|
|
||||||
public static final int UNIVERSAL_STRING = 0x1c;
|
|
||||||
public static final int BMP_STRING = 0x1e;
|
|
||||||
public static final int UTF8_STRING = 0x0c;
|
|
||||||
|
|
||||||
public static final int CONSTRUCTED = 0x20;
|
|
||||||
public static final int APPLICATION = 0x40;
|
|
||||||
public static final int TAGGED = 0x80;
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
class ConstructedOctetStream
|
|
||||||
extends InputStream
|
|
||||||
{
|
|
||||||
private final ASN1StreamParser _parser;
|
|
||||||
|
|
||||||
private boolean _first = true;
|
|
||||||
private InputStream _currentStream;
|
|
||||||
|
|
||||||
ConstructedOctetStream(
|
|
||||||
ASN1StreamParser parser)
|
|
||||||
{
|
|
||||||
_parser = parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read(byte[] b, int off, int len) throws IOException
|
|
||||||
{
|
|
||||||
if (_currentStream == null)
|
|
||||||
{
|
|
||||||
if (!_first)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
|
|
||||||
|
|
||||||
if (s == null)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_first = false;
|
|
||||||
_currentStream = s.getOctetStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
int totalRead = 0;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int numRead = _currentStream.read(b, off + totalRead, len - totalRead);
|
|
||||||
|
|
||||||
if (numRead >= 0)
|
|
||||||
{
|
|
||||||
totalRead += numRead;
|
|
||||||
|
|
||||||
if (totalRead == len)
|
|
||||||
{
|
|
||||||
return totalRead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASN1OctetStringParser aos = (ASN1OctetStringParser)_parser.readObject();
|
|
||||||
|
|
||||||
if (aos == null)
|
|
||||||
{
|
|
||||||
_currentStream = null;
|
|
||||||
return totalRead < 1 ? -1 : totalRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentStream = aos.getOctetStream();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (_currentStream == null)
|
|
||||||
{
|
|
||||||
if (!_first)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
|
|
||||||
|
|
||||||
if (s == null)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_first = false;
|
|
||||||
_currentStream = s.getOctetStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int b = _currentStream.read();
|
|
||||||
|
|
||||||
if (b >= 0)
|
|
||||||
{
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
|
|
||||||
|
|
||||||
if (s == null)
|
|
||||||
{
|
|
||||||
_currentStream = null;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentStream = s.getOctetStream();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,267 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for an application specific object
|
|
||||||
*/
|
|
||||||
public class DERApplicationSpecific
|
|
||||||
extends ASN1Primitive
|
|
||||||
{
|
|
||||||
private final boolean isConstructed;
|
|
||||||
private final int tag;
|
|
||||||
private final byte[] octets;
|
|
||||||
|
|
||||||
DERApplicationSpecific(
|
|
||||||
boolean isConstructed,
|
|
||||||
int tag,
|
|
||||||
byte[] octets)
|
|
||||||
{
|
|
||||||
this.isConstructed = isConstructed;
|
|
||||||
this.tag = tag;
|
|
||||||
this.octets = octets;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERApplicationSpecific(
|
|
||||||
int tag,
|
|
||||||
byte[] octets)
|
|
||||||
{
|
|
||||||
this(false, tag, octets);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERApplicationSpecific(
|
|
||||||
int tag,
|
|
||||||
ASN1Encodable object)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
this(true, tag, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERApplicationSpecific(
|
|
||||||
boolean explicit,
|
|
||||||
int tag,
|
|
||||||
ASN1Encodable object)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
ASN1Primitive primitive = object.toASN1Primitive();
|
|
||||||
|
|
||||||
byte[] data = primitive.getEncoded(ASN1Encoding.DER);
|
|
||||||
|
|
||||||
this.isConstructed = explicit || (primitive instanceof ASN1Set || primitive instanceof ASN1Sequence);
|
|
||||||
this.tag = tag;
|
|
||||||
|
|
||||||
if (explicit)
|
|
||||||
{
|
|
||||||
this.octets = data;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int lenBytes = getLengthOfHeader(data);
|
|
||||||
byte[] tmp = new byte[data.length - lenBytes];
|
|
||||||
System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
|
|
||||||
this.octets = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
|
|
||||||
{
|
|
||||||
this.tag = tagNo;
|
|
||||||
this.isConstructed = true;
|
|
||||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
for (int i = 0; i != vec.size(); i++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DER));
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new ASN1ParsingException("malformed object: " + e, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.octets = bOut.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DERApplicationSpecific getInstance(Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof DERApplicationSpecific)
|
|
||||||
{
|
|
||||||
return (DERApplicationSpecific)obj;
|
|
||||||
}
|
|
||||||
else if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return DERApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("failed to construct object from byte[]: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getLengthOfHeader(byte[] data)
|
|
||||||
{
|
|
||||||
int length = data[1] & 0xff; // TODO: assumes 1 byte tag
|
|
||||||
|
|
||||||
if (length == 0x80)
|
|
||||||
{
|
|
||||||
return 2; // indefinite-length encoding
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length > 127)
|
|
||||||
{
|
|
||||||
int size = length & 0x7f;
|
|
||||||
|
|
||||||
// Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
|
|
||||||
if (size > 4)
|
|
||||||
{
|
|
||||||
throw new IllegalStateException("DER length more than 4 bytes: " + size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return size + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConstructed()
|
|
||||||
{
|
|
||||||
return isConstructed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getContents()
|
|
||||||
{
|
|
||||||
return octets;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getApplicationTag()
|
|
||||||
{
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the enclosed object assuming explicit tagging.
|
|
||||||
*
|
|
||||||
* @return the resulting object
|
|
||||||
* @throws IOException if reconstruction fails.
|
|
||||||
*/
|
|
||||||
public ASN1Primitive getObject()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return new ASN1InputStream(getContents()).readObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the enclosed object assuming implicit tagging.
|
|
||||||
*
|
|
||||||
* @param derTagNo the type tag that should be applied to the object's contents.
|
|
||||||
* @return the resulting object
|
|
||||||
* @throws IOException if reconstruction fails.
|
|
||||||
*/
|
|
||||||
public ASN1Primitive getObject(int derTagNo)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (derTagNo >= 0x1f)
|
|
||||||
{
|
|
||||||
throw new IOException("unsupported tag number");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] orig = this.getEncoded();
|
|
||||||
byte[] tmp = replaceTagNumber(derTagNo, orig);
|
|
||||||
|
|
||||||
if ((orig[0] & BERTags.CONSTRUCTED) != 0)
|
|
||||||
{
|
|
||||||
tmp[0] |= BERTags.CONSTRUCTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ASN1InputStream(tmp).readObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.spongycastle.asn1.ASN1Primitive#encode(org.spongycastle.asn1.DEROutputStream)
|
|
||||||
*/
|
|
||||||
void encode(ASN1OutputStream out) throws IOException
|
|
||||||
{
|
|
||||||
int classBits = BERTags.APPLICATION;
|
|
||||||
if (isConstructed)
|
|
||||||
{
|
|
||||||
classBits |= BERTags.CONSTRUCTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.writeEncoded(classBits, tag, octets);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof DERApplicationSpecific))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DERApplicationSpecific other = (DERApplicationSpecific)o;
|
|
||||||
|
|
||||||
return isConstructed == other.isConstructed
|
|
||||||
&& tag == other.tag
|
|
||||||
&& Arrays.areEqual(octets, other.octets);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] replaceTagNumber(int newTag, byte[] input)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int tagNo = input[0] & 0x1f;
|
|
||||||
int index = 1;
|
|
||||||
//
|
|
||||||
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
|
|
||||||
//
|
|
||||||
if (tagNo == 0x1f)
|
|
||||||
{
|
|
||||||
tagNo = 0;
|
|
||||||
|
|
||||||
int b = input[index++] & 0xff;
|
|
||||||
|
|
||||||
// X.690-0207 8.1.2.4.2
|
|
||||||
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
|
|
||||||
if ((b & 0x7f) == 0) // Note: -1 will pass
|
|
||||||
{
|
|
||||||
throw new ASN1ParsingException("corrupted stream - invalid high tag number found");
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((b >= 0) && ((b & 0x80) != 0))
|
|
||||||
{
|
|
||||||
tagNo |= (b & 0x7f);
|
|
||||||
tagNo <<= 7;
|
|
||||||
b = input[index++] & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
tagNo |= (b & 0x7f);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] tmp = new byte[input.length - index + 1];
|
|
||||||
|
|
||||||
System.arraycopy(input, index, tmp, 1, tmp.length - 1);
|
|
||||||
|
|
||||||
tmp[0] = (byte)newTag;
|
|
||||||
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,157 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DER BMPString object.
|
|
||||||
*/
|
|
||||||
public class DERBMPString
|
|
||||||
extends ASN1Primitive
|
|
||||||
implements ASN1String
|
|
||||||
{
|
|
||||||
private char[] string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a BMP String from the given object.
|
|
||||||
*
|
|
||||||
* @param obj the object we want converted.
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
* @return a DERBMPString instance, or null.
|
|
||||||
*/
|
|
||||||
public static DERBMPString getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof DERBMPString)
|
|
||||||
{
|
|
||||||
return (DERBMPString)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof byte[])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (DERBMPString)fromByteArray((byte[])obj);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a BMP String from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
* @return a DERBMPString instance.
|
|
||||||
*/
|
|
||||||
public static DERBMPString getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Primitive o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof DERBMPString)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new DERBMPString(ASN1OctetString.getInstance(o).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* basic constructor - byte encoded string.
|
|
||||||
* @param string the encoded BMP STRING to wrap.
|
|
||||||
*/
|
|
||||||
DERBMPString(
|
|
||||||
byte[] string)
|
|
||||||
{
|
|
||||||
char[] cs = new char[string.length / 2];
|
|
||||||
|
|
||||||
for (int i = 0; i != cs.length; i++)
|
|
||||||
{
|
|
||||||
cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.string = cs;
|
|
||||||
}
|
|
||||||
|
|
||||||
DERBMPString(char[] string)
|
|
||||||
{
|
|
||||||
this.string = string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* basic constructor
|
|
||||||
* @param string a String to wrap as a BMP STRING.
|
|
||||||
*/
|
|
||||||
public DERBMPString(
|
|
||||||
String string)
|
|
||||||
{
|
|
||||||
this.string = string.toCharArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getString()
|
|
||||||
{
|
|
||||||
return new String(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return getString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Arrays.hashCode(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof DERBMPString))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DERBMPString s = (DERBMPString)o;
|
|
||||||
|
|
||||||
return Arrays.areEqual(string, s.string);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
{
|
|
||||||
return 1 + StreamUtil.calculateBodyLength(string.length * 2) + (string.length * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
out.write(BERTags.BMP_STRING);
|
|
||||||
out.writeLength(string.length * 2);
|
|
||||||
|
|
||||||
for (int i = 0; i != string.length; i++)
|
|
||||||
{
|
|
||||||
char c = string[i];
|
|
||||||
|
|
||||||
out.write((byte)(c >> 8));
|
|
||||||
out.write((byte)c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,318 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
import org.spongycastle.util.io.Streams;
|
|
||||||
|
|
||||||
public class DERBitString
|
|
||||||
extends ASN1Primitive
|
|
||||||
implements ASN1String
|
|
||||||
{
|
|
||||||
private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
|
||||||
|
|
||||||
protected byte[] data;
|
|
||||||
protected int padBits;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bitString an int containing the BIT STRING
|
|
||||||
* @return the correct number of pad bits for a bit string defined in
|
|
||||||
* a 32 bit constant
|
|
||||||
*/
|
|
||||||
static protected int getPadBits(
|
|
||||||
int bitString)
|
|
||||||
{
|
|
||||||
int val = 0;
|
|
||||||
for (int i = 3; i >= 0; i--)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// this may look a little odd, but if it isn't done like this pre jdk1.2
|
|
||||||
// JVM's break!
|
|
||||||
//
|
|
||||||
if (i != 0)
|
|
||||||
{
|
|
||||||
if ((bitString >> (i * 8)) != 0)
|
|
||||||
{
|
|
||||||
val = (bitString >> (i * 8)) & 0xFF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (bitString != 0)
|
|
||||||
{
|
|
||||||
val = bitString & 0xFF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val == 0)
|
|
||||||
{
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int bits = 1;
|
|
||||||
|
|
||||||
while (((val <<= 1) & 0xFF) != 0)
|
|
||||||
{
|
|
||||||
bits++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 8 - bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bitString an int containing the BIT STRING
|
|
||||||
* @return the correct number of bytes for a bit string defined in
|
|
||||||
* a 32 bit constant
|
|
||||||
*/
|
|
||||||
static protected byte[] getBytes(int bitString)
|
|
||||||
{
|
|
||||||
int bytes = 4;
|
|
||||||
for (int i = 3; i >= 1; i--)
|
|
||||||
{
|
|
||||||
if ((bitString & (0xFF << (i * 8))) != 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bytes--;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] result = new byte[bytes];
|
|
||||||
for (int i = 0; i < bytes; i++)
|
|
||||||
{
|
|
||||||
result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a Bit String from the passed in object
|
|
||||||
*
|
|
||||||
* @param obj a DERBitString or an object that can be converted into one.
|
|
||||||
* @exception IllegalArgumentException if the object cannot be converted.
|
|
||||||
* @return a DERBitString instance, or null.
|
|
||||||
*/
|
|
||||||
public static DERBitString getInstance(
|
|
||||||
Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj instanceof DERBitString)
|
|
||||||
{
|
|
||||||
return (DERBitString)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a Bit String from a tagged object.
|
|
||||||
*
|
|
||||||
* @param obj the tagged object holding the object we want
|
|
||||||
* @param explicit true if the object is meant to be explicitly
|
|
||||||
* tagged false otherwise.
|
|
||||||
* @exception IllegalArgumentException if the tagged object cannot
|
|
||||||
* be converted.
|
|
||||||
* @return a DERBitString instance, or null.
|
|
||||||
*/
|
|
||||||
public static DERBitString getInstance(
|
|
||||||
ASN1TaggedObject obj,
|
|
||||||
boolean explicit)
|
|
||||||
{
|
|
||||||
ASN1Primitive o = obj.getObject();
|
|
||||||
|
|
||||||
if (explicit || o instanceof DERBitString)
|
|
||||||
{
|
|
||||||
return getInstance(o);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return fromOctetString(((ASN1OctetString)o).getOctets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected DERBitString(
|
|
||||||
byte data,
|
|
||||||
int padBits)
|
|
||||||
{
|
|
||||||
this.data = new byte[1];
|
|
||||||
this.data[0] = data;
|
|
||||||
this.padBits = padBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param data the octets making up the bit string.
|
|
||||||
* @param padBits the number of extra bits at the end of the string.
|
|
||||||
*/
|
|
||||||
public DERBitString(
|
|
||||||
byte[] data,
|
|
||||||
int padBits)
|
|
||||||
{
|
|
||||||
this.data = data;
|
|
||||||
this.padBits = padBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERBitString(
|
|
||||||
byte[] data)
|
|
||||||
{
|
|
||||||
this(data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERBitString(
|
|
||||||
int value)
|
|
||||||
{
|
|
||||||
this.data = getBytes(value);
|
|
||||||
this.padBits = getPadBits(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DERBitString(
|
|
||||||
ASN1Encodable obj)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
this.data = obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
|
|
||||||
this.padBits = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes()
|
|
||||||
{
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPadBits()
|
|
||||||
{
|
|
||||||
return padBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the value of the bit string as an int (truncating if necessary)
|
|
||||||
*/
|
|
||||||
public int intValue()
|
|
||||||
{
|
|
||||||
int value = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i != data.length && i != 4; i++)
|
|
||||||
{
|
|
||||||
value |= (data[i] & 0xff) << (8 * i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isConstructed()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encodedLength()
|
|
||||||
{
|
|
||||||
return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
ASN1OutputStream out)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
byte[] bytes = new byte[getBytes().length + 1];
|
|
||||||
|
|
||||||
bytes[0] = (byte)getPadBits();
|
|
||||||
System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
|
|
||||||
|
|
||||||
out.writeEncoded(BERTags.BIT_STRING, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return padBits ^ Arrays.hashCode(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean asn1Equals(
|
|
||||||
ASN1Primitive o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof DERBitString))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DERBitString other = (DERBitString)o;
|
|
||||||
|
|
||||||
return this.padBits == other.padBits
|
|
||||||
&& Arrays.areEqual(this.data, other.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getString()
|
|
||||||
{
|
|
||||||
StringBuffer buf = new StringBuffer("#");
|
|
||||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
||||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
aOut.writeObject(this);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("internal error encoding BitString");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] string = bOut.toByteArray();
|
|
||||||
|
|
||||||
for (int i = 0; i != string.length; i++)
|
|
||||||
{
|
|
||||||
buf.append(table[(string[i] >>> 4) & 0xf]);
|
|
||||||
buf.append(table[string[i] & 0xf]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return getString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static DERBitString fromOctetString(byte[] bytes)
|
|
||||||
{
|
|
||||||
if (bytes.length < 1)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("truncated BIT STRING detected");
|
|
||||||
}
|
|
||||||
|
|
||||||
int padBits = bytes[0];
|
|
||||||
byte[] data = new byte[bytes.length - 1];
|
|
||||||
|
|
||||||
if (data.length != 0)
|
|
||||||
{
|
|
||||||
System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DERBitString(data, padBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DERBitString fromInputStream(int length, InputStream stream)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (length < 1)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("truncated BIT STRING detected");
|
|
||||||
}
|
|
||||||
|
|
||||||
int padBits = stream.read();
|
|
||||||
byte[] data = new byte[length - 1];
|
|
||||||
|
|
||||||
if (data.length != 0)
|
|
||||||
{
|
|
||||||
if (Streams.readFully(stream, data) != data.length)
|
|
||||||
{
|
|
||||||
throw new EOFException("EOF encountered in middle of BIT STRING");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DERBitString(data, padBits);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package org.spongycastle.asn1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use ASN1Boolean
|
|
||||||
*/
|
|
||||||
public class DERBoolean
|
|
||||||
extends ASN1Boolean
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @deprecated use getInstance(boolean) method.
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public DERBoolean(boolean value)
|
|
||||||
{
|
|
||||||
super(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
DERBoolean(byte[] value)
|
|
||||||
{
|
|
||||||
super(value);
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user