add files

This commit is contained in:
Timothy Prepscius 2013-07-16 22:52:57 -04:00
parent cc91996404
commit 93e7a6c424
1113 changed files with 167520 additions and 0 deletions

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>

17
java/ext/apache/.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Mailiverse.Ext.Apache</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,226 @@
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.cli.probe.impl;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
//import org.apache.james.cli.probe.ServerProbe;
//import org.apache.james.domainlist.api.DomainListManagementMBean;
//import org.apache.james.rrt.api.RecipientRewriteTableManagementMBean;
import org.apache.james.user.api.UsersRepositoryManagementMBean;
public class JmxServerProbe { //implements ServerProbe {
// TODO: Move this to somewhere else
private final static String DOMAINLIST_OBJECT_NAME = "org.apache.james:type=component,name=domainlist";
private final static String VIRTUALUSERTABLE_OBJECT_NAME = "org.apache.james:type=component,name=recipientrewritetable";
private final static String USERSREPOSITORY_OBJECT_NAME = "org.apache.james:type=component,name=usersrepository";
private MBeanServerConnection mbeanServerConn;
// private DomainListManagementMBean domainListProcxy;
// private RecipientRewriteTableManagementMBean virtualUserTableProxy;
private UsersRepositoryManagementMBean usersRepositoryProxy;
private static final String fmtUrl = "service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi";
private static final int defaultPort = 9999;
private String host;
private int port;
/**
* Creates a ServerProbe using the specified JMX host and port.
*
* @param host
* hostname or IP address of the JMX agent
* @param port
* TCP port of the remote JMX agent
* @throws IOException
* on connection failures
*/
public JmxServerProbe(String host, int port) throws IOException, InterruptedException {
this.host = host;
this.port = port;
connect();
}
/**
* Creates a NodeProbe using the specified JMX host and default port.
*
* @param host
* hostname or IP address of the JMX agent
* @throws IOException
* on connection failures
*/
public JmxServerProbe(String host) throws IOException, InterruptedException {
this.host = host;
this.port = defaultPort;
connect();
}
/*
* Create a connection to the JMX agent and setup the M[X]Bean proxies.
*
* @throws IOException
* on connection failures
*/
private void connect() throws IOException {
JMXServiceURL jmxUrl = new JMXServiceURL(String.format(fmtUrl, host, port));
JMXConnector jmxc = JMXConnectorFactory.connect(jmxUrl, null);
mbeanServerConn = jmxc.getMBeanServerConnection();
try {
ObjectName name;
// name = new ObjectName(DOMAINLIST_OBJECT_NAME);
// domainListProcxy = (DomainListManagementMBean) MBeanServerInvocationHandler.newProxyInstance(mbeanServerConn, name, DomainListManagementMBean.class, true);
// name = new ObjectName(VIRTUALUSERTABLE_OBJECT_NAME);
// virtualUserTableProxy = (RecipientRewriteTableManagementMBean) MBeanServerInvocationHandler.newProxyInstance(mbeanServerConn, name, RecipientRewriteTableManagementMBean.class, true);
name = new ObjectName(USERSREPOSITORY_OBJECT_NAME);
usersRepositoryProxy = (UsersRepositoryManagementMBean) MBeanServerInvocationHandler.newProxyInstance(mbeanServerConn, name, UsersRepositoryManagementMBean.class, true);
} catch (MalformedObjectNameException e) {
throw new RuntimeException("Invalid ObjectName? Please report this as a bug.", e);
}
}
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#addUser(java.lang.String, java.lang.String)
*/
public void addUser(String userName, String password) throws Exception {
usersRepositoryProxy.addUser(userName, password);
}
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#removeUser(java.lang.String)
*/
public void removeUser(String username) throws Exception {
usersRepositoryProxy.deleteUser(username);
}
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#listUsers()
*/
public String[] listUsers() throws Exception {
return usersRepositoryProxy.listAllUsers();
}
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#setPassword(java.lang.String, java.lang.String)
*/
public void setPassword(String userName, String password) throws Exception {
usersRepositoryProxy.setPassword(userName, password);
}
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#addDomain(java.lang.String)
*/
// public void addDomain(String domain) throws Exception {
// domainListProcxy.addDomain(domain);
// }
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#removeDomain(java.lang.String)
*/
// public void removeDomain(String domain) throws Exception {
// domainListProcxy.removeDomain(domain);
// }
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#listDomains()
*/
// public String[] listDomains() throws Exception {
// return domainListProcxy.getDomains();
// }
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#listMappings()
*/
// public Map<String, Collection<String>> listMappings() throws Exception {
// return virtualUserTableProxy.getAllMappings();
// }
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#addAddressMapping(java.lang.String, java.lang.String, java.lang.String)
*/
// public void addAddressMapping(String user, String domain, String toAddress) throws Exception {
// virtualUserTableProxy.addAddressMapping(user, domain, toAddress);
// }
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#removeAddressMapping(java.lang.String, java.lang.String, java.lang.String)
*/
// public void removeAddressMapping(String user, String domain, String fromAddress) throws Exception {
// virtualUserTableProxy.removeAddressMapping(user, domain, fromAddress);
// }
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#listUserDomainMappings(java.lang.String, java.lang.String)
*/
// public Collection<String> listUserDomainMappings(String user, String domain) throws Exception {
// return virtualUserTableProxy.getUserDomainMappings(user, domain);
// }
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#addRegexMapping(java.lang.String, java.lang.String, java.lang.String)
*/
// public void addRegexMapping(String user, String domain, String regex) throws Exception {
// virtualUserTableProxy.addRegexMapping(user, domain, regex);
// }
/*
* (non-Javadoc)
*
* @see org.apache.james.cli.probe.ServerProbe#removeRegexMapping(java.lang.String, java.lang.String, java.lang.String)
*/
// public void removeRegexMapping(String user, String domain, String regex) throws Exception {
// virtualUserTableProxy.removeRegexMapping(user, domain, regex);
// }
}

View File

@ -0,0 +1,149 @@
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.user.api;
/**
* Expose user account management functionality through JMX.
*/
public interface UsersRepositoryManagementMBean {
/**
* Adds a user to this mail server.
*
*
* @param userName
* The name of the user being added
* @param password
* The password of the user being added
*/
void addUser(String userName, String password) throws Exception;
/**
* Deletes a user from this mail server.
*
*
* @param userName
* The name of the user being deleted
* @throws UsersRepositoryException
* if error
*/
void deleteUser(String userName) throws Exception;
/**
* Check if a user exists with the given name.
*
*
* @param userName
* The name of the user
* @return TRUE, if the user exists
* @throws UsersRepositoryException
* if error
*/
boolean verifyExists(String userName) throws Exception;
/**
* Total count of existing users
*
*
* @return Total count of existing users
*/
long countUsers() throws Exception;
/**
* List the names of all users
*
*
* @return List of all user names
* @throws UsersRepositoryException
* if error
*/
String[] listAllUsers() throws Exception;
/**
* Set a user's password
*
*
* @param userName
* The name of the user whose password will be changed
* @param password
* The new password
* @throws UsersRepositoryException
* if error
*/
void setPassword(String userName, String password) throws Exception;
/**
* Removes a user's alias which terminates local mail forwarding
*
*
* @param userName
* The name of the user whose alias is unset
* @throws UsersRepositoryException
* if error
*/
@Deprecated
void unsetAlias(String userName) throws Exception;
/**
* Retrieves the user's alias, if set
*
*
* @return User's alias, or NULL, if no alias is set
* @throws UsersRepositoryException
* if error
*/
@Deprecated
String getAlias(String userName) throws Exception;
/**
* Removes a user's forward email address which terminates remote mail
* forwarding
*
*
* @param userName
* The name of the user whose forward is unset
* @throws UsersRepositoryException
* if error
*/
@Deprecated
void unsetForwardAddress(String userName) throws Exception;
/**
* Retrieves the user's forward, if set
*
*
* @param userName
* The name of the user whose forward is set
* @return User's forward email address, or NULL, if no forward is set
* @throws UsersRepositoryException
* if error
*/
@Deprecated
String getForwardAddress(String userName) throws Exception;
/**
* Return true if the UserRepository has VirtualHosting enabled
*
* @return virtual
* @throws UsersRepositoryException
*/
boolean getVirtualHostingEnabled() throws Exception;
}

1
java/ext/bouncycastle Symbolic link
View File

@ -0,0 +1 @@
lcrypto-jdk15on-148

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/Mailiverse.Ext.BouncyCastle"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Mailiverse.Ext.JordanZimmerman</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,18 @@
package com.jordanzimmerman;
import org.bc.crypto.digests.SHA256Digest;
public class Hash256i {
byte[] hash(byte[] bytes)
{
SHA256Digest hash = new SHA256Digest();
hash.update(bytes, 0, bytes.length);
byte output[] = new byte[hash.getDigestSize()];
hash.doFinal(output, 0);
return output;
}
}

View File

@ -0,0 +1,25 @@
package com.jordanzimmerman;
import java.io.IOException;
/**
* Exception thrown when authentication fails
* <p>
* Released into the public domain
*
* @author Jordan Zimmerman - jordan@jordanzimmerman.com
* @see SRPFactory Full Documentation
* @version 1.1
*/
public class SRPAuthenticationFailedException extends IOException
{
public SRPAuthenticationFailedException()
{
super();
}
public SRPAuthenticationFailedException(String message)
{
super(message);
}
}

View File

@ -0,0 +1,179 @@
package com.jordanzimmerman;
import java.math.BigInteger;
/**
* Manages a client SRP session
* <p>
* Released into the public domain
*
* @author Jordan Zimmerman - jordan@jordanzimmerman.com
* @see SRPFactory Full Documentation
* @version 1.4 Make sure safeguards are checked: abort if B == 0 (mod N) or u == 0 - 2/27/07
* @version 1.3 Updated to use the SRP-6 spec - 2/21/07
* @version 1.2
*/
public class SRPClientSession
{
protected SRPClientSession ()
{
}
/**
* @param constants constants to use
* @param password password as passed to {@link SRPFactory#makeVerifier(byte[])}
*/
public SRPClientSession(SRPConstants constants, byte[] password)
{
fConstants = constants;
fPassword = password;
}
/**
* Once the server sends the salt (value s in the docs), call this method to save the value
*
* @param salt salt from the server
*/
public void setSalt_s(BigInteger salt)
{
fPrivateKey_x = SRPUtils.makePrivateKey(fPassword, salt);
fRandom_a = SRPUtils.random(fConstants);
fCommonValue_S = null;
fEvidenceValue_M1 = null;
fSessionKey_K = null;
// A = g^a
fPublicKey_A = fConstants.primitiveRoot_g.modPow(fRandom_a, fConstants.largePrime_N);
}
public void setSalt_s(byte[] v)
{ setSalt_s(new BigInteger(v)); }
/**
* Returns the public key (value A in the docs). This should be passed to the server
*
* @return A
*/
public BigInteger getPublicKey_A()
{
return fPublicKey_A;
}
public byte[] getPublicKey_A_()
{ return getPublicKey_A().toByteArray(); }
/**
* Call to save the public key (value B in the docs) when received from the server
*
* @param publicKey_B B
* @throws SRPAuthenticationFailedException if B is invalid
*/
public void setServerPublicKey_B(BigInteger publicKey_B) throws SRPAuthenticationFailedException
{
if ( fPublicKey_A == null )
{
throw new IllegalStateException("setSalt_s() has not been called yet.");
}
if ( publicKey_B.mod(fConstants.largePrime_N).equals(BigInteger.ZERO) )
{
throw new SRPAuthenticationFailedException("B%N == 0");
}
BigInteger SRP6_u = SRPUtils.calc_u(fPublicKey_A, publicKey_B);
if ( SRP6_u.mod(fConstants.largePrime_N).equals(BigInteger.ZERO) )
{
throw new SRPAuthenticationFailedException("u%N == 0");
}
// S = (B - 3(g^x))^(a + ux)
BigInteger three_g_pow_x = fConstants.srp6Multiplier_k.multiply(fConstants.primitiveRoot_g.modPow(fPrivateKey_x, fConstants.largePrime_N));
BigInteger B_minus_g_pow_x = publicKey_B.subtract(three_g_pow_x);
BigInteger ux = SRP6_u.multiply(fPrivateKey_x);
fCommonValue_S = B_minus_g_pow_x.modPow(fRandom_a.add(ux), fConstants.largePrime_N).mod(fConstants.largePrime_N);
fEvidenceValue_M1 = SRPUtils.calcM1(fPublicKey_A, publicKey_B, fCommonValue_S);
// the MD5 output is the same as the AES key length
fSessionKey_K = SRPUtils.hashToBytesMD5(fCommonValue_S);
}
public void setServerPublicKey_B(byte[] v) throws SRPAuthenticationFailedException
{ setServerPublicKey_B(new BigInteger(v)); }
/**
* After the session key has been computed, use this method to return the evidence value to send to the server (value M[1] in the docs).
*
* @return M(1)
*/
public BigInteger getEvidenceValue_M1()
{
if ( fEvidenceValue_M1 == null )
{
throw new IllegalStateException("computeCommonValue_S() has not been called yet.");
}
return fEvidenceValue_M1;
}
public byte[] getEvidenceValue_M1_()
{ return getEvidenceValue_M1().toByteArray(); }
/**
* When the server sends M(2), call this method to validate the number.
*
* @param evidenceValueFromServer_M2 M(2) from the server.
* @throws SRPAuthenticationFailedException if M(2) is incorrect
*/
public void validateServerEvidenceValue_M2(BigInteger evidenceValueFromServer_M2) throws SRPAuthenticationFailedException
{
if ( fEvidenceValue_M1 == null )
{
throw new IllegalStateException("computeCommonValue_S() has not been called yet.");
}
BigInteger M2 = SRPUtils.calcM2(fPublicKey_A, fEvidenceValue_M1, fCommonValue_S);
if ( !evidenceValueFromServer_M2.equals(M2) )
{
throw new SRPAuthenticationFailedException("M(2) is incorrect");
}
}
public void validateServerEvidenceValue_M2(byte[] v) throws SRPAuthenticationFailedException
{ validateServerEvidenceValue_M2(new BigInteger(v)); }
/**
* Returns the session common value which is the pre-hashed version of K
*
* @return common value
*/
public BigInteger getSessionCommonValue()
{
return fCommonValue_S;
}
/**
* The 16 byte session key suitable for encryption
*
* @return session key - K
*/
public byte[] getSessionKey_K()
{
return fSessionKey_K;
}
SRPConstants getConstants()
{
return fConstants;
}
protected SRPConstants fConstants;
protected byte[] fPassword;
protected BigInteger fPrivateKey_x;
protected BigInteger fRandom_a;
protected BigInteger fPublicKey_A;
protected BigInteger fCommonValue_S;
protected byte[] fSessionKey_K;
protected BigInteger fEvidenceValue_M1;
}

View File

@ -0,0 +1,48 @@
package com.jordanzimmerman;
import java.math.BigInteger;
import java.io.Serializable;
/**
* POJO for holding the prime number and primitve root.<br>
*
* Released into the public domain
*
* @author Jordan Zimmerman - jordan@jordanzimmerman.com
* @see SRPFactory Full Documentation
* @version 1.3 Updated to use the SRP-6a spec - k = H(N, g) 2/27/07
* @version 1.2 Updated to use the SRP-6 spec 2/21/07
* @version 1.1
*/
public class SRPConstants implements Serializable
{
/**
* NOTE: this constructor validates the values passed via {@link SRPUtils#validateConstants(java.math.BigInteger,java.math.BigInteger)}
*
* @param largePrime a very large prime number
* @param primitiveRoot a primitive root that relates to the prime number.
*/
public SRPConstants(BigInteger largePrime, BigInteger primitiveRoot)
{
SRPUtils.validateConstants(largePrime, primitiveRoot);
this.largePrime_N = largePrime;
this.primitiveRoot_g = primitiveRoot;
this.srp6Multiplier_k = SRPUtils.hash(SRPUtils.combine(this.largePrime_N, this.primitiveRoot_g));
}
/**
* N
*/
public final BigInteger largePrime_N;
/**
* g
*/
public final BigInteger primitiveRoot_g;
/**
* k from SRP-6
*/
public final BigInteger srp6Multiplier_k;
}

View File

@ -0,0 +1,164 @@
package com.jordanzimmerman;
import java.math.BigInteger;
/**
* An implementation of SRP-6a - Secure Remote Password Protocol. See <a href="http://srp.stanford.edu">http://srp.stanford.edu</a>
* and <a href="http://srp.stanford.edu/ndss.html">http://srp.stanford.edu/ndss.html</a>. The improvements described in
* <a href="http://srp.stanford.edu/srp6.ps">SRP-6: Improvements and Refinements to the Secure Remote Password Protocol</a> have been incorporated.
* <p>
*
* SRP attempts to eliminate many of the security problems involved in a client/server user authentication.
* I don't understand the math, but the ideas are farily simple. On the server, store a mathematically generated number that is
* based on a user chosen password and a randomly generated "salt". Both the client and server maintain a predetermined prime
* number "N" and a "primitive root" based on N called "g". The nature of all these numbers allows an authentication without
* the server needing to save the password. The client asks for the salt that was created, then a series of calculations
* are performed with the client and server exchanging the calculated values. At the end of this, both the client and server
* can safely know that authentication has occurred.
* <p>
*
* From the SRP website, SRP assures:
* <ol>
* <li>No useful information about the password P or its associated private key x is revealed during a successful run. Specifically, we wish to prevent an attacker from being able to guess and verify passwords based on exchanged messages.</li>
* <li>No useful information about the session key K is revealed to an eavesdropper during a successful run. Since K is a cryptographically strong key instead of a limited-entropy password, we are not concerned about guessing attacks on K, as long as K cannot be computed directly by an intruder.</li>
* <li>Even if an intruder has the ability to alter or create his own messages and make them appear to originate from Carol or Steve, the protocol should prevent the intruder from gaining access to the host or learning any information about passwords or session keys. At worst, an intruder should only be able to cause authentication to fail between the two parties (often termed a denial-of-service attack).</li>
* <li>If the host's password file is captured and the intruder learns the value of v, it should still not allow the intruder to impersonate the user without an expensive dictionary search. </li>
* <li>If the session key of any past session is compromised, it should not help the intruder guess at or otherwise deduce the user's password.</li>
* <li>If the user's password itself is compromised, it should not allow the intruder to determine the session key K for past sessions and decrypt them. Even present sessions should at least be protected from passive eavesdropping.</li>
* </ol>
* <p>
*
* <i>Using this library:</i><br>
* For general use, you should only need to directly use these three classes: {@link SRPFactory}, {@link SRPInputStream}
* and {@link SRPOutputStream}. Besides these three, you will use two POJOs: {@link SRPConstants} and {@link SRPVerifier}
* <p>
* For all interactions, you obtain an {@link SRPFactory} via one of the static getInstance() methods. The no-args version uses
* default values for the prime number and primitive root. The other version allows you to specify values for these.
* <p>
* The first activity is to generate a "verifier" for a password. Given a password P, this is accomplished via the {@link SRPFactory#makeVerifier(byte[])}
* method. E.g.
<code><pre>
SRPFactory.getInstance().makeVerifier(P);
</pre></code>
* This value should be stored away referenced via a username.
* <p>
*
* The second activity is a client/server session. On the server, allocate a {@link SRPServerSessionRunner} loaded with
* a session from {@link SRPFactory#newServerSession(SRPVerifier)}. On the client, allocate a {@link SRPClientSessionRunner}
* loaded with a session from {@link SRPFactory#newClientSession(byte[])}. Once you have a Session Runner, you can pass it to an
* {@link SRPInputStream} and an {@link SRPOutputStream}. For each of these streams, call both {@link SRPInputStream#authenticate(SRPRunner, SRPOutputStream)}
* and {@link SRPOutputStream#authenticate(SRPRunner, SRPInputStream)}. Once authenticated, use them as you would any I/O stream. All I/O
* on these streams are encrypted using <a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard">AES</a> with the SRP session key as the encryption key.
* <p>
*
* <i>Stream Protocol</i><br>
* The SRPInputStream/SRPOutStream authenticate using, essentially, the protocol as specified here: <a href="http://srp.stanford.edu/design.html">http://srp.stanford.edu/design.html</a>.
* All values are sent as {@link java.math.BigInteger#toString(int)} with a radix of 16. The only difference is that the method to combine values is
* unique to this library (see {@link SRPUtils#combine(java.math.BigInteger, java.math.BigInteger)}). If at any point authentication
* fails, the stream is closed.
* <p>
* Once authentication is complete, the streams use the following protocol to send data:<br>
<code><pre>
[data size][newline]
[data]
</pre></code>
* <br>
* "data size" is the number of bytes in the data block. The size is specified as radix 16 BigInteger. The data block is
* encrypted via AES using K as the key. K is an MD5 hash of S. A new data block is sent each time flush() is called on the
* output stream.
* <p>
*
* IMPORTANT: This library relies on <a href="http://java.sun.com/products/jce/">JCE</a>
* <p>
*
* Released into the public domain
*
* @author Jordan Zimmerman - jordan@jordanzimmerman.com
* @version 1.4 a) Updated to use the SRP-6a spec. b) Updated Javadoc. 2/27/07
* @version 1.3 Updated to use the SRP-6 spec 2/21/07
* @version 1.2
*/
public class SRPFactory
{
/**
* Utility for generating a verifier (using default constants)
*
* @param args args[0] is the Password
*/
public static void main(String[] args)
{
SRPVerifier verifier = SRPFactory.getInstance().makeVerifier(args[0].getBytes());
System.out.println("v: " + verifier.verifier_v.toString(16));
System.out.println("s: " + verifier.salt_s.toString(16));
}
/**
* Return a factory that uses default constants
*
* @return the factory
*/
public static SRPFactory getInstance()
{
return new SRPFactory(DEFAULT_CONSTANTS);
}
/**
* Return a factory that uses the given constants
*
* @param constants prime number constants
* @return the factory
*/
public static SRPFactory getInstance(SRPConstants constants)
{
return new SRPFactory(constants);
}
/**
* Create a new "verifier" (v in the SRP docs). A random salt value is created.
*
* @param password bytes of the password. Client will need this same password later on for a client session.
*
* @return the verifier
*/
public SRPVerifier makeVerifier(byte[] password)
{
return SRPUtils.makeVerifier(fConstants, password);
}
/**
* Start a new client session.
*
* @param password The same password that was passed to {@link #makeVerifier(byte[])}
*
* @return the client session. Normally, this is passed directly to a new {@link SRPClientSessionRunner}
*/
public SRPClientSession newClientSession(byte[] password)
{
return new SRPClientSession(fConstants, password);
}
/**
* Start a new server session.
*
* @param verifier The same verifier that was returned by {@link #makeVerifier(byte[])}
*
* @return the server session. Normally, this is passed directly to a new {@link SRPServerSessionRunner}
*/
public SRPServerSession newServerSession(SRPVerifier verifier)
{
return new SRPServerSession(fConstants, verifier);
}
private SRPFactory(SRPConstants constants)
{
fConstants = constants;
}
public static final SRPConstants DEFAULT_CONSTANTS = new SRPConstants
(
new BigInteger("115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16),
new BigInteger("2")
);
private SRPConstants fConstants;
}

View File

@ -0,0 +1,166 @@
package com.jordanzimmerman;
import java.math.BigInteger;
/**
* Manages a server SRP session
*
* <p>
* Released into the public domain
*
* @author Jordan Zimmerman - jordan@jordanzimmerman.com
* @see SRPFactory Full Documentation
* @version 1.4 Make sure safeguards are checked: abort if A == 0 (mod N) or u == 0 - 2/27/07
* @version 1.3 Updated to use the SRP-6 spec 2/21/07
* @version 1.2
*/
public class SRPServerSession
{
/**
* @param constants constants to use
* @param verifier the verifier as returned from {@link SRPFactory#makeVerifier(byte[])}
*/
public SRPServerSession(SRPConstants constants, SRPVerifier verifier)
{
fConstants = constants;
fVerifier = verifier;
fRandom_b = SRPUtils.random(fConstants);
fSRP6_u = null;
fPublicKey_A = null;
fCommonValue_S = null;
fEvidenceValue_M1 = null;
fSessionKey_K = null;
// B = 3v + g^b
fPublicKey_B = fVerifier.verifier_v.multiply(constants.srp6Multiplier_k).add(fConstants.primitiveRoot_g.modPow(fRandom_b, fConstants.largePrime_N));
}
/**
* When the client sends the public key (value A in the docs) call this method to store the value
*
* @param publicKey_A A
* @throws SRPAuthenticationFailedException if A is invalid
*/
public void setClientPublicKey_A(BigInteger publicKey_A) throws SRPAuthenticationFailedException
{
if ( publicKey_A.mod(fConstants.largePrime_N).equals(BigInteger.ZERO) )
{
throw new SRPAuthenticationFailedException("A%N == 0");
}
fPublicKey_A = publicKey_A;
fSRP6_u = SRPUtils.calc_u(fPublicKey_A, fPublicKey_B);
if ( fSRP6_u.mod(fConstants.largePrime_N).equals(BigInteger.ZERO) )
{
throw new SRPAuthenticationFailedException("u%N == 0");
}
}
public void setClientPublicKey_A(byte[] publicKey) throws SRPAuthenticationFailedException
{ setClientPublicKey_A(new BigInteger(publicKey)); }
/**
* Returns the public key that should be sent to the client (value B in the docs).
*
* @return B
*/
public BigInteger getPublicKey_B()
{
return fPublicKey_B;
}
/**
* Call to calculate the common session key (S/K in the docs)
*/
public void computeCommonValue_S()
{
if ( fPublicKey_A == null )
{
throw new IllegalStateException("setClientPublicKey_A() has not been called yet.");
}
// S = (A · v^u)^b
fCommonValue_S = fPublicKey_A.multiply(fVerifier.verifier_v.modPow(fSRP6_u, fConstants.largePrime_N)).modPow(fRandom_b, fConstants.largePrime_N);
fEvidenceValue_M1 = SRPUtils.calcM1(fPublicKey_A, fPublicKey_B, fCommonValue_S);
// the MD5 output is the same as the AES key length
fSessionKey_K = SRPUtils.hashToBytesMD5(fCommonValue_S);
}
/**
* When M(1) is received from the client, call this method to validate it
*
* @param evidenceValueFromClient_M1 M(1) as recevied from the client
* @throws SRPAuthenticationFailedException if M(1) is incorrect
*/
public void validateClientEvidenceValue_M1(BigInteger evidenceValueFromClient_M1) throws SRPAuthenticationFailedException
{
if ( fEvidenceValue_M1 == null )
{
throw new IllegalStateException("computeCommonValue_S() has not been called yet.");
}
if ( !fEvidenceValue_M1.equals(evidenceValueFromClient_M1) )
{
throw new SRPAuthenticationFailedException("M(1) incorrect");
}
}
public void validateClientEvidenceValue_M1(byte[] evidenceValueFromClient_M1) throws SRPAuthenticationFailedException
{ validateClientEvidenceValue_M1(new BigInteger(evidenceValueFromClient_M1)); }
/**
* Return the value M(2) that should be sent to the client
*
* @return M(2)
*/
public BigInteger getEvidenceValue_M2()
{
if ( fEvidenceValue_M1 == null )
{
throw new IllegalStateException("computeCommonValue_S() has not been called yet.");
}
return SRPUtils.calcM2(fPublicKey_A, fEvidenceValue_M1, fCommonValue_S);
}
/**
* Returns the session common value which is the pre-hashed version of K
*
* @return common value
*/
public BigInteger getSessionCommonValue()
{
return fCommonValue_S;
}
/**
* The 16 byte session key suitable for encryption
*
* @return session key - K
*/
public byte[] getSessionKey_K()
{
return fSessionKey_K;
}
SRPConstants getConstants()
{
return fConstants;
}
public SRPVerifier getVerifier()
{
return fVerifier;
}
private SRPConstants fConstants;
private SRPVerifier fVerifier;
private BigInteger fRandom_b;
private BigInteger fSRP6_u;
private BigInteger fPublicKey_A;
private BigInteger fPublicKey_B;
private BigInteger fCommonValue_S;
private byte[] fSessionKey_K;
private BigInteger fEvidenceValue_M1;
}

View File

@ -0,0 +1,286 @@
package com.jordanzimmerman;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.nio.ByteBuffer;
/**
* Various utilities<br>
*
* Released into the public domain
*
* @author Jordan Zimmerman - jordan@jordanzimmerman.com
* @see SRPFactory Full Documentation
* @version 1.2 Updated to use the SRP-6 spec 2/21/07
* @version 1.1
*/
class SRPUtils
{
/**
* Validates the given constants. Throws {@link IllegalArgumentException} if the values are not valid.
* NOTE: due to prime number calculations, this method can be slow.
*
* @param N large prime
* @param g primitve root of N
*/
static void validateConstants(BigInteger N, BigInteger g)
{
// Developed from "SRP JavaScript Demo" from http://srp.stanford.edu<p>
if ( !N.isProbablePrime(10) )
{
throw new IllegalArgumentException("isProbablePrime(10) failed for " + N.toString(16));
}
BigInteger n_minus_one_div_2 = N.subtract(BigInteger.ONE).divide(TWO);
if ( !n_minus_one_div_2.isProbablePrime(10) )
{
throw new IllegalArgumentException("(N-1)/2 is not prime for " + N.toString(16));
}
if( g.modPow(n_minus_one_div_2, N).add(BigInteger.ONE).compareTo(N) != 0)
{
throw new IllegalArgumentException("Not a primitive root: " + g.toString(16));
}
}
/**
* Make a verifier. First, x is generated via x = H(s, P) where H is a hash() function, s is random salt, and P is the password.
* The verifier is then v = g^x
*
* @param constants the constants to use
* @param password the password to process
* @return the verifier
*/
static SRPVerifier makeVerifier(SRPConstants constants, byte[] password)
{
BigInteger salt = random(constants);
BigInteger x = makePrivateKey(password, salt);
BigInteger v = constants.primitiveRoot_g.modPow(x, constants.largePrime_N);
return new SRPVerifier(v, salt);
}
/**
* Make a new private key via x = H(s, P) where H is a hash() function, s is random salt, and P is the password.
*
* @param password the password
* @param salt random salt
* @return the private key
*/
static BigInteger makePrivateKey(byte[] password, BigInteger salt)
{
BigInteger passwordInt = new BigInteger(password);
return hash(combine(passwordInt, salt));
}
/**
* Combine two integers into one. This method uses a novel combining method rather than simple concatenation. My assumption is
* that it will add an additional level of security as a malicious party would not be able to guess this method. The bytes from
* each value are interleaved in pairs. If the first value of the pair is odd, two bytes are taken from the second value. Any
* remaining bytes are appended at the end.
*
* @param a first value to combine
* @param b second value to combine
* @return combined value
*/
/*
static BigInteger combine(BigInteger a, BigInteger b)
{
ByteBuffer abuf = ByteBuffer.wrap(a.toByteArray());
ByteBuffer bbuf = ByteBuffer.wrap(b.toByteArray());
byte[] combined = new byte[abuf.capacity() + bbuf.capacity()];
ByteBuffer combinedbuf = ByteBuffer.wrap(combined);
abuf.rewind();
bbuf.rewind();
combinedbuf.clear();
while ( abuf.hasRemaining() && bbuf.hasRemaining() )
{
byte abyte = abuf.get();
combinedbuf.put(abyte);
byte bbyte = bbuf.get();
combinedbuf.put(bbyte);
if ( ((abyte & 1) == 0) && bbuf.hasRemaining() )
{
bbyte = bbuf.get();
combinedbuf.put(bbyte);
}
}
while ( abuf.hasRemaining() )
{
byte x = abuf.get();
combinedbuf.put(x);
}
while ( bbuf.hasRemaining() )
{
byte x = bbuf.get();
combinedbuf.put(x);
}
return new BigInteger(combined);
}
*/
static BigInteger combine(BigInteger a, BigInteger b)
{
byte[] abuf = a.toByteArray();
byte[] bbuf = b.toByteArray();
byte[] cbuf = new byte[abuf.length + bbuf.length];
int ai = 0;
int bi = 0;
int ci = 0;
int al = abuf.length;
int bl = bbuf.length;
while ( ai < al && bi < bl )
{
byte abyte = abuf[ai++];
cbuf[ci++] = abyte;
byte bbyte = bbuf[bi++];
cbuf[ci++] = bbyte;
if ( ((abyte & 1) == 0) && bi < bl )
{
cbuf[ci++] = bbuf[bi++];
}
}
while ( ai < al )
{
cbuf[ci++] = abuf[ai++];
}
while ( bi < bl )
{
cbuf[ci++] = bbuf[bi++];
}
return new BigInteger(cbuf);
}
/**
* hash a big int. Use SHA 256.
*
* @param i int to hash
* @return the hash
*/
static BigInteger hash(BigInteger i)
{
return new BigInteger(hashToBytes(i));
}
/**
* hash a big int. Use SHA 256.
*
* @param i int to hash
* @return the hash
*/
static byte[] hashToBytes(BigInteger i)
{
Hash256i d = new Hash256i();
byte[] b = i.toByteArray();
return d.hash(b);
}
/**
* hash a big int. Use MD5.
*
* @param i int to hash
* @return the hash
*/
static byte[] hashToBytesMD5(BigInteger i)
{
/*
try
{
MessageDigest sha = MessageDigest.getInstance("MD5");
byte[] b = i.toByteArray();
sha.update(b, 0, b.length);
return sha.digest();
}
catch ( NoSuchAlgorithmException e )
{
throw new UnsupportedOperationException(e);
}
*/
return hashToBytesForAES(i);
}
static byte[] hashToBytesForAES(BigInteger i)
{
return hashToBytes(i);
}
/**
* Return a random number that satsifies: 1 < r < n
*
* @param constants constants to use
* @return the random number
*/
static BigInteger random(SRPConstants constants)
{
int numberOfBytes = (constants.largePrime_N.bitLength() + (constants.largePrime_N.bitLength() - 1)) / 8;
byte[] b = new byte[numberOfBytes];
fRandom.nextBytes(b);
BigInteger i = new BigInteger(b);
// random numbers must be: 1 < r < n
BigInteger max = constants.largePrime_N.subtract(TWO);
return i.mod(max).add(TWO);
}
/**
* Calculate M(1) - H(A, B, K)
*
* @param publicKey_A generated public key - A
* @param publicKey_B generated public key - B
* @param commonValue_S the session common value - S
* @return M(1)
*/
static BigInteger calcM1(BigInteger publicKey_A, BigInteger publicKey_B, BigInteger commonValue_S)
{
return hash(combine(combine(publicKey_A, publicKey_B), commonValue_S));
}
/**
* Calculate M(1) - H(A, M[1], K)
*
* @param publicKey_A generated public key - A
* @param evidenceValue_M1 generated hash - M(1)
* @param commonValue_S the session common value - S
* @return M(1)
*/
static BigInteger calcM2(BigInteger publicKey_A, BigInteger evidenceValue_M1, BigInteger commonValue_S)
{
return hash(combine(combine(publicKey_A, evidenceValue_M1), commonValue_S));
}
/**
* Return the SRP-6 version of u - H(A, B)
*
* @param A Public Key A
* @param B Public Key B
* @return u
*/
static BigInteger calc_u(BigInteger A, BigInteger B)
{
return hash(combine(A, B));
}
private SRPUtils()
{
}
private static final BigInteger TWO = BigInteger.valueOf(2);
private static final SecureRandom fRandom = new SecureRandom();
}

View File

@ -0,0 +1,32 @@
package com.jordanzimmerman;
import java.math.BigInteger;
import java.io.Serializable;
/**
* POJO for holding the random salt and verifier<br>
*
* Released into the public domain
*
* @author Jordan Zimmerman - jordan@jordanzimmerman.com
* @see SRPFactory Full Documentation
* @version 1.1
*/
public class SRPVerifier implements Serializable
{
public SRPVerifier(BigInteger verifier, BigInteger salt)
{
this.verifier_v = verifier;
this.salt_s = salt;
}
/**
* v
*/
public final BigInteger verifier_v;
/**
* s
*/
public final BigInteger salt_s;
}

16
java/ext/json/.classpath Normal file
View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
<classpathentry kind="con" path="org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v7.0">
<attributes>
<attribute name="owner.project.facets" value="jst.utility"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/Java SE 6 (MacOS X Default)">
<attributes>
<attribute name="owner.project.facets" value="java"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin"/>
</classpath>

30
java/ext/json/.project Normal file
View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Mailiverse.Ext.Json</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="Mailiverse.Ext.Json">
<wb-resource deploy-path="/" source-path="/src"/>
</wb-module>
</project-modules>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<runtime name="Apache Tomcat v7.0"/>
<fixed facet="java"/>
<fixed facet="jst.utility"/>
<installed facet="java" version="1.6"/>
<installed facet="jst.utility" version="1.0"/>
</faceted-project>

View File

@ -0,0 +1,68 @@
JSON in Java [package org.json]
Douglas Crockford
douglas@crockford.com
2011-02-02
JSON is a light-weight, language independent, data interchange format.
See http://www.JSON.org/
The files in this package implement JSON encoders/decoders in Java.
It also includes the capability to convert between JSON and XML, HTTP
headers, Cookies, and CDL.
This is a reference implementation. There is a large number of JSON packages
in Java. Perhaps someday the Java community will standardize on one. Until
then, choose carefully.
The license includes this restriction: "The software shall be used for good,
not evil." If your conscience cannot live with that, then choose a different
package.
The package compiles on Java 1.2 thru Java 1.4.
JSONObject.java: The JSONObject can parse text from a String or a JSONTokener
to produce a map-like object. The object provides methods for manipulating its
contents, and for producing a JSON compliant object serialization.
JSONArray.java: The JSONObject can parse text from a String or a JSONTokener
to produce a vector-like object. The object provides methods for manipulating
its contents, and for producing a JSON compliant array serialization.
JSONTokener.java: The JSONTokener breaks a text into a sequence of individual
tokens. It can be constructed from a String, Reader, or InputStream.
JSONException.java: The JSONException is the standard exception type thrown
by this package.
JSONString.java: The JSONString interface requires a toJSONString method,
allowing an object to provide its own serialization.
JSONStringer.java: The JSONStringer provides a convenient facility for
building JSON strings.
JSONWriter.java: The JSONWriter provides a convenient facility for building
JSON text through a writer.
CDL.java: CDL provides support for converting between JSON and comma
delimited lists.
Cookie.java: Cookie provides support for converting between JSON and cookies.
CookieList.java: CookieList provides support for converting between JSON and
cookie lists.
HTTP.java: HTTP provides support for converting between JSON and HTTP headers.
HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers.
XML.java: XML provides support for converting between JSON and XML.
JSONML.java: JSONML provides support for converting between JSONML and XML.
XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text.

View File

@ -0,0 +1,907 @@
package org.json;
/*
Copyright (c) 2002 JSON.org
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
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.
*/
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
/**
* A JSONArray is an ordered sequence of values. Its external text form is a
* string wrapped in square brackets with commas separating the values. The
* internal form is an object having <code>get</code> and <code>opt</code>
* methods for accessing the values by index, and <code>put</code> methods for
* adding or replacing values. The values can be any of these types:
* <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
* <code>Number</code>, <code>String</code>, or the
* <code>JSONObject.NULL object</code>.
* <p>
* The constructor can convert a JSON text into a Java object. The
* <code>toString</code> method converts to JSON text.
* <p>
* A <code>get</code> method returns a value if one can be found, and throws an
* exception if one cannot be found. An <code>opt</code> method returns a
* default value instead of throwing an exception, and so is useful for
* obtaining optional values.
* <p>
* The generic <code>get()</code> and <code>opt()</code> methods return an
* object which you can cast or query for type. There are also typed
* <code>get</code> and <code>opt</code> methods that do type checking and type
* coercion for you.
* <p>
* The texts produced by the <code>toString</code> methods strictly conform to
* JSON syntax rules. The constructors are more forgiving in the texts they will
* accept:
* <ul>
* <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
* before the closing bracket.</li>
* <li>The <code>null</code> value will be inserted when there is <code>,</code>
* &nbsp;<small>(comma)</small> elision.</li>
* <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
* quote)</small>.</li>
* <li>Strings do not need to be quoted at all if they do not begin with a quote
* or single quote, and if they do not contain leading or trailing spaces, and
* if they do not contain any of these characters:
* <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
* if they are not the reserved words <code>true</code>, <code>false</code>, or
* <code>null</code>.</li>
* <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
* well as by <code>,</code> <small>(comma)</small>.</li>
* </ul>
*
* @author JSON.org
* @version 2012-04-20
*/
public class JSONArray {
/**
* The arrayList where the JSONArray's properties are kept.
*/
private final ArrayList myArrayList;
/**
* Construct an empty JSONArray.
*/
public JSONArray() {
this.myArrayList = new ArrayList();
}
/**
* Construct a JSONArray from a JSONTokener.
* @param x A JSONTokener
* @throws JSONException If there is a syntax error.
*/
public JSONArray(JSONTokener x) throws JSONException {
this();
if (x.nextClean() != '[') {
throw x.syntaxError("A JSONArray text must start with '['");
}
if (x.nextClean() != ']') {
x.back();
for (;;) {
if (x.nextClean() == ',') {
x.back();
this.myArrayList.add(JSONObject.NULL);
} else {
x.back();
this.myArrayList.add(x.nextValue());
}
switch (x.nextClean()) {
case ';':
case ',':
if (x.nextClean() == ']') {
return;
}
x.back();
break;
case ']':
return;
default:
throw x.syntaxError("Expected a ',' or ']'");
}
}
}
}
/**
* Construct a JSONArray from a source JSON text.
* @param source A string that begins with
* <code>[</code>&nbsp;<small>(left bracket)</small>
* and ends with <code>]</code>&nbsp;<small>(right bracket)</small>.
* @throws JSONException If there is a syntax error.
*/
public JSONArray(String source) throws JSONException {
this(new JSONTokener(source));
}
/**
* Construct a JSONArray from a Collection.
* @param collection A Collection.
*/
public JSONArray(Collection collection) {
this.myArrayList = new ArrayList();
if (collection != null) {
Iterator iter = collection.iterator();
while (iter.hasNext()) {
this.myArrayList.add(JSONObject.wrap(iter.next()));
}
}
}
/**
* Construct a JSONArray from an array
* @throws JSONException If not an array.
*/
public JSONArray(Object array) throws JSONException {
this();
throw new JSONException("not supported");
/*
if (array.getClass().isArray()) {
int length = Array.getLength(array);
for (int i = 0; i < length; i += 1) {
this.put(JSONObject.wrap(Array.get(array, i)));
}
} else {
throw new JSONException(
"JSONArray initial value should be a string or collection or array.");
}
*/
}
/**
* Get the object value associated with an index.
* @param index
* The index must be between 0 and length() - 1.
* @return An object value.
* @throws JSONException If there is no value for the index.
*/
public Object get(int index) throws JSONException {
Object object = this.opt(index);
if (object == null) {
throw new JSONException("JSONArray[" + index + "] not found.");
}
return object;
}
/**
* Get the boolean value associated with an index.
* The string values "true" and "false" are converted to boolean.
*
* @param index The index must be between 0 and length() - 1.
* @return The truth.
* @throws JSONException If there is no value for the index or if the
* value is not convertible to boolean.
*/
public boolean getBoolean(int index) throws JSONException {
Object object = this.get(index);
if (object.equals(Boolean.FALSE) ||
(object instanceof String &&
((String)object).equalsIgnoreCase("false"))) {
return false;
} else if (object.equals(Boolean.TRUE) ||
(object instanceof String &&
((String)object).equalsIgnoreCase("true"))) {
return true;
}
throw new JSONException("JSONArray[" + index + "] is not a boolean.");
}
/**
* Get the double value associated with an index.
*
* @param index The index must be between 0 and length() - 1.
* @return The value.
* @throws JSONException If the key is not found or if the value cannot
* be converted to a number.
*/
public double getDouble(int index) throws JSONException {
Object object = this.get(index);
try {
return object instanceof Number
? ((Number)object).doubleValue()
: Double.parseDouble((String)object);
} catch (Exception e) {
throw new JSONException("JSONArray[" + index +
"] is not a number.");
}
}
/**
* Get the int value associated with an index.
*
* @param index The index must be between 0 and length() - 1.
* @return The value.
* @throws JSONException If the key is not found or if the value is not a number.
*/
public int getInt(int index) throws JSONException {
Object object = this.get(index);
try {
return object instanceof Number
? ((Number)object).intValue()
: Integer.parseInt((String)object);
} catch (Exception e) {
throw new JSONException("JSONArray[" + index +
"] is not a number.");
}
}
/**
* Get the JSONArray associated with an index.
* @param index The index must be between 0 and length() - 1.
* @return A JSONArray value.
* @throws JSONException If there is no value for the index. or if the
* value is not a JSONArray
*/
public JSONArray getJSONArray(int index) throws JSONException {
Object object = this.get(index);
if (object instanceof JSONArray) {
return (JSONArray)object;
}
throw new JSONException("JSONArray[" + index +
"] is not a JSONArray.");
}
/**
* Get the JSONObject associated with an index.
* @param index subscript
* @return A JSONObject value.
* @throws JSONException If there is no value for the index or if the
* value is not a JSONObject
*/
public JSONObject getJSONObject(int index) throws JSONException {
Object object = this.get(index);
if (object instanceof JSONObject) {
return (JSONObject)object;
}
throw new JSONException("JSONArray[" + index +
"] is not a JSONObject.");
}
/**
* Get the long value associated with an index.
*
* @param index The index must be between 0 and length() - 1.
* @return The value.
* @throws JSONException If the key is not found or if the value cannot
* be converted to a number.
*/
public long getLong(int index) throws JSONException {
Object object = this.get(index);
try {
return object instanceof Number
? ((Number)object).longValue()
: Long.parseLong((String)object);
} catch (Exception e) {
throw new JSONException("JSONArray[" + index +
"] is not a number.");
}
}
/**
* Get the string associated with an index.
* @param index The index must be between 0 and length() - 1.
* @return A string value.
* @throws JSONException If there is no string value for the index.
*/
public String getString(int index) throws JSONException {
Object object = this.get(index);
if (object instanceof String) {
return (String)object;
}
throw new JSONException("JSONArray[" + index + "] not a string.");
}
/**
* Determine if the value is null.
* @param index The index must be between 0 and length() - 1.
* @return true if the value at the index is null, or if there is no value.
*/
public boolean isNull(int index) {
return JSONObject.NULL.equals(this.opt(index));
}
/**
* Make a string from the contents of this JSONArray. The
* <code>separator</code> string is inserted between each element.
* Warning: This method assumes that the data structure is acyclical.
* @param separator A string that will be inserted between the elements.
* @return a string.
* @throws JSONException If the array contains an invalid number.
*/
public String join(String separator) throws JSONException {
int len = this.length();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < len; i += 1) {
if (i > 0) {
sb.append(separator);
}
sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
}
return sb.toString();
}
/**
* Get the number of elements in the JSONArray, included nulls.
*
* @return The length (or size).
*/
public int length() {
return this.myArrayList.size();
}
/**
* Get the optional object value associated with an index.
* @param index The index must be between 0 and length() - 1.
* @return An object value, or null if there is no
* object at that index.
*/
public Object opt(int index) {
return (index < 0 || index >= this.length())
? null
: this.myArrayList.get(index);
}
/**
* Get the optional boolean value associated with an index.
* It returns false if there is no value at that index,
* or if the value is not Boolean.TRUE or the String "true".
*
* @param index The index must be between 0 and length() - 1.
* @return The truth.
*/
public boolean optBoolean(int index) {
return this.optBoolean(index, false);
}
/**
* Get the optional boolean value associated with an index.
* It returns the defaultValue if there is no value at that index or if
* it is not a Boolean or the String "true" or "false" (case insensitive).
*
* @param index The index must be between 0 and length() - 1.
* @param defaultValue A boolean default.
* @return The truth.
*/
public boolean optBoolean(int index, boolean defaultValue) {
try {
return this.getBoolean(index);
} catch (Exception e) {
return defaultValue;
}
}
/**
* Get the optional double value associated with an index.
* NaN is returned if there is no value for the index,
* or if the value is not a number and cannot be converted to a number.
*
* @param index The index must be between 0 and length() - 1.
* @return The value.
*/
public double optDouble(int index) {
return this.optDouble(index, Double.NaN);
}
/**
* Get the optional double value associated with an index.
* The defaultValue is returned if there is no value for the index,
* or if the value is not a number and cannot be converted to a number.
*
* @param index subscript
* @param defaultValue The default value.
* @return The value.
*/
public double optDouble(int index, double defaultValue) {
try {
return this.getDouble(index);
} catch (Exception e) {
return defaultValue;
}
}
/**
* Get the optional int value associated with an index.
* Zero is returned if there is no value for the index,
* or if the value is not a number and cannot be converted to a number.
*
* @param index The index must be between 0 and length() - 1.
* @return The value.
*/
public int optInt(int index) {
return this.optInt(index, 0);
}
/**
* Get the optional int value associated with an index.
* The defaultValue is returned if there is no value for the index,
* or if the value is not a number and cannot be converted to a number.
* @param index The index must be between 0 and length() - 1.
* @param defaultValue The default value.
* @return The value.
*/
public int optInt(int index, int defaultValue) {
try {
return this.getInt(index);
} catch (Exception e) {
return defaultValue;
}
}
/**
* Get the optional JSONArray associated with an index.
* @param index subscript
* @return A JSONArray value, or null if the index has no value,
* or if the value is not a JSONArray.
*/
public JSONArray optJSONArray(int index) {
Object o = this.opt(index);
return o instanceof JSONArray ? (JSONArray)o : null;
}
/**
* Get the optional JSONObject associated with an index.
* Null is returned if the key is not found, or null if the index has
* no value, or if the value is not a JSONObject.
*
* @param index The index must be between 0 and length() - 1.
* @return A JSONObject value.
*/
public JSONObject optJSONObject(int index) {
Object o = this.opt(index);
return o instanceof JSONObject ? (JSONObject)o : null;
}
/**
* Get the optional long value associated with an index.
* Zero is returned if there is no value for the index,
* or if the value is not a number and cannot be converted to a number.
*
* @param index The index must be between 0 and length() - 1.
* @return The value.
*/
public long optLong(int index) {
return this.optLong(index, 0);
}
/**
* Get the optional long value associated with an index.
* The defaultValue is returned if there is no value for the index,
* or if the value is not a number and cannot be converted to a number.
* @param index The index must be between 0 and length() - 1.
* @param defaultValue The default value.
* @return The value.
*/
public long optLong(int index, long defaultValue) {
try {
return this.getLong(index);
} catch (Exception e) {
return defaultValue;
}
}
/**
* Get the optional string value associated with an index. It returns an
* empty string if there is no value at that index. If the value
* is not a string and is not null, then it is coverted to a string.
*
* @param index The index must be between 0 and length() - 1.
* @return A String value.
*/
public String optString(int index) {
return this.optString(index, "");
}
/**
* Get the optional string associated with an index.
* The defaultValue is returned if the key is not found.
*
* @param index The index must be between 0 and length() - 1.
* @param defaultValue The default value.
* @return A String value.
*/
public String optString(int index, String defaultValue) {
Object object = this.opt(index);
return JSONObject.NULL.equals(object)
? defaultValue : object
.toString();
}
/**
* Append a boolean value. This increases the array's length by one.
*
* @param value A boolean value.
* @return this.
*/
public JSONArray put(boolean value) {
this.put(value ? Boolean.TRUE : Boolean.FALSE);
return this;
}
/**
* Put a value in the JSONArray, where the value will be a
* JSONArray which is produced from a Collection.
* @param value A Collection value.
* @return this.
*/
public JSONArray put(Collection value) {
this.put(new JSONArray(value));
return this;
}
/**
* Append a double value. This increases the array's length by one.
*
* @param value A double value.
* @throws JSONException if the value is not finite.
* @return this.
*/
public JSONArray put(double value) throws JSONException {
Double d = new Double(value);
JSONObject.testValidity(d);
this.put(d);
return this;
}
/**
* Append an int value. This increases the array's length by one.
*
* @param value An int value.
* @return this.
*/
public JSONArray put(int value) {
this.put(new Integer(value));
return this;
}
/**
* Append an long value. This increases the array's length by one.
*
* @param value A long value.
* @return this.
*/
public JSONArray put(long value) {
this.put(new Long(value));
return this;
}
/**
* Put a value in the JSONArray, where the value will be a
* JSONObject which is produced from a Map.
* @param value A Map value.
* @return this.
*/
public JSONArray put(Map value) {
this.put(new JSONObject(value));
return this;
}
/**
* Append an object value. This increases the array's length by one.
* @param value An object value. The value should be a
* Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
* JSONObject.NULL object.
* @return this.
*/
public JSONArray put(Object value) {
this.myArrayList.add(value);
return this;
}
/**
* Put or replace a boolean value in the JSONArray. If the index is greater
* than the length of the JSONArray, then null elements will be added as
* necessary to pad it out.
* @param index The subscript.
* @param value A boolean value.
* @return this.
* @throws JSONException If the index is negative.
*/
public JSONArray put(int index, boolean value) throws JSONException {
this.put(index, value ? Boolean.TRUE : Boolean.FALSE);
return this;
}
/**
* Put a value in the JSONArray, where the value will be a
* JSONArray which is produced from a Collection.
* @param index The subscript.
* @param value A Collection value.
* @return this.
* @throws JSONException If the index is negative or if the value is
* not finite.
*/
public JSONArray put(int index, Collection value) throws JSONException {
this.put(index, new JSONArray(value));
return this;
}
/**
* Put or replace a double value. If the index is greater than the length of
* the JSONArray, then null elements will be added as necessary to pad
* it out.
* @param index The subscript.
* @param value A double value.
* @return this.
* @throws JSONException If the index is negative or if the value is
* not finite.
*/
public JSONArray put(int index, double value) throws JSONException {
this.put(index, new Double(value));
return this;
}
/**
* Put or replace an int value. If the index is greater than the length of
* the JSONArray, then null elements will be added as necessary to pad
* it out.
* @param index The subscript.
* @param value An int value.
* @return this.
* @throws JSONException If the index is negative.
*/
public JSONArray put(int index, int value) throws JSONException {
this.put(index, new Integer(value));
return this;
}
/**
* Put or replace a long value. If the index is greater than the length of
* the JSONArray, then null elements will be added as necessary to pad
* it out.
* @param index The subscript.
* @param value A long value.
* @return this.
* @throws JSONException If the index is negative.
*/
public JSONArray put(int index, long value) throws JSONException {
this.put(index, new Long(value));
return this;
}
/**
* Put a value in the JSONArray, where the value will be a
* JSONObject that is produced from a Map.
* @param index The subscript.
* @param value The Map value.
* @return this.
* @throws JSONException If the index is negative or if the the value is
* an invalid number.
*/
public JSONArray put(int index, Map value) throws JSONException {
this.put(index, new JSONObject(value));
return this;
}
/**
* Put or replace an object value in the JSONArray. If the index is greater
* than the length of the JSONArray, then null elements will be added as
* necessary to pad it out.
* @param index The subscript.
* @param value The value to put into the array. The value should be a
* Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
* JSONObject.NULL object.
* @return this.
* @throws JSONException If the index is negative or if the the value is
* an invalid number.
*/
public JSONArray put(int index, Object value) throws JSONException {
JSONObject.testValidity(value);
if (index < 0) {
throw new JSONException("JSONArray[" + index + "] not found.");
}
if (index < this.length()) {
this.myArrayList.set(index, value);
} else {
while (index != this.length()) {
this.put(JSONObject.NULL);
}
this.put(value);
}
return this;
}
/**
* Remove an index and close the hole.
* @param index The index of the element to be removed.
* @return The value that was associated with the index,
* or null if there was no value.
*/
public Object remove(int index) {
Object o = this.opt(index);
this.myArrayList.remove(index);
return o;
}
/**
* Produce a JSONObject by combining a JSONArray of names with the values
* of this JSONArray.
* @param names A JSONArray containing a list of key strings. These will be
* paired with the values.
* @return A JSONObject, or null if there are no names or if this JSONArray
* has no values.
* @throws JSONException If any of the names are null.
*/
public JSONObject toJSONObject(JSONArray names) throws JSONException {
if (names == null || names.length() == 0 || this.length() == 0) {
return null;
}
JSONObject jo = new JSONObject();
for (int i = 0; i < names.length(); i += 1) {
jo.put(names.getString(i), this.opt(i));
}
return jo;
}
/**
* Make a JSON text of this JSONArray. For compactness, no
* unnecessary whitespace is added. If it is not possible to produce a
* syntactically correct JSON text then null will be returned instead. This
* could occur if the array contains an invalid number.
* <p>
* Warning: This method assumes that the data structure is acyclical.
*
* @return a printable, displayable, transmittable
* representation of the array.
*/
public String toString() {
try {
return '[' + this.join(",") + ']';
} catch (Exception e) {
return null;
}
}
/**
* Make a prettyprinted JSON text of this JSONArray.
* Warning: This method assumes that the data structure is acyclical.
* @param indentFactor The number of spaces to add to each level of
* indentation.
* @return a printable, displayable, transmittable
* representation of the object, beginning
* with <code>[</code>&nbsp;<small>(left bracket)</small> and ending
* with <code>]</code>&nbsp;<small>(right bracket)</small>.
* @throws JSONException
*/
public String toString(int indentFactor) throws JSONException {
StringWriter sw = new StringWriter();
synchronized (sw.getBuffer()) {
return this.write(sw, indentFactor, 0).toString();
}
}
/**
* Write the contents of the JSONArray as JSON text to a writer. For
* compactness, no whitespace is added.
* <p>
* Warning: This method assumes that the data structure is acyclical.
*
* @return The writer.
* @throws JSONException
*/
public Writer write(Writer writer) throws JSONException {
return this.write(writer, 0, 0);
}
/**
* Write the contents of the JSONArray as JSON text to a writer. For
* compactness, no whitespace is added.
* <p>
* Warning: This method assumes that the data structure is acyclical.
*
* @param indentFactor
* The number of spaces to add to each level of indentation.
* @param indent
* The indention of the top level.
* @return The writer.
* @throws JSONException
*/
Writer write(Writer writer, int indentFactor, int indent)
throws JSONException {
try {
boolean commanate = false;
int length = this.length();
writer.write('[');
if (length == 1) {
JSONObject.writeValue(writer, this.myArrayList.get(0),
indentFactor, indent);
} else if (length != 0) {
final int newindent = indent + indentFactor;
for (int i = 0; i < length; i += 1) {
if (commanate) {
writer.write(',');
}
if (indentFactor > 0) {
writer.write('\n');
}
JSONObject.indent(writer, newindent);
JSONObject.writeValue(writer, this.myArrayList.get(i),
indentFactor, newindent);
commanate = true;
}
if (indentFactor > 0) {
writer.write('\n');
}
JSONObject.indent(writer, indent);
}
writer.write(']');
return writer;
} catch (IOException e) {
throw new JSONException(e);
}
}
}

View File

@ -0,0 +1,28 @@
package org.json;
/**
* The JSONException is thrown by the JSON.org classes when things are amiss.
* @author JSON.org
* @version 2010-12-24
*/
public class JSONException extends Exception {
private static final long serialVersionUID = 0;
private Throwable cause;
/**
* Constructs a JSONException with an explanatory message.
* @param message Detail about the reason for the exception.
*/
public JSONException(String message) {
super(message);
}
public JSONException(Throwable cause) {
super(cause.getMessage());
this.cause = cause;
}
public Throwable getCause() {
return this.cause;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
package org.json;
/**
* The <code>JSONString</code> interface allows a <code>toJSONString()</code>
* method so that a class can change the behavior of
* <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
* and <code>JSONWriter.value(</code>Object<code>)</code>. The
* <code>toJSONString</code> method will be used instead of the default behavior
* of using the Object's <code>toString()</code> method and quoting the result.
*/
public interface JSONString {
/**
* The <code>toJSONString</code> method allows a class to produce its own JSON
* serialization.
*
* @return A strictly syntactically correct JSON text.
*/
public String toJSONString();
}

View File

@ -0,0 +1,78 @@
package org.json;
import java.io.StringWriter;
/*
Copyright (c) 2006 JSON.org
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
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.
*/
/**
* JSONStringer provides a quick and convenient way of producing JSON text.
* The texts produced strictly conform to JSON syntax rules. No whitespace is
* added, so the results are ready for transmission or storage. Each instance of
* JSONStringer can produce one JSON text.
* <p>
* A JSONStringer instance provides a <code>value</code> method for appending
* values to the
* text, and a <code>key</code>
* method for adding keys before values in objects. There are <code>array</code>
* and <code>endArray</code> methods that make and bound array values, and
* <code>object</code> and <code>endObject</code> methods which make and bound
* object values. All of these methods return the JSONWriter instance,
* permitting cascade style. For example, <pre>
* myString = new JSONStringer()
* .object()
* .key("JSON")
* .value("Hello, World!")
* .endObject()
* .toString();</pre> which produces the string <pre>
* {"JSON":"Hello, World!"}</pre>
* <p>
* The first method called must be <code>array</code> or <code>object</code>.
* There are no methods for adding commas or colons. JSONStringer adds them for
* you. Objects and arrays can be nested up to 20 levels deep.
* <p>
* This can sometimes be easier than using a JSONObject to build a string.
* @author JSON.org
* @version 2008-09-18
*/
public class JSONStringer extends JSONWriter {
/**
* Make a fresh JSONStringer. It can be used to build one JSON text.
*/
public JSONStringer() {
super(new StringWriter());
}
/**
* Return the JSON text. This method is used to obtain the product of the
* JSONStringer instance. It will return <code>null</code> if there was a
* problem in the construction of the JSON text (such as the calls to
* <code>array</code> were not properly balanced with calls to
* <code>endArray</code>).
* @return The JSON text.
*/
public String toString() {
return this.mode == 'd' ? this.writer.toString() : null;
}
}

View File

@ -0,0 +1,433 @@
package org.json;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
/*
Copyright (c) 2002 JSON.org
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
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.
*/
/**
* A JSONTokener takes a source string and extracts characters and tokens from
* it. It is used by the JSONObject and JSONArray constructors to parse
* JSON source strings.
* @author JSON.org
* @version 2012-02-16
*/
public class JSONTokener {
private long character;
private boolean eof;
private long index;
private long line;
private char previous;
private Reader reader;
private boolean usePrevious;
/**
* Construct a JSONTokener from a Reader.
*
* @param reader A reader.
*/
public JSONTokener(Reader reader) {
this.reader = reader;
this.eof = false;
this.usePrevious = false;
this.previous = 0;
this.index = 0;
this.character = 1;
this.line = 1;
}
/**
* Construct a JSONTokener from a string.
*
* @param s A source string.
*/
public JSONTokener(String s) {
this(new StringReader(s));
}
/**
* Back up one character. This provides a sort of lookahead capability,
* so that you can test for a digit or letter before attempting to parse
* the next number or identifier.
*/
public void back() throws JSONException {
if (this.usePrevious || this.index <= 0) {
throw new JSONException("Stepping back two steps is not supported");
}
this.index -= 1;
this.character -= 1;
this.usePrevious = true;
this.eof = false;
}
/**
* Get the hex value of a character (base16).
* @param c A character between '0' and '9' or between 'A' and 'F' or
* between 'a' and 'f'.
* @return An int between 0 and 15, or -1 if c was not a hex digit.
*/
public static int dehexchar(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'A' && c <= 'F') {
return c - ('A' - 10);
}
if (c >= 'a' && c <= 'f') {
return c - ('a' - 10);
}
return -1;
}
public boolean end() {
return this.eof && !this.usePrevious;
}
/**
* Determine if the source string still contains characters that next()
* can consume.
* @return true if not yet at the end of the source.
*/
public boolean more() throws JSONException {
this.next();
if (this.end()) {
return false;
}
this.back();
return true;
}
/**
* Get the next character in the source string.
*
* @return The next character, or 0 if past the end of the source string.
*/
public char next() throws JSONException {
int c;
if (this.usePrevious) {
this.usePrevious = false;
c = this.previous;
} else {
try {
c = this.reader.read();
} catch (IOException exception) {
throw new JSONException(exception);
}
if (c <= 0) { // End of stream
this.eof = true;
c = 0;
}
}
this.index += 1;
if (this.previous == '\r') {
this.line += 1;
this.character = c == '\n' ? 0 : 1;
} else if (c == '\n') {
this.line += 1;
this.character = 0;
} else {
this.character += 1;
}
this.previous = (char) c;
return this.previous;
}
/**
* Consume the next character, and check that it matches a specified
* character.
* @param c The character to match.
* @return The character.
* @throws JSONException if the character does not match.
*/
public char next(char c) throws JSONException {
char n = this.next();
if (n != c) {
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
n + "'");
}
return n;
}
/**
* Get the next n characters.
*
* @param n The number of characters to take.
* @return A string of n characters.
* @throws JSONException
* Substring bounds error if there are not
* n characters remaining in the source string.
*/
public String next(int n) throws JSONException {
if (n == 0) {
return "";
}
char[] chars = new char[n];
int pos = 0;
while (pos < n) {
chars[pos] = this.next();
if (this.end()) {
throw this.syntaxError("Substring bounds error");
}
pos += 1;
}
return new String(chars);
}
/**
* Get the next char in the string, skipping whitespace.
* @throws JSONException
* @return A character, or 0 if there are no more characters.
*/
public char nextClean() throws JSONException {
for (;;) {
char c = this.next();
if (c == 0 || c > ' ') {
return c;
}
}
}
/**
* Return the characters up to the next close quote character.
* Backslash processing is done. The formal JSON format does not
* allow strings in single quotes, but an implementation is allowed to
* accept them.
* @param quote The quoting character, either
* <code>"</code>&nbsp;<small>(double quote)</small> or
* <code>'</code>&nbsp;<small>(single quote)</small>.
* @return A String.
* @throws JSONException Unterminated string.
*/
public String nextString(char quote) throws JSONException {
char c;
StringBuffer sb = new StringBuffer();
for (;;) {
c = this.next();
switch (c) {
case 0:
case '\n':
case '\r':
throw this.syntaxError("Unterminated string");
case '\\':
c = this.next();
switch (c) {
case 'b':
sb.append('\b');
break;
case 't':
sb.append('\t');
break;
case 'n':
sb.append('\n');
break;
case 'f':
sb.append('\f');
break;
case 'r':
sb.append('\r');
break;
case 'u':
sb.append((char)Integer.parseInt(this.next(4), 16));
break;
case '"':
case '\'':
case '\\':
case '/':
sb.append(c);
break;
default:
throw this.syntaxError("Illegal escape.");
}
break;
default:
if (c == quote) {
return sb.toString();
}
sb.append(c);
}
}
}
/**
* Get the text up but not including the specified character or the
* end of line, whichever comes first.
* @param delimiter A delimiter character.
* @return A string.
*/
public String nextTo(char delimiter) throws JSONException {
StringBuffer sb = new StringBuffer();
for (;;) {
char c = this.next();
if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
if (c != 0) {
this.back();
}
return sb.toString().trim();
}
sb.append(c);
}
}
/**
* Get the text up but not including one of the specified delimiter
* characters or the end of line, whichever comes first.
* @param delimiters A set of delimiter characters.
* @return A string, trimmed.
*/
public String nextTo(String delimiters) throws JSONException {
char c;
StringBuffer sb = new StringBuffer();
for (;;) {
c = this.next();
if (delimiters.indexOf(c) >= 0 || c == 0 ||
c == '\n' || c == '\r') {
if (c != 0) {
this.back();
}
return sb.toString().trim();
}
sb.append(c);
}
}
/**
* Get the next value. The value can be a Boolean, Double, Integer,
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
* @throws JSONException If syntax error.
*
* @return An object.
*/
public Object nextValue() throws JSONException {
char c = this.nextClean();
String string;
switch (c) {
case '"':
case '\'':
return this.nextString(c);
case '{':
this.back();
return new JSONObject(this);
case '[':
this.back();
return new JSONArray(this);
}
/*
* Handle unquoted text. This could be the values true, false, or
* null, or it can be a number. An implementation (such as this one)
* is allowed to also accept non-standard forms.
*
* Accumulate characters until we reach the end of the text or a
* formatting character.
*/
StringBuffer sb = new StringBuffer();
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
sb.append(c);
c = this.next();
}
this.back();
string = sb.toString().trim();
if ("".equals(string)) {
throw this.syntaxError("Missing value");
}
return JSONObject.stringToValue(string);
}
/**
* Skip characters until the next character is the requested character.
* If the requested character is not found, no characters are skipped.
* @param to A character to skip to.
* @return The requested character, or zero if the requested character
* is not found.
*/
public char skipTo(char to) throws JSONException {
char c;
try {
long startIndex = this.index;
long startCharacter = this.character;
long startLine = this.line;
this.reader.mark(1000000);
do {
c = this.next();
if (c == 0) {
this.reader.reset();
this.index = startIndex;
this.character = startCharacter;
this.line = startLine;
return c;
}
} while (c != to);
} catch (IOException exc) {
throw new JSONException(exc);
}
this.back();
return c;
}
/**
* Make a JSONException to signal a syntax error.
*
* @param message The error message.
* @return A JSONException object, suitable for throwing
*/
public JSONException syntaxError(String message) {
return new JSONException(message + this.toString());
}
/**
* Make a printable string of this JSONTokener.
*
* @return " at {index} [character {character} line {line}]"
*/
public String toString() {
return " at " + this.index + " [character " + this.character + " line " +
this.line + "]";
}
}

View File

@ -0,0 +1,327 @@
package org.json;
import java.io.IOException;
import java.io.Writer;
/*
Copyright (c) 2006 JSON.org
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
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.
*/
/**
* JSONWriter provides a quick and convenient way of producing JSON text.
* The texts produced strictly conform to JSON syntax rules. No whitespace is
* added, so the results are ready for transmission or storage. Each instance of
* JSONWriter can produce one JSON text.
* <p>
* A JSONWriter instance provides a <code>value</code> method for appending
* values to the
* text, and a <code>key</code>
* method for adding keys before values in objects. There are <code>array</code>
* and <code>endArray</code> methods that make and bound array values, and
* <code>object</code> and <code>endObject</code> methods which make and bound
* object values. All of these methods return the JSONWriter instance,
* permitting a cascade style. For example, <pre>
* new JSONWriter(myWriter)
* .object()
* .key("JSON")
* .value("Hello, World!")
* .endObject();</pre> which writes <pre>
* {"JSON":"Hello, World!"}</pre>
* <p>
* The first method called must be <code>array</code> or <code>object</code>.
* There are no methods for adding commas or colons. JSONWriter adds them for
* you. Objects and arrays can be nested up to 20 levels deep.
* <p>
* This can sometimes be easier than using a JSONObject to build a string.
* @author JSON.org
* @version 2011-11-24
*/
public class JSONWriter {
private static final int maxdepth = 200;
/**
* The comma flag determines if a comma should be output before the next
* value.
*/
private boolean comma;
/**
* The current mode. Values:
* 'a' (array),
* 'd' (done),
* 'i' (initial),
* 'k' (key),
* 'o' (object).
*/
protected char mode;
/**
* The object/array stack.
*/
private final JSONObject stack[];
/**
* The stack top index. A value of 0 indicates that the stack is empty.
*/
private int top;
/**
* The writer that will receive the output.
*/
protected Writer writer;
/**
* Make a fresh JSONWriter. It can be used to build one JSON text.
*/
public JSONWriter(Writer w) {
this.comma = false;
this.mode = 'i';
this.stack = new JSONObject[maxdepth];
this.top = 0;
this.writer = w;
}
/**
* Append a value.
* @param string A string value.
* @return this
* @throws JSONException If the value is out of sequence.
*/
private JSONWriter append(String string) throws JSONException {
if (string == null) {
throw new JSONException("Null pointer");
}
if (this.mode == 'o' || this.mode == 'a') {
try {
if (this.comma && this.mode == 'a') {
this.writer.write(',');
}
this.writer.write(string);
} catch (IOException e) {
throw new JSONException(e);
}
if (this.mode == 'o') {
this.mode = 'k';
}
this.comma = true;
return this;
}
throw new JSONException("Value out of sequence.");
}
/**
* Begin appending a new array. All values until the balancing
* <code>endArray</code> will be appended to this array. The
* <code>endArray</code> method must be called to mark the array's end.
* @return this
* @throws JSONException If the nesting is too deep, or if the object is
* started in the wrong place (for example as a key or after the end of the
* outermost array or object).
*/
public JSONWriter array() throws JSONException {
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
this.push(null);
this.append("[");
this.comma = false;
return this;
}
throw new JSONException("Misplaced array.");
}
/**
* End something.
* @param mode Mode
* @param c Closing character
* @return this
* @throws JSONException If unbalanced.
*/
private JSONWriter end(char mode, char c) throws JSONException {
if (this.mode != mode) {
throw new JSONException(mode == 'a'
? "Misplaced endArray."
: "Misplaced endObject.");
}
this.pop(mode);
try {
this.writer.write(c);
} catch (IOException e) {
throw new JSONException(e);
}
this.comma = true;
return this;
}
/**
* End an array. This method most be called to balance calls to
* <code>array</code>.
* @return this
* @throws JSONException If incorrectly nested.
*/
public JSONWriter endArray() throws JSONException {
return this.end('a', ']');
}
/**
* End an object. This method most be called to balance calls to
* <code>object</code>.
* @return this
* @throws JSONException If incorrectly nested.
*/
public JSONWriter endObject() throws JSONException {
return this.end('k', '}');
}
/**
* Append a key. The key will be associated with the next value. In an
* object, every value must be preceded by a key.
* @param string A key string.
* @return this
* @throws JSONException If the key is out of place. For example, keys
* do not belong in arrays or if the key is null.
*/
public JSONWriter key(String string) throws JSONException {
if (string == null) {
throw new JSONException("Null key.");
}
if (this.mode == 'k') {
try {
this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
if (this.comma) {
this.writer.write(',');
}
this.writer.write(JSONObject.quote(string));
this.writer.write(':');
this.comma = false;
this.mode = 'o';
return this;
} catch (IOException e) {
throw new JSONException(e);
}
}
throw new JSONException("Misplaced key.");
}
/**
* Begin appending a new object. All keys and values until the balancing
* <code>endObject</code> will be appended to this object. The
* <code>endObject</code> method must be called to mark the object's end.
* @return this
* @throws JSONException If the nesting is too deep, or if the object is
* started in the wrong place (for example as a key or after the end of the
* outermost array or object).
*/
public JSONWriter object() throws JSONException {
if (this.mode == 'i') {
this.mode = 'o';
}
if (this.mode == 'o' || this.mode == 'a') {
this.append("{");
this.push(new JSONObject());
this.comma = false;
return this;
}
throw new JSONException("Misplaced object.");
}
/**
* Pop an array or object scope.
* @param c The scope to close.
* @throws JSONException If nesting is wrong.
*/
private void pop(char c) throws JSONException {
if (this.top <= 0) {
throw new JSONException("Nesting error.");
}
char m = this.stack[this.top - 1] == null ? 'a' : 'k';
if (m != c) {
throw new JSONException("Nesting error.");
}
this.top -= 1;
this.mode = this.top == 0
? 'd'
: this.stack[this.top - 1] == null
? 'a'
: 'k';
}
/**
* Push an array or object scope.
* @param c The scope to open.
* @throws JSONException If nesting is too deep.
*/
private void push(JSONObject jo) throws JSONException {
if (this.top >= maxdepth) {
throw new JSONException("Nesting too deep.");
}
this.stack[this.top] = jo;
this.mode = jo == null ? 'a' : 'k';
this.top += 1;
}
/**
* Append either the value <code>true</code> or the value
* <code>false</code>.
* @param b A boolean.
* @return this
* @throws JSONException
*/
public JSONWriter value(boolean b) throws JSONException {
return this.append(b ? "true" : "false");
}
/**
* Append a double value.
* @param d A double.
* @return this
* @throws JSONException If the number is not finite.
*/
public JSONWriter value(double d) throws JSONException {
return this.value(new Double(d));
}
/**
* Append a long value.
* @param l A long.
* @return this
* @throws JSONException
*/
public JSONWriter value(long l) throws JSONException {
return this.append(Long.toString(l));
}
/**
* Append an object value.
* @param object The object to append. It can be null, or a Boolean, Number,
* String, JSONObject, or JSONArray, or an object that implements JSONString.
* @return this
* @throws JSONException If the value is out of sequence.
*/
public JSONWriter value(Object object) throws JSONException {
return this.append(JSONObject.valueToString(object));
}
}

View File

@ -0,0 +1,68 @@
JSON in Java [package org.json]
Douglas Crockford
douglas@crockford.com
2011-02-02
JSON is a light-weight, language independent, data interchange format.
See http://www.JSON.org/
The files in this package implement JSON encoders/decoders in Java.
It also includes the capability to convert between JSON and XML, HTTP
headers, Cookies, and CDL.
This is a reference implementation. There is a large number of JSON packages
in Java. Perhaps someday the Java community will standardize on one. Until
then, choose carefully.
The license includes this restriction: "The software shall be used for good,
not evil." If your conscience cannot live with that, then choose a different
package.
The package compiles on Java 1.2 thru Java 1.4.
JSONObject.java: The JSONObject can parse text from a String or a JSONTokener
to produce a map-like object. The object provides methods for manipulating its
contents, and for producing a JSON compliant object serialization.
JSONArray.java: The JSONObject can parse text from a String or a JSONTokener
to produce a vector-like object. The object provides methods for manipulating
its contents, and for producing a JSON compliant array serialization.
JSONTokener.java: The JSONTokener breaks a text into a sequence of individual
tokens. It can be constructed from a String, Reader, or InputStream.
JSONException.java: The JSONException is the standard exception type thrown
by this package.
JSONString.java: The JSONString interface requires a toJSONString method,
allowing an object to provide its own serialization.
JSONStringer.java: The JSONStringer provides a convenient facility for
building JSON strings.
JSONWriter.java: The JSONWriter provides a convenient facility for building
JSON text through a writer.
CDL.java: CDL provides support for converting between JSON and comma
delimited lists.
Cookie.java: Cookie provides support for converting between JSON and cookies.
CookieList.java: CookieList provides support for converting between JSON and
cookie lists.
HTTP.java: HTTP provides support for converting between JSON and HTTP headers.
HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers.
XML.java: XML provides support for converting between JSON and XML.
JSONML.java: JSONML provides support for converting between JSONML and XML.
XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text.

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
<classpathentry kind="con" path="org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v7.0">
<attributes>
<attribute name="owner.project.facets" value="jst.utility"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/Java SE 6 (MacOS X Default)">
<attributes>
<attribute name="owner.project.facets" value="java"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Mailiverse.Ext.BouncyCastle</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,7 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="Mailiverse.Ext.BouncyCastle">
<wb-resource deploy-path="/" source-path="/src"/>
</wb-module>
</project-modules>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<runtime name="Apache Tomcat v7.0"/>
<fixed facet="jst.utility"/>
<fixed facet="java"/>
<installed facet="java" version="1.6"/>
<installed facet="jst.utility" version="1.0"/>
</faceted-project>

View File

@ -0,0 +1,324 @@
<html>
<body bgcolor=#ffffff>
The following organisations and people have contributed to the Bouncy Castle Cryptography Package.
<p>
Thanks, may your castles never deflate!
<p>
Organisations
<ul>
<li><a href="http://www.atlassian.com/">Atlassian Software Systems</a> donation of Confluence and JIRA licences.</li>
<li>TU-Darmstadt, Computer Science Department, RBG, for the initial
lightweight TLS implementation, which is based on MicroTLS. MicroTLS was developed
by Erik Tews at TU-Darmstadt, Computer Science Department, RBG under the supervision of Dipl.-Ing.
Henning Baer and Prof. Max Muehlhaeuser. More information on MicroTLS can be found at:
<a href="http://www.rbg.informatik.tu-darmstadt.de/MicroTLS/">http://www.rbg.informatik.tu-darmstadt.de/MicroTLS/</a>
</li>
<li>TU-Darmstadt, Computer Science Department, RBG, for the initial
Post Quantum provider, which was based on the FlexiProvider. The FlexiProvider was developed
by the Theoretical Computer Science Research Group at TU-Darmstadt, Computer Science Department, RBG under the supervision of Prof. Dr. Johannes Buchmann. More information on the history of FlexiProvider can be found at:
<a href="http://www.flexiprovider.de/">http://www.flexiprovider.de/</a>
</li>
</ul>
People
<ul>
<li>Tito Pena &lt;Fortunato.Pena&#064;AdNovum.CH&gt; - initial RC5 implementation</li>
<li>Michael Lee &lt;yfl&#064;mira.net&gt; - initial RC6 implementation, MD2 implementation</li>
<li>Nuno Santos &lt;nsantos&#064;student.dei.uc.pt&gt; - finding toString bug in certificate object.</li>
<li>Brett Sealey &lt;bretts&#064;mortbay.com&gt; - fixing the missing return problem in JDKKeyFactory (affected SSLeay private keys).</li>
<li>Victor A. Salaman &lt;salaman&#064;teknos.com&gt; - fixing the bug in Cipher.java which caused it to ignore specified providers, fixing the bug in RSAKeyGenerator which caused keys to be occasionally produced 1 bit too small.</li>
<li>Eran Librach &lt;eranl&#064;valicert.com&gt; - spotting and fixing the classLoader bug that occurs if javax.crypto and the provider aren't sharing the same classpath (occurs in JDK 1.3 and greater).</li>
<li>Jonathan Knudsen &lt;jonathan&#064;LearningPatterns.com&gt; - porting
information and restrictions when using the lightweight library with the
MIDP environment.</li>
<li>Markus Niedermann &lt;markus.niedermann&#064;softwired-inc.com&gt; - porting
information and restrictions when using the lightweight library with the
MIDP environment.</li>
<li>Mike Benham &lt;moxie&#064;thoughtcrime.org&gt; - detection and fixing of an
incorrect weak key in the DES key generation support classes. Suggestions
for simplifying DESedeParameter objects. Optimisations for the Blowfish engine
and BufferedBlockCipher class.</li>
<li>Soren Hilmer &lt;hilmer&#064;mail.tele.dk&gt; - initial implementation of
netscape certificate request classes.</li>
<li>Uwe Guenther &lt;uwe&#064;cscc.de&gt; - detection and fixing of 3 incorrect semi-weak keys in the DES key generation support classes.</li>
<li>Markus Bradtke &lt;mab&#064;informatik.uni-kiel.de&gt; - fixing of a logic
error in the JDKKeyStore class.</li>
<li>Waclaw Sierek &lt;waclaw.sierek&#064;tpg.pl&gt; - fix to setOddParity in
the DESParameter class. Assistance with adding ordering to X509 names for
certificate generation, proper processing of byte strings in the ASN1
package, further simplifications and additional classes to improve pkcs7
support, bug fixes in CertPath API.</li>
<li>Ly-Na Phu &lt;lyna.phu&#064;init-consulting.de&gt; - assistance in the
addition of ISO 9796-1 padding.</li>
<li>Stefan K&ouml;psell &lt;sk13&#064;mail.inf.tu-dresden.de&gt; - making the jdk 1.1
version of the collections API available. For further details see
<a href="http://sourceforge.net/projects/jcf/">http://sourceforge.net/projects/jcf/</a></li>
<li>Carmen Bastiaans &lt;cbastiaa&#064;microbits.com.au&gt; - fixing the improper
null pointer problem in the setting of certificates in the PKCS12 key store.</li>
<li>Tomas Gustavsson &lt;tomasg&#064;primekey.se&gt; - initial implementation of the AuthorityInformationAccess, SubjectKeyIdentifier, AuthorityKeyIdentifier, CRLNumber, CRLReason, CertificatePolicies, V2TBSCertListGenerator, and X509V2CRLGenerator classes in the ASN.1 library. Additions to GeneralName class, other bug fixes in the X.509 package. Initial implementation of the CertificationRequest classes. getRevocationReason() patch for OCSP. Patch to SemanticsInformation to prevent ClassCastException.</li>
<li>Eugen Kuleshov &lt;euxx&#064;hotmail.com&gt; - optimisations for Blowfish, assistance with PKCS12/keytool interoperability.
<li>Megan Woods &lt;meganwoods&#064;sekurafile.com&gt; - initial implementation of
ECIES.</li>
<li>Christian Geuer-Pollmann &lt;geuerp&#064;apache.org&gt; -
adding IV's to the AESWrap implementations. Initial implementation of
DESedeWrap.</li>
<li>Michael M&#252;hle &lt;michael&#064;mouling.de&gt; - contributing the initial CertPath implementation and compatibility classes, fixing provider bug in JDK 1.1 java.security.cert.CertificateFactory compatibilty class.</li>
<li>Michael Mansell &lt;me&#064;michaelmansell.com&gt; - fixing the parsing of the empty DER set in the ASN.1 library.</li>
<li>Eike Recker &lt;eike.recker&#064;gmx.de&gt; - fixing misspelling of provider reference for RSA/1 and RSA/2.</li>
<li>Chris Southern &lt;CSouthern&#064;baltimore.com&gt; - fixing misuse of specified provider in the PKCS10 certification request class.</li>
<li>Sidney Markowitz &lt;sidney&#064;sidney.com&gt; - fixing null pointed exception on unknown OID in X509Name class, initial implementation of the three AES engines.</li>
<li>Chris Kerr &lt;ckerr&#064;filonet.ca&gt; - initial implementation of the cms,
asn1.cms, and the mail/smime packages,
assistance in simplifying the ASN.1 package, miscellaneous other optimisations,
NIST CertPath certification test, PKIXPolicyNode class, CertPath subtree validation and policy tree construction. We also
wish to acknowledge the generosity of Filonet
Corporation for allowing Chris to make the initial cms and mail/smime packages available to us.</li>
<li>Mike Bean &lt;mbean&#064;lucentradius.com&gt; - fixing the fall through bug
in the IV algorithm parameters class.</li>
<li>Martin Petraschek &lt;e9526225&#064;student.tuwien.ac.at&gt; - fixing ASN1
tagging so tag values up to 30 are now supported.</li>
<li>Jess Garms &lt;jgarms&#064;yahoo.com&gt; - fixing 112/168 key size bug for
DESede key generation.</li>
<li>Mike Bremford &lt;mike&#064;big.faceless.org&gt; - contributing the inital PKCS7 implementation.</li>
<li>Shankar Srinivasan &lt;ssr002&#064;yahoo.com&gt; - S/Mime interoperability testing and debugging.</li>
<li>Stef Hoeben &lt;ilsestef&#064;skynet.be&gt; - adding Montgomery multiplication to the BigInteger class.</li>
<li>Klaudiusz Ciosk &lt;kciosk&#064;max.com.pl&gt; - improving the compatibility of
the SMIME package with the Sun JCE.</li>
<li>Thomas Houtekier &lt;Thomas.Houtekier&#064;tectrade.net&gt; - S/Mime testing and debugging. Interoperability with
Biztalk.</li>
<li>Don Hillsberry &lt;hillsber&#064;dialcorp.com&gt; - S/Mime testing and debugging.</li>
<li>Kazuo Furuya &lt;kfuruya&#064;infoteria.co.jp&gt; - fixing root certificate chaining bug in PKCS12 key store.</li>
<li>Jason Novotny &lt;jdnovotny&#064;lbl.gov&gt; - initial work on the openSSL PEM processing.</li>
<li>Joel Hockey &lt;joel.hockey&#064;qsipayments.com&gt; - initial work on the openSSL PEM processing.</li>
<li>John Steenbruggen &lt;JohnS&#064;geotrust.com&gt; - fixing CertificationRequestInfo to handle cert request info objects without attribute blocks.</li>
<li>Justin Chapweske &lt;justin&#064;chapweske.com&gt; - ordering patch for Tiger message digest.</li>
<li>John Serock &lt;jserock&#064;hotmail.com&gt; - fixing null pointer exception
in constructor for ExtendedKeyUsage. Fixing of base OID bug in KeyPurposeId.
Compliance of KeyUsage extension return value with security API.</li>
<li>Sascha Weinreuter &lt;Sascha.Weinreuter&#064;cit.de&gt; - fixed SMIME saveChanges() bug.</li>
<li>Andre Wehnert &lt;aw5&#064;mail.inf.tu-dresden.de&gt; - fixing key schedule problem in RC5-64, fixing buffer cleaning issue in buffered block cipher.</li>
<li>Luigi Lo Iacono &lt;lo_iacono&#064;nue.et-inf.uni-siegen.de&gt; - adding SIC
mode to the blockciphers in the provider.</li>
<li>Tim Sakach &lt;tsakach&#064;certivo.net&gt; - SMIME v2 compatibility patches.</li>
<li>Marcus Povey &lt;mpovey&#064;brookes.ac.uk&gt; - adding the PGP mode to the lightweight API and the provider.</li>
<li>Sebastian Clau&szlig; &lt;sc2&#064;inf.tu-dresden.de&gt; - adding randomness setting
to the certificate and CRL generators.</li>
<li>Nicolas Bielza &lt;nicolas.bielza&#064;alligacom.com&gt; - isolating the tagging bug in the ASN.1 library that was misrepresenting some ASN.1 constructed data types. Contributions to the streaming S/MIME classes.</li>
<li>Casey Marshall &lt;rsdio&#064;metastatic.org&gt; - fixing the clone problem with Macs in the clean room JCE.
<li>Rick Zeldes &lt;rick.zeldes&#064;eds.com&gt; - initial code for CMS/SMIME CompressedData.</li>
<li>Jarek Gawor &lt;gawor&#064;mcs.anl.gov&gt; - fixing ASN.1 sequence unpacking in BasicConstraints constructor.</li>
<li>Brett Neumeier &lt;random&#064;rnd.cx&gt; - patch to OriginatorIdentifierOrKey object, improvements to encoders package, introduction of UrlBase64.</li>
<li>Graham Coles &lt;graham.coles&#064;retail-logic.com&gt; - patch to isParityAdjusted in DESKeySpec.</li>
<li>J&ouml;rn von Kattch&eacute;e &lt;J.Kattchee&#064;seeburger.de&gt; - patch to SMIMEGenerator for preventing class cast exceptions with BodyParts containing Multipart objects.</li>
<li>Matteo Artuso &lt;matartuso&#064;libero.it&gt; - picking up the possible overead in ASN1InputStream.</li>
<li>Julian Morrison &lt;julian&#064;extropy.demon.co.uk&gt; - spotting the slow down
in Diffie-Hellman key generation.</li>
<li>Elmar Sonnenschein &lt;eso&#064;esomail.de&gt; - fix to long conversion in clean room
SecureRandom.</li>
<li>J&ouml;rn Schwarze &lt;JSchwarze&#064;ulc.de&gt; - Locale fix for the clean room JCE.</li>
<li>Bryan Lovquist &lt;bkl&#064;cps.com.au&gt; - Other provider compatibility fixes for CMS signing.</li>
<li>Artem Portnoy &lt;Artem_Portnoy&#064;ibi.com&gt; - generalisations for CMSProcessableBodyPart in S/MIME. Header fix for mime messages.</li>
<li>Michael H&auml;usler &lt;haeusler&#064ponton-consulting.de&gt; - missing OID update for SHA1 with RSA Signature.</li>
<li>Johan Seland &lt;johans&#064netfonds.no&gt; - general toString for BigInteger class.</li>
<li>Johannes Nicolai &lt;johannes.nicolai&#064novosec.com&gt; - further enhancements to OCSP response generation, fix to CertificateID issuer.</li>
<li>Marc Doberva &lt;marc.doberva&#064ilex-si.com&gt; - help in isolating the JSSE/BC RSA key issue.</li>
<li>Jan Dvorak &lt;jan.dvorak&#064mathan.cz&gt; - initial implementation of the light weight Null block cipher.</li>
<li>Joe Cohen &lt;jcohen&#064forumsys.com&gt; - converting the ArrayOutOfBoundsException in DERInputStream into what it should have been.</li>
<li>Chris Long&lt;aclong&#064ece.cmu.edu&gt; - adding public key decoding to PEMReader.</li>
<li>Hes Siemelink&lt;hes&#064izecom.com&gt; - findIssuer fix for CertPathBuilder, toMimeMessage converter for Mail API, getSize() fix for zero length messages in SMIMEMessage.</li>
<li>Stefan Puiu&lt;stefanpuiuro&#064yahoo.com&gt; - initial implementation V3 policy mapping, policy qualifier objects in ASN.1 X.509 package.</li>
<li>Kaiser Yang &lt;kaiseryang&#064;yahoo.com&gt; - Finding BigInteger loop problem in prime generation.</li>
<li>Jiri Urbanec &lt;jiri.urbanec&#064logicacmg.com&gt; - patch to fix defect in DERBMPString.equals().</li>
<li>Justin Kolb &lt;jkolb&#064pristx.com&gt; - patch to DSA signature generation in OpenPGP. Fix for the unexpected "Unexpected end of ZLIB input stream" exception.</li>
<li>Ralf Hauser &lt;ralfhauser&#064gmx.ch&gt; - patch to exception handling in PublicKeyRing, PEMReader, 1.4 build script, X509 Certificate Factory, CertPathValidatorUtilities.</li>
<li>Michal Dvorak &lt;M_Dvorak&#064kb.cz&gt; - getNextUpdate patch for OCSP SingleResp.</li>
<li>Klaus Greve Fiorentini &lt;Klaus&#064cpqd.com.br&gt; - array fix in PGP PublickKeyEncSessionPacket.</li>
<li>Olivier Refalo &lt;Olivier_Refalo&#064fpl.com&gt; - null pointer exception fix for JDK 1.3 CMSSignedData objects.</li>
<li>Mariusz Bandola &lt;mariusz.bandola&#064cryptotech.com.pl&gt; - patch to DERGeneralizedTime. Compliance patch for OCSP TBSRequest class. Patch to X509Name for delaing with general objects in sequences.</li>
<li>Brien Oberstein &lt;brien.oberstein&#064transacttools.net&gt; - patch to S2K algorithm in OpenPGP, initial PGP version 3 secret key support, initial PGP version 3 signature generation, RIPEMD160 addition to PGPUtil.</li>
<li>Ian Haywood &lt;ian&#064haywood.bpa.nu&gt; - addition of getSignatureType to PGPSignature.</li>
<li>Jonathan Edwards &lt;s34gull&#064mac.com&gt; - initial support for reading multiple rings from a PGP key file.</li>
<li>Andrew Thornton &lt;andrew&#064caret.cam.ac.uk&gt; - patch for RSA PUBLIC KEY in PEMReader.</li>
<li>Gregor Leander &lt;gl&#064bos-bremen.de&gt; - initial parsing of multiple sequence entries in an X.500 Name.</li>
<li>Antoon Bosselaers &lt;Antoon.Bosselaers&#064esat.kuleuven.ac.be&gt; - help with RipeMD320 implementation.</li>
<li>Peter Sylvester &lt;Peter.Sylvester&#064edelweb.fr&gt; - improvements to the ASN.1 BasicConstraints object.</li>
<li>Doug &lt;ummmmm&#064myrealbox.com&gt; - addition of isEncryptionKey method to OpenPGP public keys.</li>
<li>Francois Staes &lt;fstaes&#064netconsult.be&gt; - improvements to DEBitString, DERGeneralizedTime and initial implimentation of DERGeneralString, addition of settable signed content info to CMSSignedDataGenerator, patch to DH key agreement.</li>
<li>W.R. Dittmer &lt;wdittmer&#064cs.vu.nl&gt; - patch to decoding of SignatureCreationTime in BCPG. Patch to PGPKeyPair to fix nullpointer exception.</li>
<li>Perez Paz Luis Alberto &lt;laperez&#064banxico.org.mx&gt; - patch to use of BitString in X.500 name.</li>
<li>James Wright &lt;James_Wright&#064harte-hanks.com&gt; - patches for dealing with "odd" ArmoredInputStreams.</li>
<li>Jim Ford &lt;jim&#064muirford.com&gt; - patch to PGPSecretKey to avoid null pointer exception on encoding secret keys, comments on KeyExpirationTime, getBitStrength for ElGamal keys. Signature creation time patch for newly created v4 signatures.</li>
<li>Michael Hausler &lt;haeusler&#064ponton-consulting.de&gt; - extra aliases for provider.</li>
<li>Sai Pullabhotla &lt;psai&#064linoma.com&gt; - fix to PGP compressed data generator to improve compression levels. Performance improvements for KeyBasedLargeFileProcessor.</li>
<li>Joseph Miller &lt;joseph&#064digiweb.net.nz&gt; - addition of ZeroBytePadding.</li>
<li>Lars &lt;xyz&#064sagemdenmark.dk&gt; - patch to explicit padded mode for CBC block cipher MAC.</li>
<li>Jeroen van Vianen &lt;jeroen&#064vanvianen.nl&gt; - the Signed and Encrypted mail example.</li>
<li>Jun Sun &lt;JSun&#064diversinet.com&gt; - patch to SecureRandom to work around problem in wtk 1.0.4 and wtk 2.1.</li>
<li>Petr Dukem &lt;pdukem&#064email.cz&gt; - patch to CMSSignedDataGenerator to allow it to work with PKCS11 providers.</li>
<li>Filipe Silva &lt;filipe.silva&#064wedoconsulting.com&gt; - patch to fix overead issue in BCPGInputStream.</li>
<li>Alpesh Parmar &lt;alps&#064linuxmail.org&gt; - patch for class cast problem in PGPPublicKey.getSignatures().</li>
<li>Jay Gengelbach &lt;jgengelbach&#064webmethods.com&gt; - patch to fix isSigningKey in PGPSecretKey class, patch to hashedPackets in PGP signatureGenerator, initial cut for indefinite length output.</li>
<li>Doug &lt;doug&#064tigerprivacy.com&gt; - public key ring patches for ElGamal Signatures, problem key ring data.</li>
<li>Matthew Mundy &lt;mmundy1&#064umbc.edu&gt; - infinite loop prevention patch to PKCS5S2ParametersGenerator.</li>
<li>Tom Cargill &lt;cargill&#064profcon.com&gt; - spelling patch in provider.</li>
<li>Breitenstrom Christian &lt;C.Breitenstrom&#064t-systems.com&gt; - compatibility patch to SignaturePacket, DetachedSignatureProcessor.</li>
<li>Zanotti Mirko &lt;zanotti&#064cad.it&gt; - patch to ordered equality test for X509Name.</li>
<li>Nicola Scendoni &lt;nscendoni&#064babelps.it&gt; - patch to add sorting to CertPath validation.</li>
<li>Ville Skytt&auml; &lt;ville.skytta&#064iki.fi&gt; - patch to CRLDistPoint for cRLIssuer field. KeyStore compliance on add patches. DiffieHellman patch for provider compliance. Exception handling patch in PEMReader.</li>
<li>Bruce Gordon &lt;bruce.gordon&#064savvis.net&gt; - patch to secret key creation encoding NullPointerException in OpenPGP, speed up for BCPGInputStream.</li>
<li>Miles Whiteley &lt;Miles.Whiteley&#064savvis.net&gt; - "223" fix for BCPGInputStream new packets.</li>
<li>Albert Moliner &lt;amoliner&#064evintia.com&gt; - initial TSP implementation.</li>
<li>Carlos Lozano &lt;carlos&#064evintia.com&gt; - initial TSP implementation, patch to SignerInformation for supporting repeated signers, initial updates for supporting repeated attributes in CMS.</li>
<li>Javier Delgadillo &lt;javi&#064javi.codewarp.org&gt; - initial Mozilla PublicKeyAndChallenge classes.</li>
<li>Joni Hahkala &lt;joni.hahkala&#064cern.ch&gt; - initial implementations of VOMS Attribute Certificate Validation, IetfAttrSyntax, and ObjectDigestInfo. We also wish to thank the <a href="http://www.eu-egee.org">EGEE project</a> for making the work available.</li>
<li>Rolf Schillinger&lt;rolf&#064sir-wum.de&gt; - initial implementation of Attribute Certificate generation.</li>
<li>Sergey Bahtin &lt;Sergey_Bahtin&#064yahoo.com&gt; - fix for recovering certificate aliases in BKS and UBER key stores. Initial implementations of GOST-28147, GOST-3410, EC GOST-3410, GOST OFB mode (GOFB) and GOST-3411.</li>
<li>Franck Leroy &lt;Franck.Leroy&#064keynectis.com&gt; - ANS.1 set sorting. Contributions to TSP implementation. Test vectors for Bleichenbacher's forgery attack.</li>
<li>Atsuhiko Yamanaka &lt;ymnk&#064jcraft.com&gt; - patch for improving use of Montgomery numbers in BigInteger library. Patch to use size of private exponent in DH parameters.</li>
<li>Nickolay Bolshackov &lt;tyrex&#064reksoft.ru&gt; - patch for class cast exception in AuthorityInformationAccess class.</li>
<li>Soren Hilmer &lt;soren.hilmer&#064tietoenator.com&gt; - patches for CertID with issuerSerial set in TSP implementation, additional compliance testing.</li>
<li>Steve Mitchell &lt;mitchell&#064intertrust.com&gt; - patch for stateful path validator fix. Patch to allow BigInteger class to create negative numbers from byte arrays. Additions to allow different providers to be used for asymmetric/symmetric encryption in OpenPGP.
Optimisation to avoid redundant verification in path validator. Suggestion to use PKIXParameters.getSigProvider() correctly.</li>
<li>Dirk Eisner &lt;D.Eisner&#064seeburger.de&gt; - initial implementation of ISO 78164-4 padding.</li>
<li>Julien Pasquier &lt;julienpasquier&#064free.fr&gt; - initial implementation of attribute classes from RFC 3126. Fix to KEKIdentifier, OtherKeyAttribute parsing. Initial ContentHints class.</li>
<li>Matteo &lt;matartuso&#064libero.it&gt; - sequence patch to ASN1Dump.</li>
<li>Andrew Paterson &lt;andrew.paterson&#064burnsecs.com&gt; - patches to PGP tools, isRevoked method on PGPPublicKey.</li>
<li>Vladimir Molotkov &lt;vladimir.n.molotkov&#064intel.com&gt; - extensive provider exception handling compliance testing.</li>
<li>Florin Kollan &lt;adlocflo&#064web.de&gt; - fix to ElGamalKeyParameters equality testing.</li>
<li>Pavel Vassiliev &lt;paulvas&#064gmail.com&gt; - Initial GOST28147Mac implementation.</li>
<li>Tom Pesman &lt;tom&#064tnux.net&gt; - addition of DES-EDE encryption for RSAPrivate keys to PEMWriter.</li>
<li>Lukasz Kowalczyk &lt;lukasz.b.kowalczyk&#064gmail.com&gt; - patch to fix parsing issue with OpenSSL PEM based certificate requests.</li>
<li>Arndt Hasch &lt;Arndt.Hasch&#064maxence.de&gt; - additional fix for partial reading with new style PGP packets.</li>
<li>Fix Bernd (KCDP 11) &lt;bernd.fix&#064credit-suisse.com&gt; - fix for 31 byte issue and exception throwing by Whirlpool.</li>
<li>David M. Lee &lt;dmlee&#064Crossroads.com&gt; - code for add and remove secret key in the PGPSecretKeyRing class. Additions to S/MIME and CMS unit tests.</li>
<li>Mike Dillon &lt;md5&#064embody.org&gt; - additional checks for PGP secret and public key construction, patches to copyWithNewPassword.</li>
<li>tu-vi cung &lt;t2cung&#064hotmail.com&gt; - patch for out of bounds problem in getDecoderStream method.</li>
<li>Chris Schultz &lt;cschultz&#064gmail.com&gt; - fix for InputStream constructor for X509V2AttributeCertificate.</li>
<li>David M. Lee &lt;dmlee&#064Crossroads.com&gt; - implementation assistance with streaming CMS classes.</li>
<li>Joel Rees &lt;rees&#064ddcom.co.jp&gt; - fix to correct getOID methods from returning same set on X.509 attribute certificates.</li>
<li>Francesc Sau &lt;francesc.sau&#064partners.netfocus.es&gt; - micro fix for tsp Accuracy class.</li>
<li>Larry Bugbee &lt;bugbee&#064mac.com&gt; - initial ECNR implementation.</li>
<li>Remi Blancher &lt;Remi.Blancher&#064keynectis.com&gt; - Contributions to TSP implementation. Initial implementation of RFC 3739 and ICAO ASN.1 classes.</li>
<li>Brian O'Rourke &lt;brianorourke&#064gmail.com&gt; - patch for signature creation time override in OpenPGP.</li>
<li>Andreas Schwier &lt;andreas.schwier&#064cardcontact.de&gt; - initial implementation of ISO9797 MAC Algorithm 3, addition of DES-EDE 64 MAC to the provider, fix to EC point encoding, addition of EC and RSA-PSS OIDs to CMS, addition of AES-CMAC and DESede-CMAC to JCE provider.</li>
<li>David Josse &lt;david.josse&#064transacttools.net&gt; - Patch for trailer function in version 2 signature packets.</li>
<li>Kishimoto Kazuhiko &lt;kazu-k&#064hi-ho.ne.jp&gt; - RFC 3280 updates to policy processing in the CertPath validator. Additional test data not covered by NIST.</li>
<li>Lawrence Tan &lt;lwrnctan&#064gmail.com&gt - Large field OID sample test data. Missing key types in JDKKeyFactory.</li>
<li>Carlos Valiente &lt;superdupont&#064gmail.com&gt; - Addition of CRL writing to the PEMWriter class.</li>
<li>Keyon AG, Martin Christinat, <a href="http://www.keyon.ch">http://www.keyon.ch</a> - fixing incorrect
ASN.1 encoding of field elements in X9FieldElement class.</li>
<li>Olaf Keller, &lt;olaf.keller.bc&#064bluewin.ch&gt; - initial implementation of the elliptic curves over binary fields F2m. Additional tests and modifications to elliptic curve support for both F2m and Fp. Performance improvements to F2m multiplication. Initial implementation of WNAF/WTNAF point multiplication. Improvement to k value generation in ECDSA.</li>
<li>J&ouml;rg Eichhorn &lt;eichhorn&#064ponton-consulting.de&gt; - patch to fix EOF read on SharedFileInputStream, support for F2m compression.</li>
<li>Karsten Ohme &lt;widerstand&#064t-online.de&gt; - initial check against for out of range data on non byte aligned RSA keys. Addition of equals/hashCode on ECCurve.Fp. Additional curve type support for Fp, contributions to F2m compression. F2m decoding for ECPointUtil. Infinity fix and prime192v2 fix for Fp. Extra validation for RSA key creation. Fix to name typos for some OpenSSL key generators. RFC-1779 table, improved RFC 2253 compliance for X509Name. Additional constructor validation for X.509/ESS ASN.1 classes. Validation for Printable, IA5, and Numeric Strings.
Support for surrogate pairs in DERUTF8String, DER UTF8 test. Additional X.509 name attributes for ISIS-MTT, RFC 3039, addition of indirect CRL support, initial X509 LDAP CertStore implementation, CertificatePair class, and X509CertificatePair class. Contributions to X509Store/Parser infrastructure and design.
CertPath support for implicit DSA parameters and a range of NameConstraints. Addition of support for V1 attribute certificates and attribute certificate path validation. Initial classes for ASN.1 ISIS-MTT support. Enhancements for improving compliance with the NIST CertPath tests.</li>
<li>Carlos Lozano Ruiz &lt;carlos&#064tradise.com&gt; - patch for &lt;ctrl&gt;&lt;m&gt; only handling in CRLFOutputStream.</li>
<li>John Alfred Prufrock &lt;j.a.prufrock&#064gmail.com&gt; - mods to GOST-3411 and MD2 to support ExtendedDigest.</li>
<li>Stefan Neusatz Guilhen &lt;sneusatz&#064gmail.com&gt; - initial version of RoleSyntax, improvements to AttributeCertificateHolder and AttributeCertificateIssuer.</li>
<li>Marzio Lo Giudice &lt;marzio.logiudice&#064gmail.com&gt; - fix to endianess in KDF2BytesGenerator, additional KDF2 tests.</li>
<li>Georg Lippold &lt;georg.lippold&#064gmx.de&gt; - initial implementation of NaccacheStern cipher.</li>
<li>Chris Viles &lt;chris_viles&#064yahoo.com&gt; - fix to SignatureSubpacket critical bit setting.</li>
<li>Pasi Eronen &lt;Pasi.Eronen&#064nokia.com&gt; - extra toString() support for ASN.1 library. Initial patch for large OID components.</li>
<li>Lijun Liao &lt;lijun.liao&#064rub.de&gt; - performance enhancements for SHA family of digests. Bug report and patch for blank line handling in ArmoredInputStream.</li>
<li>Maria Ivanova &lt;maria.ivanova&#064gmail.com&gt; - support for tags > 30 in ASN.1 parsing.</li>
<li>Armin H&auml;berling &lt;arminha&#064student.ethz.ch&gt; - first cut of internationalisation, initial PKIX validation classes.</li>
<li>Marius Schilder &lt;mschilder&#064google.com&gt; - main set of test vectors for Bleichenbacher's forgery attack.</li>
<li>Xavier Le Vourch &lt;xavier&#064brittanysoftware.com&gt; - general code clean ups.</li>
<li>Erik Tews &lt;e_tews&#064cdc.informatik.tu-darmstadt.de&gt; - initial threaded random seed generator.</li>
<li>Thomas Dixon &lt;reikomusha&#064gmail.com&gt; - initial implementations of TEA/XTEA, Salsa20, ISAAC, and Noekeon. XTEA enhancements.</li>
<li>Frank Cornelis &lt;info&#064frankcornelis.be&gt;- addition of crlAccessMethod in X509ObjectIdentifiers.</li>
<li>Rui Joaquim &lt;rjoaquim&#064cc.isel.ipl.pt&gt; - initial implementation of RSA blinding for signatures.</li>
<li>David Stacey &lt;DStacey&#064allantgroup.com&gt; - addition of trust packet checking on revocation signatures in PGPSecretKeyRing.</li>
<li>Martijn Brinkers &lt;list&#064mitm.nl&gt; - better exception handling in CMS enveloping, "just in time" modifications for CRL and Sequence evaluation.</li>
<li>Julius Davies &lt;juliusdavies&#064gmail.com&gt; - additional modes and algorithm support in PEMReader</li>
<li>Matthias &lt;g&#064rtner.de&gt; - GnuPG compatibility changes for PBEFileProcessor.</li>
<li>Olga K&auml;thler &lt;olga.kaethler&#064hjp-consulting.com&gt; - initial implementation of TeleTrusT EC curves, additional ISO 9797 MACs, contributions to EAC OIDs, addition of EAC algorithms to CMS Signing.</li>
<li>Germano Rizzo &lt;germano.rizzo&#064gmail.com&gt; - initial implementation of CMac, EAX, HC-128, and HC-256, optimisations for Salsa20.</li>
<li>N&uacute;ria Mar&iacute; &lt;numaa&#064hotmail.com&gt; - patch for alternate data type recoginition in CMSSignedDataParser.</li>
<li>Janis Schuller &lt;js&#064tzi.de&gt; - addition of NotationData packets for OpenPGP.</li>
<li>Michael Samblanet &lt;mike&#064samblanet.com&gt; - patches towards improved Sun/default provider support in CMS.</li>
<li>Mike StJohns &lt;mstjohns&#064comcast.net&gt; - patches for supporting empty subject in X.509 certificate generation, noneWithECDSA.</li>
<li>Ramon Keller &lt;ramon.keller&#064gmx.ch&gt; - patch to deal with null revocations return from other CRL in X509V2CRLGenerator.</li>
<li>Mark Nelson &lt;mark&#064nbr.com&gt; - correction to excluded DN in name constraints processing for PKIX processing.</li>
<li>Eugene Golushkov &lt;eugene_gff&#064ukr.net&gt; - mask fix to single byte read in TlsInputStream.</li>
<li>Julien Pasquier &lt;julienpasquier&#064free.fr&gt; - additional classes for supporting signature policy and signer certificates in the ASN.1 esf and ess libraries.</li>
<li>Peter Knopp &lt;pknopp&#064mtg.de&gt; - fix for named curve recognition in ECGOST key generation.</li>
<li>Jakub Gwozdz &lt;gwozdziu&#064rpg.pl&gt; - addition of getTsa() to TimeStampTokenInfo.</li>
<li>Bartosz Malkowski &lt;bmalkow&#064tigase.org&gt; - initial implementation of VMPC cipher, VMPCRandomGenerator, VMPCMac.</li>
<li>Tal Yacobi &lt;tal.yacobi&#064octavian-tech.com&gt; - fix for issue in OpenPGP examples [#BJA-55].</li>
<li>Massimiliano Ziccardi &lt;massimiliano.ziccardi&#064gmail.comt&gt; - support for counter signature reading in CMS API, update for multiple counter signature attributes.</li>
<li>Andrey Pavlenko &lt;andrey.a.pavlenko&#064gmail.com&gt; - security manager patch for PKCS1Encoding property check.</li>
<li>Mike StJohns &lt;mstjohns&#064comcast.net&gt; - updates to KeyPurposeId</li>
<li>J Ross Nicoll &lt;jrn&#064jrn.me.uk&gt; - improved exception handling for getInstance() in ASN.1 library.</li>
<li>Matthew Stevenson &lt;mavricknz&#064yahoo.com&gt; - patch to construtor for CRMF CertSequence.</li>
<li>Gabriele Contini &lt;gcontini&#064hotpop.com&gt; - identified a bug in ASN.1 library with handling of unterminated NDEF's.</li>
<li>Roelof Naude &lt;roelof.naude&#064epiuse.com&gt; - patch for TLS client to send empty client certs in response to HP_CERTIFICATE_REQUEST.</li>
<li>Patrick Peck &lt;peck&#064signaturen.at&gt; - identified problem with DERApplicationSpecific and high tag numbers in ASN.1 library.</li>
<li>Michael LeMay &lt;lemaymd&#064lemaymd.com&gt; - identified problem with EAX [#BJA-93].</li>
<li>Alex Dupre &lt;ale&#064FreeBSD.org&gt; - fix to use of Signature rather than SignatureSpi in provider [#BJA-90]. Addition of null provider use to SignedPublicKeyAndChallenge and PKCS10CertificationRequest [#BJA-102]</li>
<li>Michael Schoene &lt;michael&#064sigrid-und-michael.de&gt; - fix of improper handling of null in ExtendedPKIXParameters.setTrustedACIssuers(), check for V2 signingCertificate attribute in TimeStampResponse.validate().</li>
<li>Ion Larra&ntilde;aga &lt;ilarra&#064s21sec.com&gt; fix to default partial packet generation in BCPGOutputStream.</li>
<li>Bob Kerns &lt;bob.kerns&#064positscience.com&gt; fix to hashCode for X509CertificateObject.</li>
<li>Stefan Meyer &lt;stefan.meyer&#064ewe.de&gt; backport for PKIXCertPathValidotor and SMIMESignedMailReviewer.</li>
<li>Robert J. Moore &lt;Robert.J.Moore&#064allanbank.com&gt; speedups for OpenPGPCFB mode, clean room JCE patches.</li>
<li>Rui Hodai &lt;rui&#064po.ntts.co.jp&gt; speed ups for Camellia implementation, CamelliaLightEngine.</li>
<li>Emir Bucalovic &lt;emir.bucalovic@&#064mail.com&gt; initial implementation of Grain-v1 and Grain-128.</li>
<li>Torbjorn Svensson &lt;tobbe79&#064gmail.com&gt; initial implementation of Grain-v1 and Grain-128.</li>
<li>Paul FitzPatrick &lt;bouncycastle_pfitz&#064fitzpatrick.cc&gt; error message fix to X509LDAPCertStoreSpi, comparison fix to BCStrictStyle.</li>
<li>Henrik Andersson &lt;k.henrik.andersson&#064gmail.com&gt; addition of UniqueIssuerID to certificate generation.</li>
<li>Cagdas Cirit &lt;cagdascirit&#064gmail.com&gt; subjectAlternativeName fix for x509CertStoreSelector.</li>
<li>Harakiri &lt;harakiri_23&#064yahoo.com&gt; datahandler patch for attached parts in SMIME signatures.</li>
<li>Pedro Henriques &lt;pmahenriques&#064gmail.com&gt; explicit bounds checking for DESKeyGenerator, code simplification for OAEPEncoding.</li>
<li>Lothar Kimmeringer &lt;job&#064kimmeringer.de&gt; verbose mode for ASN1Dump, support for DERExternal.</li>
<li>Richard Farr &lt;rfarr.se&#064gmail.com&gt; initial SRP-6a implementation.</li>
<li>Thomas Castiglione &lt;castiglione&#064au.ibm.com&gt; patch to encoding for CRMF OptionalValidity.</li>
<li>Elisabetta Romani &lt;eromani&#064sogei.it&gt; patch for recognising multiple counter signatures.</li>
<li>Robin Lundgren &lt;r737lundgren&#064gmail.com&gt; CMPCertificate constructor from X509CertificateStructure fix.</li>
<li>Petr Kadlec &lt;mormegil&#064centrum.cz&gt; fix to sign extension key and IV problem in HC-128, HC-256.</li>
<li>Andreas Antener &lt;antener_a&#064gmx.ch&gt; fix to buffer reset in AsymmetricBufferedBlockCipher.</li>
<li>Harendra Rawat &lt;hsrawat&#064yahoo.com&gt; fix for BERConstructedOctetString.</li>
<li>Rolf Lindemann &lt;lindemann&#064trustcenter.de&gt; patch for PKCS12 key store to support more flexible attribute specifications [#BMA-42].</li>
<li>Alex Artamonov &lt;alexart.home&#064gmail.com&gt; name look up patch for GOST-2001 parameters.</li>
<li>Mike Lyons &lt;mlyons&#064layer7tech.com&gt; work arounds for EC JDK bug 6738532 and JSSE EC naming conventions.</li>
<li>Chris Cole &lt;chris_h_cole&#064yahoo.com&gt; identified a problem handling null passwords when loading a BKS keystore.</li>
<li>Tomas Krivanek &lt;tom&#064atack.cz&gt; added checking of Sender header to SignedMailValidator.</li>
<li>Michael &lt;emfau&#064t-online.de&gt; correction of field error in getResponse method in CertRepMessage.</li>
<li>Trevor Perrin &lt;trevor&#064cryptography.com&gt; addition of constant time equals to avoid possible timing attacks.</li>
<li>Markus Kil&aring;s &lt;markus&#064primekey.se&gt; several enhancements to TimeStampResponseGenerator.</li>
<li>Dario Novakovic &lt;darionis&#064yahoo.com&gt; fix for NPE when checking revocation reason on CRL without extensions.</li>
<li>Michael Smith &lt;msmith&#064cbnco.com&gt; bug fixes and enhancements to the CMP and CRMF classes, initial Master List classes.</li>
<li>Andrea Zilio &lt;andrea.zilio&#064gmail.com&gt; fix for PEM password encryption of private keys.</li>
<li>Alex Birkett &lt;alex&#064birkett.co.uk&gt; added support for EC cipher suites in TLS client (RFC 4492) [#BJA-291].</li>
<li>Wayne Grant &lt;waynedgrant&#064gmail.com&gt; additional OIDs for PCKS10 and certificate generation support.</li>
<li>Frank Cornelis &lt;info&#064frankcornelis.be&gt; additional support classes for CAdES, enhancements to OCSP classes.</li>
<li>Jan Dittberner &lt;jan&#064dittberner.info&gt; addHeader patch for SMIME generator.</li>
<li>Bob McGowan &lt;boab.mcgoo&#064btinternet.com&gt; patch to support different content and mgf digests in PSS signing.</li>
<li>Ivo Matheis &lt;i.matheis&#064seeburger.de&gt; fix to padding verification in ISO-9796-1.</li>
<li>Marco Sandrini &lt;nessche&#064gmail.com&gt; patch to add IV to ISO9797Alg3Mac.</li>
<li>Alf Malf &lt;alfilmalf&#064hotmail.com&gt; removal of unnecessary limit in CMSContentInfoParser.</li>
<li>Alfonso Massa &lt;alfonso.massa&#064insiel.it&gt; contributions to CMS time stamp classes.</li>
<li>Giacomo Boccardo &lt;gboccardo&#064unimaticaspa.it&gt; initial work on CMSTimeStampedDataParser.</li>
<li>Arnis Tartu &lt;arnis&#064ut.ee&gt; patches for dealing with OIDs with specific key sizes associated in CMS.</li>
<li>Janusz Sikociński &lt;J.Sikocinski&#064gdzie.pl&gt; addition of Features subpacket support to OpenPGP API.</li>
<li>Juri Hudolejev &lt;jhudolejev&#064gmail.com&gt; JavaDoc fix to CMSSignedDataParser.</li>
<li>Liane Velten &lt;liane.velten&#064hjp-consulting.com&gt; fine tuning of code for DHParameters validation.</li>
<li>Shawn Willden &lt;swillden&#064google.com&gt; additional functionality to PGPKeyRing.</li>
<li>Atanas Krachev &lt;akrachev&#064gmail.com&gt; added support for revocation signatures in OpenPGP.</li>
<li>Mickael Laiking &lt;mickael.laiking&#064keynectis.com&gt; initial cut of EAC classes.</li>
<li>Tim Buktu &lt;tbuktu&#064hotmail.com&gt; Initial implementation of NTRU signing and encryption.</li>
<li>Bernd &lt;rbernd&#064gmail.com&gt; Fix for open of PGP literal data stream with UTF-8 naming.</li>
<li>Steing Inge Morisbak &lt;stein.inge.morisbak&#064BEKK.no&gt; Test code for lower case Hex data in PEM headers.</li>
<li>Andreas Schmid &lt;andreas.schmid&#064tngtech.com&gt; Additional expiry time check in PGPPublicKeys.</li>
<li>Phil Steitz &lt;phil.steitz&#064gmail.com&gt; Final patch eliminating JCE dependencies in the OpenPGP BC classes.</li>
<li>Ignat Korchagin &lt;ignat.korchagin&#064gmail.com&gt; Initial implementation of DSTU-4145-2002.</li>
<li>Petar Petrov &lt;p.petrov&#064bers-soft.com&gt; Testing and debugging of UTF-8 OpenPGP passwords.</li>
<li>Daniel Fitzpatrick &lt;daniel.f.nwr&#064gmail.com&gt; Initial implementation of ephemeral key support for IES.</li>
<li>Andy Neilson &lt;Andy.Neilson&#064quest.com&gt;a further patches to deal with multiple providers and PEMReader.</li>
<li>Ted Shaw &lt;xiao.xj&#064gmail.com&gt; patch to MiscPEMGenerator for handling new PKCS10CeriticationRequests.</li>
<li>Eleriseth &lt;Eleriseth&#064WPECGLtYbVi8Rl6Y7Vzl2Lvd2EUVW99v3yNV3IWROG8.fms&gt; speed up for SIC/CTR mode. Provider compatibilty generalisations for EC operations.</li>
<li>Kenny Root &lt;kenny&#064the-b.org&gt; patch for issuerAltName, subjectAltName support in X509CertificateObject</li>
<li>Marteen Bodewes &lt;maarten.bodewes&#064gmail.com&gt; initial implementation of HKDF.</li>
<li>Philip Clay &lt;pilf_b&#064gyahoo.com&gt; Initial implementation of J-PAKE.</li>
<li>Brian Carlstrom &lt;bdc&#064carlstrom.com&gt; compliance patches for some JCA/JCE keystore and cipher classes, miscellaneous code quality improvements.</li>
</ul>
</body>
</html>

View File

@ -0,0 +1,22 @@
<html>
<body bgcolor=#ffffff>
Copyright (c) 2000-2011 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.
</body>
</html>

View File

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Class-Path:

View File

@ -0,0 +1,121 @@
<html>
<head>
<title>The Bouncy Castle Crypto Package</title>
</head>
<body bgcolor="#ffffff" text="#000000#">
<center>
<h1>The Bouncy Castle Crypto Package</h1>
<font size=1>
<pre>
</pre>
</font>
</center>
The Bouncy Castle Crypto package is a Java implementation of
cryptographic algorithms, it was developed by the Legion of the
Bouncy Castle - with a little help! The Legion, and the latest
goings on with this package, can be found at
<a href=http://www.bouncycastle.org>http://www.bouncycastle.org</a>.
<p>
The Legion also gratefully acknowledges the contributions made to this
package by others (see <a href=CONTRIBUTORS.html>here</a>
for the current list).
<p>
The package is organised so that it
contains a light-weight API suitable for use in any environment
(including the newly released J2ME) with the additional infrastructure
to conform the algorithms to the JCE framework.
<p>
Except where otherwise stated, this software is distributed under a license based on the MIT X Consortium license. To view the license, <a href="./LICENSE.html">see here</a>. The OpenPGP library also includes a modified BZIP2 library which is licensed under the <a href="http://www.apache.org/licenses/">Apache Software License, Version 2.0</a>.
<p>
The current release notes for this package are
<a href=releasenotes.html>here</a>.
<p>
The current specifications for this package are
<a href=specifications.html>here</a>.
<p>
The current api documentation for this package is
<a href=docs/index.html>here</a>.
</p>
</p>
<h2>Examples and Tests</h2>
<p>
<p>To view some examples, look at the test programs in the packages:
<ul>
<li><p><b>org.bouncycastle.crypto.test</b>
<li><p><b>org.bouncycastle.jce.provider.test</b>
<li><p><b>org.bouncycastle.cms.test</b>
<li><p><b>org.bouncycastle.mail.smime.test</b>
<li><p><b>org.bouncycastle.openpgp.test</b>
<li><p><b>org.bouncycastle.tsp.test</b>
</ul>
<p>There are also some specific example programs for dealing with Attribute Certificates, PKCS12, SMIME and OpenPGP. They can be found in:
<ul>
<li><p><b>org.bouncycastle.jce.examples</b>
<li><p><b>org.bouncycastle.mail.smime.examples</b>
<li><p><b>org.bouncycastle.openpgp.examples</b>
<li><p><b>org.bouncycastle.x509.examples</b>
</ul>
<p>Finally there are also code <a href="http://www.wiley.com/WileyCDA/WileyAncillary/productCd-0764596330.html">examples</a> from <a href="http://www.amazon.com/exec/obidos/redirect?path=ASIN/0764596330&amp;link_code=as2&amp;camp=1789&amp;tag=bouncycastleo-20&amp;creative=9325">Beginning Cryptography with Java</a> which demonstrate both the use of the JCE/JCA and also some of the Bouncy Castle APIs.</p>
<p>
<b>Note 1:</b>The JCE classes are only distributed with the JDK 1.1, JDK 1.2, and JDK 1.3 JCE releases. The
JDK 1.0, J2ME, and the JDK 1.1, JDK 1.2, JDK 1.3, JDK 1.4, and JDK 1.5 lightweight releases only include the
Bouncy Castle lightweight cryptography API.<br>
<b>Note 2:</b>The regression test for Diffie-Hellman is quite slow.
<h2>Building From CVS</h2>
<p>
The src and test/src directory are for JDK 1.5.
</p>
<p>
Compatibility classes for other VMs are as follows:
<ul>
<li>JDK 1.4 - jdk1.4, test/jdk1.4
<li>JDK 1.3 - jdk1.3, test/jdk1.3
<li>JDK 1.2 - jdk1.2
<li>JDK 1.1 - jdk1.1
<li>JDK 1.0 - jdk1.0
<li>J2ME - j2me
</ul>
</p>
<p>
The clean room JCE, which will compile with everything from JDK 1.1 and up is in the jce/src directory.
</p>
<p>
The build scripts that come with the full distribution allow creation of the different releases by using the tree under src and test/src, excluding classes that are not appropriate and copying in the required compatibility classes from the directories containing compatibility classes appropriate for the distribution.
</p>
<p>
If you want to try create a build for yourself, using your own environment, the best way to do it is to start with the build for the distribution you are interested in, make sure that builds, and then modify your build scripts to do the required exclusions and file copies for your setup, otherwise you are likely to get class not found exceptions. The final caveat to this is that as the j2me distribution includes some compatibility classes starting in the java package, you need to use an obfuscator to change the package names before attempting to import a midlet using the BC API.
</p>
<h2>Mailing Lists</h2>
<p>
For those who are interested, there are 2 mailing lists
for participation in this project. To subscribe use the
links below and include the word subscribe in the message body. (To unsubscribe, replace <b>subscribe</b> with
<b>unsubscribe</b> in the message body)
<ul>
<li><a href="mailto:announce-crypto-request@bouncycastle.org">announce-crypto-request@bouncycastle.org</a>
<br>
This mailing list is for new release announcements only, general subscribers cannot post to it.
<p>
<li><a href="mailto:dev-crypto-request@bouncycastle.org">dev-crypto-request@bouncycastle.org</a>
<br>
This mailing list is for discussion of development of the package. This
includes bugs, comments, requests for enhancements, questions about
use or operation.
</ul>
<b>NOTE:</b>You need to be subscribed to send mail to the above
mailing list.
<p>
If you want to provide feedback, offers of jobs (or more importantly
beer) directly to the members of <b>The Legion</b>
then please use <a href="mailto:feedback-crypto@bouncycastle.org">
feedback-crypto@bouncycastle.org</a>
<p>
Enjoy!
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,815 @@
<html>
<head>
<title>Bouncy Castle Crypto Package</title>
</head>
<body bgcolor="#ffffff" text="#000000#">
<center>
<h1>Bouncy Castle Crypto Package</h1>
<font size=1>
<pre>
</pre>
</font>
</center>
<h2>1.0 Introduction</h2>
The Bouncy Castle Crypto package is a Java implementation of
cryptographic algorithms. The package is organised so that it
contains a light-weight API suitable for use in any environment
(including the newly released J2ME) with the additional infrastructure
to conform the algorithms to the JCE framework.
<p>
Except where otherwise stated, this software is distributed under a license
based on the MIT X
Consortium license. To view the license, see <a href="./LICENSE.html">here</a>.
The OpenPGP library also includes a modified BZIP2 library which
is licensed under the <a href="http://www.apache.org/licenses/">Apache Software License, Version 2.0</a>.
<p>
If you have the full package you will have six jar files, bcprov*.jar
which contains the BC provider, jce-*.jar which contains
the JCE provider, clean room API, and bcmail*.jar which contains the
mail API.
<p>
Note: if you are using JDK 1.0, you will just find a class hierarchy in
the classes directory.
<p>
To view examples, look at the test programs in the packages:
<ul>
<li><b>org.bouncycastle.crypto.test</b>
<li><b>org.bouncycastle.jce.provider.test</b>
</ul>
<p>
To verify the packages, run the following Java programs with the
appropriate classpath:
<ul>
<li><b>java org.bouncycastle.crypto.test.RegressionTest</b>
<li><b>java org.bouncycastle.jce.provider.test.RegressionTest</b>
</ul>
<h2>2.0 Patents</h2>
<p>
Some of the algorithms in the Bouncy Castle APIs are patented in some
places. It is upon the user of the library to be aware of what the
legal situation is in their own situation, however we have been asked
to specifically mention the patent below, in the following terms, at
the request of the patent holder. Algorithms that appear here are only
distributed in the -ext- versions of the provider.
<p>
The IDEA encryption algorithm is patented in the USA, Japan, and Europe
including at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden,
Switzerland and the United Kingdom. Non-commercial use is free, however
any commercial products that make use of IDEA are liable for royalties.
Please see
<a href="http://www.mediacrypt.com">www.mediacrypt.com</a> for
further details.
<h2>3.0 Specifications</h2>
<ul>
<li> clean room implementation of the JCE API
<li> light-weight cryptographic API consisting of support for
<ul>
<li>BlockCipher
<li>BufferedBlockCipher
<li>AsymmetricBlockCipher
<li>BufferedAsymmetricBlockCipher
<li>StreamCipher
<li>BufferedStreamCipher
<li>KeyAgreement
<li>IESCipher
<li>Digest
<li>Mac
<li>PBE
<li>Signers
</ul>
<li> JCE compatible framework for a Bouncy Castle provider
</ul>
<h2>4.0 Light-weight API</h2>
<p>
This API has been specifically developed for those circumstances
where the rich API and integration requirements of the JCE are
not required.
<p>
However as a result, the light-weight API requires more effort
and understanding on the part of a developer to initialise and
utilise the algorithms.
<h3>4.1 Example</h3>
<p>To utilise the light-weight API in a program, the fundamentals
are as follows;
<pre>
<code>
/*
* This will use a supplied key, and encrypt the data
* This is the equivalent of DES/CBC/PKCS5Padding
*/
BlockCipher engine = new DESEngine();
BufferedBlockCipher cipher = new PaddedBlockCipher(new CBCCipher(engine));
byte[] key = keyString.getBytes();
byte[] input = inputString.getBytes();
cipher.init(true, new KeyParameter(key));
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int outputLen = cipher.processBytes(input, 0, input.length, cipherText, 0);
try
{
cipher.doFinal(cipherText, outputLen);
}
catch (CryptoException ce)
{
System.err.println(ce);
System.exit(1);
}
</code>
</pre>
<h3>4.2 Algorithms</h3>
<p>The light-weight API has built in support for the following:
<h4>Symmetric (Block)</h4>
<p>
The base interface is <b>BlockCipher</b> and has the following
implementations which match the modes the block cipher can
be operated in.
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Constructor</th><th>Notes</th></tr>
<tr><td><b>BufferedBlockCipher</b></td><td>BlockCipher</td><td>&nbsp;</td></tr>
<tr><td><b>CBCBlockCipher</b></td><td>BlockCipher</td><td>&nbsp;</td></tr>
<tr><td><b>CFBBlockCipher</b></td><td>BlockCipher, block size (in bits)</td><td>&nbsp;</td></tr>
<tr><td><b>CCMBlockCipher</b></td><td>BlockCipher</td><td>Packet mode - requires all data up front.</td></tr>
<tr><td><b>EAXBlockCipher</b></td><td>BlockCipher</td><td>&nbsp;</td></tr>
<tr><td><b>OFBBlockCipher</b></td><td>BlockCipher, block size (in bits)</td><td>&nbsp;</td></tr>
<tr><td><b>SICBlockCipher</b></td><td>BlockCipher, block size (in bits)</td><td>Also known as CTR mode</td></tr>
<tr><td><b>OpenPGPCFBBlockCipher</b></td><td>BlockCipher</td><td>&nbsp;</td></tr>
<tr><td><b>GOFBBlockCipher</b></td><td>BlockCipher</td><td>GOST OFB mode</td></tr>
</table>
<p>
<b>BufferedBlockCipher</b> has a further sub-classes
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Constructor</th><th>Notes</th></tr>
<tr><td><b>PaddedBufferedBlockCipher</b></td><td>BlockCipher</td><td>a buffered block cipher that can use padding - default PKCS5/7 padding</td></tr>
<tr><td><b>CTSBlockCipher</b></td><td>BlockCipher</td><td>Cipher Text Stealing</td></tr>
</table>
<p>The following paddings can be used with the PaddedBufferedBlockCipher.
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Description</th></tr>
<tr><td>PKCS7Padding</td><td>PKCS7/PKCS5 padding</td></tr>
<tr><td>ISO10126d2Padding</td><td>ISO 10126-2 padding</td></tr>
<tr><td>X932Padding</td><td>X9.23 padding</td></tr>
<tr><td>ISO7816d4Padding</td><td>ISO 7816-4 padding (ISO 9797-1 scheme 2)</td></tr>
<tr><td>ZeroBytePadding</td><td>Pad with Zeros (not recommended)</td></tr>
</table>
<p>The following cipher engines are implemented that can be
used with the above modes.
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>KeySizes (in bits) </th><th>Block Size</th><th>Notes</th></tr>
<tr><td><b>AESEngine</b></td><td>0 .. 256 </td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>AESWrapEngine</b></td><td>0 .. 256 </td><td>128 bit</td><td>Implements FIPS AES key wrapping</td></tr>
<tr><td><b>BlowfishEngine</b></td><td>0 .. 448 </b></td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td><b>CamelliaEngine</b></td><td>128, 192, 256</td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>CamelliaWrapEngine</b></td><td>128, 192, 256</td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>CAST5Engine</b></td><td>0 .. 128 </b></td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td><b>CAST6Engine</b></td><td>0 .. 256 </b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>DESEngine</b></td><td>64</td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td><b>DESedeEngine</b></td><td>128, 192</td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td><b>DESedeWrapEngine</b></td><td>128, 192</td><td>64 bit</td><td>Implements Draft IETF DESede key wrapping</td></tr>
<tr><td><b>GOST28147Engine</b></td><td>256</td><td>64 bit</td><td>Has a range of S-boxes</td></tr>
<tr><td><b>IDEAEngine</b></td><td>128</td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td><b>NoekeonEngine</b></td><td>128</td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>RC2Engine</b></td><td>0 .. 1024 </td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td><b>RC532Engine</b></td><td>0 .. 128 </td><td>64 bit</td><td>Uses a 32 bit word</td></tr>
<tr><td><b>RC564Engine</b></td><td>0 .. 128 </td><td>128 bit</td><td>Uses a 64 bit word</td></tr>
<tr><td><b>RC6Engine</b></td><td>0 .. 256 </td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>RijndaelEngine</b></td><td>0 .. 256 </td><td>128 bit, 160 bit, 192 bit, 224 bit, 256 bit</td><td>&nbsp;</td></tr>
<tr><td><b>SEEDEngine</b></td><td>128</td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>SEEDWrapEngine</b></td><td>128</td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>SerpentEngine</b></td><td>128, 192, 256 </td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>SkipjackEngine</b></td><td>0 .. 128 </td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td><b>TEAEngine</b></td><td>128</td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td><b>TwofishEngine</b></td><td>128, 192, 256 </td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td><b>XTEAEngine</b></td><td>128</td><td>64 bit</td><td>&nbsp;</td></tr>
</table>
<h4>Symmetric (Stream)</h4>
<p>
The base interface is <b>StreamCipher</b> and has the following
implementations which match the modes the stream cipher can
be operated in.
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Constructor</th><th>Notes</th></tr>
<tr><td><b>BlockStreamCipher</b></td><td>BlockCipher</td><td>&nbsp;</td></tr>
</table>
<p>The following cipher engines are implemented that can be
used with the above modes.
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>KeySizes (in bits) </th><th>Notes</th></tr>
<tr><td><b>RC4Engine</b></td><td>40 .. 2048</td><td>&nbsp;</td></tr>
<tr><td><b>HC128Engine</b></td><td>128</td><td>&nbsp;</td></tr>
<tr><td><b>HC256Engine</b></td><td>256</td><td>&nbsp;</td></tr>
<tr><td><b>Salsa20Engine</b></td><td>128/256</td><td>&nbsp;</td></tr>
<tr><td><b>ISAACEngine</b></td><td>32 .. 8192</td><td>&nbsp;</td></tr>
<tr><td><b>VMPCEngine</b></td><td>8 .. 6144</td><td>&nbsp;</td></tr>
<tr><td><b>Grainv1Engine</b></td><td>80</td><td>64 bit IV</td></tr>
<tr><td><b>Grain128Engine</b></td><td>128</td><td>96 bit IV</td></tr>
</table>
<h4>Block Asymmetric</h4>
<p>
The base interface is <b>AsymmetricBlockCipher</b> and has the following
implementations which match the modes the cipher can be operated in.
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Constructor</th><th>Notes</th></tr>
<tr><td><b>BufferedAsymmetricBlockCipher</b></td><td>AsymmetricBlockCipher</td><td>&nbsp;</td></tr>
<tr><td><b>OAEPEncoding</b></td><td>AsymmetricBlockCipher</td><td>&nbsp;</td></tr>
<tr><td><b>PKCS1Encoding</b></td><td>AsymmetricBlockCipher</td><td>&nbsp;</td></tr>
<tr><td><b>ISO9796d1Encoding</b></td><td>AsymmetricBlockCipher</td><td>ISO9796-1</td></tr>
</table>
<p>The following cipher engines are implemented that can be
used with the above modes.
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>KeySizes (in bits)</th><th>Notes</th></tr>
<tr><td><b>RSAEngine</b></td><td>any multiple of 8 large enough for the encoding.</td><td>&nbsp;</td></tr>
<tr><td><b>ElGamalEngine</b></td><td>any multiple of 8 large enough for the encoding.</td><td>&nbsp;</td></tr>
</table>
<h4>Digest</h4>
<p>
The base interface is <b>Digest</b> and has the following
implementations
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Output (in bits)</th><th>Notes</th></tr>
<tr><td><b>MD2Digest</b></td><td>128</td><td>&nbsp;</td></tr>
<tr><td><b>MD4Digest</b></td><td>128</td><td>&nbsp;</td></tr>
<tr><td><b>MD5Digest</b></td><td>128</td><td>&nbsp;</td></tr>
<tr><td><b>RipeMD128Digest</b></td><td>128</td><td>basic RipeMD</td></tr>
<tr><td><b>RipeMD160Digest</b></td><td>160</td><td>enhanced version of RipeMD</td></tr>
<tr><td><b>RipeMD256Digest</b></td><td>256</td><td>expanded version of RipeMD128</td></tr>
<tr><td><b>RipeMD320Digest</b></td><td>320</td><td>expanded version of RipeMD160</td></tr>
<tr><td><b>SHA1Digest</b></td><td>160</td><td>&nbsp;</td></tr>
<tr><td><b>SHA224Digest</b></td><td>224</td><td>FIPS 180-2</td></tr>
<tr><td><b>SHA256Digest</b></td><td>256</td><td>FIPS 180-2</td></tr>
<tr><td><b>SHA384Digest</b></td><td>384</td><td>FIPS 180-2</td></tr>
<tr><td><b>SHA512Digest</b></td><td>512</td><td>FIPS 180-2</td></tr>
<tr><td><b>SHA3Digest</b></td><td>224, 256, 288, 384, 512</td><td></td></tr>
<tr><td><b>TigerDigest</b></td><td>192</td><td>The Tiger Digest.</td></tr>
<tr><td><b>GOST3411Digest</b></td><td>256</td><td>The GOST-3411 Digest.</td></tr>
<tr><td><b>WhirlpoolDigest</b></td><td>512</td><td>The Whirlpool Digest.</td></tr>
</table>
<h4>MAC</h4>
<p>
The base interface is <b>Mac</b> and has the following
implementations
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Output (in bits)</th><th>Notes</th></tr>
<tr><td><b>CBCBlockCipherMac</b></td><td>blocksize/2 unless specified</td><td>&nbsp;</td></tr>
<tr><td><b>CFBBlockCipherMac</b></td><td>blocksize/2, in CFB 8 mode, unless specified</td><td>&nbsp;</td></tr>
<tr><td><b>HMac</b></td><td>digest length</td><td>&nbsp;</td></tr>
</table>
<h4>PBE</h4>
<p>
The base class is <b>PBEParametersGenerator</b> and has the following
sub-classes
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Constructor</th><th>Notes</th></tr>
<tr><td><b>PKCS5S1ParametersGenerator</b></td><td>Digest</td><td>&nbsp;</td></tr>
<tr><td><b>PKCS5S2ParametersGenerator</b></td><td>&nbsp;</td><td>Uses SHA1/Hmac as defined</td></tr>
<tr><td><b>PKCS12ParametersGenerator</b></td><td>Digest</td><td>&nbsp;</td></tr>
<tr><td><b>OpenSSLPBEParametersGenerator</b></td><td>&nbsp;</td><td>Uses MD5 as defined</td></tr>
</table>
<h4>Key Agreement</h4>
<p>
Two versions of Diffie-Hellman key agreement are supported, the basic
version, and one for use with long term public keys. Two versions of
key agreement using Elliptic Curve cryptography are also supported,
standard Diffie-Hellman key agreement and standard key agreement with
co-factors.
<p>
The agreement APIs are in the <b>org.bouncycastle.crypto.agreement</b> package.
Classes for generating Diffie-Hellman parameters can be found in the
<b>org.bouncycastle.crypto.params</b> and <b>org.bouncycastle.crypto.generators</b> packages.
<p>
<h4>IESCipher</h4>
<p>
The IES cipher is based on the one described in IEEE P1363a (draft 10), for
use with either traditional Diffie-Hellman or Elliptic Curve Diffie-Hellman.
<p>
<b>Note:</b> At the moment this is still a draft, don't use it for anything
that may be subject to long term storage, the key values produced may well
change as the draft is finalised.
<p>
<h4>Signers</h4>
<p>
DSA, ECDSA, ISO-9796-2, GOST-3410-94, GOST-3410-2001, DSTU-4145-2002, and RSA-PSS are supported by the <b>org.bouncycastle.crypto.signers</b>
package. Note: as these are light weight classes, if you need to use SHA1 or GOST-3411
(as defined in the relevant standards) you'll also need to make use of the appropriate
digest class in conjunction with these.
Classes for generating DSA and ECDSA parameters can be found in the
<b>org.bouncycastle.crypto.params</b> and <b>org.bouncycastle.crypto.generators</b> packages.
<p>
<h3>4.3 ASN.1 package</h3>
<p>The light-weight API has direct interfaces into a package capable of
reading and writing DER-encoded ASN.1 objects and for the generation
of X.509 V3 certificate objects and PKCS12 files. BER InputStream and
OutputStream classes are provided as well.
<h2>5.0 Bouncy Castle Provider</h2>
<p>The Bouncy Castle provider is a JCE compliant provider that
is a wrapper built on top of the light-weight API.
<p>
The advantage for writing application code that uses the
provider interface to cryptographic algorithms is that the
actual provider used can be selected at run time. This
is extremely valuable for applications that may wish to
make use of a provider that has underlying hardware for
cryptographic computation, or where an application may have
been developed in an environment with cryptographic export
controls.
<h3>5.1 Example</h3>
<p>To utilise the JCE provider in a program, the fundamentals
are as follows;
<pre>
<code>
/*
* This will generate a random key, and encrypt the data
*/
Key key;
KeyGenerator keyGen;
Cipher encrypt;
Security.addProvider(new BouncyCastleProvider());
try
{
// "BC" is the name of the BouncyCastle provider
keyGen = KeyGenerator.getInstance("DES", "BC");
keyGen.init(new SecureRandom());
key = keyGen.generateKey();
encrypt = Cipher.getInstance("DES/CBC/PKCS5Padding", "BC");
}
catch (Exception e)
{
System.err.println(e);
System.exit(1);
}
encrypt.init(Cipher.ENCRYPT_MODE, key);
bOut = new ByteArrayOutputStream();
cOut = new CipherOutputStream(bOut, encrypt);
cOut.write("plaintext".getBytes());
cOut.close();
// bOut now contains the cipher text
</code>
</pre>
<p>
The provider can also be configured as part of your environment via static registration
by adding an entry to the java.security properties file (found in $JAVA_HOME/jre/lib/security/java.security, where $JAVA_HOME is the location of your JDK/JRE distribution). You'll find detailed
instructions in the file but basically it comes down to adding a line:
<pre>
<code>
security.provider.&lt;n&gt;=org.bouncycastle.jce.provider.BouncyCastleProvider
</code>
</pre>
<p>Where &lt;n&gt; is the preference you want the provider at (1 being the most prefered).
<p>Where you put the jar is up to mostly up to you, although with jdk1.3 and
jdk1.4 the best (and in some cases only) place to have it is in $JAVA_HOME/jre/lib/ext. Note: under Windows there will normally be a JRE and a JDK install of Java if you think you have installed it correctly and it still doesn't work chances are you have added the provider to the installation not being used.
<p>
<b>Note</b>: with JDK 1.4 and later you will need to have installed the unrestricted policy
files to take full advantage of the provider. If you do not install the policy files you are likely
to get something like the following:
<b>
<pre>
java.lang.SecurityException: Unsupported keysize or algorithm parameters
at javax.crypto.Cipher.init(DashoA6275)
</pre>
</b>
The policy files can be found at the same place you downloaded the JDK.
<p>
<h3>5.2 Algorithms</h3>
<h4>Symmetric (Block)</h4>
<p>Modes:
<ul>
<li>ECB
<li>CBC
<li>OFB(n)
<li>CFB(n)
<li>SIC (also known as CTR)
<li>OpenPGPCFB
<li>CTS (equivalent to CBC/WithCTS)
<li>GOFB
<li>CCM
<li>EAX
</ul>
<p>
Where <i>(n)</i> is a multiple of 8 that gives the blocksize in bits,
eg, OFB8. Note that OFB and CFB mode can be used with plain text that
is not an exact multiple of the block size if NoPadding has been specified.
<p>
Padding Schemes:
<ul>
<li>No padding
<li>PKCS5/7
<li>ISO10126/ISO10126-2
<li>ISO7816-4/ISO9797-1
<li>X9.23/X923
<li>TBC
<li>ZeroByte
<li>withCTS (if used with ECB mode)
</ul>
<p>
When placed together this gives a specification for an algorithm
as;
<ul>
<li>DES/CBC/X9.23Padding
<li>DES/OFB8/NoPadding
<li>IDEA/CBC/ISO10126Padding
<li>IDEA/CBC/ISO7816-4Padding
<li>SKIPJACK/ECB/PKCS7Padding
<li>DES/ECB/WithCTS
</ul>
<p>
Note: default key sizes are in bold.
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>KeySizes (in bits) </th><th>Block Size</th><th>Notes</th></tr>
<tr><td>AES</td><td>0 .. 256 <b>(192)</b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>AESWrap</td><td>0 .. 256 <b>(192)</b></td><td>128 bit</td><td>A FIPS AES key wrapper</td></tr>
<tr><td>Blowfish</td><td>0 .. 448 <b>(448)</b></td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td>Camellia</td><td>128, 192, 256</td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>CamelliaWrap</td><td>128, 192, 256</td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>CAST5</td><td>0 .. 128<b>(128)</b></td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td>CAST6</td><td>0 .. 256<b>(256)</b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>DES</td><td>64</td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td>DESede</td><td>128, 192</td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td>DESedeWrap</td><td>128, 192</td><td>128 bit</td><td>A Draft IETF DESede key wrapper</td></tr>
<tr><td>GOST28147</td><td>256</td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td>IDEA</td><td>128 <b>(128)</b></td><td>64 bit</td><td>Only included in extended provider jar.</td></tr>
<tr><td>Noekeon</td><td>128<b>(128)</b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>RC2</td><td>0 .. 1024 <b>(128)</b></td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td>RC5</td><td>0 .. 128 <b>(128)</b></td><td>64 bit</td><td>Uses a 32 bit word</td></tr>
<tr><td>RC5-64</td><td>0 .. 256 <b>(256)</b></td><td>128 bit</td><td>Uses a 64 bit word</td></tr>
<tr><td>RC6</td><td>0 .. 256 <b>(128)</b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>Rijndael</td><td>0 .. 256 <b>(192)</b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>SEED</td><td>128<b>(128)</b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>SEEDWrap</td><td>128<b>(128)</b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>Serpent</td><td>128, 192, 256 <b>(256)</b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>Skipjack</td><td>0 .. 128 <b>(128)</b></td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td>TEA</td><td>128 <b>(128)</b></td><td>64 bit</td><td>&nbsp;</td></tr>
<tr><td>Twofish</td><td>128, 192, 256 <b>(256)</b></td><td>128 bit</td><td>&nbsp;</td></tr>
<tr><td>XTEA</td><td>128 <b>(128)</b></td><td>64 bit</td><td>&nbsp;</td></tr>
</table>
<h4>Symmetric (Stream)</h4>
<p>
Note: default key sizes are in bold.
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>KeySizes (in bits)</th><th>Notes</th></tr>
<tr><td>RC4</td><td>40 .. 2048 bits <b>(128)</b></td><td>&nbsp;</td></tr>
<tr><td>HC128</td><td>(128)</td><td>&nbsp;</td></tr>
<tr><td>HC256</td><td>(256)</td><td>&nbsp;</td></tr>
<tr><td>Salsa20</td><td>128/256<b>(128)</b></td><td>&nbsp;</td></tr>
<tr><td>VMPC</td><td>128/6144<b>(128)</b></td><td>&nbsp;</td></tr>
<tr><td>Grainv1</b></td><td>80</td><td>64 bit IV</td></tr>
<tr><td>Grain128</b></td><td>128</td><td>96 bit IV</td></tr>
</table>
<h4>Block Asymmetric</h4>
<p>Encoding:
<ul>
<li>OAEP - Optimal Asymmetric Encryption Padding
<li>PCKS1 - PKCS v1.5 Padding
<li>ISO9796-1 - ISO9796-1 edition 1 Padding
</ul>
<p>Note: except as indicated in PKCS 1v2 we recommend you use OAEP, as
mandated in X9.44.
<p>
When placed together with RSA this gives a specification for an algorithm
as;
<ul>
<li>RSA/NONE/NoPadding
<li>RSA/NONE/PKCS1Padding
<li>RSA/NONE/OAEPWithMD5AndMGF1Padding
<li>RSA/NONE/OAEPWithSHA1AndMGF1Padding
<li>RSA/NONE/OAEPWithSHA224AndMGF1Padding
<li>RSA/NONE/OAEPWithSHA256AndMGF1Padding
<li>RSA/NONE/OAEPWithSHA384AndMGF1Padding
<li>RSA/NONE/OAEPWithSHA512AndMGF1Padding
<li>RSA/NONE/ISO9796-1Padding
</ul>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>KeySizes (in bits)</th><th>Notes</th></tr>
<tr><td>RSA</td><td>any multiple of 8 bits large enough for the encryption<b>(2048)</b></td><td>&nbsp;</td></tr>
<tr><td>ElGamal</td><td>any multiple of 8 bits large enough for the encryption<b>(1024)</b></td><td>&nbsp;</td></tr>
</table>
<h4>Key Agreement</h4>
<p>
Diffie-Hellman key agreement is supported using the "DH", "ECDH", and
"ECDHC" (ECDH with cofactors) key agreement instances.
<p>
Note: with basic "DH" only the basic algorithm fits in with the JCE API, if
you're using long-term public keys you may want to look at the light-weight
API.
<p>
<h4>ECIES</h4>
<p>
An implementation of ECIES (stream mode) as described in IEEE P 1363a.
<p>
<b>Note:</b> At the moment this is still a draft, don't use it for anything
that may be subject to long term storage, the key values produced may well
change as the draft is finalised.
<p>
<h4>Digest</h4>
<p>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Output (in bits)</th><th>Notes</th></tr>
<tr><td>GOST3411</td><td>256</td><td>&nbsp;</td></tr>
<tr><td>MD2</td><td>128</td><td>&nbsp;</td></tr>
<tr><td>MD4</td><td>128</td><td>&nbsp;</td></tr>
<tr><td>MD5</td><td>128</td><td>&nbsp;</td></tr>
<tr><td>RipeMD128</td><td>128</td><td>basic RipeMD</td></tr>
<tr><td>RipeMD160</td><td>160</td><td>enhanced version of RipeMD</td></tr>
<tr><td>RipeMD256Digest</td><td>256</td><td>expanded version of RipeMD128</td></tr>
<tr><td>RipeMD320Digest</td><td>320</td><td>expanded version of RipeMD160</td></tr>
<tr><td>SHA1</td><td>160</td><td>&nbsp;</td></tr>
<tr><td>SHA-224</td><td>224</td><td>FIPS 180-2</td></tr>
<tr><td>SHA-256</td><td>256</td><td>FIPS 180-2</td></tr>
<tr><td>SHA-384</td><td>384</td><td>FIPS 180-2</td></tr>
<tr><td>SHA-512</td><td>512</td><td>FIPS 180-2</td></tr>
<tr><td>SHA3-224</td><td>224</td><td>&nbsp;</td></tr>
<tr><td>SHA3-256</td><td>256</td><td>&nbsp;</td></tr>
<tr><td>SHA3-384</td><td>384</td><td>&nbsp;</td></tr>
<tr><td>SHA3-512</td><td>512</td><td>&nbsp;</td></tr>
<tr><td>Tiger</td><td>192</td><td>&nbsp;</td></tr>
<tr><td>Whirlpool</td><td>512</td><td>&nbsp;</td></tr>
</table>
<h4>MAC</h4>
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Output (in bits)</th><th>Notes</th></tr>
<tr><td>Any MAC based on a block cipher, CBC (the default) and CFB modes.</td><td>half the cipher's block size (usually 32 bits)</td><td>&nbsp;</td></tr>
<tr><td>VMPC-MAC</td><td>128</td><td>&nbsp;</td></tr>
<tr><td>HMac-MD2</td><td>128</td><td>&nbsp;</td></tr>
<tr><td>HMac-MD4</td><td>128</td><td>&nbsp;</td></tr>
<tr><td>HMac-MD5</td><td>128</td><td>&nbsp;</td></tr>
<tr><td>HMac-RipeMD128</td><td>128</td><td>&nbsp;</td></tr>
<tr><td>HMac-RipeMD160</td><td>160</td><td>&nbsp;</td></tr>
<tr><td>HMac-SHA1</td><td>160</td><td>&nbsp;</td></tr>
<tr><td>HMac-SHA224</td><td>224</td><td>&nbsp;</td></tr>
<tr><td>HMac-SHA256</td><td>256</td><td>&nbsp;</td></tr>
<tr><td>HMac-SHA384</td><td>384</td><td>&nbsp;</td></tr>
<tr><td>HMac-SHA512</td><td>512</td><td>&nbsp;</td></tr>
<tr><td>HMac-Tiger</td><td>192</td><td>&nbsp;</td></tr>
</table>
<p>Examples:
<ul>
<li>DESMac
<li>DESMac/CFB8
<li>DESedeMac
<li>DESedeMac/CFB8
<li>DESedeMac64
<li>SKIPJACKMac
<li>SKIPJACKMac/CFB8
<li>IDEAMac
<li>IDEAMac/CFB8
<li>RC2Mac
<li>RC2Mac/CFB8
<li>RC5Mac
<li>RC5Mac/CFB8
<li>ISO9797ALG3Mac
</ul>
<h4>Signature Algorithms</h4>
<p>Schemes:
<ul>
<li>DSTU4145</li>
<li>GOST3411withGOST3410 (GOST3411withGOST3410-94)
<li>GOST3411withECGOST3410 (GOST3411withGOST3410-2001)
<li>MD2withRSA
<li>MD5withRSA
<li>SHA1withRSA
<li>RIPEMD128withRSA
<li>RIPEMD160withRSA
<li>RIPEMD160withECDSA
<li>RIPEMD256withRSA
<li>SHA1withDSA
<li>NONEwithDSA
<li>SHA1withECDSA
<li>NONEwithECDSA
<li>SHA224withECDSA
<li>SHA256withECDSA
<li>SHA384withECDSA
<li>SHA512withECDSA
<li>SHA224withRSA
<li>SHA256withRSA
<li>SHA384withRSA
<li>SHA512withRSA
<li>SHA1withRSAandMGF1
<li>SHA256withRSAandMGF1
<li>SHA384withRSAandMGF1
<li>SHA512withRSAandMGF1
</ul>
<h4>PBE</h4>
<p>Schemes:
<ul>
<li>PKCS5S1, any Digest, any symmetric Cipher, ASCII
<li>PKCS5S2, SHA1/HMac, any symmetric Cipher, ASCII
<li>PKCS12, any Digest, any symmetric Cipher, Unicode
</ul>
<p>
Defined in Bouncy Castle JCE Provider
<table cellpadding=5 cellspacing=0 border=1 width=80%>
<tr><th>Name</th><th>Key Generation Scheme</th><th>Key Length (in bits)</th></tr>
<tr><td>PBEWithMD2AndDES</td><td>PKCS5 Scheme 1</td><td>64</td></tr>
<tr><td>PBEWithMD2AndRC2</td><td>PKCS5 Scheme 1</td><td>128</td></tr>
<tr><td>PBEWithMD5AndDES</td><td>PKCS5 Scheme 1</td><td>64</td></tr>
<tr><td>PBEWithMD5AndRC2</td><td>PKCS5 Scheme 1</td><td>128</td></tr>
<tr><td>PBEWithSHA1AndDES</td><td>PKCS5 Scheme 1</td><td>64</td></tr>
<tr><td>PBEWithSHA1AndRC2</td><td>PKCS5 Scheme 1</td><td>128</td></tr>
<tr><td>PBEWithSHAAnd2-KeyTripleDES-CBC</td><td>PKCS12</td><td>128</td></tr>
<tr><td>PBEWithSHAAnd3-KeyTripleDES-CBC</td><td>PKCS12</td><td>192</td></tr>
<tr><td>PBEWithSHAAnd128BitRC2-CBC</td><td>PKCS12</td><td>128</td></tr>
<tr><td>PBEWithSHAAnd40BitRC2-CBC</td><td>PKCS12</td><td>40</td></tr>
<tr><td>PBEWithSHAAnd128BitRC4</td><td>PKCS12</td><td>128</td></tr>
<tr><td>PBEWithSHAAnd40BitRC4</td><td>PKCS12</td><td>40</td></tr>
<tr><td>PBEWithSHAAndTwofish-CBC</td><td>PKCS12</td><td>256</td></tr>
<tr><td>PBEWithSHAAndIDEA-CBC</td><td>PKCS12</td><td>128</td></tr>
</table>
<h3>5.3 Certificates</h3>
<p>
The Bouncy Castle provider will read X.509 certficates (v2 or v3) as per the examples in
the java.security.cert.CertificateFactory class. They can be provided either
in the normal PEM encoded format, or as DER binaries.
<p>
The CertificiateFactory will also read X.509 CRLs (v2) from either PEM or DER encodings.
<p>
In addition to the classes in the org.bouncycastle.asn1.x509 package for certificate
generation a more JCE "friendly" class is provided in the package org.bouncycastle.x509. The JCE "friendly" class supports RSA, DSA, and EC-DSA.
<p>
<h3>5.4 Keystore</h3>
<p>
The Bouncy Castle package has three implementation of a keystore.
<p>
The first "BKS" is a keystore that will work with the keytool in the same
fashion as the Sun "JKS" keystore. The keystore is resistent to tampering
but not inspection.
<p>
The second, <b>Keystore.BouncyCastle</b>, or <b>Keystore.UBER</b> will only work with the keytool
if the password is provided on the command line, as the entire keystore
is encrypted
with a PBE based on SHA1 and Twofish. <b>PBEWithSHAAndTwofish-CBC</b>.
This makes the entire keystore resistant to tampering and inspection,
and forces verification.
The Sun JDK provided keytool will attempt to load a keystore even if no
password is given,
this is impossible for this version. (One might wonder about going to all
this trouble and then having the password on the command line! New keytool
anyone?).
<p>
In the first case, the keys are encrypted with 3-Key-TripleDES.
<p>
The third is a PKCS12 compatible keystore. PKCS12 provides a slightly
different situation from the regular key store, the keystore password is
currently the only password used for storing keys. Otherwise it supports
all the functionality required for it to be used with the keytool. In some
situations other libraries always expect to be dealing with Sun certificates,
if this is the case use PKCS12-DEF, and the certificates produced by the
key store will be made using the default provider. In the default case PKCS12 uses 3DES for key protection and 40 bit RC2 for protecting the certificates. It is also possible to use 3DES for both by using PKCS12-3DES-3DES or PKCS12-DEF-3DES-3DES as the KeyStore type.
<p>
There is an example program that produces PKCS12 files suitable for
loading into browsers. It is in the package
org.bouncycastle.jce.examples.
<p>
<p>
<h3>5.5 Additional support classes for Elliptic Curve.</h3>
<p>
There are no classes for supporting EC in the JDK prior to JDK 1.5. If you are using
an earlier JDK you can find classes for using EC in the following
packages:
<ul>
<li>org.bouncycastle.jce.spec</li>
<li>org.bouncycastle.jce.interfaces</li>
<li>org.bouncycastle.jce</li>
</ul>
<h3>6.0 BouncyCastle S/MIME</h3>
To be able to fully compile and utilise the BouncyCastle S/MIME
package (including the test classes) you need the jar files for
the following APIs.
<ul>
<li>Junit - <a href="http://www.junit.org">http://www.junit.org</a>
<li>JavaMail - <a href="http://java.sun.com/products/javamail/index.html">http://java.sun.com/products/javamail/index.html</a>
<li>The Java Activation Framework - <a href="http://java.sun.com/products/javabeans/glasgow/jaf.html">http://java.sun.com/products/javabeans/glasgow/jaf.html</a>
</ul>
<h3>6.1 Setting up BouncyCastle S/MIME in JavaMail</h3>
The BouncyCastle S/MIME handlers may be set in JavaMail two ways.
<ul>
<li> STATICALLY<br>
Add the following entries to the mailcap file:
<pre>
application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature
application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime
application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature
application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime
multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed
</pre>
<li> DYNAMICALLY<br>
The following code will add the BouncyCastle S/MIME handlers dynamically:
<pre>
import javax.activation.MailcapCommandMap;
import javax.activation.CommandMap;
public static void setDefaultMailcap()
{
MailcapCommandMap _mailcap =
(MailcapCommandMap)CommandMap.getDefaultCommandMap();
_mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
_mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
_mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
_mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
_mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
CommandMap.setDefaultCommandMap(_mailcap);
}
</pre>
</body>
</html>

View File

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Class-Path:

View File

@ -0,0 +1,63 @@
package org.bc;
/**
* The Bouncy Castle License
*
* Copyright (c) 2000-2012 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-2012 The Legion Of The Bouncy Castle (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.bc.asn1;
import java.io.IOException;
public interface ASN1ApplicationSpecificParser
extends ASN1Encodable, InMemoryRepresentable
{
ASN1Encodable readObject()
throws IOException;
}

View File

@ -0,0 +1,15 @@
package org.bc.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.bc.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.bc.asn1;
public interface ASN1Encodable
{
ASN1Primitive toASN1Primitive();
}

View File

@ -0,0 +1,36 @@
package org.bc.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.bc.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.bc.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.bc.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.bc.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.bc.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.bc.asn1;
import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.bc.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.bc.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.bc.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.bc.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,37 @@
package org.bc.asn1;
public class ASN1ObjectIdentifier
extends DERObjectIdentifier
{
public ASN1ObjectIdentifier(String identifier)
{
super(identifier);
}
ASN1ObjectIdentifier(byte[] bytes)
{
super(bytes);
}
/**
* 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(getId() + "." + 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.bc.asn1;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.bc.util.Arrays;
import org.bc.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.bc.asn1;
import java.io.InputStream;
public interface ASN1OctetStringParser
extends ASN1Encodable, InMemoryRepresentable
{
public InputStream getOctetStream();
}

View File

@ -0,0 +1,194 @@
package org.bc.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.bc.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.bc.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.bc.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.bc.asn1;
import java.io.IOException;
public interface ASN1SequenceParser
extends ASN1Encodable, InMemoryRepresentable
{
ASN1Encodable readObject()
throws IOException;
}

View File

@ -0,0 +1,460 @@
package org.bc.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.bc.asn1;
import java.io.IOException;
public interface ASN1SetParser
extends ASN1Encodable, InMemoryRepresentable
{
public ASN1Encodable readObject()
throws IOException;
}

View File

@ -0,0 +1,247 @@
package org.bc.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.bc.asn1;
public interface ASN1String
{
public String getString();
}

View File

@ -0,0 +1,236 @@
package org.bc.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.bc.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.bc.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.bc.asn1;
public class BERApplicationSpecific
extends DERApplicationSpecific
{
public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
{
super(tagNo, vec);
}
}

View File

@ -0,0 +1,41 @@
package org.bc.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.bc.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.bc.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.bc.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.bc.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.bc.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.bc.asn1;
import java.io.IOException;
import java.io.InputStream;
import org.bc.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.bc.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.bc.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.bc.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.bc.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.bc.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.bc.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.bc.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.bc.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.bc.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
public static final int SET = 0x11;
public static final int SET_OF = 0x11; // for completeness
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.bc.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.bc.asn1;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.bc.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.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.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.bc.asn1;
import java.io.IOException;
import org.bc.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.bc.asn1;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import org.bc.util.Arrays;
import org.bc.util.io.Streams;
public class DERBitString
extends ASN1Primitive
implements ASN1String
{
private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
protected byte[] data;
protected int padBits;
/**
* return the correct number of pad bits for a bit string defined in
* a 32 bit constant
*/
static protected int getPadBits(
int bitString)
{
int val = 0;
for (int i = 3; i >= 0; i--)
{
//
// this may look a little odd, but if it isn't done like this pre jdk1.2
// JVM's break!
//
if (i != 0)
{
if ((bitString >> (i * 8)) != 0)
{
val = (bitString >> (i * 8)) & 0xFF;
break;
}
}
else
{
if (bitString != 0)
{
val = bitString & 0xFF;
break;
}
}
}
if (val == 0)
{
return 7;
}
int bits = 1;
while (((val <<= 1) & 0xFF) != 0)
{
bits++;
}
return 8 - bits;
}
/**
* return the correct number of bytes for a bit string defined in
* a 32 bit constant
*/
static protected byte[] getBytes(int bitString)
{
int bytes = 4;
for (int i = 3; i >= 1; i--)
{
if ((bitString & (0xFF << (i * 8))) != 0)
{
break;
}
bytes--;
}
byte[] result = new byte[bytes];
for (int i = 0; i < bytes; i++)
{
result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
}
return result;
}
/**
* return a Bit String from the passed in object
*
* @exception IllegalArgumentException if the object cannot be converted.
*/
public static DERBitString getInstance(
Object obj)
{
if (obj == null || obj instanceof DERBitString)
{
return (DERBitString)obj;
}
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
}
/**
* return a Bit String from a tagged object.
*
* @param obj the tagged object holding the object we want
* @param explicit true if the object is meant to be explicitly
* tagged false otherwise.
* @exception IllegalArgumentException if the tagged object cannot
* be converted.
*/
public static DERBitString getInstance(
ASN1TaggedObject obj,
boolean explicit)
{
ASN1Primitive o = obj.getObject();
if (explicit || o instanceof DERBitString)
{
return getInstance(o);
}
else
{
return fromOctetString(((ASN1OctetString)o).getOctets());
}
}
protected DERBitString(
byte data,
int padBits)
{
this.data = new byte[1];
this.data[0] = data;
this.padBits = padBits;
}
/**
* @param data the octets making up the bit string.
* @param padBits the number of extra bits at the end of the string.
*/
public DERBitString(
byte[] data,
int padBits)
{
this.data = data;
this.padBits = padBits;
}
public DERBitString(
byte[] data)
{
this(data, 0);
}
public DERBitString(
int value)
{
this.data = getBytes(value);
this.padBits = getPadBits(value);
}
public DERBitString(
ASN1Encodable obj)
throws IOException
{
this.data = obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
this.padBits = 0;
}
public byte[] getBytes()
{
return data;
}
public int getPadBits()
{
return padBits;
}
/**
* @return the value of the bit string as an int (truncating if necessary)
*/
public int intValue()
{
int value = 0;
for (int i = 0; i != data.length && i != 4; i++)
{
value |= (data[i] & 0xff) << (8 * i);
}
return value;
}
boolean isConstructed()
{
return false;
}
int encodedLength()
{
return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;
}
void encode(
ASN1OutputStream out)
throws IOException
{
byte[] bytes = new byte[getBytes().length + 1];
bytes[0] = (byte)getPadBits();
System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
out.writeEncoded(BERTags.BIT_STRING, bytes);
}
public int hashCode()
{
return padBits ^ Arrays.hashCode(data);
}
protected boolean asn1Equals(
ASN1Primitive o)
{
if (!(o instanceof DERBitString))
{
return false;
}
DERBitString other = (DERBitString)o;
return this.padBits == other.padBits
&& Arrays.areEqual(this.data, other.data);
}
public String getString()
{
StringBuffer buf = new StringBuffer("#");
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
try
{
aOut.writeObject(this);
}
catch (IOException e)
{
throw new RuntimeException("internal error encoding BitString");
}
byte[] string = bOut.toByteArray();
for (int i = 0; i != string.length; i++)
{
buf.append(table[(string[i] >>> 4) & 0xf]);
buf.append(table[string[i] & 0xf]);
}
return buf.toString();
}
public String toString()
{
return getString();
}
static DERBitString fromOctetString(byte[] bytes)
{
if (bytes.length < 1)
{
throw new IllegalArgumentException("truncated BIT STRING detected");
}
int padBits = bytes[0];
byte[] data = new byte[bytes.length - 1];
if (data.length != 0)
{
System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
}
return new DERBitString(data, padBits);
}
static DERBitString fromInputStream(int length, InputStream stream)
throws IOException
{
if (length < 1)
{
throw new IllegalArgumentException("truncated BIT STRING detected");
}
int padBits = stream.read();
byte[] data = new byte[length - 1];
if (data.length != 0)
{
if (Streams.readFully(stream, data) != data.length)
{
throw new EOFException("EOF encountered in middle of BIT STRING");
}
}
return new DERBitString(data, padBits);
}
}

View File

@ -0,0 +1,179 @@
package org.bc.asn1;
import java.io.IOException;
import org.bc.util.Arrays;
public class DERBoolean
extends ASN1Primitive
{
private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
private static final byte[] FALSE_VALUE = new byte[] { 0 };
private byte[] value;
public static final ASN1Boolean FALSE = new ASN1Boolean(false);
public static final ASN1Boolean TRUE = new ASN1Boolean(true);
/**
* return a boolean from the passed in object.
*
* @exception IllegalArgumentException if the object cannot be converted.
*/
public static ASN1Boolean getInstance(
Object obj)
{
if (obj == null || obj instanceof ASN1Boolean)
{
return (ASN1Boolean)obj;
}
if (obj instanceof DERBoolean)
{
return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE;
}
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
}
/**
* return a ASN1Boolean from the passed in boolean.
*/
public static ASN1Boolean getInstance(
boolean value)
{
return (value ? TRUE : FALSE);
}
/**
* return a ASN1Boolean from the passed in boolean.
*/
public static ASN1Boolean getInstance(
int value)
{
return (value != 0 ? TRUE : FALSE);
}
/**
* return a Boolean from a tagged object.
*
* @param obj the tagged object holding the object we want
* @param explicit true if the object is meant to be explicitly
* tagged false otherwise.
* @exception IllegalArgumentException if the tagged object cannot
* be converted.
*/
public static DERBoolean getInstance(
ASN1TaggedObject obj,
boolean explicit)
{
ASN1Primitive o = obj.getObject();
if (explicit || o instanceof DERBoolean)
{
return getInstance(o);
}
else
{
return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
}
}
DERBoolean(
byte[] value)
{
if (value.length != 1)
{
throw new IllegalArgumentException("byte value should have 1 byte in it");
}
if (value[0] == 0)
{
this.value = FALSE_VALUE;
}
else if (value[0] == 0xff)
{
this.value = TRUE_VALUE;
}
else
{
this.value = Arrays.clone(value);
}
}
/**
* @deprecated use getInstance(boolean) method.
* @param value
*/
public DERBoolean(
boolean value)
{
this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
}
public boolean isTrue()
{
return (value[0] != 0);
}
boolean isConstructed()
{
return false;
}
int encodedLength()
{
return 3;
}
void encode(
ASN1OutputStream out)
throws IOException
{
out.writeEncoded(BERTags.BOOLEAN, value);
}
protected boolean asn1Equals(
ASN1Primitive o)
{
if ((o == null) || !(o instanceof DERBoolean))
{
return false;
}
return (value[0] == ((DERBoolean)o).value[0]);
}
public int hashCode()
{
return value[0];
}
public String toString()
{
return (value[0] != 0) ? "TRUE" : "FALSE";
}
static ASN1Boolean fromOctetString(byte[] value)
{
if (value.length != 1)
{
throw new IllegalArgumentException("byte value should have 1 byte in it");
}
if (value[0] == 0)
{
return FALSE;
}
else if (value[0] == 0xff)
{
return TRUE;
}
else
{
return new ASN1Boolean(value);
}
}
}

View File

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

View File

@ -0,0 +1,158 @@
package org.bc.asn1;
import java.io.IOException;
import java.math.BigInteger;
import org.bc.util.Arrays;
public class DEREnumerated
extends ASN1Primitive
{
byte[] bytes;
/**
* return an integer from the passed in object
*
* @exception IllegalArgumentException if the object cannot be converted.
*/
public static ASN1Enumerated getInstance(
Object obj)
{
if (obj == null || obj instanceof ASN1Enumerated)
{
return (ASN1Enumerated)obj;
}
if (obj instanceof DEREnumerated)
{
return new ASN1Enumerated(((DEREnumerated)obj).getValue());
}
if (obj instanceof byte[])
{
try
{
return (ASN1Enumerated)fromByteArray((byte[])obj);
}
catch (Exception e)
{
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
}
}
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
}
/**
* return an Enumerated from a tagged object.
*
* @param obj the tagged object holding the object we want
* @param explicit true if the object is meant to be explicitly
* tagged false otherwise.
* @exception IllegalArgumentException if the tagged object cannot
* be converted.
*/
public static DEREnumerated getInstance(
ASN1TaggedObject obj,
boolean explicit)
{
ASN1Primitive o = obj.getObject();
if (explicit || o instanceof DEREnumerated)
{
return getInstance(o);
}
else
{
return fromOctetString(((ASN1OctetString)o).getOctets());
}
}
public DEREnumerated(
int value)
{
bytes = BigInteger.valueOf(value).toByteArray();
}
public DEREnumerated(
BigInteger value)
{
bytes = value.toByteArray();
}
public DEREnumerated(
byte[] bytes)
{
this.bytes = bytes;
}
public BigInteger getValue()
{
return new BigInteger(bytes);
}
boolean isConstructed()
{
return false;
}
int encodedLength()
{
return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
}
void encode(
ASN1OutputStream out)
throws IOException
{
out.writeEncoded(BERTags.ENUMERATED, bytes);
}
boolean asn1Equals(
ASN1Primitive o)
{
if (!(o instanceof DEREnumerated))
{
return false;
}
DEREnumerated other = (DEREnumerated)o;
return Arrays.areEqual(this.bytes, other.bytes);
}
public int hashCode()
{
return Arrays.hashCode(bytes);
}
private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
static ASN1Enumerated fromOctetString(byte[] enc)
{
if (enc.length > 1)
{
return new ASN1Enumerated(Arrays.clone(enc));
}
if (enc.length == 0)
{
throw new IllegalArgumentException("ENUMERATED has zero length");
}
int value = enc[0] & 0xff;
if (value >= cache.length)
{
return new ASN1Enumerated(Arrays.clone(enc));
}
ASN1Enumerated possibleMatch = cache[value];
if (possibleMatch == null)
{
possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
}
return possibleMatch;
}
}

View File

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

View File

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

View File

@ -0,0 +1,17 @@
package org.bc.asn1;
class DERFactory
{
static final ASN1Sequence EMPTY_SEQUENCE = new DERSequence();
static final ASN1Set EMPTY_SET = new DERSet();
static ASN1Sequence createSequence(ASN1EncodableVector v)
{
return v.size() < 1 ? EMPTY_SEQUENCE : new DLSequence(v);
}
static ASN1Set createSet(ASN1EncodableVector v)
{
return v.size() < 1 ? EMPTY_SET : new DLSet(v);
}
}

View File

@ -0,0 +1,110 @@
package org.bc.asn1;
import java.io.IOException;
import org.bc.util.Arrays;
import org.bc.util.Strings;
public class DERGeneralString
extends ASN1Primitive
implements ASN1String
{
private byte[] string;
public static DERGeneralString getInstance(
Object obj)
{
if (obj == null || obj instanceof DERGeneralString)
{
return (DERGeneralString) obj;
}
if (obj instanceof byte[])
{
try
{
return (DERGeneralString)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());
}
public static DERGeneralString getInstance(
ASN1TaggedObject obj,
boolean explicit)
{
ASN1Primitive o = obj.getObject();
if (explicit || o instanceof DERGeneralString)
{
return getInstance(o);
}
else
{
return new DERGeneralString(((ASN1OctetString)o).getOctets());
}
}
DERGeneralString(byte[] string)
{
this.string = string;
}
public DERGeneralString(String string)
{
this.string = Strings.toByteArray(string);
}
public String getString()
{
return Strings.fromByteArray(string);
}
public String toString()
{
return getString();
}
public byte[] getOctets()
{
return Arrays.clone(string);
}
boolean isConstructed()
{
return false;
}
int encodedLength()
{
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
}
void encode(ASN1OutputStream out)
throws IOException
{
out.writeEncoded(BERTags.GENERAL_STRING, string);
}
public int hashCode()
{
return Arrays.hashCode(string);
}
boolean asn1Equals(ASN1Primitive o)
{
if (!(o instanceof DERGeneralString))
{
return false;
}
DERGeneralString s = (DERGeneralString)o;
return Arrays.areEqual(string, s.string);
}
}

View File

@ -0,0 +1,350 @@
package org.bc.asn1;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import org.bc.util.Arrays;
import org.bc.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);
}
if (obj instanceof byte[])
{
try
{
return (ASN1GeneralizedTime)fromByteArray((byte[])obj);
}
catch (Exception e)
{
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
}
}
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
}
/**
* return a Generalized Time object from a tagged object.
*
* @param obj the tagged object holding the object we want
* @param explicit true if the object is meant to be explicitly
* tagged false otherwise.
* @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)
{
this.time = Strings.toByteArray(time);
try
{
this.getDate();
}
catch (ParseException e)
{
throw new IllegalArgumentException("invalid date string: " + e.getMessage());
}
}
/**
* base constructor from a java.util.date object
*/
public DERGeneralizedTime(
Date time)
{
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
this.time = Strings.toByteArray(dateF.format(time));
}
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()
throws ParseException
{
SimpleDateFormat dateF;
String stime = Strings.fromByteArray(time);
String d = stime;
if (stime.endsWith("Z"))
{
if (hasFractionalSeconds())
{
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
}
else
{
dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
}
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
}
else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0)
{
d = this.getTime();
if (hasFractionalSeconds())
{
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz");
}
else
{
dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
}
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
}
else
{
if (hasFractionalSeconds())
{
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
}
else
{
dateF = new SimpleDateFormat("yyyyMMddHHmmss");
}
dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
}
if (hasFractionalSeconds())
{
// java misinterprets extra digits as being milliseconds...
String frac = d.substring(14);
int index;
for (index = 1; index < frac.length(); index++)
{
char ch = frac.charAt(index);
if (!('0' <= ch && ch <= '9'))
{
break;
}
}
if (index - 1 > 3)
{
frac = frac.substring(0, 4) + frac.substring(index);
d = d.substring(0, 14) + frac;
}
else if (index - 1 == 1)
{
frac = frac.substring(0, index) + "00" + frac.substring(index);
d = d.substring(0, 14) + frac;
}
else if (index - 1 == 2)
{
frac = frac.substring(0, index) + "0" + frac.substring(index);
d = d.substring(0, 14) + frac;
}
}
return dateF.parse(d);
}
private boolean hasFractionalSeconds()
{
for (int i = 0; i != time.length; i++)
{
if (time[i] == '.')
{
if (i == 14)
{
return true;
}
}
}
return false;
}
boolean isConstructed()
{
return false;
}
int encodedLength()
{
int length = time.length;
return 1 + StreamUtil.calculateBodyLength(length) + length;
}
void encode(
ASN1OutputStream out)
throws IOException
{
out.writeEncoded(BERTags.GENERALIZED_TIME, time);
}
boolean asn1Equals(
ASN1Primitive o)
{
if (!(o instanceof DERGeneralizedTime))
{
return false;
}
return Arrays.areEqual(time, ((DERGeneralizedTime)o).time);
}
public int hashCode()
{
return Arrays.hashCode(time);
}
}

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