Replace spongycastle submodule with checked in code

This commit is contained in:
Daniel Martí 2015-03-31 19:56:19 +02:00
parent 4258ea1c40
commit 93c5bd4a95
2432 changed files with 400964 additions and 5 deletions

4
.gitmodules vendored
View File

@ -10,10 +10,6 @@
path = extern/Support
url = https://android.googlesource.com/platform/frameworks/support
ignore = dirty
[submodule "extern/spongycastle"]
path = extern/spongycastle
url = https://github.com/open-keychain/spongycastle
ignore = dirty
[submodule "extern/nanohttpd"]
path = extern/nanohttpd
url = https://github.com/eighthave/nanohttpd

1
extern/spongycastle vendored

@ -1 +0,0 @@
Subproject commit 9e4fb80c4f8efb8a0f8fd0c1cc1e74a421d1eb7e

22
extern/spongycastle/LICENSE.html vendored Normal file
View File

@ -0,0 +1,22 @@
<html>
<body bgcolor=#ffffff>
Copyright (c) 2000-2013 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org)
<p>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
<p>
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</body>
</html>

100
extern/spongycastle/build.gradle vendored Normal file
View File

@ -0,0 +1,100 @@
allprojects {
apply plugin: 'idea'
}
ext {
bcTestDataHome = file('core/src/test/data').absolutePath
}
subprojects {
apply plugin: 'eclipse'
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'signing'
group = 'com.madgag.spongycastle'
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from 'build/docs/javadoc'
}
task sourcesJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
}
artifacts {
archives jar
archives javadocJar
archives sourcesJar
}
if (project.hasProperty("signing.keyId")) {
signing {
sign configurations.archives
}
}
if (project.hasProperty("sonatypeUsername")) {
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: sonatypeUsername, password: sonatypePassword)
}
pom.project {
name 'Spongy Castle'
packaging 'jar'
description 'Spongy Castle is a package-rename (org.bouncycastle.* to org.spongycastle.*) of Bouncy Castle\n' +
'intended for the Android platform. Android unfortunately ships with a stripped-down version of\n' +
'Bouncy Castle, which prevents easy upgrades - Spongy Castle overcomes this and provides a full,\n' +
'up-to-date version of the Bouncy Castle cryptographic libs.'
url 'http://rtyley.github.io/spongycastle/'
scm {
url 'scm:git@github.com:rtyley/spongycastle.git'
connection 'scm:git@github.com:rtyley/spongycastle.git'
developerConnection 'scm:git@github.com:rtyley/spongycastle.git'
}
licenses {
license {
name 'Bouncy Castle Licence'
url 'http://www.bouncycastle.org/licence.html'
distribution 'repo'
}
}
developers {
developer {
id 'rtyley'
name 'Roberto Tyley'
}
}
}
}
}
}
}
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
}
sourceCompatibility = 1.5
targetCompatibility = 1.5
version = '1.50.0.0'
test {
systemProperty 'bc.test.data.home', bcTestDataHome
}
}

9
extern/spongycastle/core/build.gradle vendored Normal file
View File

@ -0,0 +1,9 @@
apply plugin: 'java'
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
}
sourceCompatibility = 1.5
targetCompatibility = 1.5
version = '1.50.0.0'

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);
}
}

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