Add spongy castle sources to libraries folder

This commit is contained in:
Dominik Schürmann
2014-01-27 14:00:22 +01:00
parent 8ca42b9bf9
commit 5aec25ac05
4258 changed files with 848014 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
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();
}
}

View File

@@ -0,0 +1,39 @@
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

View File

@@ -0,0 +1,141 @@
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);
}
}

View File

@@ -0,0 +1,261 @@
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();
}
}

View File

@@ -0,0 +1,304 @@
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);
}
}
}

View File

@@ -0,0 +1,173 @@
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()");
}
}

View File

@@ -0,0 +1,46 @@
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;
}
}

View File

@@ -0,0 +1,107 @@
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();
}
}

View File

@@ -0,0 +1,118 @@
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;
}
}
}

View File

@@ -0,0 +1,21 @@
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;
}

View File

@@ -0,0 +1,365 @@
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();
}
};
}
}

View File

@@ -0,0 +1,279 @@
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;
}
}

View File

@@ -0,0 +1,71 @@
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;
}
}

View File

@@ -0,0 +1,9 @@
package java.util;
public interface Iterator
{
public abstract boolean hasNext();
public abstract Object next() throws NoSuchElementException;
public abstract void remove() throws RuntimeException,IllegalStateException;
}

View File

@@ -0,0 +1,32 @@
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;
}

View File

@@ -0,0 +1,20 @@
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;
}

View File

@@ -0,0 +1,54 @@
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();
}

View File

@@ -0,0 +1,38 @@
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();
}

View File

@@ -0,0 +1,115 @@
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;
}
}

View File

@@ -0,0 +1,142 @@
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);
}
}

View File

@@ -0,0 +1,27 @@
package org.spongycastle.asn1;
import java.util.Date;
public class ASN1GeneralizedTime
extends DERGeneralizedTime
{
ASN1GeneralizedTime(byte[] bytes)
{
super(bytes);
}
public ASN1GeneralizedTime(Date date)
{
super(date);
}
public ASN1GeneralizedTime(Date date, boolean includeMillis)
{
super(date, includeMillis);
}
public ASN1GeneralizedTime(String time)
{
super(time);
}
}

View File

@@ -0,0 +1,22 @@
package org.spongycastle.asn1;
import java.util.Date;
public class ASN1UTCTime
extends DERUTCTime
{
ASN1UTCTime(byte[] bytes)
{
super(bytes);
}
public ASN1UTCTime(Date date)
{
super(date);
}
public ASN1UTCTime(String time)
{
super(time);
}
}

View File

@@ -0,0 +1,31 @@
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);
}
}
}

View File

@@ -0,0 +1,260 @@
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 DERGeneralizedTime
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 DERGeneralizedTime)
{
return new ASN1GeneralizedTime(((DERGeneralizedTime)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 DERGeneralizedTime)
{
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 DERGeneralizedTime(
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 DERGeneralizedTime(
Date time)
{
this.time = Strings.toByteArray(DateFormatter.getGeneralizedTimeDateString(time, false));
}
protected DERGeneralizedTime(Date date, boolean includeMillis)
{
this.time = Strings.toByteArray(DateFormatter.getGeneralizedTimeDateString(date, true));
}
DERGeneralizedTime(
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 DERGeneralizedTime))
{
return false;
}
return Arrays.areEqual(time, ((DERGeneralizedTime)o).time);
}
public int hashCode()
{
return Arrays.hashCode(time);
}
}

View File

@@ -0,0 +1,259 @@
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 DERUTCTime
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 DERUTCTime)
{
return new ASN1UTCTime(((DERUTCTime)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 DERUTCTime(
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 DERUTCTime(
Date time)
{
this.time = Strings.toByteArray(DateFormatter.toUTCDateString(time));
}
DERUTCTime(
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 DERUTCTime))
{
return false;
}
return Arrays.areEqual(time, ((DERUTCTime)o).time);
}
public int hashCode()
{
return Arrays.hashCode(time);
}
public String toString()
{
return Strings.fromByteArray(time);
}
}

View File

@@ -0,0 +1,272 @@
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) ;
}
}

View File

@@ -0,0 +1,88 @@
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;
}
}

View File

@@ -0,0 +1,122 @@
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.DERGeneralizedTime;
import org.spongycastle.asn1.DERUTCTime;
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 DERUTCTime)
&& !(time instanceof DERGeneralizedTime))
{
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 DERGeneralizedTime(date);
}
else
{
time = new DERUTCTime(date);
}
}
public static Time getInstance(
Object obj)
{
if (obj == null || obj instanceof Time)
{
return (Time)obj;
}
else if (obj instanceof DERUTCTime)
{
return new Time((DERUTCTime)obj);
}
else if (obj instanceof DERGeneralizedTime)
{
return new Time((DERGeneralizedTime)obj);
}
throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
}
public String getTime()
{
if (time instanceof DERUTCTime)
{
return ((DERUTCTime)time).getAdjustedTime();
}
else
{
return ((DERGeneralizedTime)time).getTime();
}
}
public Date getDate()
{
if (time instanceof DERUTCTime)
{
return ((DERUTCTime)time).getAdjustedDate();
}
else
{
return ((DERGeneralizedTime)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();
}
}

View File

@@ -0,0 +1,70 @@
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;
}
}

View File

@@ -0,0 +1,122 @@
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.DERGeneralizedTime;
import org.spongycastle.asn1.DERUTCTime;
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 DERUTCTime)
&& !(time instanceof DERGeneralizedTime))
{
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 DERGeneralizedTime(date);
}
else
{
time = new DERUTCTime(date);
}
}
public static Time getInstance(
Object obj)
{
if (obj == null || obj instanceof Time)
{
return (Time)obj;
}
else if (obj instanceof DERUTCTime)
{
return new Time((DERUTCTime)obj);
}
else if (obj instanceof DERGeneralizedTime)
{
return new Time((DERGeneralizedTime)obj);
}
throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
}
public String getTime()
{
if (time instanceof DERUTCTime)
{
return ((DERUTCTime)time).getAdjustedTime();
}
else
{
return ((DERGeneralizedTime)time).getTime();
}
}
public Date getDate()
{
if (time instanceof DERUTCTime)
{
return ((DERUTCTime)time).getAdjustedDate();
}
else
{
return ((DERGeneralizedTime)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();
}
}

View File

@@ -0,0 +1,238 @@
package org.spongycastle.crypto.encodings;
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;
import java.security.SecureRandom;
/**
* 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;
/**
* Basic constructor.
* @param cipher
*/
public PKCS1Encoding(
AsymmetricBlockCipher cipher)
{
this.engine = cipher;
this.useStrictLength = useStrict();
}
//
// for J2ME compatibility
//
private boolean useStrict()
{
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);
}
/**
* @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format.
*/
private byte[] decodeBlock(
byte[] in,
int inOff,
int inLen)
throws InvalidCipherTextException
{
byte[] block = engine.processBlock(in, inOff, inLen);
if (block.length < getOutputBlockSize())
{
throw new InvalidCipherTextException("block truncated");
}
byte type = block[0];
if (type != 1 && type != 2)
{
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;
}
}

View File

@@ -0,0 +1,177 @@
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);
}
}

View File

@@ -0,0 +1,6 @@
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

View File

@@ -0,0 +1,7 @@
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

View File

@@ -0,0 +1,258 @@
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);
}
}
}

View File

@@ -0,0 +1,131 @@
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 a {@link OCSPStatusRequest} from an {@link InputStream}.
*
* @param input
* the {@link InputStream} to parse from.
* @return a {@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);
}
}

View File

@@ -0,0 +1,86 @@
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);
}
}

View File

@@ -0,0 +1,107 @@
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

View File

@@ -0,0 +1,9 @@
package org.spongycastle.util;
public class Integers
{
public static Integer valueOf(int value)
{
return new Integer(value);
}
}

View File

@@ -0,0 +1,8 @@
package org.spongycastle.util;
public interface Selector
{
boolean match(Object obj);
Object clone();
}

View File

@@ -0,0 +1,9 @@
package org.spongycastle.util;
public class Shorts
{
public static Short valueOf(short value)
{
return new Short(value);
}
}

View File

@@ -0,0 +1,84 @@
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;
}

View File

@@ -0,0 +1,63 @@
package org.spongycastle;
/**
* The Bouncy Castle License
*
* Copyright (c) 2000-2013 The Legion Of The Bouncy Castle (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-2013 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);
}
}

View File

@@ -0,0 +1,10 @@
package org.spongycastle.asn1;
import java.io.IOException;
public interface ASN1ApplicationSpecificParser
extends ASN1Encodable, InMemoryRepresentable
{
ASN1Encodable readObject()
throws IOException;
}

View File

@@ -0,0 +1,15 @@
package org.spongycastle.asn1;
public class ASN1Boolean
extends DERBoolean
{
public ASN1Boolean(boolean value)
{
super(value);
}
ASN1Boolean(byte[] value)
{
super(value);
}
}

View File

@@ -0,0 +1,14 @@
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.
*/
public interface ASN1Choice
{
// marker interface
}

View File

@@ -0,0 +1,6 @@
package org.spongycastle.asn1;
public interface ASN1Encodable
{
ASN1Primitive toASN1Primitive();
}

View File

@@ -0,0 +1,36 @@
package org.spongycastle.asn1;
import java.util.Enumeration;
import java.util.Vector;
public class ASN1EncodableVector
{
Vector v = new Vector();
public ASN1EncodableVector()
{
}
public void add(ASN1Encodable obj)
{
v.addElement(obj);
}
public void addAll(ASN1EncodableVector other)
{
for (Enumeration en = other.v.elements(); en.hasMoreElements();)
{
v.addElement(en.nextElement());
}
}
public ASN1Encodable get(int i)
{
return (ASN1Encodable)v.elementAt(i);
}
public int size()
{
return v.size();
}
}

View File

@@ -0,0 +1,8 @@
package org.spongycastle.asn1;
public interface ASN1Encoding
{
static final String DER = "DER";
static final String DL = "DL";
static final String BER = "BER";
}

View File

@@ -0,0 +1,22 @@
package org.spongycastle.asn1;
import java.math.BigInteger;
public class ASN1Enumerated
extends DEREnumerated
{
ASN1Enumerated(byte[] bytes)
{
super(bytes);
}
public ASN1Enumerated(BigInteger value)
{
super(value);
}
public ASN1Enumerated(int value)
{
super(value);
}
}

View File

@@ -0,0 +1,25 @@
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;
}
}

View File

@@ -0,0 +1,22 @@
package org.spongycastle.asn1;
import java.util.Date;
public class ASN1GeneralizedTime
extends DERGeneralizedTime
{
ASN1GeneralizedTime(byte[] bytes)
{
super(bytes);
}
public ASN1GeneralizedTime(Date time)
{
super(time);
}
public ASN1GeneralizedTime(String time)
{
super(time);
}
}

View File

@@ -0,0 +1,15 @@
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();
}

View File

@@ -0,0 +1,466 @@
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.
*/
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());
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");
}
}
}

View File

@@ -0,0 +1,22 @@
package org.spongycastle.asn1;
import java.math.BigInteger;
public class ASN1Integer
extends DERInteger
{
ASN1Integer(byte[] bytes)
{
super(bytes);
}
public ASN1Integer(BigInteger value)
{
super(value);
}
public ASN1Integer(long value)
{
super(value);
}
}

View File

@@ -0,0 +1,67 @@
package org.spongycastle.asn1;
import java.io.IOException;
/**
* A NULL object.
*/
public abstract class ASN1Null
extends ASN1Primitive
{
/**
* @deprecated use DERNull.INSTANCE
*/
public ASN1Null()
{
}
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";
}
}

View File

@@ -0,0 +1,97 @@
package org.spongycastle.asn1;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
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();
}
protected static boolean hasEncodedTagValue(Object obj, int tagValue)
{
return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue;
}
public abstract ASN1Primitive toASN1Primitive();
}

View File

@@ -0,0 +1,42 @@
package org.spongycastle.asn1;
public class ASN1ObjectIdentifier
extends DERObjectIdentifier
{
public ASN1ObjectIdentifier(String identifier)
{
super(identifier);
}
ASN1ObjectIdentifier(byte[] bytes)
{
super(bytes);
}
ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch)
{
super(oid, branch);
}
/**
* 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);
}
}

View File

@@ -0,0 +1,146 @@
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;
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;
}
public InputStream getOctetStream()
{
return new ByteArrayInputStream(string);
}
public ASN1OctetStringParser parser()
{
return this;
}
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));
}
}

View File

@@ -0,0 +1,9 @@
package org.spongycastle.asn1;
import java.io.InputStream;
public interface ASN1OctetStringParser
extends ASN1Encodable, InMemoryRepresentable
{
public InputStream getOctetStream();
}

View File

@@ -0,0 +1,194 @@
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);
}
}
}
}

View File

@@ -0,0 +1,23 @@
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;
}
}

View File

@@ -0,0 +1,69 @@
package org.spongycastle.asn1;
import java.io.IOException;
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;
}
ASN1Primitive toDERObject()
{
return 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);
}

View File

@@ -0,0 +1,323 @@
package org.spongycastle.asn1;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
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.
*/
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.
*/
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
*/
protected ASN1Sequence(
ASN1Encodable obj)
{
seq.addElement(obj);
}
/**
* create a sequence containing a vector of objects.
*/
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;
}
ASN1Primitive toDERObject()
{
ASN1Sequence derSeq = new DERSequence();
derSeq.seq = this.seq;
return derSeq;
}
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();
}
}

View File

@@ -0,0 +1,10 @@
package org.spongycastle.asn1;
import java.io.IOException;
public interface ASN1SequenceParser
extends ASN1Encodable, InMemoryRepresentable
{
ASN1Encodable readObject()
throws IOException;
}

View File

@@ -0,0 +1,460 @@
package org.spongycastle.asn1;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
abstract public 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.
*/
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.
*/
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
*/
protected ASN1Set(
ASN1Encodable obj)
{
set.addElement(obj);
}
/**
* create a sequence containing a vector of objects.
*/
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;
}
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;
}
}
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();
}
}

View File

@@ -0,0 +1,10 @@
package org.spongycastle.asn1;
import java.io.IOException;
public interface ASN1SetParser
extends ASN1Encodable, InMemoryRepresentable
{
public ASN1Encodable readObject()
throws IOException;
}

View File

@@ -0,0 +1,247 @@
package org.spongycastle.asn1;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
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;
}
}

View File

@@ -0,0 +1,6 @@
package org.spongycastle.asn1;
public interface ASN1String
{
public String getString();
}

View File

@@ -0,0 +1,236 @@
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;
}
}

View File

@@ -0,0 +1,12 @@
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;
}

View File

@@ -0,0 +1,22 @@
package org.spongycastle.asn1;
import java.util.Date;
public class ASN1UTCTime
extends DERUTCTime
{
ASN1UTCTime(byte[] bytes)
{
super(bytes);
}
public ASN1UTCTime(Date time)
{
super(time);
}
public ASN1UTCTime(String time)
{
super(time);
}
}

View File

@@ -0,0 +1,10 @@
package org.spongycastle.asn1;
public class BERApplicationSpecific
extends DERApplicationSpecific
{
public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
{
super(tagNo, vec);
}
}

View File

@@ -0,0 +1,41 @@
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);
}
}
}

View File

@@ -0,0 +1,144 @@
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);
}
}

View File

@@ -0,0 +1,17 @@
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);
}
}

View File

@@ -0,0 +1,100 @@
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);
}
}
}

View File

@@ -0,0 +1,168 @@
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);
}
}

View File

@@ -0,0 +1,102 @@
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();
}
}
}

View File

@@ -0,0 +1,41 @@
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);
}
}
}

View File

@@ -0,0 +1,36 @@
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");
}
}
}

View File

@@ -0,0 +1,73 @@
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);
}
}

View File

@@ -0,0 +1,41 @@
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();
}
}

View File

@@ -0,0 +1,38 @@
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());
}
}
}

View File

@@ -0,0 +1,73 @@
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);
}
}

View File

@@ -0,0 +1,38 @@
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);
}
}
}

View File

@@ -0,0 +1,147 @@
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);
}
}

View File

@@ -0,0 +1,66 @@
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());
}
}
}

View File

@@ -0,0 +1,36 @@
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;
}

View File

@@ -0,0 +1,111 @@
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();
}
}
}

View File

@@ -0,0 +1,276 @@
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());
}
}
else if (obj instanceof ASN1Encodable)
{
ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
if (primitive instanceof ASN1Sequence)
{
return (DERApplicationSpecific)primitive;
}
}
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;
}
}

View File

@@ -0,0 +1,153 @@
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.
*/
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.
*/
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.
*/
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
*/
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);
}
}
}

View File

@@ -0,0 +1,313 @@
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;
/**
* 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;
}
/**
* 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
*
* @exception IllegalArgumentException if the object cannot be converted.
*/
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.
*/
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);
}
}

View File

@@ -0,0 +1,179 @@
package org.spongycastle.asn1;
import java.io.IOException;
import org.spongycastle.util.Arrays;
public class DERBoolean
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.
*
* @exception IllegalArgumentException if the object cannot be converted.
*/
public static ASN1Boolean getInstance(
Object obj)
{
if (obj == null || obj instanceof ASN1Boolean)
{
return (ASN1Boolean)obj;
}
if (obj instanceof DERBoolean)
{
return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE;
}
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
}
/**
* return a ASN1Boolean from the passed in boolean.
*/
public static ASN1Boolean getInstance(
boolean value)
{
return (value ? TRUE : FALSE);
}
/**
* return a ASN1Boolean from the passed in boolean.
*/
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.
*/
public static ASN1Boolean getInstance(
ASN1TaggedObject obj,
boolean explicit)
{
ASN1Primitive o = obj.getObject();
if (explicit || o instanceof DERBoolean)
{
return getInstance(o);
}
else
{
return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
}
}
DERBoolean(
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)
{
this.value = TRUE_VALUE;
}
else
{
this.value = Arrays.clone(value);
}
}
/**
* @deprecated use getInstance(boolean) method.
* @param value
*/
public DERBoolean(
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 == null) || !(o instanceof DERBoolean))
{
return false;
}
return (value[0] == ((DERBoolean)o).value[0]);
}
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)
{
return TRUE;
}
else
{
return new ASN1Boolean(value);
}
}
}

View File

@@ -0,0 +1,18 @@
package org.spongycastle.asn1;
/**
* a general class for building up a vector of DER encodable objects -
* this will eventually be superceded by ASN1EncodableVector so you should
* use that class in preference.
*/
public class DEREncodableVector
extends ASN1EncodableVector
{
/**
* @deprecated use ASN1EncodableVector instead.
*/
public DEREncodableVector()
{
}
}

View File

@@ -0,0 +1,170 @@
package org.spongycastle.asn1;
import java.io.IOException;
import java.math.BigInteger;
import org.spongycastle.util.Arrays;
/**
* Use ASN1Enumerated instead of this.
*/
public class DEREnumerated
extends ASN1Primitive
{
byte[] bytes;
/**
* return an integer from the passed in object
*
* @exception IllegalArgumentException if the object cannot be converted.
*/
public static ASN1Enumerated getInstance(
Object obj)
{
if (obj == null || obj instanceof ASN1Enumerated)
{
return (ASN1Enumerated)obj;
}
if (obj instanceof DEREnumerated)
{
return new ASN1Enumerated(((DEREnumerated)obj).getValue());
}
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.
*/
public static ASN1Enumerated getInstance(
ASN1TaggedObject obj,
boolean explicit)
{
ASN1Primitive o = obj.getObject();
if (explicit || o instanceof DEREnumerated)
{
return getInstance(o);
}
else
{
return fromOctetString(((ASN1OctetString)o).getOctets());
}
}
/**
* @deprecated use ASN1Enumerated
*/
public DEREnumerated(
int value)
{
bytes = BigInteger.valueOf(value).toByteArray();
}
/**
* @deprecated use ASN1Enumerated
*/
public DEREnumerated(
BigInteger value)
{
bytes = value.toByteArray();
}
/**
* @deprecated use ASN1Enumerated
*/
public DEREnumerated(
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 DEREnumerated))
{
return false;
}
DEREnumerated other = (DEREnumerated)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;
}
}

View File

@@ -0,0 +1,294 @@
package org.spongycastle.asn1;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Class representing the DER-type External
*/
public class DERExternal
extends ASN1Primitive
{
private ASN1ObjectIdentifier directReference;
private ASN1Integer indirectReference;
private ASN1Primitive dataValueDescriptor;
private int encoding;
private ASN1Primitive externalContent;
public DERExternal(ASN1EncodableVector vector)
{
int offset = 0;
ASN1Primitive enc = getObjFromVector(vector, offset);
if (enc instanceof ASN1ObjectIdentifier)
{
directReference = (ASN1ObjectIdentifier)enc;
offset++;
enc = getObjFromVector(vector, offset);
}
if (enc instanceof ASN1Integer)
{
indirectReference = (ASN1Integer) enc;
offset++;
enc = getObjFromVector(vector, offset);
}
if (!(enc instanceof DERTaggedObject))
{
dataValueDescriptor = (ASN1Primitive) enc;
offset++;
enc = getObjFromVector(vector, offset);
}
if (vector.size() != offset + 1)
{
throw new IllegalArgumentException("input vector too large");
}
if (!(enc instanceof DERTaggedObject))
{
throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External");
}
DERTaggedObject obj = (DERTaggedObject)enc;
setEncoding(obj.getTagNo());
externalContent = obj.getObject();
}
private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index)
{
if (v.size() <= index)
{
throw new IllegalArgumentException("too few objects in input vector");
}
return v.get(index).toASN1Primitive();
}
/**
* Creates a new instance of DERExternal
* See X.690 for more informations about the meaning of these parameters
* @param directReference The direct reference or <code>null</code> if not set.
* @param indirectReference The indirect reference or <code>null</code> if not set.
* @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
* @param externalData The external data in its encoded form.
*/
public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData)
{
this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive());
}
/**
* Creates a new instance of DERExternal.
* See X.690 for more informations about the meaning of these parameters
* @param directReference The direct reference or <code>null</code> if not set.
* @param indirectReference The indirect reference or <code>null</code> if not set.
* @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
* @param encoding The encoding to be used for the external data
* @param externalData The external data
*/
public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData)
{
setDirectReference(directReference);
setIndirectReference(indirectReference);
setDataValueDescriptor(dataValueDescriptor);
setEncoding(encoding);
setExternalContent(externalData.toASN1Primitive());
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode()
{
int ret = 0;
if (directReference != null)
{
ret = directReference.hashCode();
}
if (indirectReference != null)
{
ret ^= indirectReference.hashCode();
}
if (dataValueDescriptor != null)
{
ret ^= dataValueDescriptor.hashCode();
}
ret ^= externalContent.hashCode();
return ret;
}
boolean isConstructed()
{
return true;
}
int encodedLength()
throws IOException
{
return this.getEncoded().length;
}
/* (non-Javadoc)
* @see org.spongycastle.asn1.ASN1Primitive#encode(org.spongycastle.asn1.DEROutputStream)
*/
void encode(ASN1OutputStream out)
throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (directReference != null)
{
baos.write(directReference.getEncoded(ASN1Encoding.DER));
}
if (indirectReference != null)
{
baos.write(indirectReference.getEncoded(ASN1Encoding.DER));
}
if (dataValueDescriptor != null)
{
baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DER));
}
DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent);
baos.write(obj.getEncoded(ASN1Encoding.DER));
out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray());
}
/* (non-Javadoc)
* @see org.spongycastle.asn1.ASN1Primitive#asn1Equals(org.spongycastle.asn1.ASN1Primitive)
*/
boolean asn1Equals(ASN1Primitive o)
{
if (!(o instanceof DERExternal))
{
return false;
}
if (this == o)
{
return true;
}
DERExternal other = (DERExternal)o;
if (directReference != null)
{
if (other.directReference == null || !other.directReference.equals(directReference))
{
return false;
}
}
if (indirectReference != null)
{
if (other.indirectReference == null || !other.indirectReference.equals(indirectReference))
{
return false;
}
}
if (dataValueDescriptor != null)
{
if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor))
{
return false;
}
}
return externalContent.equals(other.externalContent);
}
/**
* Returns the data value descriptor
* @return The descriptor
*/
public ASN1Primitive getDataValueDescriptor()
{
return dataValueDescriptor;
}
/**
* Returns the direct reference of the external element
* @return The reference
*/
public ASN1ObjectIdentifier getDirectReference()
{
return directReference;
}
/**
* Returns the encoding of the content. Valid values are
* <ul>
* <li><code>0</code> single-ASN1-type</li>
* <li><code>1</code> OCTET STRING</li>
* <li><code>2</code> BIT STRING</li>
* </ul>
* @return The encoding
*/
public int getEncoding()
{
return encoding;
}
/**
* Returns the content of this element
* @return The content
*/
public ASN1Primitive getExternalContent()
{
return externalContent;
}
/**
* Returns the indirect reference of this element
* @return The reference
*/
public ASN1Integer getIndirectReference()
{
return indirectReference;
}
/**
* Sets the data value descriptor
* @param dataValueDescriptor The descriptor
*/
private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor)
{
this.dataValueDescriptor = dataValueDescriptor;
}
/**
* Sets the direct reference of the external element
* @param directReferemce The reference
*/
private void setDirectReference(ASN1ObjectIdentifier directReferemce)
{
this.directReference = directReferemce;
}
/**
* Sets the encoding of the content. Valid values are
* <ul>
* <li><code>0</code> single-ASN1-type</li>
* <li><code>1</code> OCTET STRING</li>
* <li><code>2</code> BIT STRING</li>
* </ul>
* @param encoding The encoding
*/
private void setEncoding(int encoding)
{
if (encoding < 0 || encoding > 2)
{
throw new IllegalArgumentException("invalid encoding value: " + encoding);
}
this.encoding = encoding;
}
/**
* Sets the content of this element
* @param externalContent The content
*/
private void setExternalContent(ASN1Primitive externalContent)
{
this.externalContent = externalContent;
}
/**
* Sets the indirect reference of this element
* @param indirectReference The reference
*/
private void setIndirectReference(ASN1Integer indirectReference)
{
this.indirectReference = indirectReference;
}
}

View File

@@ -0,0 +1,52 @@
package org.spongycastle.asn1;
import java.io.IOException;
public class DERExternalParser
implements ASN1Encodable, InMemoryRepresentable
{
private ASN1StreamParser _parser;
/**
*
*/
public DERExternalParser(ASN1StreamParser parser)
{
this._parser = parser;
}
public ASN1Encodable readObject()
throws IOException
{
return _parser.readObject();
}
public ASN1Primitive getLoadedObject()
throws IOException
{
try
{
return new DERExternal(_parser.readVector());
}
catch (IllegalArgumentException e)
{
throw new ASN1Exception(e.getMessage(), e);
}
}
public ASN1Primitive toASN1Primitive()
{
try
{
return getLoadedObject();
}
catch (IOException ioe)
{
throw new ASN1ParsingException("unable to get DER object", ioe);
}
catch (IllegalArgumentException ioe)
{
throw new ASN1ParsingException("unable to get DER object", ioe);
}
}
}

Some files were not shown because too many files have changed in this diff Show More