changeset 52:c29040605f25

2007-06-22 Andrew Haley <aph@redhat.com> * Makefile.am (ICEDTEA_PATCHES): Add icedtea-debuginfo.patch. Add -g option to all Java compilations. (ICEDTEA_COPY_SRC): Copy a bunch of files needed to build GNU crypto. * jce/gnu/java/security/hash/BaseHash.java, jce/gnu/java/security/hash/HashFactory.java, jce/gnu/java/security/hash/Haval.java, jce/gnu/java/security/hash/IMessageDigest.java, jce/gnu/java/security/hash/MD2.java, jce/gnu/java/security/hash/MD4.java, jce/gnu/java/security/hash/MD5.java, jce/gnu/java/security/hash/RipeMD128.java, jce/gnu/java/security/hash/RipeMD160.java, jce/gnu/java/security/hash/Sha160.java, jce/gnu/java/security/hash/Sha256.java, jce/gnu/java/security/hash/Sha384.java, jce/gnu/java/security/hash/Sha512.java, jce/gnu/java/security/hash/Tiger.java, jce/gnu/java/security/hash/Whirlpool.java, jce/gnu/java/security/jce/hash/HavalSpi.java, jce/gnu/java/security/jce/hash/MD2Spi.java, jce/gnu/java/security/jce/hash/MD4Spi.java, jce/gnu/java/security/jce/hash/MD5Spi.java, jce/gnu/java/security/jce/hash/MessageDigestAdapter.java, jce/gnu/java/security/jce/hash/RipeMD128Spi.java, jce/gnu/java/security/jce/hash/RipeMD160Spi.java, jce/gnu/java/security/jce/hash/Sha160Spi.java, jce/gnu/java/security/jce/hash/Sha256Spi.java, jce/gnu/java/security/jce/hash/Sha384Spi.java, jce/gnu/java/security/jce/hash/Sha512Spi.java, jce/gnu/java/security/jce/hash/TigerSpi.java, jce/gnu/java/security/jce/hash/WhirlpoolSpi.java, jce/gnu/java/security/jce/prng/HavalRandomSpi.java, jce/gnu/java/security/jce/prng/MD2RandomSpi.java, jce/gnu/java/security/jce/prng/MD4RandomSpi.java, jce/gnu/java/security/jce/prng/MD5RandomSpi.java, jce/gnu/java/security/jce/prng/RipeMD128RandomSpi.java, jce/gnu/java/security/jce/prng/RipeMD160RandomSpi.java, jce/gnu/java/security/jce/prng/SecureRandomAdapter.java, jce/gnu/java/security/jce/prng/Sha160RandomSpi.java, jce/gnu/java/security/jce/prng/Sha256RandomSpi.java, jce/gnu/java/security/jce/prng/Sha384RandomSpi.java, jce/gnu/java/security/jce/prng/Sha512RandomSpi.java, jce/gnu/java/security/jce/prng/TigerRandomSpi.java, jce/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java, jce/gnu/java/security/jce/sig/DSSKeyFactory.java, jce/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java, jce/gnu/java/security/jce/sig/DSSParameters.java, jce/gnu/java/security/jce/sig/DSSParametersGenerator.java, jce/gnu/java/security/jce/sig/DSSRawSignatureSpi.java, jce/gnu/java/security/jce/sig/EncodedKeyFactory.java, jce/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java, jce/gnu/java/security/jce/sig/MD2withRSA.java, jce/gnu/java/security/jce/sig/MD5withRSA.java, jce/gnu/java/security/jce/sig/RSAKeyFactory.java, jce/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java, jce/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java, jce/gnu/java/security/jce/sig/SHA160withDSS.java, jce/gnu/java/security/jce/sig/SHA160withRSA.java, jce/gnu/java/security/jce/sig/SHA256withRSA.java, jce/gnu/java/security/jce/sig/SHA384withRSA.java, jce/gnu/java/security/jce/sig/SHA512withRSA.java, jce/gnu/java/security/jce/sig/SignatureAdapter.java, jce/gnu/java/security/key/IKeyPairCodec.java, jce/gnu/java/security/key/IKeyPairGenerator.java, jce/gnu/java/security/key/KeyPairCodecFactory.java, jce/gnu/java/security/key/KeyPairGeneratorFactory.java, jce/gnu/java/security/key/dss/DSSKey.java, jce/gnu/java/security/key/dss/DSSKeyPairGenerator.java, jce/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java, jce/gnu/java/security/key/dss/DSSKeyPairRawCodec.java, jce/gnu/java/security/key/dss/DSSKeyPairX509Codec.java, jce/gnu/java/security/key/dss/DSSPrivateKey.java, jce/gnu/java/security/key/dss/DSSPublicKey.java, jce/gnu/java/security/key/dss/FIPS186.java, jce/gnu/java/security/key/rsa/GnuRSAKey.java, jce/gnu/java/security/key/rsa/GnuRSAPrivateKey.java, jce/gnu/java/security/key/rsa/GnuRSAPublicKey.java, jce/gnu/java/security/key/rsa/RSAKeyPairGenerator.java, jce/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java, jce/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java, jce/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java, jce/gnu/java/security/prng/BasePRNG.java, jce/gnu/java/security/prng/EntropySource.java, jce/gnu/java/security/prng/IRandom.java, jce/gnu/java/security/prng/LimitReachedException.java, jce/gnu/java/security/prng/MDGenerator.java, jce/gnu/java/security/prng/PRNGFactory.java, jce/gnu/java/security/prng/RandomEvent.java, jce/gnu/java/security/prng/RandomEventListener.java, jce/gnu/java/security/provider/CollectionCertStoreImpl.java, jce/gnu/java/security/provider/DefaultPolicy.java, jce/gnu/java/security/provider/Gnu.java, jce/gnu/java/security/provider/PKIXCertPathValidatorImpl.java, jce/gnu/java/security/provider/X509CertificateFactory.java, jce/gnu/java/security/provider/package.html, jce/gnu/java/security/sig/BaseSignature.java, jce/gnu/java/security/sig/ISignature.java, jce/gnu/java/security/sig/ISignatureCodec.java, jce/gnu/java/security/sig/SignatureCodecFactory.java, jce/gnu/java/security/sig/SignatureFactory.java, jce/gnu/java/security/sig/dss/DSSSignature.java, jce/gnu/java/security/sig/dss/DSSSignatureRawCodec.java, jce/gnu/java/security/sig/dss/DSSSignatureX509Codec.java, jce/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java, jce/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java, jce/gnu/java/security/sig/rsa/EMSA_PSS.java, jce/gnu/java/security/sig/rsa/RSA.java, jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java, jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java, jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java, jce/gnu/java/security/sig/rsa/RSAPSSSignature.java, jce/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java, jce/gnu/java/security/sig/rsa/RSASignatureFactory.java, jce/gnu/java/security/util/ByteArray.java, jce/gnu/java/security/util/ByteBufferOutputStream.java, jce/gnu/java/security/util/DerUtil.java, jce/gnu/java/security/util/ExpirableObject.java, jce/gnu/java/security/util/FormatUtil.java, jce/gnu/java/security/util/IntegerUtil.java, jce/gnu/java/security/util/PRNG.java, jce/gnu/java/security/util/Prime.java, jce/gnu/java/security/util/Sequence.java, jce/gnu/java/security/util/SimpleList.java, jce/gnu/java/security/util/Util.java, jce/gnu/java/security/util/package.html, jce/gnu/java/security/x509/GnuPKIExtension.java, jce/gnu/java/security/x509/PolicyNodeImpl.java, jce/gnu/java/security/x509/X500DistinguishedName.java, jce/gnu/java/security/x509/X509CRL.java, jce/gnu/java/security/x509/X509CRLEntry.java, jce/gnu/java/security/x509/X509CRLSelectorImpl.java, jce/gnu/java/security/x509/X509CertPath.java, jce/gnu/java/security/x509/X509CertSelectorImpl.java, jce/gnu/java/security/x509/X509Certificate.java, jce/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java, jce/gnu/java/security/x509/ext/BasicConstraints.java, jce/gnu/java/security/x509/ext/CRLNumber.java, jce/gnu/java/security/x509/ext/CertificatePolicies.java, jce/gnu/java/security/x509/ext/ExtendedKeyUsage.java, jce/gnu/java/security/x509/ext/Extension.java, jce/gnu/java/security/x509/ext/GeneralName.java, jce/gnu/java/security/x509/ext/GeneralNames.java, jce/gnu/java/security/x509/ext/GeneralSubtree.java, jce/gnu/java/security/x509/ext/IssuerAlternativeNames.java, jce/gnu/java/security/x509/ext/KeyUsage.java, jce/gnu/java/security/x509/ext/NameConstraints.java, jce/gnu/java/security/x509/ext/PolicyConstraint.java, jce/gnu/java/security/x509/ext/PolicyMappings.java, jce/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java, jce/gnu/java/security/x509/ext/ReasonCode.java, jce/gnu/java/security/x509/ext/SubjectAlternativeNames.java, jce/gnu/java/security/x509/ext/SubjectKeyIdentifier.java, jce/gnu/java/security/x509/ext/package.html, jce/gnu/java/security/x509/package.html, jce/gnu/javax/crypto/RSACipherImpl.java, jce/gnu/javax/crypto/assembly/Assembly.java, jce/gnu/javax/crypto/assembly/Cascade.java, jce/gnu/javax/crypto/assembly/CascadeStage.java, jce/gnu/javax/crypto/assembly/CascadeTransformer.java, jce/gnu/javax/crypto/assembly/DeflateTransformer.java, jce/gnu/javax/crypto/assembly/Direction.java, jce/gnu/javax/crypto/assembly/LoopbackTransformer.java, jce/gnu/javax/crypto/assembly/ModeStage.java, jce/gnu/javax/crypto/assembly/Operation.java, jce/gnu/javax/crypto/assembly/PaddingTransformer.java, jce/gnu/javax/crypto/assembly/Stage.java, jce/gnu/javax/crypto/assembly/Transformer.java, jce/gnu/javax/crypto/assembly/TransformerException.java, jce/gnu/javax/crypto/cipher/Anubis.java, jce/gnu/javax/crypto/cipher/BaseCipher.java, jce/gnu/javax/crypto/cipher/Blowfish.java, jce/gnu/javax/crypto/cipher/Cast5.java, jce/gnu/javax/crypto/cipher/CipherFactory.java, jce/gnu/javax/crypto/cipher/DES.java, jce/gnu/javax/crypto/cipher/IBlockCipher.java, jce/gnu/javax/crypto/cipher/IBlockCipherSpi.java, jce/gnu/javax/crypto/cipher/Khazad.java, jce/gnu/javax/crypto/cipher/NullCipher.java, jce/gnu/javax/crypto/cipher/Rijndael.java, jce/gnu/javax/crypto/cipher/Serpent.java, jce/gnu/javax/crypto/cipher/Square.java, jce/gnu/javax/crypto/cipher/TripleDES.java, jce/gnu/javax/crypto/cipher/Twofish.java, jce/gnu/javax/crypto/cipher/WeakKeyException.java, jce/gnu/javax/crypto/jce/DiffieHellmanImpl.java, jce/gnu/javax/crypto/jce/GnuCrypto.java, jce/gnu/javax/crypto/jce/GnuSasl.java, jce/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java, jce/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java, jce/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java, jce/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java, jce/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java, jce/gnu/javax/crypto/jce/cipher/AESSpi.java, jce/gnu/javax/crypto/jce/cipher/ARCFourSpi.java, jce/gnu/javax/crypto/jce/cipher/AnubisSpi.java, jce/gnu/javax/crypto/jce/cipher/BlowfishSpi.java, jce/gnu/javax/crypto/jce/cipher/Cast5Spi.java, jce/gnu/javax/crypto/jce/cipher/CipherAdapter.java, jce/gnu/javax/crypto/jce/cipher/DESSpi.java, jce/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java, jce/gnu/javax/crypto/jce/cipher/KhazadSpi.java, jce/gnu/javax/crypto/jce/cipher/NullCipherSpi.java, jce/gnu/javax/crypto/jce/cipher/PBES2.java, jce/gnu/javax/crypto/jce/cipher/RijndaelSpi.java, jce/gnu/javax/crypto/jce/cipher/SerpentSpi.java, jce/gnu/javax/crypto/jce/cipher/SquareSpi.java, jce/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java, jce/gnu/javax/crypto/jce/cipher/TripleDESSpi.java, jce/gnu/javax/crypto/jce/cipher/TwofishSpi.java, jce/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java, jce/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java, jce/gnu/javax/crypto/jce/keyring/GnuKeyring.java, jce/gnu/javax/crypto/jce/mac/HMacHavalSpi.java, jce/gnu/javax/crypto/jce/mac/HMacMD2Spi.java, jce/gnu/javax/crypto/jce/mac/HMacMD4Spi.java, jce/gnu/javax/crypto/jce/mac/HMacMD5Spi.java, jce/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java, jce/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java, jce/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java, jce/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java, jce/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java, jce/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java, jce/gnu/javax/crypto/jce/mac/HMacTigerSpi.java, jce/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java, jce/gnu/javax/crypto/jce/mac/MacAdapter.java, jce/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java, jce/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java, jce/gnu/javax/crypto/jce/mac/OMacCast5Impl.java, jce/gnu/javax/crypto/jce/mac/OMacDESImpl.java, jce/gnu/javax/crypto/jce/mac/OMacImpl.java, jce/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java, jce/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java, jce/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java, jce/gnu/javax/crypto/jce/mac/OMacSquareImpl.java, jce/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java, jce/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java, jce/gnu/javax/crypto/jce/mac/TMMH16Spi.java, jce/gnu/javax/crypto/jce/mac/UHash32Spi.java, jce/gnu/javax/crypto/jce/mac/UMac32Spi.java, jce/gnu/javax/crypto/jce/params/BlockCipherParameters.java, jce/gnu/javax/crypto/jce/params/DEREncodingException.java, jce/gnu/javax/crypto/jce/params/DERReader.java, jce/gnu/javax/crypto/jce/params/DERWriter.java, jce/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java, jce/gnu/javax/crypto/jce/prng/CSPRNGSpi.java, jce/gnu/javax/crypto/jce/prng/FortunaImpl.java, jce/gnu/javax/crypto/jce/prng/ICMRandomSpi.java, jce/gnu/javax/crypto/jce/prng/UMacRandomSpi.java, jce/gnu/javax/crypto/jce/sig/DHKeyFactory.java, jce/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java, jce/gnu/javax/crypto/jce/sig/DHParameters.java, jce/gnu/javax/crypto/jce/sig/DHParametersGenerator.java, jce/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java, jce/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java, jce/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java, jce/gnu/javax/crypto/key/BaseKeyAgreementParty.java, jce/gnu/javax/crypto/key/GnuPBEKey.java, jce/gnu/javax/crypto/key/GnuSecretKey.java, jce/gnu/javax/crypto/key/IKeyAgreementParty.java, jce/gnu/javax/crypto/key/IncomingMessage.java, jce/gnu/javax/crypto/key/KeyAgreementException.java, jce/gnu/javax/crypto/key/KeyAgreementFactory.java, jce/gnu/javax/crypto/key/OutgoingMessage.java, jce/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java, jce/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java, jce/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java, jce/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java, jce/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java, jce/gnu/javax/crypto/key/dh/DiffieHellmanSender.java, jce/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java, jce/gnu/javax/crypto/key/dh/ElGamalReceiver.java, jce/gnu/javax/crypto/key/dh/ElGamalSender.java, jce/gnu/javax/crypto/key/dh/GnuDHKey.java, jce/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java, jce/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java, jce/gnu/javax/crypto/key/dh/GnuDHPublicKey.java, jce/gnu/javax/crypto/key/dh/RFC2631.java, jce/gnu/javax/crypto/key/srp6/SRP6Host.java, jce/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java, jce/gnu/javax/crypto/key/srp6/SRP6SaslClient.java, jce/gnu/javax/crypto/key/srp6/SRP6SaslServer.java, jce/gnu/javax/crypto/key/srp6/SRP6TLSClient.java, jce/gnu/javax/crypto/key/srp6/SRP6TLSServer.java, jce/gnu/javax/crypto/key/srp6/SRP6User.java, jce/gnu/javax/crypto/key/srp6/SRPAlgorithm.java, jce/gnu/javax/crypto/key/srp6/SRPKey.java, jce/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java, jce/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java, jce/gnu/javax/crypto/key/srp6/SRPPrivateKey.java, jce/gnu/javax/crypto/key/srp6/SRPPublicKey.java, jce/gnu/javax/crypto/keyring/AuthenticatedEntry.java, jce/gnu/javax/crypto/keyring/BaseKeyring.java, jce/gnu/javax/crypto/keyring/BinaryDataEntry.java, jce/gnu/javax/crypto/keyring/CertPathEntry.java, jce/gnu/javax/crypto/keyring/CertificateEntry.java, jce/gnu/javax/crypto/keyring/CompressedEntry.java, jce/gnu/javax/crypto/keyring/EncryptedEntry.java, jce/gnu/javax/crypto/keyring/Entry.java, jce/gnu/javax/crypto/keyring/EnvelopeEntry.java, jce/gnu/javax/crypto/keyring/GnuPrivateKeyring.java, jce/gnu/javax/crypto/keyring/GnuPublicKeyring.java, jce/gnu/javax/crypto/keyring/IKeyring.java, jce/gnu/javax/crypto/keyring/IPrivateKeyring.java, jce/gnu/javax/crypto/keyring/IPublicKeyring.java, jce/gnu/javax/crypto/keyring/MalformedKeyringException.java, jce/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java, jce/gnu/javax/crypto/keyring/MeteredInputStream.java, jce/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java, jce/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java, jce/gnu/javax/crypto/keyring/PasswordProtectedEntry.java, jce/gnu/javax/crypto/keyring/PrimitiveEntry.java, jce/gnu/javax/crypto/keyring/PrivateKeyEntry.java, jce/gnu/javax/crypto/keyring/Properties.java, jce/gnu/javax/crypto/keyring/PublicKeyEntry.java, jce/gnu/javax/crypto/kwa/AESKeyWrap.java, jce/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java, jce/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java, jce/gnu/javax/crypto/kwa/KeyUnwrappingException.java, jce/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java, jce/gnu/javax/crypto/kwa/TripleDESKeyWrap.java, jce/gnu/javax/crypto/mac/BaseMac.java, jce/gnu/javax/crypto/mac/HMac.java, jce/gnu/javax/crypto/mac/HMacFactory.java, jce/gnu/javax/crypto/mac/IMac.java, jce/gnu/javax/crypto/mac/MacFactory.java, jce/gnu/javax/crypto/mac/MacInputStream.java, jce/gnu/javax/crypto/mac/MacOutputStream.java, jce/gnu/javax/crypto/mac/OMAC.java, jce/gnu/javax/crypto/mac/TMMH16.java, jce/gnu/javax/crypto/mac/UHash32.java, jce/gnu/javax/crypto/mac/UMac32.java, jce/gnu/javax/crypto/mode/BaseMode.java, jce/gnu/javax/crypto/mode/CBC.java, jce/gnu/javax/crypto/mode/CFB.java, jce/gnu/javax/crypto/mode/CTR.java, jce/gnu/javax/crypto/mode/EAX.java, jce/gnu/javax/crypto/mode/ECB.java, jce/gnu/javax/crypto/mode/IAuthenticatedMode.java, jce/gnu/javax/crypto/mode/ICM.java, jce/gnu/javax/crypto/mode/IMode.java, jce/gnu/javax/crypto/mode/ModeFactory.java, jce/gnu/javax/crypto/mode/OFB.java, jce/gnu/javax/crypto/pad/BasePad.java, jce/gnu/javax/crypto/pad/IPad.java, jce/gnu/javax/crypto/pad/ISO10126.java, jce/gnu/javax/crypto/pad/PKCS1_V1_5.java, jce/gnu/javax/crypto/pad/PKCS7.java, jce/gnu/javax/crypto/pad/PadFactory.java, jce/gnu/javax/crypto/pad/SSL3.java, jce/gnu/javax/crypto/pad/TBC.java, jce/gnu/javax/crypto/pad/TLS1.java, jce/gnu/javax/crypto/pad/WrongPaddingException.java, jce/gnu/javax/crypto/prng/ARCFour.java, jce/gnu/javax/crypto/prng/CSPRNG.java, jce/gnu/javax/crypto/prng/Fortuna.java, jce/gnu/javax/crypto/prng/ICMGenerator.java, jce/gnu/javax/crypto/prng/IPBE.java, jce/gnu/javax/crypto/prng/PBKDF2.java, jce/gnu/javax/crypto/prng/PRNGFactory.java, jce/gnu/javax/crypto/prng/UMacGenerator.java, jce/gnu/javax/crypto/sasl/AuthInfo.java, jce/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java, jce/gnu/javax/crypto/sasl/ClientFactory.java, jce/gnu/javax/crypto/sasl/ClientMechanism.java, jce/gnu/javax/crypto/sasl/ConfidentialityException.java, jce/gnu/javax/crypto/sasl/IAuthInfoProvider.java, jce/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java, jce/gnu/javax/crypto/sasl/IllegalMechanismStateException.java, jce/gnu/javax/crypto/sasl/InputBuffer.java, jce/gnu/javax/crypto/sasl/IntegrityException.java, jce/gnu/javax/crypto/sasl/NoSuchMechanismException.java, jce/gnu/javax/crypto/sasl/NoSuchUserException.java, jce/gnu/javax/crypto/sasl/OutputBuffer.java, jce/gnu/javax/crypto/sasl/SaslEncodingException.java, jce/gnu/javax/crypto/sasl/SaslInputStream.java, jce/gnu/javax/crypto/sasl/SaslOutputStream.java, jce/gnu/javax/crypto/sasl/SaslUtil.java, jce/gnu/javax/crypto/sasl/ServerFactory.java, jce/gnu/javax/crypto/sasl/ServerMechanism.java, jce/gnu/javax/crypto/sasl/UserAlreadyExistsException.java, jce/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java, jce/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java, jce/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java, jce/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java, jce/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java, jce/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java, jce/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java, jce/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java, jce/gnu/javax/crypto/sasl/crammd5/PasswordFile.java, jce/gnu/javax/crypto/sasl/plain/PasswordFile.java, jce/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java, jce/gnu/javax/crypto/sasl/plain/PlainClient.java, jce/gnu/javax/crypto/sasl/plain/PlainRegistry.java, jce/gnu/javax/crypto/sasl/plain/PlainServer.java, jce/gnu/javax/crypto/sasl/srp/CALG.java, jce/gnu/javax/crypto/sasl/srp/ClientStore.java, jce/gnu/javax/crypto/sasl/srp/IALG.java, jce/gnu/javax/crypto/sasl/srp/KDF.java, jce/gnu/javax/crypto/sasl/srp/PasswordFile.java, jce/gnu/javax/crypto/sasl/srp/SRP.java, jce/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java, jce/gnu/javax/crypto/sasl/srp/SRPClient.java, jce/gnu/javax/crypto/sasl/srp/SRPRegistry.java, jce/gnu/javax/crypto/sasl/srp/SRPServer.java, jce/gnu/javax/crypto/sasl/srp/SecurityContext.java, jce/gnu/javax/crypto/sasl/srp/ServerStore.java, jce/gnu/javax/crypto/sasl/srp/StoreEntry.java, jce/gnu/javax/security/auth/Password.java, jce/gnu/javax/security/auth/callback/AbstractCallbackHandler.java, jce/gnu/javax/security/auth/callback/CertificateCallback.java, jce/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java, jce/gnu/javax/security/auth/callback/DefaultCallbackHandler.java, jce/gnu/javax/security/auth/callback/GnuCallbacks.java, jce/gnu/javax/security/auth/login/ConfigFileParser.java, jce/gnu/javax/security/auth/login/ConfigFileTokenizer.java, jce/gnu/javax/security/auth/login/GnuConfiguration.java, lib/rt/gnu/java/security/provider/Gnu.java, rt/gnu/java/io/Base64InputStream.java, rt/gnu/java/security/provider/Gnu.java, rt/java/util/Timer.java, rt/javax/security/auth/callback/ChoiceCallback.java, rt/javax/security/auth/callback/ConfirmationCallback.java, rt/javax/security/auth/callback/LanguageCallback.java, rt/javax/security/auth/callback/NameCallback.java, rt/javax/security/auth/callback/TextInputCallback.java, rt/javax/security/auth/callback/TextOutputCallback.java, rt/javax/security/sasl/AuthenticationException.java, rt/javax/security/sasl/Sasl.java, rt/javax/security/sasl/SaslClient.java, rt/javax/security/sasl/SaslClientFactory.java, rt/javax/security/sasl/SaslException.java, rt/javax/security/sasl/SaslServer.java, rt/javax/security/sasl/SaslServerFactory.java: New files
author Andrew Haley <aph@redhat.com>
date Tue, 26 Jun 2007 16:11:37 +0100
parents f320d231c00a
children 5c28d36051b8
files ChangeLog Makefile.am Makefile.in jce/gnu/java/security/hash/BaseHash.java jce/gnu/java/security/hash/HashFactory.java jce/gnu/java/security/hash/Haval.java jce/gnu/java/security/hash/IMessageDigest.java jce/gnu/java/security/hash/MD2.java jce/gnu/java/security/hash/MD4.java jce/gnu/java/security/hash/MD5.java jce/gnu/java/security/hash/RipeMD128.java jce/gnu/java/security/hash/RipeMD160.java jce/gnu/java/security/hash/Sha160.java jce/gnu/java/security/hash/Sha256.java jce/gnu/java/security/hash/Sha384.java jce/gnu/java/security/hash/Sha512.java jce/gnu/java/security/hash/Tiger.java jce/gnu/java/security/hash/Whirlpool.java jce/gnu/java/security/jce/hash/HavalSpi.java jce/gnu/java/security/jce/hash/MD2Spi.java jce/gnu/java/security/jce/hash/MD4Spi.java jce/gnu/java/security/jce/hash/MD5Spi.java jce/gnu/java/security/jce/hash/MessageDigestAdapter.java jce/gnu/java/security/jce/hash/RipeMD128Spi.java jce/gnu/java/security/jce/hash/RipeMD160Spi.java jce/gnu/java/security/jce/hash/Sha160Spi.java jce/gnu/java/security/jce/hash/Sha256Spi.java jce/gnu/java/security/jce/hash/Sha384Spi.java jce/gnu/java/security/jce/hash/Sha512Spi.java jce/gnu/java/security/jce/hash/TigerSpi.java jce/gnu/java/security/jce/hash/WhirlpoolSpi.java jce/gnu/java/security/jce/prng/HavalRandomSpi.java jce/gnu/java/security/jce/prng/MD2RandomSpi.java jce/gnu/java/security/jce/prng/MD4RandomSpi.java jce/gnu/java/security/jce/prng/MD5RandomSpi.java jce/gnu/java/security/jce/prng/RipeMD128RandomSpi.java jce/gnu/java/security/jce/prng/RipeMD160RandomSpi.java jce/gnu/java/security/jce/prng/SecureRandomAdapter.java jce/gnu/java/security/jce/prng/Sha160RandomSpi.java jce/gnu/java/security/jce/prng/Sha256RandomSpi.java jce/gnu/java/security/jce/prng/Sha384RandomSpi.java jce/gnu/java/security/jce/prng/Sha512RandomSpi.java jce/gnu/java/security/jce/prng/TigerRandomSpi.java jce/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java jce/gnu/java/security/jce/sig/DSSKeyFactory.java jce/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java jce/gnu/java/security/jce/sig/DSSParameters.java jce/gnu/java/security/jce/sig/DSSParametersGenerator.java jce/gnu/java/security/jce/sig/DSSRawSignatureSpi.java jce/gnu/java/security/jce/sig/EncodedKeyFactory.java jce/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java jce/gnu/java/security/jce/sig/MD2withRSA.java jce/gnu/java/security/jce/sig/MD5withRSA.java jce/gnu/java/security/jce/sig/RSAKeyFactory.java jce/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java jce/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java jce/gnu/java/security/jce/sig/SHA160withDSS.java jce/gnu/java/security/jce/sig/SHA160withRSA.java jce/gnu/java/security/jce/sig/SHA256withRSA.java jce/gnu/java/security/jce/sig/SHA384withRSA.java jce/gnu/java/security/jce/sig/SHA512withRSA.java jce/gnu/java/security/jce/sig/SignatureAdapter.java jce/gnu/java/security/key/IKeyPairCodec.java jce/gnu/java/security/key/IKeyPairGenerator.java jce/gnu/java/security/key/KeyPairCodecFactory.java jce/gnu/java/security/key/KeyPairGeneratorFactory.java jce/gnu/java/security/key/dss/DSSKey.java jce/gnu/java/security/key/dss/DSSKeyPairGenerator.java jce/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java jce/gnu/java/security/key/dss/DSSKeyPairRawCodec.java jce/gnu/java/security/key/dss/DSSKeyPairX509Codec.java jce/gnu/java/security/key/dss/DSSPrivateKey.java jce/gnu/java/security/key/dss/DSSPublicKey.java jce/gnu/java/security/key/dss/FIPS186.java jce/gnu/java/security/key/rsa/GnuRSAKey.java jce/gnu/java/security/key/rsa/GnuRSAPrivateKey.java jce/gnu/java/security/key/rsa/GnuRSAPublicKey.java jce/gnu/java/security/key/rsa/RSAKeyPairGenerator.java jce/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java jce/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java jce/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java jce/gnu/java/security/prng/BasePRNG.java jce/gnu/java/security/prng/EntropySource.java jce/gnu/java/security/prng/IRandom.java jce/gnu/java/security/prng/LimitReachedException.java jce/gnu/java/security/prng/MDGenerator.java jce/gnu/java/security/prng/PRNGFactory.java jce/gnu/java/security/prng/RandomEvent.java jce/gnu/java/security/prng/RandomEventListener.java jce/gnu/java/security/provider/CollectionCertStoreImpl.java jce/gnu/java/security/provider/DefaultPolicy.java jce/gnu/java/security/provider/Gnu.java jce/gnu/java/security/provider/PKIXCertPathValidatorImpl.java jce/gnu/java/security/provider/X509CertificateFactory.java jce/gnu/java/security/provider/package.html jce/gnu/java/security/sig/BaseSignature.java jce/gnu/java/security/sig/ISignature.java jce/gnu/java/security/sig/ISignatureCodec.java jce/gnu/java/security/sig/SignatureCodecFactory.java jce/gnu/java/security/sig/SignatureFactory.java jce/gnu/java/security/sig/dss/DSSSignature.java jce/gnu/java/security/sig/dss/DSSSignatureRawCodec.java jce/gnu/java/security/sig/dss/DSSSignatureX509Codec.java jce/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java jce/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java jce/gnu/java/security/sig/rsa/EMSA_PSS.java jce/gnu/java/security/sig/rsa/RSA.java jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java jce/gnu/java/security/sig/rsa/RSAPSSSignature.java jce/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java jce/gnu/java/security/sig/rsa/RSASignatureFactory.java jce/gnu/java/security/util/ByteArray.java jce/gnu/java/security/util/ByteBufferOutputStream.java jce/gnu/java/security/util/DerUtil.java jce/gnu/java/security/util/ExpirableObject.java jce/gnu/java/security/util/FormatUtil.java jce/gnu/java/security/util/IntegerUtil.java jce/gnu/java/security/util/PRNG.java jce/gnu/java/security/util/Prime.java jce/gnu/java/security/util/Sequence.java jce/gnu/java/security/util/SimpleList.java jce/gnu/java/security/util/Util.java jce/gnu/java/security/util/package.html jce/gnu/java/security/x509/GnuPKIExtension.java jce/gnu/java/security/x509/PolicyNodeImpl.java jce/gnu/java/security/x509/X500DistinguishedName.java jce/gnu/java/security/x509/X509CRL.java jce/gnu/java/security/x509/X509CRLEntry.java jce/gnu/java/security/x509/X509CRLSelectorImpl.java jce/gnu/java/security/x509/X509CertPath.java jce/gnu/java/security/x509/X509CertSelectorImpl.java jce/gnu/java/security/x509/X509Certificate.java jce/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java jce/gnu/java/security/x509/ext/BasicConstraints.java jce/gnu/java/security/x509/ext/CRLNumber.java jce/gnu/java/security/x509/ext/CertificatePolicies.java jce/gnu/java/security/x509/ext/ExtendedKeyUsage.java jce/gnu/java/security/x509/ext/Extension.java jce/gnu/java/security/x509/ext/GeneralName.java jce/gnu/java/security/x509/ext/GeneralNames.java jce/gnu/java/security/x509/ext/GeneralSubtree.java jce/gnu/java/security/x509/ext/IssuerAlternativeNames.java jce/gnu/java/security/x509/ext/KeyUsage.java jce/gnu/java/security/x509/ext/NameConstraints.java jce/gnu/java/security/x509/ext/PolicyConstraint.java jce/gnu/java/security/x509/ext/PolicyMappings.java jce/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java jce/gnu/java/security/x509/ext/ReasonCode.java jce/gnu/java/security/x509/ext/SubjectAlternativeNames.java jce/gnu/java/security/x509/ext/SubjectKeyIdentifier.java jce/gnu/java/security/x509/ext/package.html jce/gnu/java/security/x509/package.html jce/gnu/javax/crypto/RSACipherImpl.java jce/gnu/javax/crypto/assembly/Assembly.java jce/gnu/javax/crypto/assembly/Cascade.java jce/gnu/javax/crypto/assembly/CascadeStage.java jce/gnu/javax/crypto/assembly/CascadeTransformer.java jce/gnu/javax/crypto/assembly/DeflateTransformer.java jce/gnu/javax/crypto/assembly/Direction.java jce/gnu/javax/crypto/assembly/LoopbackTransformer.java jce/gnu/javax/crypto/assembly/ModeStage.java jce/gnu/javax/crypto/assembly/Operation.java jce/gnu/javax/crypto/assembly/PaddingTransformer.java jce/gnu/javax/crypto/assembly/Stage.java jce/gnu/javax/crypto/assembly/Transformer.java jce/gnu/javax/crypto/assembly/TransformerException.java jce/gnu/javax/crypto/cipher/Anubis.java jce/gnu/javax/crypto/cipher/BaseCipher.java jce/gnu/javax/crypto/cipher/Blowfish.java jce/gnu/javax/crypto/cipher/Cast5.java jce/gnu/javax/crypto/cipher/CipherFactory.java jce/gnu/javax/crypto/cipher/DES.java jce/gnu/javax/crypto/cipher/IBlockCipher.java jce/gnu/javax/crypto/cipher/IBlockCipherSpi.java jce/gnu/javax/crypto/cipher/Khazad.java jce/gnu/javax/crypto/cipher/NullCipher.java jce/gnu/javax/crypto/cipher/Rijndael.java jce/gnu/javax/crypto/cipher/Serpent.java jce/gnu/javax/crypto/cipher/Square.java jce/gnu/javax/crypto/cipher/TripleDES.java jce/gnu/javax/crypto/cipher/Twofish.java jce/gnu/javax/crypto/cipher/WeakKeyException.java jce/gnu/javax/crypto/jce/DiffieHellmanImpl.java jce/gnu/javax/crypto/jce/GnuCrypto.java jce/gnu/javax/crypto/jce/GnuSasl.java jce/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java jce/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java jce/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java jce/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java jce/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java jce/gnu/javax/crypto/jce/cipher/AESSpi.java jce/gnu/javax/crypto/jce/cipher/ARCFourSpi.java jce/gnu/javax/crypto/jce/cipher/AnubisSpi.java jce/gnu/javax/crypto/jce/cipher/BlowfishSpi.java jce/gnu/javax/crypto/jce/cipher/Cast5Spi.java jce/gnu/javax/crypto/jce/cipher/CipherAdapter.java jce/gnu/javax/crypto/jce/cipher/DESSpi.java jce/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java jce/gnu/javax/crypto/jce/cipher/KhazadSpi.java jce/gnu/javax/crypto/jce/cipher/NullCipherSpi.java jce/gnu/javax/crypto/jce/cipher/PBES2.java jce/gnu/javax/crypto/jce/cipher/RijndaelSpi.java jce/gnu/javax/crypto/jce/cipher/SerpentSpi.java jce/gnu/javax/crypto/jce/cipher/SquareSpi.java jce/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java jce/gnu/javax/crypto/jce/cipher/TripleDESSpi.java jce/gnu/javax/crypto/jce/cipher/TwofishSpi.java jce/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java jce/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java jce/gnu/javax/crypto/jce/keyring/GnuKeyring.java jce/gnu/javax/crypto/jce/mac/HMacHavalSpi.java jce/gnu/javax/crypto/jce/mac/HMacMD2Spi.java jce/gnu/javax/crypto/jce/mac/HMacMD4Spi.java jce/gnu/javax/crypto/jce/mac/HMacMD5Spi.java jce/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java jce/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java jce/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java jce/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java jce/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java jce/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java jce/gnu/javax/crypto/jce/mac/HMacTigerSpi.java jce/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java jce/gnu/javax/crypto/jce/mac/MacAdapter.java jce/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java jce/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java jce/gnu/javax/crypto/jce/mac/OMacCast5Impl.java jce/gnu/javax/crypto/jce/mac/OMacDESImpl.java jce/gnu/javax/crypto/jce/mac/OMacImpl.java jce/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java jce/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java jce/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java jce/gnu/javax/crypto/jce/mac/OMacSquareImpl.java jce/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java jce/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java jce/gnu/javax/crypto/jce/mac/TMMH16Spi.java jce/gnu/javax/crypto/jce/mac/UHash32Spi.java jce/gnu/javax/crypto/jce/mac/UMac32Spi.java jce/gnu/javax/crypto/jce/params/BlockCipherParameters.java jce/gnu/javax/crypto/jce/params/DEREncodingException.java jce/gnu/javax/crypto/jce/params/DERReader.java jce/gnu/javax/crypto/jce/params/DERWriter.java jce/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java jce/gnu/javax/crypto/jce/prng/CSPRNGSpi.java jce/gnu/javax/crypto/jce/prng/FortunaImpl.java jce/gnu/javax/crypto/jce/prng/ICMRandomSpi.java jce/gnu/javax/crypto/jce/prng/UMacRandomSpi.java jce/gnu/javax/crypto/jce/sig/DHKeyFactory.java jce/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java jce/gnu/javax/crypto/jce/sig/DHParameters.java jce/gnu/javax/crypto/jce/sig/DHParametersGenerator.java jce/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java jce/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java jce/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java jce/gnu/javax/crypto/key/BaseKeyAgreementParty.java jce/gnu/javax/crypto/key/GnuPBEKey.java jce/gnu/javax/crypto/key/GnuSecretKey.java jce/gnu/javax/crypto/key/IKeyAgreementParty.java jce/gnu/javax/crypto/key/IncomingMessage.java jce/gnu/javax/crypto/key/KeyAgreementException.java jce/gnu/javax/crypto/key/KeyAgreementFactory.java jce/gnu/javax/crypto/key/OutgoingMessage.java jce/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java jce/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java jce/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java jce/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java jce/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java jce/gnu/javax/crypto/key/dh/DiffieHellmanSender.java jce/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java jce/gnu/javax/crypto/key/dh/ElGamalReceiver.java jce/gnu/javax/crypto/key/dh/ElGamalSender.java jce/gnu/javax/crypto/key/dh/GnuDHKey.java jce/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java jce/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java jce/gnu/javax/crypto/key/dh/GnuDHPublicKey.java jce/gnu/javax/crypto/key/dh/RFC2631.java jce/gnu/javax/crypto/key/srp6/SRP6Host.java jce/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java jce/gnu/javax/crypto/key/srp6/SRP6SaslClient.java jce/gnu/javax/crypto/key/srp6/SRP6SaslServer.java jce/gnu/javax/crypto/key/srp6/SRP6TLSClient.java jce/gnu/javax/crypto/key/srp6/SRP6TLSServer.java jce/gnu/javax/crypto/key/srp6/SRP6User.java jce/gnu/javax/crypto/key/srp6/SRPAlgorithm.java jce/gnu/javax/crypto/key/srp6/SRPKey.java jce/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java jce/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java jce/gnu/javax/crypto/key/srp6/SRPPrivateKey.java jce/gnu/javax/crypto/key/srp6/SRPPublicKey.java jce/gnu/javax/crypto/keyring/AuthenticatedEntry.java jce/gnu/javax/crypto/keyring/BaseKeyring.java jce/gnu/javax/crypto/keyring/BinaryDataEntry.java jce/gnu/javax/crypto/keyring/CertPathEntry.java jce/gnu/javax/crypto/keyring/CertificateEntry.java jce/gnu/javax/crypto/keyring/CompressedEntry.java jce/gnu/javax/crypto/keyring/EncryptedEntry.java jce/gnu/javax/crypto/keyring/Entry.java jce/gnu/javax/crypto/keyring/EnvelopeEntry.java jce/gnu/javax/crypto/keyring/GnuPrivateKeyring.java jce/gnu/javax/crypto/keyring/GnuPublicKeyring.java jce/gnu/javax/crypto/keyring/IKeyring.java jce/gnu/javax/crypto/keyring/IPrivateKeyring.java jce/gnu/javax/crypto/keyring/IPublicKeyring.java jce/gnu/javax/crypto/keyring/MalformedKeyringException.java jce/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java jce/gnu/javax/crypto/keyring/MeteredInputStream.java jce/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java jce/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java jce/gnu/javax/crypto/keyring/PasswordProtectedEntry.java jce/gnu/javax/crypto/keyring/PrimitiveEntry.java jce/gnu/javax/crypto/keyring/PrivateKeyEntry.java jce/gnu/javax/crypto/keyring/Properties.java jce/gnu/javax/crypto/keyring/PublicKeyEntry.java jce/gnu/javax/crypto/kwa/AESKeyWrap.java jce/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java jce/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java jce/gnu/javax/crypto/kwa/KeyUnwrappingException.java jce/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java jce/gnu/javax/crypto/kwa/TripleDESKeyWrap.java jce/gnu/javax/crypto/mac/BaseMac.java jce/gnu/javax/crypto/mac/HMac.java jce/gnu/javax/crypto/mac/HMacFactory.java jce/gnu/javax/crypto/mac/IMac.java jce/gnu/javax/crypto/mac/MacFactory.java jce/gnu/javax/crypto/mac/MacInputStream.java jce/gnu/javax/crypto/mac/MacOutputStream.java jce/gnu/javax/crypto/mac/OMAC.java jce/gnu/javax/crypto/mac/TMMH16.java jce/gnu/javax/crypto/mac/UHash32.java jce/gnu/javax/crypto/mac/UMac32.java jce/gnu/javax/crypto/mode/BaseMode.java jce/gnu/javax/crypto/mode/CBC.java jce/gnu/javax/crypto/mode/CFB.java jce/gnu/javax/crypto/mode/CTR.java jce/gnu/javax/crypto/mode/EAX.java jce/gnu/javax/crypto/mode/ECB.java jce/gnu/javax/crypto/mode/IAuthenticatedMode.java jce/gnu/javax/crypto/mode/ICM.java jce/gnu/javax/crypto/mode/IMode.java jce/gnu/javax/crypto/mode/ModeFactory.java jce/gnu/javax/crypto/mode/OFB.java jce/gnu/javax/crypto/pad/BasePad.java jce/gnu/javax/crypto/pad/IPad.java jce/gnu/javax/crypto/pad/ISO10126.java jce/gnu/javax/crypto/pad/PKCS1_V1_5.java jce/gnu/javax/crypto/pad/PKCS7.java jce/gnu/javax/crypto/pad/PadFactory.java jce/gnu/javax/crypto/pad/SSL3.java jce/gnu/javax/crypto/pad/TBC.java jce/gnu/javax/crypto/pad/TLS1.java jce/gnu/javax/crypto/pad/WrongPaddingException.java jce/gnu/javax/crypto/prng/ARCFour.java jce/gnu/javax/crypto/prng/CSPRNG.java jce/gnu/javax/crypto/prng/Fortuna.java jce/gnu/javax/crypto/prng/ICMGenerator.java jce/gnu/javax/crypto/prng/IPBE.java jce/gnu/javax/crypto/prng/PBKDF2.java jce/gnu/javax/crypto/prng/PRNGFactory.java jce/gnu/javax/crypto/prng/UMacGenerator.java jce/gnu/javax/crypto/sasl/AuthInfo.java jce/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java jce/gnu/javax/crypto/sasl/ClientFactory.java jce/gnu/javax/crypto/sasl/ClientMechanism.java jce/gnu/javax/crypto/sasl/ConfidentialityException.java jce/gnu/javax/crypto/sasl/IAuthInfoProvider.java jce/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java jce/gnu/javax/crypto/sasl/IllegalMechanismStateException.java jce/gnu/javax/crypto/sasl/InputBuffer.java jce/gnu/javax/crypto/sasl/IntegrityException.java jce/gnu/javax/crypto/sasl/NoSuchMechanismException.java jce/gnu/javax/crypto/sasl/NoSuchUserException.java jce/gnu/javax/crypto/sasl/OutputBuffer.java jce/gnu/javax/crypto/sasl/SaslEncodingException.java jce/gnu/javax/crypto/sasl/SaslInputStream.java jce/gnu/javax/crypto/sasl/SaslOutputStream.java jce/gnu/javax/crypto/sasl/SaslUtil.java jce/gnu/javax/crypto/sasl/ServerFactory.java jce/gnu/javax/crypto/sasl/ServerMechanism.java jce/gnu/javax/crypto/sasl/UserAlreadyExistsException.java jce/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java jce/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java jce/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java jce/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java jce/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java jce/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java jce/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java jce/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java jce/gnu/javax/crypto/sasl/crammd5/PasswordFile.java jce/gnu/javax/crypto/sasl/plain/PasswordFile.java jce/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java jce/gnu/javax/crypto/sasl/plain/PlainClient.java jce/gnu/javax/crypto/sasl/plain/PlainRegistry.java jce/gnu/javax/crypto/sasl/plain/PlainServer.java jce/gnu/javax/crypto/sasl/srp/CALG.java jce/gnu/javax/crypto/sasl/srp/ClientStore.java jce/gnu/javax/crypto/sasl/srp/IALG.java jce/gnu/javax/crypto/sasl/srp/KDF.java jce/gnu/javax/crypto/sasl/srp/PasswordFile.java jce/gnu/javax/crypto/sasl/srp/SRP.java jce/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java jce/gnu/javax/crypto/sasl/srp/SRPClient.java jce/gnu/javax/crypto/sasl/srp/SRPRegistry.java jce/gnu/javax/crypto/sasl/srp/SRPServer.java jce/gnu/javax/crypto/sasl/srp/SecurityContext.java jce/gnu/javax/crypto/sasl/srp/ServerStore.java jce/gnu/javax/crypto/sasl/srp/StoreEntry.java jce/gnu/javax/security/auth/Password.java jce/gnu/javax/security/auth/callback/AbstractCallbackHandler.java jce/gnu/javax/security/auth/callback/CertificateCallback.java jce/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java jce/gnu/javax/security/auth/callback/DefaultCallbackHandler.java jce/gnu/javax/security/auth/callback/GnuCallbacks.java jce/gnu/javax/security/auth/login/ConfigFileParser.java jce/gnu/javax/security/auth/login/ConfigFileTokenizer.java jce/gnu/javax/security/auth/login/GnuConfiguration.java rt/gnu/java/io/Base64InputStream.java rt/gnu/java/security/provider/Gnu.java rt/java/util/Timer.java rt/javax/security/auth/callback/ChoiceCallback.java rt/javax/security/auth/callback/ConfirmationCallback.java rt/javax/security/auth/callback/LanguageCallback.java rt/javax/security/auth/callback/NameCallback.java rt/javax/security/auth/callback/TextInputCallback.java rt/javax/security/auth/callback/TextOutputCallback.java rt/javax/security/sasl/AuthenticationException.java rt/javax/security/sasl/Sasl.java rt/javax/security/sasl/SaslClient.java rt/javax/security/sasl/SaslClientFactory.java rt/javax/security/sasl/SaslException.java rt/javax/security/sasl/SaslServer.java rt/javax/security/sasl/SaslServerFactory.java
diffstat 452 files changed, 82727 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Jun 21 16:06:05 2007 +0100
+++ b/ChangeLog	Tue Jun 26 16:11:37 2007 +0100
@@ -1,3 +1,465 @@
+2007-06-22  Andrew Haley  <aph@redhat.com>
+
+	* Makefile.am (ICEDTEA_PATCHES): Add icedtea-debuginfo.patch.
+	Add -g option to all Java compilations.
+	(ICEDTEA_COPY_SRC): Copy a bunch of files needed to build GNU
+	crypto.
+	* jce/gnu/java/security/hash/BaseHash.java,
+	jce/gnu/java/security/hash/HashFactory.java,
+	jce/gnu/java/security/hash/Haval.java,
+	jce/gnu/java/security/hash/IMessageDigest.java,
+	jce/gnu/java/security/hash/MD2.java,
+	jce/gnu/java/security/hash/MD4.java,
+	jce/gnu/java/security/hash/MD5.java,
+	jce/gnu/java/security/hash/RipeMD128.java,
+	jce/gnu/java/security/hash/RipeMD160.java,
+	jce/gnu/java/security/hash/Sha160.java,
+	jce/gnu/java/security/hash/Sha256.java,
+	jce/gnu/java/security/hash/Sha384.java,
+	jce/gnu/java/security/hash/Sha512.java,
+	jce/gnu/java/security/hash/Tiger.java,
+	jce/gnu/java/security/hash/Whirlpool.java,
+	jce/gnu/java/security/jce/hash/HavalSpi.java,
+	jce/gnu/java/security/jce/hash/MD2Spi.java,
+	jce/gnu/java/security/jce/hash/MD4Spi.java,
+	jce/gnu/java/security/jce/hash/MD5Spi.java,
+	jce/gnu/java/security/jce/hash/MessageDigestAdapter.java,
+	jce/gnu/java/security/jce/hash/RipeMD128Spi.java,
+	jce/gnu/java/security/jce/hash/RipeMD160Spi.java,
+	jce/gnu/java/security/jce/hash/Sha160Spi.java,
+	jce/gnu/java/security/jce/hash/Sha256Spi.java,
+	jce/gnu/java/security/jce/hash/Sha384Spi.java,
+	jce/gnu/java/security/jce/hash/Sha512Spi.java,
+	jce/gnu/java/security/jce/hash/TigerSpi.java,
+	jce/gnu/java/security/jce/hash/WhirlpoolSpi.java,
+	jce/gnu/java/security/jce/prng/HavalRandomSpi.java,
+	jce/gnu/java/security/jce/prng/MD2RandomSpi.java,
+	jce/gnu/java/security/jce/prng/MD4RandomSpi.java,
+	jce/gnu/java/security/jce/prng/MD5RandomSpi.java,
+	jce/gnu/java/security/jce/prng/RipeMD128RandomSpi.java,
+	jce/gnu/java/security/jce/prng/RipeMD160RandomSpi.java,
+	jce/gnu/java/security/jce/prng/SecureRandomAdapter.java,
+	jce/gnu/java/security/jce/prng/Sha160RandomSpi.java,
+	jce/gnu/java/security/jce/prng/Sha256RandomSpi.java,
+	jce/gnu/java/security/jce/prng/Sha384RandomSpi.java,
+	jce/gnu/java/security/jce/prng/Sha512RandomSpi.java,
+	jce/gnu/java/security/jce/prng/TigerRandomSpi.java,
+	jce/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java,
+	jce/gnu/java/security/jce/sig/DSSKeyFactory.java,
+	jce/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java,
+	jce/gnu/java/security/jce/sig/DSSParameters.java,
+	jce/gnu/java/security/jce/sig/DSSParametersGenerator.java,
+	jce/gnu/java/security/jce/sig/DSSRawSignatureSpi.java,
+	jce/gnu/java/security/jce/sig/EncodedKeyFactory.java,
+	jce/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java,
+	jce/gnu/java/security/jce/sig/MD2withRSA.java,
+	jce/gnu/java/security/jce/sig/MD5withRSA.java,
+	jce/gnu/java/security/jce/sig/RSAKeyFactory.java,
+	jce/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java,
+	jce/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java,
+	jce/gnu/java/security/jce/sig/SHA160withDSS.java,
+	jce/gnu/java/security/jce/sig/SHA160withRSA.java,
+	jce/gnu/java/security/jce/sig/SHA256withRSA.java,
+	jce/gnu/java/security/jce/sig/SHA384withRSA.java,
+	jce/gnu/java/security/jce/sig/SHA512withRSA.java,
+	jce/gnu/java/security/jce/sig/SignatureAdapter.java,
+	jce/gnu/java/security/key/IKeyPairCodec.java,
+	jce/gnu/java/security/key/IKeyPairGenerator.java,
+	jce/gnu/java/security/key/KeyPairCodecFactory.java,
+	jce/gnu/java/security/key/KeyPairGeneratorFactory.java,
+	jce/gnu/java/security/key/dss/DSSKey.java,
+	jce/gnu/java/security/key/dss/DSSKeyPairGenerator.java,
+	jce/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java,
+	jce/gnu/java/security/key/dss/DSSKeyPairRawCodec.java,
+	jce/gnu/java/security/key/dss/DSSKeyPairX509Codec.java,
+	jce/gnu/java/security/key/dss/DSSPrivateKey.java,
+	jce/gnu/java/security/key/dss/DSSPublicKey.java,
+	jce/gnu/java/security/key/dss/FIPS186.java,
+	jce/gnu/java/security/key/rsa/GnuRSAKey.java,
+	jce/gnu/java/security/key/rsa/GnuRSAPrivateKey.java,
+	jce/gnu/java/security/key/rsa/GnuRSAPublicKey.java,
+	jce/gnu/java/security/key/rsa/RSAKeyPairGenerator.java,
+	jce/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java,
+	jce/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java,
+	jce/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java,
+	jce/gnu/java/security/prng/BasePRNG.java,
+	jce/gnu/java/security/prng/EntropySource.java,
+	jce/gnu/java/security/prng/IRandom.java,
+	jce/gnu/java/security/prng/LimitReachedException.java,
+	jce/gnu/java/security/prng/MDGenerator.java,
+	jce/gnu/java/security/prng/PRNGFactory.java,
+	jce/gnu/java/security/prng/RandomEvent.java,
+	jce/gnu/java/security/prng/RandomEventListener.java,
+	jce/gnu/java/security/provider/CollectionCertStoreImpl.java,
+	jce/gnu/java/security/provider/DefaultPolicy.java,
+	jce/gnu/java/security/provider/Gnu.java,
+	jce/gnu/java/security/provider/PKIXCertPathValidatorImpl.java,
+	jce/gnu/java/security/provider/X509CertificateFactory.java,
+	jce/gnu/java/security/provider/package.html,
+	jce/gnu/java/security/sig/BaseSignature.java,
+	jce/gnu/java/security/sig/ISignature.java,
+	jce/gnu/java/security/sig/ISignatureCodec.java,
+	jce/gnu/java/security/sig/SignatureCodecFactory.java,
+	jce/gnu/java/security/sig/SignatureFactory.java,
+	jce/gnu/java/security/sig/dss/DSSSignature.java,
+	jce/gnu/java/security/sig/dss/DSSSignatureRawCodec.java,
+	jce/gnu/java/security/sig/dss/DSSSignatureX509Codec.java,
+	jce/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java,
+	jce/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java,
+	jce/gnu/java/security/sig/rsa/EMSA_PSS.java,
+	jce/gnu/java/security/sig/rsa/RSA.java,
+	jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java,
+	jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java,
+	jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java,
+	jce/gnu/java/security/sig/rsa/RSAPSSSignature.java,
+	jce/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java,
+	jce/gnu/java/security/sig/rsa/RSASignatureFactory.java,
+	jce/gnu/java/security/util/ByteArray.java,
+	jce/gnu/java/security/util/ByteBufferOutputStream.java,
+	jce/gnu/java/security/util/DerUtil.java,
+	jce/gnu/java/security/util/ExpirableObject.java,
+	jce/gnu/java/security/util/FormatUtil.java,
+	jce/gnu/java/security/util/IntegerUtil.java,
+	jce/gnu/java/security/util/PRNG.java,
+	jce/gnu/java/security/util/Prime.java,
+	jce/gnu/java/security/util/Sequence.java,
+	jce/gnu/java/security/util/SimpleList.java,
+	jce/gnu/java/security/util/Util.java,
+	jce/gnu/java/security/util/package.html,
+	jce/gnu/java/security/x509/GnuPKIExtension.java,
+	jce/gnu/java/security/x509/PolicyNodeImpl.java,
+	jce/gnu/java/security/x509/X500DistinguishedName.java,
+	jce/gnu/java/security/x509/X509CRL.java,
+	jce/gnu/java/security/x509/X509CRLEntry.java,
+	jce/gnu/java/security/x509/X509CRLSelectorImpl.java,
+	jce/gnu/java/security/x509/X509CertPath.java,
+	jce/gnu/java/security/x509/X509CertSelectorImpl.java,
+	jce/gnu/java/security/x509/X509Certificate.java,
+	jce/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java,
+	jce/gnu/java/security/x509/ext/BasicConstraints.java,
+	jce/gnu/java/security/x509/ext/CRLNumber.java,
+	jce/gnu/java/security/x509/ext/CertificatePolicies.java,
+	jce/gnu/java/security/x509/ext/ExtendedKeyUsage.java,
+	jce/gnu/java/security/x509/ext/Extension.java,
+	jce/gnu/java/security/x509/ext/GeneralName.java,
+	jce/gnu/java/security/x509/ext/GeneralNames.java,
+	jce/gnu/java/security/x509/ext/GeneralSubtree.java,
+	jce/gnu/java/security/x509/ext/IssuerAlternativeNames.java,
+	jce/gnu/java/security/x509/ext/KeyUsage.java,
+	jce/gnu/java/security/x509/ext/NameConstraints.java,
+	jce/gnu/java/security/x509/ext/PolicyConstraint.java,
+	jce/gnu/java/security/x509/ext/PolicyMappings.java,
+	jce/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java,
+	jce/gnu/java/security/x509/ext/ReasonCode.java,
+	jce/gnu/java/security/x509/ext/SubjectAlternativeNames.java,
+	jce/gnu/java/security/x509/ext/SubjectKeyIdentifier.java,
+	jce/gnu/java/security/x509/ext/package.html,
+	jce/gnu/java/security/x509/package.html,
+	jce/gnu/javax/crypto/RSACipherImpl.java,
+	jce/gnu/javax/crypto/assembly/Assembly.java,
+	jce/gnu/javax/crypto/assembly/Cascade.java,
+	jce/gnu/javax/crypto/assembly/CascadeStage.java,
+	jce/gnu/javax/crypto/assembly/CascadeTransformer.java,
+	jce/gnu/javax/crypto/assembly/DeflateTransformer.java,
+	jce/gnu/javax/crypto/assembly/Direction.java,
+	jce/gnu/javax/crypto/assembly/LoopbackTransformer.java,
+	jce/gnu/javax/crypto/assembly/ModeStage.java,
+	jce/gnu/javax/crypto/assembly/Operation.java,
+	jce/gnu/javax/crypto/assembly/PaddingTransformer.java,
+	jce/gnu/javax/crypto/assembly/Stage.java,
+	jce/gnu/javax/crypto/assembly/Transformer.java,
+	jce/gnu/javax/crypto/assembly/TransformerException.java,
+	jce/gnu/javax/crypto/cipher/Anubis.java,
+	jce/gnu/javax/crypto/cipher/BaseCipher.java,
+	jce/gnu/javax/crypto/cipher/Blowfish.java,
+	jce/gnu/javax/crypto/cipher/Cast5.java,
+	jce/gnu/javax/crypto/cipher/CipherFactory.java,
+	jce/gnu/javax/crypto/cipher/DES.java,
+	jce/gnu/javax/crypto/cipher/IBlockCipher.java,
+	jce/gnu/javax/crypto/cipher/IBlockCipherSpi.java,
+	jce/gnu/javax/crypto/cipher/Khazad.java,
+	jce/gnu/javax/crypto/cipher/NullCipher.java,
+	jce/gnu/javax/crypto/cipher/Rijndael.java,
+	jce/gnu/javax/crypto/cipher/Serpent.java,
+	jce/gnu/javax/crypto/cipher/Square.java,
+	jce/gnu/javax/crypto/cipher/TripleDES.java,
+	jce/gnu/javax/crypto/cipher/Twofish.java,
+	jce/gnu/javax/crypto/cipher/WeakKeyException.java,
+	jce/gnu/javax/crypto/jce/DiffieHellmanImpl.java,
+	jce/gnu/javax/crypto/jce/GnuCrypto.java,
+	jce/gnu/javax/crypto/jce/GnuSasl.java,
+	jce/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java,
+	jce/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/AESSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/ARCFourSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/AnubisSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/BlowfishSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/Cast5Spi.java,
+	jce/gnu/javax/crypto/jce/cipher/CipherAdapter.java,
+	jce/gnu/javax/crypto/jce/cipher/DESSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java,
+	jce/gnu/javax/crypto/jce/cipher/KhazadSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/NullCipherSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/PBES2.java,
+	jce/gnu/javax/crypto/jce/cipher/RijndaelSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/SerpentSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/SquareSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/TripleDESSpi.java,
+	jce/gnu/javax/crypto/jce/cipher/TwofishSpi.java,
+	jce/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java,
+	jce/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java,
+	jce/gnu/javax/crypto/jce/keyring/GnuKeyring.java,
+	jce/gnu/javax/crypto/jce/mac/HMacHavalSpi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacMD2Spi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacMD4Spi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacMD5Spi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacTigerSpi.java,
+	jce/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java,
+	jce/gnu/javax/crypto/jce/mac/MacAdapter.java,
+	jce/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacCast5Impl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacDESImpl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacImpl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacSquareImpl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java,
+	jce/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java,
+	jce/gnu/javax/crypto/jce/mac/TMMH16Spi.java,
+	jce/gnu/javax/crypto/jce/mac/UHash32Spi.java,
+	jce/gnu/javax/crypto/jce/mac/UMac32Spi.java,
+	jce/gnu/javax/crypto/jce/params/BlockCipherParameters.java,
+	jce/gnu/javax/crypto/jce/params/DEREncodingException.java,
+	jce/gnu/javax/crypto/jce/params/DERReader.java,
+	jce/gnu/javax/crypto/jce/params/DERWriter.java,
+	jce/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java,
+	jce/gnu/javax/crypto/jce/prng/CSPRNGSpi.java,
+	jce/gnu/javax/crypto/jce/prng/FortunaImpl.java,
+	jce/gnu/javax/crypto/jce/prng/ICMRandomSpi.java,
+	jce/gnu/javax/crypto/jce/prng/UMacRandomSpi.java,
+	jce/gnu/javax/crypto/jce/sig/DHKeyFactory.java,
+	jce/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java,
+	jce/gnu/javax/crypto/jce/sig/DHParameters.java,
+	jce/gnu/javax/crypto/jce/sig/DHParametersGenerator.java,
+	jce/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java,
+	jce/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java,
+	jce/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java,
+	jce/gnu/javax/crypto/key/BaseKeyAgreementParty.java,
+	jce/gnu/javax/crypto/key/GnuPBEKey.java,
+	jce/gnu/javax/crypto/key/GnuSecretKey.java,
+	jce/gnu/javax/crypto/key/IKeyAgreementParty.java,
+	jce/gnu/javax/crypto/key/IncomingMessage.java,
+	jce/gnu/javax/crypto/key/KeyAgreementException.java,
+	jce/gnu/javax/crypto/key/KeyAgreementFactory.java,
+	jce/gnu/javax/crypto/key/OutgoingMessage.java,
+	jce/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java,
+	jce/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java,
+	jce/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java,
+	jce/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java,
+	jce/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java,
+	jce/gnu/javax/crypto/key/dh/DiffieHellmanSender.java,
+	jce/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java,
+	jce/gnu/javax/crypto/key/dh/ElGamalReceiver.java,
+	jce/gnu/javax/crypto/key/dh/ElGamalSender.java,
+	jce/gnu/javax/crypto/key/dh/GnuDHKey.java,
+	jce/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java,
+	jce/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java,
+	jce/gnu/javax/crypto/key/dh/GnuDHPublicKey.java,
+	jce/gnu/javax/crypto/key/dh/RFC2631.java,
+	jce/gnu/javax/crypto/key/srp6/SRP6Host.java,
+	jce/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java,
+	jce/gnu/javax/crypto/key/srp6/SRP6SaslClient.java,
+	jce/gnu/javax/crypto/key/srp6/SRP6SaslServer.java,
+	jce/gnu/javax/crypto/key/srp6/SRP6TLSClient.java,
+	jce/gnu/javax/crypto/key/srp6/SRP6TLSServer.java,
+	jce/gnu/javax/crypto/key/srp6/SRP6User.java,
+	jce/gnu/javax/crypto/key/srp6/SRPAlgorithm.java,
+	jce/gnu/javax/crypto/key/srp6/SRPKey.java,
+	jce/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java,
+	jce/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java,
+	jce/gnu/javax/crypto/key/srp6/SRPPrivateKey.java,
+	jce/gnu/javax/crypto/key/srp6/SRPPublicKey.java,
+	jce/gnu/javax/crypto/keyring/AuthenticatedEntry.java,
+	jce/gnu/javax/crypto/keyring/BaseKeyring.java,
+	jce/gnu/javax/crypto/keyring/BinaryDataEntry.java,
+	jce/gnu/javax/crypto/keyring/CertPathEntry.java,
+	jce/gnu/javax/crypto/keyring/CertificateEntry.java,
+	jce/gnu/javax/crypto/keyring/CompressedEntry.java,
+	jce/gnu/javax/crypto/keyring/EncryptedEntry.java,
+	jce/gnu/javax/crypto/keyring/Entry.java,
+	jce/gnu/javax/crypto/keyring/EnvelopeEntry.java,
+	jce/gnu/javax/crypto/keyring/GnuPrivateKeyring.java,
+	jce/gnu/javax/crypto/keyring/GnuPublicKeyring.java,
+	jce/gnu/javax/crypto/keyring/IKeyring.java,
+	jce/gnu/javax/crypto/keyring/IPrivateKeyring.java,
+	jce/gnu/javax/crypto/keyring/IPublicKeyring.java,
+	jce/gnu/javax/crypto/keyring/MalformedKeyringException.java,
+	jce/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java,
+	jce/gnu/javax/crypto/keyring/MeteredInputStream.java,
+	jce/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java,
+	jce/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java,
+	jce/gnu/javax/crypto/keyring/PasswordProtectedEntry.java,
+	jce/gnu/javax/crypto/keyring/PrimitiveEntry.java,
+	jce/gnu/javax/crypto/keyring/PrivateKeyEntry.java,
+	jce/gnu/javax/crypto/keyring/Properties.java,
+	jce/gnu/javax/crypto/keyring/PublicKeyEntry.java,
+	jce/gnu/javax/crypto/kwa/AESKeyWrap.java,
+	jce/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java,
+	jce/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java,
+	jce/gnu/javax/crypto/kwa/KeyUnwrappingException.java,
+	jce/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java,
+	jce/gnu/javax/crypto/kwa/TripleDESKeyWrap.java,
+	jce/gnu/javax/crypto/mac/BaseMac.java,
+	jce/gnu/javax/crypto/mac/HMac.java,
+	jce/gnu/javax/crypto/mac/HMacFactory.java,
+	jce/gnu/javax/crypto/mac/IMac.java,
+	jce/gnu/javax/crypto/mac/MacFactory.java,
+	jce/gnu/javax/crypto/mac/MacInputStream.java,
+	jce/gnu/javax/crypto/mac/MacOutputStream.java,
+	jce/gnu/javax/crypto/mac/OMAC.java,
+	jce/gnu/javax/crypto/mac/TMMH16.java,
+	jce/gnu/javax/crypto/mac/UHash32.java,
+	jce/gnu/javax/crypto/mac/UMac32.java,
+	jce/gnu/javax/crypto/mode/BaseMode.java,
+	jce/gnu/javax/crypto/mode/CBC.java,
+	jce/gnu/javax/crypto/mode/CFB.java,
+	jce/gnu/javax/crypto/mode/CTR.java,
+	jce/gnu/javax/crypto/mode/EAX.java,
+	jce/gnu/javax/crypto/mode/ECB.java,
+	jce/gnu/javax/crypto/mode/IAuthenticatedMode.java,
+	jce/gnu/javax/crypto/mode/ICM.java,
+	jce/gnu/javax/crypto/mode/IMode.java,
+	jce/gnu/javax/crypto/mode/ModeFactory.java,
+	jce/gnu/javax/crypto/mode/OFB.java,
+	jce/gnu/javax/crypto/pad/BasePad.java,
+	jce/gnu/javax/crypto/pad/IPad.java,
+	jce/gnu/javax/crypto/pad/ISO10126.java,
+	jce/gnu/javax/crypto/pad/PKCS1_V1_5.java,
+	jce/gnu/javax/crypto/pad/PKCS7.java,
+	jce/gnu/javax/crypto/pad/PadFactory.java,
+	jce/gnu/javax/crypto/pad/SSL3.java,
+	jce/gnu/javax/crypto/pad/TBC.java,
+	jce/gnu/javax/crypto/pad/TLS1.java,
+	jce/gnu/javax/crypto/pad/WrongPaddingException.java,
+	jce/gnu/javax/crypto/prng/ARCFour.java,
+	jce/gnu/javax/crypto/prng/CSPRNG.java,
+	jce/gnu/javax/crypto/prng/Fortuna.java,
+	jce/gnu/javax/crypto/prng/ICMGenerator.java,
+	jce/gnu/javax/crypto/prng/IPBE.java,
+	jce/gnu/javax/crypto/prng/PBKDF2.java,
+	jce/gnu/javax/crypto/prng/PRNGFactory.java,
+	jce/gnu/javax/crypto/prng/UMacGenerator.java,
+	jce/gnu/javax/crypto/sasl/AuthInfo.java,
+	jce/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java,
+	jce/gnu/javax/crypto/sasl/ClientFactory.java,
+	jce/gnu/javax/crypto/sasl/ClientMechanism.java,
+	jce/gnu/javax/crypto/sasl/ConfidentialityException.java,
+	jce/gnu/javax/crypto/sasl/IAuthInfoProvider.java,
+	jce/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java,
+	jce/gnu/javax/crypto/sasl/IllegalMechanismStateException.java,
+	jce/gnu/javax/crypto/sasl/InputBuffer.java,
+	jce/gnu/javax/crypto/sasl/IntegrityException.java,
+	jce/gnu/javax/crypto/sasl/NoSuchMechanismException.java,
+	jce/gnu/javax/crypto/sasl/NoSuchUserException.java,
+	jce/gnu/javax/crypto/sasl/OutputBuffer.java,
+	jce/gnu/javax/crypto/sasl/SaslEncodingException.java,
+	jce/gnu/javax/crypto/sasl/SaslInputStream.java,
+	jce/gnu/javax/crypto/sasl/SaslOutputStream.java,
+	jce/gnu/javax/crypto/sasl/SaslUtil.java,
+	jce/gnu/javax/crypto/sasl/ServerFactory.java,
+	jce/gnu/javax/crypto/sasl/ServerMechanism.java,
+	jce/gnu/javax/crypto/sasl/UserAlreadyExistsException.java,
+	jce/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java,
+	jce/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java,
+	jce/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java,
+	jce/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java,
+	jce/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java,
+	jce/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java,
+	jce/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java,
+	jce/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java,
+	jce/gnu/javax/crypto/sasl/crammd5/PasswordFile.java,
+	jce/gnu/javax/crypto/sasl/plain/PasswordFile.java,
+	jce/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java,
+	jce/gnu/javax/crypto/sasl/plain/PlainClient.java,
+	jce/gnu/javax/crypto/sasl/plain/PlainRegistry.java,
+	jce/gnu/javax/crypto/sasl/plain/PlainServer.java,
+	jce/gnu/javax/crypto/sasl/srp/CALG.java,
+	jce/gnu/javax/crypto/sasl/srp/ClientStore.java,
+	jce/gnu/javax/crypto/sasl/srp/IALG.java,
+	jce/gnu/javax/crypto/sasl/srp/KDF.java,
+	jce/gnu/javax/crypto/sasl/srp/PasswordFile.java,
+	jce/gnu/javax/crypto/sasl/srp/SRP.java,
+	jce/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java,
+	jce/gnu/javax/crypto/sasl/srp/SRPClient.java,
+	jce/gnu/javax/crypto/sasl/srp/SRPRegistry.java,
+	jce/gnu/javax/crypto/sasl/srp/SRPServer.java,
+	jce/gnu/javax/crypto/sasl/srp/SecurityContext.java,
+	jce/gnu/javax/crypto/sasl/srp/ServerStore.java,
+	jce/gnu/javax/crypto/sasl/srp/StoreEntry.java,
+	jce/gnu/javax/security/auth/Password.java,
+	jce/gnu/javax/security/auth/callback/AbstractCallbackHandler.java,
+	jce/gnu/javax/security/auth/callback/CertificateCallback.java,
+	jce/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java,
+	jce/gnu/javax/security/auth/callback/DefaultCallbackHandler.java,
+	jce/gnu/javax/security/auth/callback/GnuCallbacks.java,
+	jce/gnu/javax/security/auth/login/ConfigFileParser.java,
+	jce/gnu/javax/security/auth/login/ConfigFileTokenizer.java,
+	jce/gnu/javax/security/auth/login/GnuConfiguration.java,
+	lib/rt/gnu/java/security/provider/Gnu.java,
+	rt/gnu/java/io/Base64InputStream.java,
+	rt/gnu/java/security/provider/Gnu.java,
+	rt/java/util/Timer.java,
+	rt/javax/security/auth/callback/ChoiceCallback.java,
+	rt/javax/security/auth/callback/ConfirmationCallback.java,
+	rt/javax/security/auth/callback/LanguageCallback.java,
+	rt/javax/security/auth/callback/NameCallback.java,
+	rt/javax/security/auth/callback/TextInputCallback.java,
+	rt/javax/security/auth/callback/TextOutputCallback.java,
+	rt/javax/security/sasl/AuthenticationException.java,
+	rt/javax/security/sasl/Sasl.java,
+	rt/javax/security/sasl/SaslClient.java,
+	rt/javax/security/sasl/SaslClientFactory.java,
+	rt/javax/security/sasl/SaslException.java,
+	rt/javax/security/sasl/SaslServer.java,
+	rt/javax/security/sasl/SaslServerFactory.java: New files
+
+2007-06-21  Andrew Haley  <aph@redhat.com>
+
+	* Makefile (ICEDTEA_PATCHES): Add icedtea-debuginfo.patch.
+	patches/icedtea-debuginfo.patch: New file.
+
 2007-06-25  Kyle Galloway  <kgallowa@redhat.com>
 
 	* rt/java/awt/color/ICC_Profile.java(isRGBProfile): Add tags parameter to
--- a/Makefile.am	Thu Jun 21 16:06:05 2007 +0100
+++ b/Makefile.am	Tue Jun 26 16:11:37 2007 +0100
@@ -33,6 +33,7 @@
 	patches/icedtea-text-relocations.patch \
 	patches/icedtea-graphics.patch \
 	patches/icedtea-gcc.patch \
+	patches/icedtea-debuginfo.patch \
 	$(FAST_BUILD_PATCH) \
 	$(CCACHE_PATCH)
 
@@ -209,7 +210,21 @@
 	com/sun/jdi/VoidType.java \
 	com/sun/jdi/VoidValue.java \
 	com/sun/tools/jdi/LinkedHashMap.java \
-	java/util/Observer.java
+	java/util/Observer.java \
+	java/util/Timer.java \
+	javax/security/sasl/SaslException.java \
+	javax/security/sasl/AuthenticationException.java \
+	javax/security/auth/callback/NameCallback.java \
+	javax/security/sasl/Sasl.java \
+	javax/security/sasl/SaslServer.java \
+	javax/security/sasl/SaslClient.java \
+	javax/security/sasl/SaslClientFactory.java \
+	javax/security/sasl/SaslServerFactory.java \
+	javax/security/auth/callback/ChoiceCallback.java \
+	javax/security/auth/callback/ConfirmationCallback.java \
+	javax/security/auth/callback/LanguageCallback.java \
+	javax/security/auth/callback/TextInputCallback.java \
+	javax/security/auth/callback/TextOutputCallback.java
 
 if FOUND_ECJ
   JCOMPILER = $(ECJ) -nowarn
@@ -383,7 +398,7 @@
 rt-compile-classes: rt-classes
 	mkdir -p lib/rt
 	cd rt ; \
-	  $(JCOMPILER) -d ../lib/rt -bootclasspath '' -source 1.6 \
+	  $(JCOMPILER) -g -d ../lib/rt -bootclasspath '' -source 1.6 \
 	    -sourcepath $(OPENJDK_SRC_DIR)/j2se/src/share/classes:$(OPENJDK_SRC_DIR)/j2se/src/solaris/classes:../generated:../jce \
 	    @../rt-classes
 
@@ -417,7 +432,7 @@
 	    generated/sun/nio/ch; \
 	  mkdir -p $(abs_top_srcdir)/lib; \
 	  cd $(OPENJDK_SRC_DIR)/j2se/make/tools/CompileProperties; \
-	    $(JCOMPILER) -d ../../../../../lib -1.5 CompileProperties.java; \
+	    $(JCOMPILER) -g -d ../../../../../lib -1.5 CompileProperties.java; \
 	  mkdir -p $(abs_top_srcdir)/generated/sun/util/resources; \
 	  cd $(abs_top_srcdir)/lib ; \
 	    for FILE in `ls $(OPENJDK_SRC_DIR)/j2se/src/share/classes/sun/util/resources/*.properties`; do \
@@ -438,7 +453,7 @@
 jce-compile-classes: jce-classes rt-classes
 	mkdir -p lib/jce
 	cd jce ; \
-	  $(JCOMPILER) -d ../lib/jce -source 1.6 -bootclasspath '' \
+	  $(JCOMPILER) -g -d ../lib/jce -source 1.6 -bootclasspath '' \
 	    -classpath ../lib/rt @../jce-classes
 
 lib/jce/jce.jar: jce-compile-classes
--- a/Makefile.in	Thu Jun 21 16:06:05 2007 +0100
+++ b/Makefile.in	Tue Jun 26 16:11:37 2007 +0100
@@ -193,6 +193,7 @@
 	patches/icedtea-text-relocations.patch \
 	patches/icedtea-graphics.patch \
 	patches/icedtea-gcc.patch \
+	patches/icedtea-debuginfo.patch \
 	$(FAST_BUILD_PATCH) \
 	$(CCACHE_PATCH)
 
@@ -369,7 +370,21 @@
 	com/sun/jdi/VoidType.java \
 	com/sun/jdi/VoidValue.java \
 	com/sun/tools/jdi/LinkedHashMap.java \
-	java/util/Observer.java
+	java/util/Observer.java \
+	java/util/Timer.java \
+	javax/security/sasl/SaslException.java \
+	javax/security/sasl/AuthenticationException.java \
+	javax/security/auth/callback/NameCallback.java \
+	javax/security/sasl/Sasl.java \
+	javax/security/sasl/SaslServer.java \
+	javax/security/sasl/SaslClient.java \
+	javax/security/sasl/SaslClientFactory.java \
+	javax/security/sasl/SaslServerFactory.java \
+	javax/security/auth/callback/ChoiceCallback.java \
+	javax/security/auth/callback/ConfirmationCallback.java \
+	javax/security/auth/callback/LanguageCallback.java \
+	javax/security/auth/callback/TextInputCallback.java \
+	javax/security/auth/callback/TextOutputCallback.java
 
 @FOUND_ECJ_FALSE@@FOUND_JAVAC_TRUE@JCOMPILER = $(JAVAC)
 @FOUND_ECJ_TRUE@JCOMPILER = $(ECJ) -nowarn
@@ -809,7 +824,7 @@
 rt-compile-classes: rt-classes
 	mkdir -p lib/rt
 	cd rt ; \
-	  $(JCOMPILER) -d ../lib/rt -bootclasspath '' -source 1.6 \
+	  $(JCOMPILER) -g -d ../lib/rt -bootclasspath '' -source 1.6 \
 	    -sourcepath $(OPENJDK_SRC_DIR)/j2se/src/share/classes:$(OPENJDK_SRC_DIR)/j2se/src/solaris/classes:../generated:../jce \
 	    @../rt-classes
 
@@ -843,7 +858,7 @@
 	    generated/sun/nio/ch; \
 	  mkdir -p $(abs_top_srcdir)/lib; \
 	  cd $(OPENJDK_SRC_DIR)/j2se/make/tools/CompileProperties; \
-	    $(JCOMPILER) -d ../../../../../lib -1.5 CompileProperties.java; \
+	    $(JCOMPILER) -g -d ../../../../../lib -1.5 CompileProperties.java; \
 	  mkdir -p $(abs_top_srcdir)/generated/sun/util/resources; \
 	  cd $(abs_top_srcdir)/lib ; \
 	    for FILE in `ls $(OPENJDK_SRC_DIR)/j2se/src/share/classes/sun/util/resources/*.properties`; do \
@@ -864,7 +879,7 @@
 jce-compile-classes: jce-classes rt-classes
 	mkdir -p lib/jce
 	cd jce ; \
-	  $(JCOMPILER) -d ../lib/jce -source 1.6 -bootclasspath '' \
+	  $(JCOMPILER) -g -d ../lib/jce -source 1.6 -bootclasspath '' \
 	    -classpath ../lib/rt @../jce-classes
 
 lib/jce/jce.jar: jce-compile-classes
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/BaseHash.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,183 @@
+/* BaseHash.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+/**
+ * A base abstract class to facilitate hash implementations.
+ */
+public abstract class BaseHash
+    implements IMessageDigest
+{
+  /** The canonical name prefix of the hash. */
+  protected String name;
+
+  /** The hash (output) size in bytes. */
+  protected int hashSize;
+
+  /** The hash (inner) block size in bytes. */
+  protected int blockSize;
+
+  /** Number of bytes processed so far. */
+  protected long count;
+
+  /** Temporary input buffer. */
+  protected byte[] buffer;
+
+  /**
+   * Trivial constructor for use by concrete subclasses.
+   * 
+   * @param name the canonical name prefix of this instance.
+   * @param hashSize the block size of the output in bytes.
+   * @param blockSize the block size of the internal transform.
+   */
+  protected BaseHash(String name, int hashSize, int blockSize)
+  {
+    super();
+
+    this.name = name;
+    this.hashSize = hashSize;
+    this.blockSize = blockSize;
+    this.buffer = new byte[blockSize];
+
+    resetContext();
+  }
+
+  public String name()
+  {
+    return name;
+  }
+
+  public int hashSize()
+  {
+    return hashSize;
+  }
+
+  public int blockSize()
+  {
+    return blockSize;
+  }
+
+  public void update(byte b)
+  {
+    // compute number of bytes still unhashed; ie. present in buffer
+    int i = (int) (count % blockSize);
+    count++;
+    buffer[i] = b;
+    if (i == (blockSize - 1))
+      transform(buffer, 0);
+  }
+
+  public void update(byte[] b)
+  {
+    update(b, 0, b.length);
+  }
+
+  public void update(byte[] b, int offset, int len)
+  {
+    int n = (int) (count % blockSize);
+    count += len;
+    int partLen = blockSize - n;
+    int i = 0;
+
+    if (len >= partLen)
+      {
+        System.arraycopy(b, offset, buffer, n, partLen);
+        transform(buffer, 0);
+        for (i = partLen; i + blockSize - 1 < len; i += blockSize)
+          transform(b, offset + i);
+
+        n = 0;
+      }
+
+    if (i < len)
+      System.arraycopy(b, offset + i, buffer, n, len - i);
+  }
+
+  public byte[] digest()
+  {
+    byte[] tail = padBuffer(); // pad remaining bytes in buffer
+    update(tail, 0, tail.length); // last transform of a message
+    byte[] result = getResult(); // make a result out of context
+
+    reset(); // reset this instance for future re-use
+
+    return result;
+  }
+
+  public void reset()
+  { // reset this instance for future re-use
+    count = 0L;
+    for (int i = 0; i < blockSize;)
+      buffer[i++] = 0;
+
+    resetContext();
+  }
+
+  public abstract Object clone();
+
+  public abstract boolean selfTest();
+
+  /**
+   * Returns the byte array to use as padding before completing a hash
+   * operation.
+   * 
+   * @return the bytes to pad the remaining bytes in the buffer before
+   *         completing a hash operation.
+   */
+  protected abstract byte[] padBuffer();
+
+  /**
+   * Constructs the result from the contents of the current context.
+   * 
+   * @return the output of the completed hash operation.
+   */
+  protected abstract byte[] getResult();
+
+  /** Resets the instance for future re-use. */
+  protected abstract void resetContext();
+
+  /**
+   * The block digest transformation per se.
+   * 
+   * @param in the <i>blockSize</i> long block, as an array of bytes to digest.
+   * @param offset the index where the data to digest is located within the
+   *          input buffer.
+   */
+  protected abstract void transform(byte[] in, int offset);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/HashFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,135 @@
+/* HashFactory.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A <i>Factory</i> to instantiate message digest algorithm instances.
+ */
+public class HashFactory
+{
+  /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+  private HashFactory()
+  {
+    super();
+  }
+
+  /**
+   * Return an instance of a hash algorithm given its name.
+   * 
+   * @param name the name of the hash algorithm.
+   * @return an instance of the hash algorithm, or null if none found.
+   * @exception InternalError if the implementation does not pass its self-
+   *              test.
+   */
+  public static IMessageDigest getInstance(String name)
+  {
+    if (name == null)
+      return null;
+
+    name = name.trim();
+    IMessageDigest result = null;
+    if (name.equalsIgnoreCase(Registry.WHIRLPOOL_HASH))
+      result = new Whirlpool();
+    else if (name.equalsIgnoreCase(Registry.RIPEMD128_HASH)
+             || name.equalsIgnoreCase(Registry.RIPEMD_128_HASH))
+      result = new RipeMD128();
+    else if (name.equalsIgnoreCase(Registry.RIPEMD160_HASH)
+             || name.equalsIgnoreCase(Registry.RIPEMD_160_HASH))
+      result = new RipeMD160();
+    else if (name.equalsIgnoreCase(Registry.SHA160_HASH)
+             || name.equalsIgnoreCase(Registry.SHA_1_HASH)
+             || name.equalsIgnoreCase(Registry.SHA1_HASH)
+             || name.equalsIgnoreCase(Registry.SHA_HASH))
+      result = new Sha160();
+    else if (name.equalsIgnoreCase(Registry.SHA256_HASH))
+      result = new Sha256();
+    else if (name.equalsIgnoreCase(Registry.SHA384_HASH))
+      result = new Sha384();
+    else if (name.equalsIgnoreCase(Registry.SHA512_HASH))
+      result = new Sha512();
+    else if (name.equalsIgnoreCase(Registry.TIGER_HASH))
+      result = new Tiger();
+    else if (name.equalsIgnoreCase(Registry.HAVAL_HASH))
+      result = new Haval();
+    else if (name.equalsIgnoreCase(Registry.MD5_HASH))
+      result = new MD5();
+    else if (name.equalsIgnoreCase(Registry.MD4_HASH))
+      result = new MD4();
+    else if (name.equalsIgnoreCase(Registry.MD2_HASH))
+      result = new MD2();
+    else if (name.equalsIgnoreCase(Registry.HAVAL_HASH))
+      result = new Haval();
+
+    if (result != null && ! result.selfTest())
+      throw new InternalError(result.name());
+
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of names of hash algorithms supported by this
+   * <i>Factory</i>.
+   * 
+   * @return a {@link Set} of hash names (Strings).
+   */
+  public static final Set getNames()
+  {
+    HashSet hs = new HashSet();
+    hs.add(Registry.WHIRLPOOL_HASH);
+    hs.add(Registry.RIPEMD128_HASH);
+    hs.add(Registry.RIPEMD160_HASH);
+    hs.add(Registry.SHA160_HASH);
+    hs.add(Registry.SHA256_HASH);
+    hs.add(Registry.SHA384_HASH);
+    hs.add(Registry.SHA512_HASH);
+    hs.add(Registry.TIGER_HASH);
+    hs.add(Registry.HAVAL_HASH);
+    hs.add(Registry.MD5_HASH);
+    hs.add(Registry.MD4_HASH);
+    hs.add(Registry.MD2_HASH);
+
+    return Collections.unmodifiableSet(hs);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/Haval.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,807 @@
+/* Haval.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * The <i>HAVAL</i> message-digest algorithm is a variable output length, with
+ * variable number of rounds. By default, this implementation allows <i>HAVAL</i>
+ * to be used as a drop-in replacement for <i>MD5</i>.
+ * <p>
+ * References:
+ * <ol>
+ * <li>HAVAL - A One-Way Hashing Algorithm with Variable Length of Output<br>
+ * Advances in Cryptology - AUSCRYPT'92, Lecture Notes in Computer Science,<br>
+ * Springer-Verlag, 1993; <br>
+ * Y. Zheng, J. Pieprzyk and J. Seberry.</li>
+ * </ol>
+ */
+public class Haval
+    extends BaseHash
+{
+  public static final int HAVAL_VERSION = 1;
+
+  public static final int HAVAL_128_BIT = 16;
+
+  public static final int HAVAL_160_BIT = 20;
+
+  public static final int HAVAL_192_BIT = 24;
+
+  public static final int HAVAL_224_BIT = 28;
+
+  public static final int HAVAL_256_BIT = 32;
+
+  public static final int HAVAL_3_ROUND = 3;
+
+  public static final int HAVAL_4_ROUND = 4;
+
+  public static final int HAVAL_5_ROUND = 5;
+
+  private static final int BLOCK_SIZE = 128; // inner block size in bytes
+
+  private static final String DIGEST0 = "C68F39913F901F3DDF44C707357A7D70";
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /**
+   * Number of HAVAL rounds. Allowed values are integers in the range <code>3
+   * .. 5</code>.
+   * The default is <code>3</code>.
+   */
+  private int rounds = HAVAL_3_ROUND;
+
+  /** 128-bit interim result. */
+  private int h0, h1, h2, h3, h4, h5, h6, h7;
+
+  /**
+   * Calls the constructor with two argument using {@link #HAVAL_128_BIT} as the
+   * value for the output size (i.e. <code>128</code> bits, and
+   * {@link #HAVAL_3_ROUND} for the value of number of rounds.
+   */
+  public Haval()
+  {
+    this(HAVAL_128_BIT, HAVAL_3_ROUND);
+  }
+
+  /**
+   * Calls the constructor with two arguments using the designated output size,
+   * and {@link #HAVAL_3_ROUND} for the value of number of rounds.
+   * 
+   * @param size the output size in bytes of this instance.
+   * @throws IllegalArgumentException if the designated output size is invalid.
+   * @see #HAVAL_128_BIT
+   * @see #HAVAL_160_BIT
+   * @see #HAVAL_192_BIT
+   * @see #HAVAL_224_BIT
+   * @see #HAVAL_256_BIT
+   */
+  public Haval(int size)
+  {
+    this(size, HAVAL_3_ROUND);
+  }
+
+  /**
+   * Constructs a <code>Haval</code> instance with the designated output size
+   * (in bytes). Valid output <code>size</code> values are <code>16</code>,
+   * <code>20</code>, <code>24</code>, <code>28</code> and
+   * <code>32</code>. Valid values for <code>rounds</code> are in the range
+   * <code>3..5</code> inclusive.
+   * 
+   * @param size the output size in bytes of this instance.
+   * @param rounds the number of rounds to apply when transforming data.
+   * @throws IllegalArgumentException if the designated output size is invalid,
+   *           or if the number of rounds is invalid.
+   * @see #HAVAL_128_BIT
+   * @see #HAVAL_160_BIT
+   * @see #HAVAL_192_BIT
+   * @see #HAVAL_224_BIT
+   * @see #HAVAL_256_BIT
+   * @see #HAVAL_3_ROUND
+   * @see #HAVAL_4_ROUND
+   * @see #HAVAL_5_ROUND
+   */
+  public Haval(int size, int rounds)
+  {
+    super(Registry.HAVAL_HASH, size, BLOCK_SIZE);
+
+    if (size != HAVAL_128_BIT
+        && size != HAVAL_160_BIT
+        && size != HAVAL_192_BIT
+        && size != HAVAL_224_BIT
+        && size != HAVAL_256_BIT)
+      throw new IllegalArgumentException("Invalid HAVAL output size");
+
+    if (rounds != HAVAL_3_ROUND
+        && rounds != HAVAL_4_ROUND
+        && rounds != HAVAL_5_ROUND)
+      throw new IllegalArgumentException("Invalid HAVAL number of rounds");
+
+    this.rounds = rounds;
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   * 
+   * @param md the instance to clone.
+   */
+  private Haval(Haval md)
+  {
+    this(md.hashSize, md.rounds);
+
+    this.h0 = md.h0;
+    this.h1 = md.h1;
+    this.h2 = md.h2;
+    this.h3 = md.h3;
+    this.h4 = md.h4;
+    this.h5 = md.h5;
+    this.h6 = md.h6;
+    this.h7 = md.h7;
+    this.count = md.count;
+    this.buffer = (byte[]) md.buffer.clone();
+  }
+
+  public Object clone()
+  {
+    return new Haval(this);
+  }
+
+  protected synchronized void transform(byte[] in, int i)
+  {
+    int X0 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X1 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X2 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X3 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X4 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X5 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X6 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X7 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X8 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X9 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) << 24;
+    int X10 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X11 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X12 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X13 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X14 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X15 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X16 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X17 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X18 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X19 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X20 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X21 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X22 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X23 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X24 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X25 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X26 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X27 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X28 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X29 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X30 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int X31 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | (in[i++] & 0xFF) << 24;
+    int t0 = h0, t1 = h1, t2 = h2, t3 = h3, t4 = h4, t5 = h5, t6 = h6, t7 = h7;
+    // Pass 1
+    t7 = FF1(t7, t6, t5, t4, t3, t2, t1, t0, X0);
+    t6 = FF1(t6, t5, t4, t3, t2, t1, t0, t7, X1);
+    t5 = FF1(t5, t4, t3, t2, t1, t0, t7, t6, X2);
+    t4 = FF1(t4, t3, t2, t1, t0, t7, t6, t5, X3);
+    t3 = FF1(t3, t2, t1, t0, t7, t6, t5, t4, X4);
+    t2 = FF1(t2, t1, t0, t7, t6, t5, t4, t3, X5);
+    t1 = FF1(t1, t0, t7, t6, t5, t4, t3, t2, X6);
+    t0 = FF1(t0, t7, t6, t5, t4, t3, t2, t1, X7);
+
+    t7 = FF1(t7, t6, t5, t4, t3, t2, t1, t0, X8);
+    t6 = FF1(t6, t5, t4, t3, t2, t1, t0, t7, X9);
+    t5 = FF1(t5, t4, t3, t2, t1, t0, t7, t6, X10);
+    t4 = FF1(t4, t3, t2, t1, t0, t7, t6, t5, X11);
+    t3 = FF1(t3, t2, t1, t0, t7, t6, t5, t4, X12);
+    t2 = FF1(t2, t1, t0, t7, t6, t5, t4, t3, X13);
+    t1 = FF1(t1, t0, t7, t6, t5, t4, t3, t2, X14);
+    t0 = FF1(t0, t7, t6, t5, t4, t3, t2, t1, X15);
+
+    t7 = FF1(t7, t6, t5, t4, t3, t2, t1, t0, X16);
+    t6 = FF1(t6, t5, t4, t3, t2, t1, t0, t7, X17);
+    t5 = FF1(t5, t4, t3, t2, t1, t0, t7, t6, X18);
+    t4 = FF1(t4, t3, t2, t1, t0, t7, t6, t5, X19);
+    t3 = FF1(t3, t2, t1, t0, t7, t6, t5, t4, X20);
+    t2 = FF1(t2, t1, t0, t7, t6, t5, t4, t3, X21);
+    t1 = FF1(t1, t0, t7, t6, t5, t4, t3, t2, X22);
+    t0 = FF1(t0, t7, t6, t5, t4, t3, t2, t1, X23);
+
+    t7 = FF1(t7, t6, t5, t4, t3, t2, t1, t0, X24);
+    t6 = FF1(t6, t5, t4, t3, t2, t1, t0, t7, X25);
+    t5 = FF1(t5, t4, t3, t2, t1, t0, t7, t6, X26);
+    t4 = FF1(t4, t3, t2, t1, t0, t7, t6, t5, X27);
+    t3 = FF1(t3, t2, t1, t0, t7, t6, t5, t4, X28);
+    t2 = FF1(t2, t1, t0, t7, t6, t5, t4, t3, X29);
+    t1 = FF1(t1, t0, t7, t6, t5, t4, t3, t2, X30);
+    t0 = FF1(t0, t7, t6, t5, t4, t3, t2, t1, X31);
+
+    // Pass 2
+    t7 = FF2(t7, t6, t5, t4, t3, t2, t1, t0, X5, 0x452821E6);
+    t6 = FF2(t6, t5, t4, t3, t2, t1, t0, t7, X14, 0x38D01377);
+    t5 = FF2(t5, t4, t3, t2, t1, t0, t7, t6, X26, 0xBE5466CF);
+    t4 = FF2(t4, t3, t2, t1, t0, t7, t6, t5, X18, 0x34E90C6C);
+    t3 = FF2(t3, t2, t1, t0, t7, t6, t5, t4, X11, 0xC0AC29B7);
+    t2 = FF2(t2, t1, t0, t7, t6, t5, t4, t3, X28, 0xC97C50DD);
+    t1 = FF2(t1, t0, t7, t6, t5, t4, t3, t2, X7, 0x3F84D5B5);
+    t0 = FF2(t0, t7, t6, t5, t4, t3, t2, t1, X16, 0xB5470917);
+
+    t7 = FF2(t7, t6, t5, t4, t3, t2, t1, t0, X0, 0x9216D5D9);
+    t6 = FF2(t6, t5, t4, t3, t2, t1, t0, t7, X23, 0x8979FB1B);
+    t5 = FF2(t5, t4, t3, t2, t1, t0, t7, t6, X20, 0xD1310BA6);
+    t4 = FF2(t4, t3, t2, t1, t0, t7, t6, t5, X22, 0x98DFB5AC);
+    t3 = FF2(t3, t2, t1, t0, t7, t6, t5, t4, X1, 0x2FFD72DB);
+    t2 = FF2(t2, t1, t0, t7, t6, t5, t4, t3, X10, 0xD01ADFB7);
+    t1 = FF2(t1, t0, t7, t6, t5, t4, t3, t2, X4, 0xB8E1AFED);
+    t0 = FF2(t0, t7, t6, t5, t4, t3, t2, t1, X8, 0x6A267E96);
+
+    t7 = FF2(t7, t6, t5, t4, t3, t2, t1, t0, X30, 0xBA7C9045);
+    t6 = FF2(t6, t5, t4, t3, t2, t1, t0, t7, X3, 0xF12C7F99);
+    t5 = FF2(t5, t4, t3, t2, t1, t0, t7, t6, X21, 0x24A19947);
+    t4 = FF2(t4, t3, t2, t1, t0, t7, t6, t5, X9, 0xB3916CF7);
+    t3 = FF2(t3, t2, t1, t0, t7, t6, t5, t4, X17, 0x0801F2E2);
+    t2 = FF2(t2, t1, t0, t7, t6, t5, t4, t3, X24, 0x858EFC16);
+    t1 = FF2(t1, t0, t7, t6, t5, t4, t3, t2, X29, 0x636920D8);
+    t0 = FF2(t0, t7, t6, t5, t4, t3, t2, t1, X6, 0x71574E69);
+
+    t7 = FF2(t7, t6, t5, t4, t3, t2, t1, t0, X19, 0xA458FEA3);
+    t6 = FF2(t6, t5, t4, t3, t2, t1, t0, t7, X12, 0xF4933D7E);
+    t5 = FF2(t5, t4, t3, t2, t1, t0, t7, t6, X15, 0x0D95748F);
+    t4 = FF2(t4, t3, t2, t1, t0, t7, t6, t5, X13, 0x728EB658);
+    t3 = FF2(t3, t2, t1, t0, t7, t6, t5, t4, X2, 0x718BCD58);
+    t2 = FF2(t2, t1, t0, t7, t6, t5, t4, t3, X25, 0x82154AEE);
+    t1 = FF2(t1, t0, t7, t6, t5, t4, t3, t2, X31, 0x7B54A41D);
+    t0 = FF2(t0, t7, t6, t5, t4, t3, t2, t1, X27, 0xC25A59B5);
+
+    // Pass 3
+    t7 = FF3(t7, t6, t5, t4, t3, t2, t1, t0, X19, 0x9C30D539);
+    t6 = FF3(t6, t5, t4, t3, t2, t1, t0, t7, X9, 0x2AF26013);
+    t5 = FF3(t5, t4, t3, t2, t1, t0, t7, t6, X4, 0xC5D1B023);
+    t4 = FF3(t4, t3, t2, t1, t0, t7, t6, t5, X20, 0x286085F0);
+    t3 = FF3(t3, t2, t1, t0, t7, t6, t5, t4, X28, 0xCA417918);
+    t2 = FF3(t2, t1, t0, t7, t6, t5, t4, t3, X17, 0xB8DB38EF);
+    t1 = FF3(t1, t0, t7, t6, t5, t4, t3, t2, X8, 0x8E79DCB0);
+    t0 = FF3(t0, t7, t6, t5, t4, t3, t2, t1, X22, 0x603A180E);
+
+    t7 = FF3(t7, t6, t5, t4, t3, t2, t1, t0, X29, 0x6C9E0E8B);
+    t6 = FF3(t6, t5, t4, t3, t2, t1, t0, t7, X14, 0xB01E8A3E);
+    t5 = FF3(t5, t4, t3, t2, t1, t0, t7, t6, X25, 0xD71577C1);
+    t4 = FF3(t4, t3, t2, t1, t0, t7, t6, t5, X12, 0xBD314B27);
+    t3 = FF3(t3, t2, t1, t0, t7, t6, t5, t4, X24, 0x78AF2FDA);
+    t2 = FF3(t2, t1, t0, t7, t6, t5, t4, t3, X30, 0x55605C60);
+    t1 = FF3(t1, t0, t7, t6, t5, t4, t3, t2, X16, 0xE65525F3);
+    t0 = FF3(t0, t7, t6, t5, t4, t3, t2, t1, X26, 0xAA55AB94);
+
+    t7 = FF3(t7, t6, t5, t4, t3, t2, t1, t0, X31, 0x57489862);
+    t6 = FF3(t6, t5, t4, t3, t2, t1, t0, t7, X15, 0x63E81440);
+    t5 = FF3(t5, t4, t3, t2, t1, t0, t7, t6, X7, 0x55CA396A);
+    t4 = FF3(t4, t3, t2, t1, t0, t7, t6, t5, X3, 0x2AAB10B6);
+    t3 = FF3(t3, t2, t1, t0, t7, t6, t5, t4, X1, 0xB4CC5C34);
+    t2 = FF3(t2, t1, t0, t7, t6, t5, t4, t3, X0, 0x1141E8CE);
+    t1 = FF3(t1, t0, t7, t6, t5, t4, t3, t2, X18, 0xA15486AF);
+    t0 = FF3(t0, t7, t6, t5, t4, t3, t2, t1, X27, 0x7C72E993);
+
+    t7 = FF3(t7, t6, t5, t4, t3, t2, t1, t0, X13, 0xB3EE1411);
+    t6 = FF3(t6, t5, t4, t3, t2, t1, t0, t7, X6, 0x636FBC2A);
+    t5 = FF3(t5, t4, t3, t2, t1, t0, t7, t6, X21, 0x2BA9C55D);
+    t4 = FF3(t4, t3, t2, t1, t0, t7, t6, t5, X10, 0x741831F6);
+    t3 = FF3(t3, t2, t1, t0, t7, t6, t5, t4, X23, 0xCE5C3E16);
+    t2 = FF3(t2, t1, t0, t7, t6, t5, t4, t3, X11, 0x9B87931E);
+    t1 = FF3(t1, t0, t7, t6, t5, t4, t3, t2, X5, 0xAFD6BA33);
+    t0 = FF3(t0, t7, t6, t5, t4, t3, t2, t1, X2, 0x6C24CF5C);
+
+    if (rounds >= 4)
+      {
+        t7 = FF4(t7, t6, t5, t4, t3, t2, t1, t0, X24, 0x7A325381);
+        t6 = FF4(t6, t5, t4, t3, t2, t1, t0, t7, X4, 0x28958677);
+        t5 = FF4(t5, t4, t3, t2, t1, t0, t7, t6, X0, 0x3B8F4898);
+        t4 = FF4(t4, t3, t2, t1, t0, t7, t6, t5, X14, 0x6B4BB9AF);
+        t3 = FF4(t3, t2, t1, t0, t7, t6, t5, t4, X2, 0xC4BFE81B);
+        t2 = FF4(t2, t1, t0, t7, t6, t5, t4, t3, X7, 0x66282193);
+        t1 = FF4(t1, t0, t7, t6, t5, t4, t3, t2, X28, 0x61D809CC);
+        t0 = FF4(t0, t7, t6, t5, t4, t3, t2, t1, X23, 0xFB21A991);
+        t7 = FF4(t7, t6, t5, t4, t3, t2, t1, t0, X26, 0x487CAC60);
+        t6 = FF4(t6, t5, t4, t3, t2, t1, t0, t7, X6, 0x5DEC8032);
+        t5 = FF4(t5, t4, t3, t2, t1, t0, t7, t6, X30, 0xEF845D5D);
+        t4 = FF4(t4, t3, t2, t1, t0, t7, t6, t5, X20, 0xE98575B1);
+        t3 = FF4(t3, t2, t1, t0, t7, t6, t5, t4, X18, 0xDC262302);
+        t2 = FF4(t2, t1, t0, t7, t6, t5, t4, t3, X25, 0xEB651B88);
+        t1 = FF4(t1, t0, t7, t6, t5, t4, t3, t2, X19, 0x23893E81);
+        t0 = FF4(t0, t7, t6, t5, t4, t3, t2, t1, X3, 0xD396ACC5);
+
+        t7 = FF4(t7, t6, t5, t4, t3, t2, t1, t0, X22, 0x0F6D6FF3);
+        t6 = FF4(t6, t5, t4, t3, t2, t1, t0, t7, X11, 0x83F44239);
+        t5 = FF4(t5, t4, t3, t2, t1, t0, t7, t6, X31, 0x2E0B4482);
+        t4 = FF4(t4, t3, t2, t1, t0, t7, t6, t5, X21, 0xA4842004);
+        t3 = FF4(t3, t2, t1, t0, t7, t6, t5, t4, X8, 0x69C8F04A);
+        t2 = FF4(t2, t1, t0, t7, t6, t5, t4, t3, X27, 0x9E1F9B5E);
+        t1 = FF4(t1, t0, t7, t6, t5, t4, t3, t2, X12, 0x21C66842);
+        t0 = FF4(t0, t7, t6, t5, t4, t3, t2, t1, X9, 0xF6E96C9A);
+        t7 = FF4(t7, t6, t5, t4, t3, t2, t1, t0, X1, 0x670C9C61);
+        t6 = FF4(t6, t5, t4, t3, t2, t1, t0, t7, X29, 0xABD388F0);
+        t5 = FF4(t5, t4, t3, t2, t1, t0, t7, t6, X5, 0x6A51A0D2);
+        t4 = FF4(t4, t3, t2, t1, t0, t7, t6, t5, X15, 0xD8542F68);
+        t3 = FF4(t3, t2, t1, t0, t7, t6, t5, t4, X17, 0x960FA728);
+        t2 = FF4(t2, t1, t0, t7, t6, t5, t4, t3, X10, 0xAB5133A3);
+        t1 = FF4(t1, t0, t7, t6, t5, t4, t3, t2, X16, 0x6EEF0B6C);
+        t0 = FF4(t0, t7, t6, t5, t4, t3, t2, t1, X13, 0x137A3BE4);
+
+        if (rounds == 5)
+          {
+            t7 = FF5(t7, t6, t5, t4, t3, t2, t1, t0, X27, 0xBA3BF050);
+            t6 = FF5(t6, t5, t4, t3, t2, t1, t0, t7, X3, 0x7EFB2A98);
+            t5 = FF5(t5, t4, t3, t2, t1, t0, t7, t6, X21, 0xA1F1651D);
+            t4 = FF5(t4, t3, t2, t1, t0, t7, t6, t5, X26, 0x39AF0176);
+            t3 = FF5(t3, t2, t1, t0, t7, t6, t5, t4, X17, 0x66CA593E);
+            t2 = FF5(t2, t1, t0, t7, t6, t5, t4, t3, X11, 0x82430E88);
+            t1 = FF5(t1, t0, t7, t6, t5, t4, t3, t2, X20, 0x8CEE8619);
+            t0 = FF5(t0, t7, t6, t5, t4, t3, t2, t1, X29, 0x456F9FB4);
+
+            t7 = FF5(t7, t6, t5, t4, t3, t2, t1, t0, X19, 0x7D84A5C3);
+            t6 = FF5(t6, t5, t4, t3, t2, t1, t0, t7, X0, 0x3B8B5EBE);
+            t5 = FF5(t5, t4, t3, t2, t1, t0, t7, t6, X12, 0xE06F75D8);
+            t4 = FF5(t4, t3, t2, t1, t0, t7, t6, t5, X7, 0x85C12073);
+            t3 = FF5(t3, t2, t1, t0, t7, t6, t5, t4, X13, 0x401A449F);
+            t2 = FF5(t2, t1, t0, t7, t6, t5, t4, t3, X8, 0x56C16AA6);
+            t1 = FF5(t1, t0, t7, t6, t5, t4, t3, t2, X31, 0x4ED3AA62);
+            t0 = FF5(t0, t7, t6, t5, t4, t3, t2, t1, X10, 0x363F7706);
+
+            t7 = FF5(t7, t6, t5, t4, t3, t2, t1, t0, X5, 0x1BFEDF72);
+            t6 = FF5(t6, t5, t4, t3, t2, t1, t0, t7, X9, 0x429B023D);
+            t5 = FF5(t5, t4, t3, t2, t1, t0, t7, t6, X14, 0x37D0D724);
+            t4 = FF5(t4, t3, t2, t1, t0, t7, t6, t5, X30, 0xD00A1248);
+            t3 = FF5(t3, t2, t1, t0, t7, t6, t5, t4, X18, 0xDB0FEAD3);
+            t2 = FF5(t2, t1, t0, t7, t6, t5, t4, t3, X6, 0x49F1C09B);
+            t1 = FF5(t1, t0, t7, t6, t5, t4, t3, t2, X28, 0x075372C9);
+            t0 = FF5(t0, t7, t6, t5, t4, t3, t2, t1, X24, 0x80991B7B);
+
+            t7 = FF5(t7, t6, t5, t4, t3, t2, t1, t0, X2, 0x25D479D8);
+            t6 = FF5(t6, t5, t4, t3, t2, t1, t0, t7, X23, 0xF6E8DEF7);
+            t5 = FF5(t5, t4, t3, t2, t1, t0, t7, t6, X16, 0xE3FE501A);
+            t4 = FF5(t4, t3, t2, t1, t0, t7, t6, t5, X22, 0xB6794C3B);
+            t3 = FF5(t3, t2, t1, t0, t7, t6, t5, t4, X4, 0x976CE0BD);
+            t2 = FF5(t2, t1, t0, t7, t6, t5, t4, t3, X1, 0x04C006BA);
+            t1 = FF5(t1, t0, t7, t6, t5, t4, t3, t2, X25, 0xC1A94FB6);
+            t0 = FF5(t0, t7, t6, t5, t4, t3, t2, t1, X15, 0x409F60C4);
+          }
+      }
+    h7 += t7;
+    h6 += t6;
+    h5 += t5;
+    h4 += t4;
+    h3 += t3;
+    h2 += t2;
+    h1 += t1;
+    h0 += t0;
+  }
+
+  protected byte[] padBuffer()
+  {
+    // pad out to 118 mod 128. other 10 bytes have special use.
+    int n = (int)(count % BLOCK_SIZE);
+    int padding = (n < 118) ? (118 - n) : (246 - n);
+    byte[] result = new byte[padding + 10];
+    result[0] = (byte) 0x01;
+    // save the version number (LSB 3), the number of rounds (3 bits in the
+    // middle), the fingerprint length (MSB 2 bits and next byte) and the
+    // number of bits in the unpadded message.
+    int bl = hashSize * 8;
+    int sigByte = (bl & 0x03) << 6;
+    sigByte |= (rounds & 0x07) << 3;
+    sigByte |= HAVAL_VERSION & 0x07;
+    result[padding++] = (byte) sigByte;
+    result[padding++] = (byte)(bl >>> 2);
+    // save number of bits, casting the long to an array of 8 bytes
+    long bits = count << 3;
+    result[padding++] = (byte) bits;
+    result[padding++] = (byte)(bits >>> 8);
+    result[padding++] = (byte)(bits >>> 16);
+    result[padding++] = (byte)(bits >>> 24);
+    result[padding++] = (byte)(bits >>> 32);
+    result[padding++] = (byte)(bits >>> 40);
+    result[padding++] = (byte)(bits >>> 48);
+    result[padding  ] = (byte)(bits >>> 56);
+    return result;
+  }
+
+  protected byte[] getResult()
+  {
+    tailorDigestBits(); // tailor context for the designated output size
+    // cast enough top context values into an array of hashSize bytes
+    byte[] result = new byte[hashSize];
+    if (hashSize >= HAVAL_256_BIT)
+      {
+        result[31] = (byte)(h7 >>> 24);
+        result[30] = (byte)(h7 >>> 16);
+        result[29] = (byte)(h7 >>> 8);
+        result[28] = (byte) h7;
+      }
+    if (hashSize >= HAVAL_224_BIT)
+      {
+        result[27] = (byte)(h6 >>> 24);
+        result[26] = (byte)(h6 >>> 16);
+        result[25] = (byte)(h6 >>> 8);
+        result[24] = (byte) h6;
+      }
+    if (hashSize >= HAVAL_192_BIT)
+      {
+        result[23] = (byte)(h5 >>> 24);
+        result[22] = (byte)(h5 >>> 16);
+        result[21] = (byte)(h5 >>> 8);
+        result[20] = (byte) h5;
+      }
+    if (hashSize >= HAVAL_160_BIT)
+      {
+        result[19] = (byte)(h4 >>> 24);
+        result[18] = (byte)(h4 >>> 16);
+        result[17] = (byte)(h4 >>> 8);
+        result[16] = (byte) h4;
+      }
+    result[15] = (byte)(h3 >>> 24);
+    result[14] = (byte)(h3 >>> 16);
+    result[13] = (byte)(h3 >>> 8);
+    result[12] = (byte) h3;
+    result[11] = (byte)(h2 >>> 24);
+    result[10] = (byte)(h2 >>> 16);
+    result[ 9] = (byte)(h2 >>> 8);
+    result[ 8] = (byte) h2;
+    result[ 7] = (byte)(h1 >>> 24);
+    result[ 6] = (byte)(h1 >>> 16);
+    result[ 5] = (byte)(h1 >>> 8);
+    result[ 4] = (byte) h1;
+    result[ 3] = (byte)(h0 >>> 24);
+    result[ 2] = (byte)(h0 >>> 16);
+    result[ 1] = (byte)(h0 >>> 8);
+    result[ 0] = (byte) h0;
+    return result;
+  }
+
+  protected void resetContext()
+  {
+    h0 = 0x243F6A88;
+    h1 = 0x85A308D3;
+    h2 = 0x13198A2E;
+    h3 = 0x03707344;
+    h4 = 0xA4093822;
+    h5 = 0x299F31D0;
+    h6 = 0x082EFA98;
+    h7 = 0xEC4E6C89;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        String d = Util.toString(new Haval().digest());
+        valid = Boolean.valueOf(DIGEST0.equals(d));
+      }
+    return valid.booleanValue();
+  }
+
+  /** Tailors the last output. */
+  private void tailorDigestBits()
+  {
+    int t;
+    switch (hashSize)
+      {
+      case HAVAL_128_BIT:
+        t = (h7 & 0x000000FF)
+          | (h6 & 0xFF000000)
+          | (h5 & 0x00FF0000)
+          | (h4 & 0x0000FF00);
+        h0 += t >>> 8 | t << 24;
+        t = (h7 & 0x0000FF00)
+          | (h6 & 0x000000FF)
+          | (h5 & 0xFF000000)
+          | (h4 & 0x00FF0000);
+        h1 += t >>> 16 | t << 16;
+        t = (h7 & 0x00FF0000)
+          | (h6 & 0x0000FF00)
+          | (h5 & 0x000000FF)
+          | (h4 & 0xFF000000);
+        h2 += t >>> 24 | t << 8;
+        t = (h7 & 0xFF000000)
+          | (h6 & 0x00FF0000)
+          | (h5 & 0x0000FF00)
+          | (h4 & 0x000000FF);
+        h3 += t;
+        break;
+      case HAVAL_160_BIT:
+        t = (h7 & 0x3F) | (h6 & (0x7F << 25)) | (h5 & (0x3F << 19));
+        h0 += t >>> 19 | t << 13;
+        t = (h7 & (0x3F << 6)) | (h6 & 0x3F) | (h5 & (0x7F << 25));
+        h1 += t >>> 25 | t << 7;
+        t = (h7 & (0x7F << 12)) | (h6 & (0x3F << 6)) | (h5 & 0x3F);
+        h2 += t;
+        t = (h7 & (0x3F << 19)) | (h6 & (0x7F << 12)) | (h5 & (0x3F << 6));
+        h3 += (t >>> 6);
+        t = (h7 & (0x7F << 25)) | (h6 & (0x3F << 19)) | (h5 & (0x7F << 12));
+        h4 += (t >>> 12);
+        break;
+      case HAVAL_192_BIT:
+        t = (h7 & 0x1F) | (h6 & (0x3F << 26));
+        h0 += t >>> 26 | t << 6;
+        t = (h7 & (0x1F << 5)) | (h6 & 0x1F);
+        h1 += t;
+        t = (h7 & (0x3F << 10)) | (h6 & (0x1F << 5));
+        h2 += (t >>> 5);
+        t = (h7 & (0x1F << 16)) | (h6 & (0x3F << 10));
+        h3 += (t >>> 10);
+        t = (h7 & (0x1F << 21)) | (h6 & (0x1F << 16));
+        h4 += (t >>> 16);
+        t = (h7 & (0x3F << 26)) | (h6 & (0x1F << 21));
+        h5 += (t >>> 21);
+        break;
+      case HAVAL_224_BIT:
+        h0 += ((h7 >>> 27) & 0x1F);
+        h1 += ((h7 >>> 22) & 0x1F);
+        h2 += ((h7 >>> 18) & 0x0F);
+        h3 += ((h7 >>> 13) & 0x1F);
+        h4 += ((h7 >>>  9) & 0x0F);
+        h5 += ((h7 >>>  4) & 0x1F);
+        h6 +=  (h7         & 0x0F);
+      }
+  }
+
+  /**
+   * Permutations phi_{i,j}, i=3,4,5, j=1,...,i.
+   *
+   * rounds = 3:   6 5 4 3 2 1 0
+   *               | | | | | | | (replaced by)
+   *  phi_{3,1}:   1 0 3 5 6 2 4
+   *  phi_{3,2}:   4 2 1 0 5 3 6
+   *  phi_{3,3}:   6 1 2 3 4 5 0
+   *
+   * rounds = 4:   6 5 4 3 2 1 0
+   *               | | | | | | | (replaced by)
+   *  phi_{4,1}:   2 6 1 4 5 3 0
+   *  phi_{4,2}:   3 5 2 0 1 6 4
+   *  phi_{4,3}:   1 4 3 6 0 2 5
+   *  phi_{4,4}:   6 4 0 5 2 1 3
+   *
+   * rounds = 5:   6 5 4 3 2 1 0
+   *               | | | | | | | (replaced by)
+   *  phi_{5,1}:   3 4 1 0 5 2 6
+   *  phi_{5,2}:   6 2 1 0 3 4 5
+   *  phi_{5,3}:   2 6 0 4 3 1 5
+   *  phi_{5,4}:   1 5 3 2 0 4 6
+   *  phi_{5,5}:   2 5 0 6 4 3 1
+   */
+  private int FF1(int x7, int x6, int x5, int x4, int x3, int x2, int x1,
+                  int x0, int w)
+  {
+    int t;
+    switch (rounds)
+      {
+      case 3:
+        t = f1(x1, x0, x3, x5, x6, x2, x4);
+        break;
+      case 4:
+        t = f1(x2, x6, x1, x4, x5, x3, x0);
+        break;
+      default:
+        t = f1(x3, x4, x1, x0, x5, x2, x6);
+      }
+    return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w;
+  }
+
+  private int FF2(int x7, int x6, int x5, int x4, int x3, int x2, int x1,
+                  int x0, int w, int c)
+  {
+    int t;
+    switch (rounds)
+      {
+      case 3:
+        t = f2(x4, x2, x1, x0, x5, x3, x6);
+        break;
+      case 4:
+        t = f2(x3, x5, x2, x0, x1, x6, x4);
+        break;
+      default:
+        t = f2(x6, x2, x1, x0, x3, x4, x5);
+      }
+    return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w + c;
+  }
+
+  private int FF3(int x7, int x6, int x5, int x4, int x3, int x2, int x1,
+                  int x0, int w, int c)
+  {
+    int t;
+    switch (rounds)
+      {
+      case 3:
+        t = f3(x6, x1, x2, x3, x4, x5, x0);
+        break;
+      case 4:
+        t = f3(x1, x4, x3, x6, x0, x2, x5);
+        break;
+      default:
+        t = f3(x2, x6, x0, x4, x3, x1, x5);
+      }
+    return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w + c;
+  }
+
+  private int FF4(int x7, int x6, int x5, int x4, int x3, int x2, int x1,
+                  int x0, int w, int c)
+  {
+    int t;
+    switch (rounds)
+      {
+      case 4:
+        t = f4(x6, x4, x0, x5, x2, x1, x3);
+        break;
+      default:
+        t = f4(x1, x5, x3, x2, x0, x4, x6);
+      }
+    return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w + c;
+  }
+
+  private int FF5(int x7, int x6, int x5, int x4, int x3, int x2, int x1,
+                  int x0, int w, int c)
+  {
+    int t = f5(x2, x5, x0, x6, x4, x3, x1);
+    return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w + c;
+  }
+
+  private int f1(int x6, int x5, int x4, int x3, int x2, int x1, int x0)
+  {
+    return x1 & (x0 ^ x4) ^ x2 & x5 ^ x3 & x6 ^ x0;
+  }
+
+  private int f2(int x6, int x5, int x4, int x3, int x2, int x1, int x0)
+  {
+    return x2 & (x1 & ~x3 ^ x4 & x5 ^ x6 ^ x0) ^ x4 & (x1 ^ x5) ^ x3 & x5 ^ x0;
+  }
+
+  private int f3(int x6, int x5, int x4, int x3, int x2, int x1, int x0)
+  {
+    return x3 & (x1 & x2 ^ x6 ^ x0) ^ x1 & x4 ^ x2 & x5 ^ x0;
+  }
+
+  private int f4(int x6, int x5, int x4, int x3, int x2, int x1, int x0)
+  {
+    return x4 & (x5 & ~x2 ^ x3 & ~x6 ^ x1 ^ x6 ^ x0) ^ x3
+           & (x1 & x2 ^ x5 ^ x6) ^ x2 & x6 ^ x0;
+  }
+
+  private int f5(int x6, int x5, int x4, int x3, int x2, int x1, int x0)
+  {
+    return x0 & (x1 & x2 & x3 ^ ~x5) ^ x1 & x4 ^ x2 & x5 ^ x3 & x6;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/IMessageDigest.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,127 @@
+/* IMessageDigest.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+/**
+ * The basic visible methods of any hash algorithm.
+ * <p>
+ * A hash (or message digest) algorithm produces its output by iterating a basic
+ * compression function on blocks of data.
+ */
+public interface IMessageDigest
+    extends Cloneable
+{
+  /**
+   * Returns the canonical name of this algorithm.
+   * 
+   * @return the canonical name of this instance.
+   */
+  String name();
+
+  /**
+   * Returns the output length in bytes of this message digest algorithm.
+   * 
+   * @return the output length in bytes of this message digest algorithm.
+   */
+  int hashSize();
+
+  /**
+   * Returns the algorithm's (inner) block size in bytes.
+   * 
+   * @return the algorithm's inner block size in bytes.
+   */
+  int blockSize();
+
+  /**
+   * Continues a message digest operation using the input byte.
+   * 
+   * @param b the input byte to digest.
+   */
+  void update(byte b);
+
+  /**
+   * Continues a message digest operation, by filling the buffer, processing
+   * data in the algorithm's HASH_SIZE-bit block(s), updating the context and
+   * count, and buffering the remaining bytes in buffer for the next operation.
+   * 
+   * @param in the input block.
+   */
+  void update(byte[] in);
+
+  /**
+   * Continues a message digest operation, by filling the buffer, processing
+   * data in the algorithm's HASH_SIZE-bit block(s), updating the context and
+   * count, and buffering the remaining bytes in buffer for the next operation.
+   * 
+   * @param in the input block.
+   * @param offset start of meaningful bytes in input block.
+   * @param length number of bytes, in input block, to consider.
+   */
+  void update(byte[] in, int offset, int length);
+
+  /**
+   * Completes the message digest by performing final operations such as padding
+   * and resetting the instance.
+   * 
+   * @return the array of bytes representing the hash value.
+   */
+  byte[] digest();
+
+  /**
+   * Resets the current context of this instance clearing any eventually cached
+   * intermediary values.
+   */
+  void reset();
+
+  /**
+   * A basic test. Ensures that the digest of a pre-determined message is equal
+   * to a known pre-computed value.
+   * 
+   * @return <code>true</code> if the implementation passes a basic self-test.
+   *         Returns <code>false</code> otherwise.
+   */
+  boolean selfTest();
+
+  /**
+   * Returns a clone copy of this instance.
+   * 
+   * @return a clone copy of this instance.
+   */
+  Object clone();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/MD2.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,256 @@
+/* MD2.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * An implementation of the MD2 message digest algorithm.
+ * <p>
+ * MD2 is not widely used. Unless it is needed for compatibility with
+ * existing systems, it is not recommended for use in new applications.
+ * <p>
+ * References:
+ * <ol>
+ *    <li>The <a href="http://www.ietf.org/rfc/rfc1319.txt">MD2</a>
+ *    Message-Digest Algorithm.<br>
+ *    B. Kaliski.</li>
+ *    <li>The <a href="http://www.rfc-editor.org/errata.html">RFC ERRATA PAGE</a>
+ *    under section RFC 1319.</li>
+ * </ol>
+ */
+public class MD2
+    extends BaseHash
+{
+  /** An MD2 message digest is always 128-bits long, or 16 bytes. */
+  private static final int DIGEST_LENGTH = 16;
+
+  /** The MD2 algorithm operates on 128-bit blocks, or 16 bytes. */
+  private static final int BLOCK_LENGTH = 16;
+
+  /** 256 byte "random" permutation of the digits of pi. */
+  private static final byte[] PI = {
+        41,   46,   67,  -55,  -94,  -40,  124,   1,
+        61,   54,   84,  -95,  -20,  -16,    6,  19,
+        98,  -89,    5,  -13,  -64,  -57,  115, -116,
+      -104, -109,   43,  -39,  -68,   76, -126,  -54,
+        30, -101,   87,   60,   -3,  -44,  -32,   22,
+       103,   66,  111,   24, -118,   23,  -27,   18,
+       -66,   78,  -60,  -42,  -38,  -98,  -34,   73,
+       -96,   -5,  -11, -114,  -69,   47,  -18,  122,
+       -87,  104,  121, -111,   21,  -78,    7,   63,
+      -108,  -62,   16, -119,   11,   34,   95,   33,
+      -128,  127,   93, -102,   90, -112,   50,   39,
+        53,   62,  -52,  -25,  -65,   -9, -105,    3,
+        -1,   25,   48,  -77,   72,  -91,  -75,  -47,
+       -41,   94, -110,   42,  -84,   86,  -86,  -58,
+        79,  -72,   56,  -46, -106,  -92,  125,  -74,
+       118,   -4,  107,  -30, -100,  116,    4,  -15,
+        69,  -99,  112,   89,  100,  113, -121,   32,
+      -122,   91,  -49,  101,  -26,   45,  -88,    2,
+        27,   96,   37,  -83,  -82,  -80,  -71,  -10,
+        28,   70,   97,  105,   52,   64,  126,   15,
+        85,   71,  -93,   35,  -35,   81,  -81,   58,
+       -61,   92,   -7,  -50,  -70,  -59,  -22,   38,
+        44,   83,   13,  110, -123,   40, -124,    9,
+       -45,  -33,  -51,  -12,   65, -127,   77,   82,
+       106,  -36,   55,  -56,  108,  -63,  -85,   -6,
+        36,  -31,  123,    8,   12,  -67,  -79,   74,
+       120, -120, -107, -117,  -29,   99,  -24,  109,
+       -23,  -53,  -43,   -2,   59,    0,   29,   57,
+       -14,  -17,  -73,   14,  102,   88,  -48,  -28,
+       -90,  119,  114,   -8,  -21,  117,   75,   10,
+        49,   68,   80,  -76, -113,  -19,   31,   26,
+       -37, -103, -115,   51, - 97,   17, -125,   20 };
+
+  /** The output of this message digest when no data has been input. */
+  private static final String DIGEST0 = "8350E5A3E24C153DF2275C9F80692773";
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /** The checksum computed so far. */
+  private byte[] checksum;
+
+  /**
+   * Work array needed by encrypt method. First <code>BLOCK_LENGTH</code> bytes
+   * are also used to store the running digest.
+   */
+  private byte[] work;
+
+  /** Creates a new MD2 digest ready for use. */
+  public MD2()
+  {
+    super(Registry.MD2_HASH, DIGEST_LENGTH, BLOCK_LENGTH);
+  }
+
+  /**
+   * Private constructor used for cloning.
+   *
+   * @param md2 the instance to clone.
+   */
+  private MD2(MD2 md2)
+  {
+    this();
+
+    // superclass field
+    this.count = md2.count;
+    this.buffer = (byte[]) md2.buffer.clone();
+    // private field
+    this.checksum = (byte[]) md2.checksum.clone();
+    this.work = (byte[]) md2.work.clone();
+  }
+
+  public Object clone()
+  {
+    return new MD2(this);
+  }
+
+  protected byte[] getResult()
+  {
+    byte[] result = new byte[DIGEST_LENGTH];
+    // Encrypt checksum as last block.
+    encryptBlock(checksum, 0);
+    for (int i = 0; i < BLOCK_LENGTH; i++)
+      result[i] = work[i];
+
+    return result;
+  }
+
+  protected void resetContext()
+  {
+    checksum = new byte[BLOCK_LENGTH];
+    work = new byte[BLOCK_LENGTH * 3];
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        String d = Util.toString(new MD2().digest());
+        valid = Boolean.valueOf(DIGEST0.equals(d));
+      }
+    return valid.booleanValue();
+  }
+
+  /**
+   * Generates an array of padding bytes. The padding is defined as
+   * <code>i</code> bytes of value <code>i</code>, where <code>i</code> is the
+   * number of bytes to fill the last block of the message to
+   * <code>BLOCK_LENGTH</code> bytes (or <code>BLOCK_LENGTH</code> bytes when
+   * the last block was completely full).
+   *
+   * @return the bytes to pad the remaining bytes in the buffer before
+   * completing a hash operation.
+   */
+  protected byte[] padBuffer()
+  {
+    int length = BLOCK_LENGTH - (int) (count % BLOCK_LENGTH);
+    if (length == 0)
+      length = BLOCK_LENGTH;
+
+    byte[] pad = new byte[length];
+    for (int i = 0; i < length; i++)
+      pad[i] = (byte) length;
+
+    return pad;
+  }
+
+  /**
+   * Adds <code>BLOCK_LENGTH</code> bytes to the running digest.
+   *
+   * @param in the byte array to take the <code>BLOCK_LENGTH</code> bytes from.
+   * @param off the offset to start from in the given byte array.
+   */
+  protected void transform(byte[] in, int off)
+  {
+    updateCheckSumAndEncryptBlock(in, off);
+  }
+
+  /**
+   * Adds a new block (<code>BLOCK_LENGTH</code> bytes) to the running digest
+   * from the given byte array starting from the given offset.
+   */
+  private void encryptBlock(byte[] in, int off)
+  {
+    for (int i = 0; i < BLOCK_LENGTH; i++)
+      {
+        byte b = in[off + i];
+        work[BLOCK_LENGTH + i] = b;
+        work[BLOCK_LENGTH * 2 + i] = (byte)(work[i] ^ b);
+      }
+    byte t = 0;
+    for (int i = 0; i < 18; i++)
+      {
+        for (int j = 0; j < 3 * BLOCK_LENGTH; j++)
+          {
+            t = (byte)(work[j] ^ PI[t & 0xFF]);
+            work[j] = t;
+          }
+        t = (byte)(t + i);
+      }
+  }
+
+  /**
+   * Optimized method that combines a checksum update and encrypt of a block.
+   */
+  private void updateCheckSumAndEncryptBlock(byte[] in, int off)
+  {
+    byte l = checksum[BLOCK_LENGTH - 1];
+    for (int i = 0; i < BLOCK_LENGTH; i++)
+      {
+        byte b = in[off + i];
+        work[BLOCK_LENGTH + i] = b;
+        work[BLOCK_LENGTH * 2 + i] = (byte)(work[i] ^ b);
+        l = (byte)(checksum[i] ^ PI[(b ^ l) & 0xFF]);
+        checksum[i] = l;
+      }
+    byte t = 0;
+    for (int i = 0; i < 18; i++)
+      {
+        for (int j = 0; j < 3 * BLOCK_LENGTH; j++)
+          {
+            t = (byte)(work[j] ^ PI[t & 0xFF]);
+            work[j] = t;
+          }
+        t = (byte)(t + i);
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/MD4.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,337 @@
+/* MD4.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * An implementation of Ron Rivest's MD4 message digest algorithm.
+ * <p>
+ * MD4 was the precursor to the stronger {@link gnu.java.security.hash.MD5}
+ * algorithm, and while not considered cryptograpically secure itself, MD4 is
+ * in use in various applications. It is slightly faster than MD5.
+ * <p>
+ * References:
+ * <ol>
+ *    <li>The <a href="http://www.ietf.org/rfc/rfc1320.txt">MD4</a>
+ *    Message-Digest Algorithm.<br>
+ *    R. Rivest.</li>
+ * </ol>
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class MD4
+    extends BaseHash
+{
+  /** An MD4 message digest is always 128-bits long, or 16 bytes. */
+  private static final int DIGEST_LENGTH = 16;
+
+  /** The MD4 algorithm operates on 512-bit blocks, or 64 bytes. */
+  private static final int BLOCK_LENGTH = 64;
+
+  private static final int A = 0x67452301;
+
+  private static final int B = 0xefcdab89;
+
+  private static final int C = 0x98badcfe;
+
+  private static final int D = 0x10325476;
+
+  /** The output of this message digest when no data has been input. */
+  private static final String DIGEST0 = "31D6CFE0D16AE931B73C59D7E0C089C0";
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  private int a, b, c, d;
+
+  /**
+   * Public constructor. Initializes the chaining variables, sets the byte
+   * count to <code>0</code>, and creates a new block of <code>512</code> bits.
+   */
+  public MD4()
+  {
+    super(Registry.MD4_HASH, DIGEST_LENGTH, BLOCK_LENGTH);
+  }
+
+  /**
+   * Trivial private constructor for cloning purposes.
+   *
+   * @param that the instance to clone.
+   */
+  private MD4(MD4 that)
+  {
+    this();
+
+    this.a = that.a;
+    this.b = that.b;
+    this.c = that.c;
+    this.d = that.d;
+    this.count = that.count;
+    this.buffer = (byte[]) that.buffer.clone();
+  }
+
+  public Object clone()
+  {
+    return new MD4(this);
+  }
+
+  protected byte[] getResult()
+  {
+    return new byte[] {
+        (byte) a, (byte)(a >>> 8), (byte)(a >>> 16), (byte)(a >>> 24),
+        (byte) b, (byte)(b >>> 8), (byte)(b >>> 16), (byte)(b >>> 24),
+        (byte) c, (byte)(c >>> 8), (byte)(c >>> 16), (byte)(c >>> 24),
+        (byte) d, (byte)(d >>> 8), (byte)(d >>> 16), (byte)(d >>> 24) };
+  }
+
+  protected void resetContext()
+  {
+    a = A;
+    b = B;
+    c = C;
+    d = D;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        String d = Util.toString(new MD4().digest());
+        valid = Boolean.valueOf(DIGEST0.equals(d));
+      }
+    return valid.booleanValue();
+  }
+
+  protected byte[] padBuffer()
+  {
+    int n = (int)(count % BLOCK_LENGTH);
+    int padding = (n < 56) ? (56 - n) : (120 - n);
+    byte[] pad = new byte[padding + 8];
+    pad[0] = (byte) 0x80;
+    long bits = count << 3;
+    pad[padding++] = (byte) bits;
+    pad[padding++] = (byte)(bits >>> 8);
+    pad[padding++] = (byte)(bits >>> 16);
+    pad[padding++] = (byte)(bits >>> 24);
+    pad[padding++] = (byte)(bits >>> 32);
+    pad[padding++] = (byte)(bits >>> 40);
+    pad[padding++] = (byte)(bits >>> 48);
+    pad[padding  ] = (byte)(bits >>> 56);
+    return pad;
+  }
+
+  protected void transform(byte[] in, int i)
+  {
+    int X0 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X1 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X2 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X3 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X4 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X5 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X6 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X7 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X8 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X9 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           | in[i++] << 24;
+    int X10 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | in[i++] << 24;
+    int X11 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | in[i++] << 24;
+    int X12 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | in[i++] << 24;
+    int X13 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | in[i++] << 24;
+    int X14 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | in[i++] << 24;
+    int X15 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            | in[i] << 24;
+    int aa, bb, cc, dd;
+    aa = a;
+    bb = b;
+    cc = c;
+    dd = d;
+
+    aa += ((bb & cc) | ((~bb) & dd)) + X0;
+    aa = aa << 3 | aa >>> -3;
+    dd += ((aa & bb) | ((~aa) & cc)) + X1;
+    dd = dd << 7 | dd >>> -7;
+    cc += ((dd & aa) | ((~dd) & bb)) + X2;
+    cc = cc << 11 | cc >>> -11;
+    bb += ((cc & dd) | ((~cc) & aa)) + X3;
+    bb = bb << 19 | bb >>> -19;
+    aa += ((bb & cc) | ((~bb) & dd)) + X4;
+    aa = aa << 3 | aa >>> -3;
+    dd += ((aa & bb) | ((~aa) & cc)) + X5;
+    dd = dd << 7 | dd >>> -7;
+    cc += ((dd & aa) | ((~dd) & bb)) + X6;
+    cc = cc << 11 | cc >>> -11;
+    bb += ((cc & dd) | ((~cc) & aa)) + X7;
+    bb = bb << 19 | bb >>> -19;
+    aa += ((bb & cc) | ((~bb) & dd)) + X8;
+    aa = aa << 3 | aa >>> -3;
+    dd += ((aa & bb) | ((~aa) & cc)) + X9;
+    dd = dd << 7 | dd >>> -7;
+    cc += ((dd & aa) | ((~dd) & bb)) + X10;
+    cc = cc << 11 | cc >>> -11;
+    bb += ((cc & dd) | ((~cc) & aa)) + X11;
+    bb = bb << 19 | bb >>> -19;
+    aa += ((bb & cc) | ((~bb) & dd)) + X12;
+    aa = aa << 3 | aa >>> -3;
+    dd += ((aa & bb) | ((~aa) & cc)) + X13;
+    dd = dd << 7 | dd >>> -7;
+    cc += ((dd & aa) | ((~dd) & bb)) + X14;
+    cc = cc << 11 | cc >>> -11;
+    bb += ((cc & dd) | ((~cc) & aa)) + X15;
+    bb = bb << 19 | bb >>> -19;
+
+    aa += ((bb & (cc | dd)) | (cc & dd)) + X0 + 0x5a827999;
+    aa = aa << 3 | aa >>> -3;
+    dd += ((aa & (bb | cc)) | (bb & cc)) + X4 + 0x5a827999;
+    dd = dd << 5 | dd >>> -5;
+    cc += ((dd & (aa | bb)) | (aa & bb)) + X8 + 0x5a827999;
+    cc = cc << 9 | cc >>> -9;
+    bb += ((cc & (dd | aa)) | (dd & aa)) + X12 + 0x5a827999;
+    bb = bb << 13 | bb >>> -13;
+    aa += ((bb & (cc | dd)) | (cc & dd)) + X1 + 0x5a827999;
+    aa = aa << 3 | aa >>> -3;
+    dd += ((aa & (bb | cc)) | (bb & cc)) + X5 + 0x5a827999;
+    dd = dd << 5 | dd >>> -5;
+    cc += ((dd & (aa | bb)) | (aa & bb)) + X9 + 0x5a827999;
+    cc = cc << 9 | cc >>> -9;
+    bb += ((cc & (dd | aa)) | (dd & aa)) + X13 + 0x5a827999;
+    bb = bb << 13 | bb >>> -13;
+    aa += ((bb & (cc | dd)) | (cc & dd)) + X2 + 0x5a827999;
+    aa = aa << 3 | aa >>> -3;
+    dd += ((aa & (bb | cc)) | (bb & cc)) + X6 + 0x5a827999;
+    dd = dd << 5 | dd >>> -5;
+    cc += ((dd & (aa | bb)) | (aa & bb)) + X10 + 0x5a827999;
+    cc = cc << 9 | cc >>> -9;
+    bb += ((cc & (dd | aa)) | (dd & aa)) + X14 + 0x5a827999;
+    bb = bb << 13 | bb >>> -13;
+    aa += ((bb & (cc | dd)) | (cc & dd)) + X3 + 0x5a827999;
+    aa = aa << 3 | aa >>> -3;
+    dd += ((aa & (bb | cc)) | (bb & cc)) + X7 + 0x5a827999;
+    dd = dd << 5 | dd >>> -5;
+    cc += ((dd & (aa | bb)) | (aa & bb)) + X11 + 0x5a827999;
+    cc = cc << 9 | cc >>> -9;
+    bb += ((cc & (dd | aa)) | (dd & aa)) + X15 + 0x5a827999;
+    bb = bb << 13 | bb >>> -13;
+
+    aa += (bb ^ cc ^ dd) + X0 + 0x6ed9eba1;
+    aa = aa << 3 | aa >>> -3;
+    dd += (aa ^ bb ^ cc) + X8 + 0x6ed9eba1;
+    dd = dd << 9 | dd >>> -9;
+    cc += (dd ^ aa ^ bb) + X4 + 0x6ed9eba1;
+    cc = cc << 11 | cc >>> -11;
+    bb += (cc ^ dd ^ aa) + X12 + 0x6ed9eba1;
+    bb = bb << 15 | bb >>> -15;
+    aa += (bb ^ cc ^ dd) + X2 + 0x6ed9eba1;
+    aa = aa << 3 | aa >>> -3;
+    dd += (aa ^ bb ^ cc) + X10 + 0x6ed9eba1;
+    dd = dd << 9 | dd >>> -9;
+    cc += (dd ^ aa ^ bb) + X6 + 0x6ed9eba1;
+    cc = cc << 11 | cc >>> -11;
+    bb += (cc ^ dd ^ aa) + X14 + 0x6ed9eba1;
+    bb = bb << 15 | bb >>> -15;
+    aa += (bb ^ cc ^ dd) + X1 + 0x6ed9eba1;
+    aa = aa << 3 | aa >>> -3;
+    dd += (aa ^ bb ^ cc) + X9 + 0x6ed9eba1;
+    dd = dd << 9 | dd >>> -9;
+    cc += (dd ^ aa ^ bb) + X5 + 0x6ed9eba1;
+    cc = cc << 11 | cc >>> -11;
+    bb += (cc ^ dd ^ aa) + X13 + 0x6ed9eba1;
+    bb = bb << 15 | bb >>> -15;
+    aa += (bb ^ cc ^ dd) + X3 + 0x6ed9eba1;
+    aa = aa << 3 | aa >>> -3;
+    dd += (aa ^ bb ^ cc) + X11 + 0x6ed9eba1;
+    dd = dd << 9 | dd >>> -9;
+    cc += (dd ^ aa ^ bb) + X7 + 0x6ed9eba1;
+    cc = cc << 11 | cc >>> -11;
+    bb += (cc ^ dd ^ aa) + X15 + 0x6ed9eba1;
+    bb = bb << 15 | bb >>> -15;
+
+    a += aa;
+    b += bb;
+    c += cc;
+    d += dd;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/MD5.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,371 @@
+/* MD5.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * The MD5 message-digest algorithm takes as input a message of arbitrary
+ * length and produces as output a 128-bit "fingerprint" or "message digest" of
+ * the input. It is conjectured that it is computationally infeasible to
+ * produce two messages having the same message digest, or to produce any
+ * message having a given prespecified target message digest.
+ * <p>
+ * References:
+ * <ol>
+ *    <li>The <a href="http://www.ietf.org/rfc/rfc1321.txt">MD5</a> Message-
+ *    Digest Algorithm.<br>
+ *    R. Rivest.</li>
+ * </ol>
+ */
+public class MD5
+    extends BaseHash
+{
+  private static final int BLOCK_SIZE = 64; // inner block size in bytes
+
+  private static final String DIGEST0 = "D41D8CD98F00B204E9800998ECF8427E";
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /** 128-bit interim result. */
+  private int h0, h1, h2, h3;
+
+  /** Trivial 0-arguments constructor. */
+  public MD5()
+  {
+    super(Registry.MD5_HASH, 16, BLOCK_SIZE);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   *
+   * @param md the instance to clone.
+   */
+  private MD5(MD5 md)
+  {
+    this();
+
+    this.h0 = md.h0;
+    this.h1 = md.h1;
+    this.h2 = md.h2;
+    this.h3 = md.h3;
+    this.count = md.count;
+    this.buffer = (byte[]) md.buffer.clone();
+  }
+
+  public Object clone()
+  {
+    return new MD5(this);
+  }
+
+  protected synchronized void transform(byte[] in, int i)
+  {
+    int X0 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X1 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X2 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X3 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X4 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X5 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X6 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X7 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X8 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X9 = (in[i++] & 0xFF)
+           | (in[i++] & 0xFF) << 8
+           | (in[i++] & 0xFF) << 16
+           |  in[i++]         << 24;
+    int X10 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            |  in[i++]         << 24;
+    int X11 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            |  in[i++]         << 24;
+    int X12 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            |  in[i++]         << 24;
+    int X13 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            |  in[i++]         << 24;
+    int X14 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            |  in[i++]         << 24;
+    int X15 = (in[i++] & 0xFF)
+            | (in[i++] & 0xFF) << 8
+            | (in[i++] & 0xFF) << 16
+            |  in[i]           << 24;
+    int A = h0;
+    int B = h1;
+    int C = h2;
+    int D = h3;
+    // hex constants are from md5.c in FSF Gnu Privacy Guard 0.9.2
+    // round 1
+    A += ((B & C) | (~B & D)) + X0 + 0xD76AA478;
+    A = B + (A << 7 | A >>> -7);
+    D += ((A & B) | (~A & C)) + X1 + 0xE8C7B756;
+    D = A + (D << 12 | D >>> -12);
+    C += ((D & A) | (~D & B)) + X2 + 0x242070DB;
+    C = D + (C << 17 | C >>> -17);
+    B += ((C & D) | (~C & A)) + X3 + 0xC1BDCEEE;
+    B = C + (B << 22 | B >>> -22);
+
+    A += ((B & C) | (~B & D)) + X4 + 0xF57C0FAF;
+    A = B + (A << 7 | A >>> -7);
+    D += ((A & B) | (~A & C)) + X5 + 0x4787C62A;
+    D = A + (D << 12 | D >>> -12);
+    C += ((D & A) | (~D & B)) + X6 + 0xA8304613;
+    C = D + (C << 17 | C >>> -17);
+    B += ((C & D) | (~C & A)) + X7 + 0xFD469501;
+    B = C + (B << 22 | B >>> -22);
+
+    A += ((B & C) | (~B & D)) + X8 + 0x698098D8;
+    A = B + (A << 7 | A >>> -7);
+    D += ((A & B) | (~A & C)) + X9 + 0x8B44F7AF;
+    D = A + (D << 12 | D >>> -12);
+    C += ((D & A) | (~D & B)) + X10 + 0xFFFF5BB1;
+    C = D + (C << 17 | C >>> -17);
+    B += ((C & D) | (~C & A)) + X11 + 0x895CD7BE;
+    B = C + (B << 22 | B >>> -22);
+
+    A += ((B & C) | (~B & D)) + X12 + 0x6B901122;
+    A = B + (A << 7 | A >>> -7);
+    D += ((A & B) | (~A & C)) + X13 + 0xFD987193;
+    D = A + (D << 12 | D >>> -12);
+    C += ((D & A) | (~D & B)) + X14 + 0xA679438E;
+    C = D + (C << 17 | C >>> -17);
+    B += ((C & D) | (~C & A)) + X15 + 0x49B40821;
+    B = C + (B << 22 | B >>> -22);
+
+    // round 2
+    A += ((B & D) | (C & ~D)) + X1 + 0xF61E2562;
+    A = B + (A << 5 | A >>> -5);
+    D += ((A & C) | (B & ~C)) + X6 + 0xC040B340;
+    D = A + (D << 9 | D >>> -9);
+    C += ((D & B) | (A & ~B)) + X11 + 0x265E5A51;
+    C = D + (C << 14 | C >>> -14);
+    B += ((C & A) | (D & ~A)) + X0 + 0xE9B6C7AA;
+    B = C + (B << 20 | B >>> -20);
+
+    A += ((B & D) | (C & ~D)) + X5 + 0xD62F105D;
+    A = B + (A << 5 | A >>> -5);
+    D += ((A & C) | (B & ~C)) + X10 + 0x02441453;
+    D = A + (D << 9 | D >>> -9);
+    C += ((D & B) | (A & ~B)) + X15 + 0xD8A1E681;
+    C = D + (C << 14 | C >>> -14);
+    B += ((C & A) | (D & ~A)) + X4 + 0xE7D3FBC8;
+    B = C + (B << 20 | B >>> -20);
+
+    A += ((B & D) | (C & ~D)) + X9 + 0x21E1CDE6;
+    A = B + (A << 5 | A >>> -5);
+    D += ((A & C) | (B & ~C)) + X14 + 0xC33707D6;
+    D = A + (D << 9 | D >>> -9);
+    C += ((D & B) | (A & ~B)) + X3 + 0xF4D50D87;
+    C = D + (C << 14 | C >>> -14);
+    B += ((C & A) | (D & ~A)) + X8 + 0x455A14ED;
+    B = C + (B << 20 | B >>> -20);
+
+    A += ((B & D) | (C & ~D)) + X13 + 0xA9E3E905;
+    A = B + (A << 5 | A >>> -5);
+    D += ((A & C) | (B & ~C)) + X2 + 0xFCEFA3F8;
+    D = A + (D << 9 | D >>> -9);
+    C += ((D & B) | (A & ~B)) + X7 + 0x676F02D9;
+    C = D + (C << 14 | C >>> -14);
+    B += ((C & A) | (D & ~A)) + X12 + 0x8D2A4C8A;
+    B = C + (B << 20 | B >>> -20);
+
+    // round 3
+    A += (B ^ C ^ D) + X5 + 0xFFFA3942;
+    A = B + (A << 4 | A >>> -4);
+    D += (A ^ B ^ C) + X8 + 0x8771F681;
+    D = A + (D << 11 | D >>> -11);
+    C += (D ^ A ^ B) + X11 + 0x6D9D6122;
+    C = D + (C << 16 | C >>> -16);
+    B += (C ^ D ^ A) + X14 + 0xFDE5380C;
+    B = C + (B << 23 | B >>> -23);
+
+    A += (B ^ C ^ D) + X1 + 0xA4BEEA44;
+    A = B + (A << 4 | A >>> -4);
+    D += (A ^ B ^ C) + X4 + 0x4BDECFA9;
+    D = A + (D << 11 | D >>> -11);
+    C += (D ^ A ^ B) + X7 + 0xF6BB4B60;
+    C = D + (C << 16 | C >>> -16);
+    B += (C ^ D ^ A) + X10 + 0xBEBFBC70;
+    B = C + (B << 23 | B >>> -23);
+
+    A += (B ^ C ^ D) + X13 + 0x289B7EC6;
+    A = B + (A << 4 | A >>> -4);
+    D += (A ^ B ^ C) + X0 + 0xEAA127FA;
+    D = A + (D << 11 | D >>> -11);
+    C += (D ^ A ^ B) + X3 + 0xD4EF3085;
+    C = D + (C << 16 | C >>> -16);
+    B += (C ^ D ^ A) + X6 + 0x04881D05;
+    B = C + (B << 23 | B >>> -23);
+
+    A += (B ^ C ^ D) + X9 + 0xD9D4D039;
+    A = B + (A << 4 | A >>> -4);
+    D += (A ^ B ^ C) + X12 + 0xE6DB99E5;
+    D = A + (D << 11 | D >>> -11);
+    C += (D ^ A ^ B) + X15 + 0x1FA27CF8;
+    C = D + (C << 16 | C >>> -16);
+    B += (C ^ D ^ A) + X2 + 0xC4AC5665;
+    B = C + (B << 23 | B >>> -23);
+
+    // round 4
+    A += (C ^ (B | ~D)) + X0 + 0xF4292244;
+    A = B + (A << 6 | A >>> -6);
+    D += (B ^ (A | ~C)) + X7 + 0x432AFF97;
+    D = A + (D << 10 | D >>> -10);
+    C += (A ^ (D | ~B)) + X14 + 0xAB9423A7;
+    C = D + (C << 15 | C >>> -15);
+    B += (D ^ (C | ~A)) + X5 + 0xFC93A039;
+    B = C + (B << 21 | B >>> -21);
+
+    A += (C ^ (B | ~D)) + X12 + 0x655B59C3;
+    A = B + (A << 6 | A >>> -6);
+    D += (B ^ (A | ~C)) + X3 + 0x8F0CCC92;
+    D = A + (D << 10 | D >>> -10);
+    C += (A ^ (D | ~B)) + X10 + 0xFFEFF47D;
+    C = D + (C << 15 | C >>> -15);
+    B += (D ^ (C | ~A)) + X1 + 0x85845dd1;
+    B = C + (B << 21 | B >>> -21);
+
+    A += (C ^ (B | ~D)) + X8 + 0x6FA87E4F;
+    A = B + (A << 6 | A >>> -6);
+    D += (B ^ (A | ~C)) + X15 + 0xFE2CE6E0;
+    D = A + (D << 10 | D >>> -10);
+    C += (A ^ (D | ~B)) + X6 + 0xA3014314;
+    C = D + (C << 15 | C >>> -15);
+    B += (D ^ (C | ~A)) + X13 + 0x4E0811A1;
+    B = C + (B << 21 | B >>> -21);
+
+    A += (C ^ (B | ~D)) + X4 + 0xF7537E82;
+    A = B + (A << 6 | A >>> -6);
+    D += (B ^ (A | ~C)) + X11 + 0xBD3AF235;
+    D = A + (D << 10 | D >>> -10);
+    C += (A ^ (D | ~B)) + X2 + 0x2AD7D2BB;
+    C = D + (C << 15 | C >>> -15);
+    B += (D ^ (C | ~A)) + X9 + 0xEB86D391;
+    B = C + (B << 21 | B >>> -21);
+
+    h0 += A;
+    h1 += B;
+    h2 += C;
+    h3 += D;
+  }
+
+  protected byte[] padBuffer()
+  {
+    int n = (int)(count % BLOCK_SIZE);
+    int padding = (n < 56) ? (56 - n) : (120 - n);
+    byte[] result = new byte[padding + 8];
+    // padding is always binary 1 followed by binary 0s
+    result[0] = (byte) 0x80;
+    // save number of bits, casting the long to an array of 8 bytes
+    long bits = count << 3;
+    result[padding++] = (byte) bits;
+    result[padding++] = (byte)(bits >>> 8);
+    result[padding++] = (byte)(bits >>> 16);
+    result[padding++] = (byte)(bits >>> 24);
+    result[padding++] = (byte)(bits >>> 32);
+    result[padding++] = (byte)(bits >>> 40);
+    result[padding++] = (byte)(bits >>> 48);
+    result[padding  ] = (byte)(bits >>> 56);
+    return result;
+  }
+
+  protected byte[] getResult()
+  {
+    return new byte[] {
+        (byte) h0, (byte)(h0 >>> 8), (byte)(h0 >>> 16), (byte)(h0 >>> 24),
+        (byte) h1, (byte)(h1 >>> 8), (byte)(h1 >>> 16), (byte)(h1 >>> 24),
+        (byte) h2, (byte)(h2 >>> 8), (byte)(h2 >>> 16), (byte)(h2 >>> 24),
+        (byte) h3, (byte)(h3 >>> 8), (byte)(h3 >>> 16), (byte)(h3 >>> 24) };
+  }
+
+  protected void resetContext()
+  {
+    // magic MD5/RIPEMD128 initialisation constants
+    h0 = 0x67452301;
+    h1 = 0xEFCDAB89;
+    h2 = 0x98BADCFE;
+    h3 = 0x10325476;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        String d = Util.toString(new MD5().digest());
+        valid = Boolean.valueOf(DIGEST0.equals(d));
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/RipeMD128.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,257 @@
+/* RipeMD128.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * RIPEMD-128 is a 128-bit message digest.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html">
+ *    RIPEMD160</a>: A Strengthened Version of RIPEMD.<br>
+ *    Hans Dobbertin, Antoon Bosselaers and Bart Preneel.</li>
+ * </ol>
+ */
+public class RipeMD128
+    extends BaseHash
+{
+  private static final int BLOCK_SIZE = 64; // inner block size in bytes
+
+  private static final String DIGEST0 = "CDF26213A150DC3ECB610F18F6B38B46";
+
+  /** Constants for the transform method. */
+  // selection of message word
+  private static final int[] R = {
+       0,  1,  2,  3,  4,  5,  6, 7,  8, 9, 10, 11, 12, 13, 14, 15,
+       7,  4, 13,  1, 10,  6, 15, 3, 12, 0,  9,  5,  2, 14, 11,  8,
+       3, 10, 14,  4,  9, 15,  8, 1,  2, 7,  0,  6, 13, 11,  5, 12,
+       1,  9, 11, 10,  0,  8, 12, 4, 13, 3,  7, 15, 14,  5,  6,  2 };
+
+  private static final int[] Rp = {
+       5, 14, 7, 0, 9,  2, 11,  4, 13,  6, 15,  8, 1, 10,  3, 12,
+       6, 11, 3, 7, 0, 13,  5, 10, 14, 15,  8, 12, 4,  9,  1,  2,
+      15,  5, 1, 3, 7, 14,  6,  9, 11,  8, 12,  2, 10, 0,  4, 13,
+       8,  6, 4, 1, 3, 11, 15,  0,  5, 12,  2, 13,  9, 7, 10, 14 };
+
+  // amount for rotate left (rol)
+  private static final int[] S = {
+      11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
+       7,  6,  8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
+      11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
+      11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12 };
+
+  private static final int[] Sp = {
+       8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
+       9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
+       9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
+      15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8 };
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /** 128-bit h0, h1, h2, h3 (interim result) */
+  private int h0, h1, h2, h3;
+
+  /** 512 bits work buffer = 16 x 32-bit words */
+  private int[] X = new int[16];
+
+  /** Trivial 0-arguments constructor. */
+  public RipeMD128()
+  {
+    super(Registry.RIPEMD128_HASH, 16, BLOCK_SIZE);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   *
+   * @param md the instance to clone.
+   */
+  private RipeMD128(RipeMD128 md)
+  {
+    this();
+
+    this.h0 = md.h0;
+    this.h1 = md.h1;
+    this.h2 = md.h2;
+    this.h3 = md.h3;
+    this.count = md.count;
+    this.buffer = (byte[]) md.buffer.clone();
+  }
+
+  public Object clone()
+  {
+    return new RipeMD128(this);
+  }
+
+  protected void transform(byte[] in, int offset)
+  {
+    int A, B, C, D, Ap, Bp, Cp, Dp, T, s, i;
+    // encode 64 bytes from input block into an array of 16 unsigned integers.
+    for (i = 0; i < 16; i++)
+      X[i] = (in[offset++] & 0xFF)
+           | (in[offset++] & 0xFF) << 8
+           | (in[offset++] & 0xFF) << 16
+           |  in[offset++]         << 24;
+    A = Ap = h0;
+    B = Bp = h1;
+    C = Cp = h2;
+    D = Dp = h3;
+    for (i = 0; i < 16; i++) // rounds 0...15
+      {
+        s = S[i];
+        T = A + (B ^ C ^ D) + X[i];
+        A = D;
+        D = C;
+        C = B;
+        B = T << s | T >>> (32 - s);
+
+        s = Sp[i];
+        T = Ap + ((Bp & Dp) | (Cp & ~Dp)) + X[Rp[i]] + 0x50A28BE6;
+        Ap = Dp;
+        Dp = Cp;
+        Cp = Bp;
+        Bp = T << s | T >>> (32 - s);
+      }
+    for (; i < 32; i++) // rounds 16...31
+      {
+        s = S[i];
+        T = A + ((B & C) | (~B & D)) + X[R[i]] + 0x5A827999;
+        A = D;
+        D = C;
+        C = B;
+        B = T << s | T >>> (32 - s);
+
+        s = Sp[i];
+        T = Ap + ((Bp | ~Cp) ^ Dp) + X[Rp[i]] + 0x5C4DD124;
+        Ap = Dp;
+        Dp = Cp;
+        Cp = Bp;
+        Bp = T << s | T >>> (32 - s);
+      }
+    for (; i < 48; i++) // rounds 32...47
+      {
+        s = S[i];
+        T = A + ((B | ~C) ^ D) + X[R[i]] + 0x6ED9EBA1;
+        A = D;
+        D = C;
+        C = B;
+        B = T << s | T >>> (32 - s);
+
+        s = Sp[i];
+        T = Ap + ((Bp & Cp) | (~Bp & Dp)) + X[Rp[i]] + 0x6D703EF3;
+        Ap = Dp;
+        Dp = Cp;
+        Cp = Bp;
+        Bp = T << s | T >>> (32 - s);
+      }
+    for (; i < 64; i++) // rounds 48...63
+      {
+        s = S[i];
+        T = A + ((B & D) | (C & ~D)) + X[R[i]] + 0x8F1BBCDC;
+        A = D;
+        D = C;
+        C = B;
+        B = T << s | T >>> (32 - s);
+
+        s = Sp[i];
+        T = Ap + (Bp ^ Cp ^ Dp) + X[Rp[i]];
+        Ap = Dp;
+        Dp = Cp;
+        Cp = Bp;
+        Bp = T << s | T >>> (32 - s);
+      }
+    T = h1 + C + Dp;
+    h1 = h2 + D + Ap;
+    h2 = h3 + A + Bp;
+    h3 = h0 + B + Cp;
+    h0 = T;
+  }
+
+  protected byte[] padBuffer()
+  {
+    int n = (int)(count % BLOCK_SIZE);
+    int padding = (n < 56) ? (56 - n) : (120 - n);
+    byte[] result = new byte[padding + 8];
+    // padding is always binary 1 followed by binary 0s
+    result[0] = (byte) 0x80;
+    // save number of bits, casting the long to an array of 8 bytes
+    long bits = count << 3;
+    result[padding++] = (byte) bits;
+    result[padding++] = (byte)(bits >>> 8);
+    result[padding++] = (byte)(bits >>> 16);
+    result[padding++] = (byte)(bits >>> 24);
+    result[padding++] = (byte)(bits >>> 32);
+    result[padding++] = (byte)(bits >>> 40);
+    result[padding++] = (byte)(bits >>> 48);
+    result[padding  ] = (byte)(bits >>> 56);
+    return result;
+  }
+
+  protected byte[] getResult()
+  {
+    return new byte[] {
+        (byte) h0, (byte)(h0 >>> 8), (byte)(h0 >>> 16), (byte)(h0 >>> 24),
+        (byte) h1, (byte)(h1 >>> 8), (byte)(h1 >>> 16), (byte)(h1 >>> 24),
+        (byte) h2, (byte)(h2 >>> 8), (byte)(h2 >>> 16), (byte)(h2 >>> 24),
+        (byte) h3, (byte)(h3 >>> 8), (byte)(h3 >>> 16), (byte)(h3 >>> 24)
+    };
+  }
+
+  protected void resetContext()
+  {
+    // magic RIPEMD128 initialisation constants
+    h0 = 0x67452301;
+    h1 = 0xEFCDAB89;
+    h2 = 0x98BADCFE;
+    h3 = 0x10325476;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        String d = Util.toString(new RipeMD128().digest());
+        valid = Boolean.valueOf(DIGEST0.equals(d));
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/RipeMD160.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,291 @@
+/* RipeMD160.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * RIPEMD-160 is a 160-bit message digest.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html">
+ *    RIPEMD160</a>: A Strengthened Version of RIPEMD.<br>
+ *    Hans Dobbertin, Antoon Bosselaers and Bart Preneel.</li>
+ * </ol>
+ */
+public class RipeMD160
+    extends BaseHash
+{
+  private static final int BLOCK_SIZE = 64; // inner block size in bytes
+
+  private static final String DIGEST0 = "9C1185A5C5E9FC54612808977EE8F548B2258D31";
+
+  // selection of message word
+  private static final int[] R = {
+      0,  1,  2,  3,  4,  5,  6,  7,  8, 9, 10, 11, 12, 13, 14, 15,
+      7,  4, 13,  1, 10,  6, 15,  3, 12, 0,  9,  5,  2, 14, 11,  8,
+      3, 10, 14,  4,  9, 15,  8,  1,  2, 7,  0,  6, 13, 11,  5, 12,
+      1,  9, 11, 10,  0,  8, 12,  4, 13, 3,  7, 15, 14,  5,  6,  2,
+      4,  0,  5,  9,  7, 12,  2, 10, 14, 1,  3,  8, 11,  6, 15, 13 };
+
+  private static final int[] Rp = {
+       5, 14,  7, 0, 9,  2, 11,  4, 13,  6, 15,  8,  1, 10,  3, 12,
+       6, 11,  3, 7, 0, 13,  5, 10, 14, 15,  8, 12,  4,  9,  1,  2,
+      15,  5,  1, 3, 7, 14,  6,  9, 11,  8, 12,  2, 10,  0,  4, 13,
+       8,  6,  4, 1, 3, 11, 15,  0,  5, 12,  2, 13,  9,  7, 10, 14,
+      12, 15, 10, 4, 1,  5,  8,  7,  6,  2, 13, 14,  0,  3,  9, 11 };
+
+  // amount for rotate left (rol)
+  private static final int[] S = {
+      11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
+       7,  6,  8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
+      11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
+      11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
+       9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6 };
+
+  private static final int[] Sp = {
+       8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
+       9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
+       9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
+      15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
+       8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11 };
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /** 160-bit h0, h1, h2, h3, h4 (interim result) */
+  private int h0, h1, h2, h3, h4;
+
+  /** 512 bits work buffer = 16 x 32-bit words */
+  private int[] X = new int[16];
+
+  /** Trivial 0-arguments constructor. */
+  public RipeMD160()
+  {
+    super(Registry.RIPEMD160_HASH, 20, BLOCK_SIZE);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   *
+   * @param md the instance to clone.
+   */
+  private RipeMD160(RipeMD160 md)
+  {
+    this();
+
+    this.h0 = md.h0;
+    this.h1 = md.h1;
+    this.h2 = md.h2;
+    this.h3 = md.h3;
+    this.h4 = md.h4;
+    this.count = md.count;
+    this.buffer = (byte[]) md.buffer.clone();
+  }
+
+  public Object clone()
+  {
+    return (new RipeMD160(this));
+  }
+
+  protected void transform(byte[] in, int offset)
+  {
+    int A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, T, s, i;
+    // encode 64 bytes from input block into an array of 16 unsigned integers
+    for (i = 0; i < 16; i++)
+      X[i] = (in[offset++] & 0xFF)
+           | (in[offset++] & 0xFF) << 8
+           | (in[offset++] & 0xFF) << 16
+           |  in[offset++]         << 24;
+    A = Ap = h0;
+    B = Bp = h1;
+    C = Cp = h2;
+    D = Dp = h3;
+    E = Ep = h4;
+    for (i = 0; i < 16; i++) // rounds 0...15
+      {
+        s = S[i];
+        T = A + (B ^ C ^ D) + X[i];
+        A = E;
+        E = D;
+        D = C << 10 | C >>> 22;
+        C = B;
+        B = (T << s | T >>> (32 - s)) + A;
+
+        s = Sp[i];
+        T = Ap + (Bp ^ (Cp | ~Dp)) + X[Rp[i]] + 0x50A28BE6;
+        Ap = Ep;
+        Ep = Dp;
+        Dp = Cp << 10 | Cp >>> 22;
+        Cp = Bp;
+        Bp = (T << s | T >>> (32 - s)) + Ap;
+      }
+    for (; i < 32; i++) // rounds 16...31
+      {
+        s = S[i];
+        T = A + ((B & C) | (~B & D)) + X[R[i]] + 0x5A827999;
+        A = E;
+        E = D;
+        D = C << 10 | C >>> 22;
+        C = B;
+        B = (T << s | T >>> (32 - s)) + A;
+
+        s = Sp[i];
+        T = Ap + ((Bp & Dp) | (Cp & ~Dp)) + X[Rp[i]] + 0x5C4DD124;
+        Ap = Ep;
+        Ep = Dp;
+        Dp = Cp << 10 | Cp >>> 22;
+        Cp = Bp;
+        Bp = (T << s | T >>> (32 - s)) + Ap;
+      }
+    for (; i < 48; i++) // rounds 32...47
+      {
+        s = S[i];
+        T = A + ((B | ~C) ^ D) + X[R[i]] + 0x6ED9EBA1;
+        A = E;
+        E = D;
+        D = C << 10 | C >>> 22;
+        C = B;
+        B = (T << s | T >>> (32 - s)) + A;
+
+        s = Sp[i];
+        T = Ap + ((Bp | ~Cp) ^ Dp) + X[Rp[i]] + 0x6D703EF3;
+        Ap = Ep;
+        Ep = Dp;
+        Dp = Cp << 10 | Cp >>> 22;
+        Cp = Bp;
+        Bp = (T << s | T >>> (32 - s)) + Ap;
+      }
+    for (; i < 64; i++) // rounds 48...63
+      {
+        s = S[i];
+        T = A + ((B & D) | (C & ~D)) + X[R[i]] + 0x8F1BBCDC;
+        A = E;
+        E = D;
+        D = C << 10 | C >>> 22;
+        C = B;
+        B = (T << s | T >>> (32 - s)) + A;
+
+        s = Sp[i];
+        T = Ap + ((Bp & Cp) | (~Bp & Dp)) + X[Rp[i]] + 0x7A6D76E9;
+        Ap = Ep;
+        Ep = Dp;
+        Dp = Cp << 10 | Cp >>> 22;
+        Cp = Bp;
+        Bp = (T << s | T >>> (32 - s)) + Ap;
+      }
+    for (; i < 80; i++) // rounds 64...79
+      {
+        s = S[i];
+        T = A + (B ^ (C | ~D)) + X[R[i]] + 0xA953FD4E;
+        A = E;
+        E = D;
+        D = C << 10 | C >>> 22;
+        C = B;
+        B = (T << s | T >>> (32 - s)) + A;
+
+        s = Sp[i];
+        T = Ap + (Bp ^ Cp ^ Dp) + X[Rp[i]];
+        Ap = Ep;
+        Ep = Dp;
+        Dp = Cp << 10 | Cp >>> 22;
+        Cp = Bp;
+        Bp = (T << s | T >>> (32 - s)) + Ap;
+      }
+    T = h1 + C + Dp;
+    h1 = h2 + D + Ep;
+    h2 = h3 + E + Ap;
+    h3 = h4 + A + Bp;
+    h4 = h0 + B + Cp;
+    h0 = T;
+  }
+
+  protected byte[] padBuffer()
+  {
+    int n = (int)(count % BLOCK_SIZE);
+    int padding = (n < 56) ? (56 - n) : (120 - n);
+    byte[] result = new byte[padding + 8];
+    // padding is always binary 1 followed by binary 0s
+    result[0] = (byte) 0x80;
+    // save number of bits, casting the long to an array of 8 bytes
+    long bits = count << 3;
+    result[padding++] = (byte) bits;
+    result[padding++] = (byte)(bits >>> 8);
+    result[padding++] = (byte)(bits >>> 16);
+    result[padding++] = (byte)(bits >>> 24);
+    result[padding++] = (byte)(bits >>> 32);
+    result[padding++] = (byte)(bits >>> 40);
+    result[padding++] = (byte)(bits >>> 48);
+    result[padding  ] = (byte)(bits >>> 56);
+    return result;
+  }
+
+  protected byte[] getResult()
+  {
+    return new byte[] {
+        (byte) h0, (byte)(h0 >>> 8), (byte)(h0 >>> 16), (byte)(h0 >>> 24),
+        (byte) h1, (byte)(h1 >>> 8), (byte)(h1 >>> 16), (byte)(h1 >>> 24),
+        (byte) h2, (byte)(h2 >>> 8), (byte)(h2 >>> 16), (byte)(h2 >>> 24),
+        (byte) h3, (byte)(h3 >>> 8), (byte)(h3 >>> 16), (byte)(h3 >>> 24),
+        (byte) h4, (byte)(h4 >>> 8), (byte)(h4 >>> 16), (byte)(h4 >>> 24)
+    };
+  }
+
+  protected void resetContext()
+  {
+    // magic RIPEMD160 initialisation constants
+    h0 = 0x67452301;
+    h1 = 0xEFCDAB89;
+    h2 = 0x98BADCFE;
+    h3 = 0x10325476;
+    h4 = 0xC3D2E1F0;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        String d = Util.toString(new RipeMD160().digest());
+        valid = Boolean.valueOf(DIGEST0.equals(d));
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/Sha160.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,241 @@
+/* Sha160.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * The Secure Hash Algorithm (SHA-1) is required for use with the Digital
+ * Signature Algorithm (DSA) as specified in the Digital Signature Standard
+ * (DSS) and whenever a secure hash algorithm is required for federal
+ * applications. For a message of length less than 2^64 bits, the SHA-1
+ * produces a 160-bit condensed representation of the message called a message
+ * digest. The message digest is used during generation of a signature for the
+ * message. The SHA-1 is also used to compute a message digest for the received
+ * version of the message during the process of verifying the signature. Any
+ * change to the message in transit will, with very high probability, result in
+ * a different message digest, and the signature will fail to verify.
+ * <p>
+ * The SHA-1 is designed to have the following properties: it is
+ * computationally infeasible to find a message which corresponds to a given
+ * message digest, or to find two different messages which produce the same
+ * message digest.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://www.itl.nist.gov/fipspubs/fip180-1.htm">SECURE HASH
+ *    STANDARD</a><br>
+ *    Federal Information, Processing Standards Publication 180-1, 1995 April 17.
+ *    </li>
+ * </ol>
+ */
+public class Sha160
+    extends BaseHash
+{
+  private static final int BLOCK_SIZE = 64; // inner block size in bytes
+
+  private static final String DIGEST0 = "A9993E364706816ABA3E25717850C26C9CD0D89D";
+
+  private static final int[] w = new int[80];
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /** 160-bit interim result. */
+  private int h0, h1, h2, h3, h4;
+
+  /** Trivial 0-arguments constructor. */
+  public Sha160()
+  {
+    super(Registry.SHA160_HASH, 20, BLOCK_SIZE);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   *
+   * @param md the instance to clone.
+   */
+  private Sha160(Sha160 md)
+  {
+    this();
+
+    this.h0 = md.h0;
+    this.h1 = md.h1;
+    this.h2 = md.h2;
+    this.h3 = md.h3;
+    this.h4 = md.h4;
+    this.count = md.count;
+    this.buffer = (byte[]) md.buffer.clone();
+  }
+
+  public static final int[] G(int hh0, int hh1, int hh2, int hh3, int hh4,
+                              byte[] in, int offset)
+  {
+    return sha(hh0, hh1, hh2, hh3, hh4, in, offset);
+  }
+
+  public Object clone()
+  {
+    return new Sha160(this);
+  }
+
+  protected void transform(byte[] in, int offset)
+  {
+    int[] result = sha(h0, h1, h2, h3, h4, in, offset);
+    h0 = result[0];
+    h1 = result[1];
+    h2 = result[2];
+    h3 = result[3];
+    h4 = result[4];
+  }
+
+  protected byte[] padBuffer()
+  {
+    int n = (int)(count % BLOCK_SIZE);
+    int padding = (n < 56) ? (56 - n) : (120 - n);
+    byte[] result = new byte[padding + 8];
+    // padding is always binary 1 followed by binary 0s
+    result[0] = (byte) 0x80;
+    // save number of bits, casting the long to an array of 8 bytes
+    long bits = count << 3;
+    result[padding++] = (byte)(bits >>> 56);
+    result[padding++] = (byte)(bits >>> 48);
+    result[padding++] = (byte)(bits >>> 40);
+    result[padding++] = (byte)(bits >>> 32);
+    result[padding++] = (byte)(bits >>> 24);
+    result[padding++] = (byte)(bits >>> 16);
+    result[padding++] = (byte)(bits >>> 8);
+    result[padding  ] = (byte) bits;
+    return result;
+  }
+
+  protected byte[] getResult()
+  {
+    return new byte[] {
+        (byte)(h0 >>> 24), (byte)(h0 >>> 16), (byte)(h0 >>> 8), (byte) h0,
+        (byte)(h1 >>> 24), (byte)(h1 >>> 16), (byte)(h1 >>> 8), (byte) h1,
+        (byte)(h2 >>> 24), (byte)(h2 >>> 16), (byte)(h2 >>> 8), (byte) h2,
+        (byte)(h3 >>> 24), (byte)(h3 >>> 16), (byte)(h3 >>> 8), (byte) h3,
+        (byte)(h4 >>> 24), (byte)(h4 >>> 16), (byte)(h4 >>> 8), (byte) h4 };
+  }
+
+  protected void resetContext()
+  {
+    // magic SHA-1/RIPEMD160 initialisation constants
+    h0 = 0x67452301;
+    h1 = 0xEFCDAB89;
+    h2 = 0x98BADCFE;
+    h3 = 0x10325476;
+    h4 = 0xC3D2E1F0;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        Sha160 md = new Sha160();
+        md.update((byte) 0x61); // a
+        md.update((byte) 0x62); // b
+        md.update((byte) 0x63); // c
+        String result = Util.toString(md.digest());
+        valid = Boolean.valueOf(DIGEST0.equals(result));
+      }
+    return valid.booleanValue();
+  }
+
+  private static synchronized final int[] sha(int hh0, int hh1, int hh2,
+                                              int hh3, int hh4, byte[] in,
+                                              int offset)
+  {
+    int A = hh0;
+    int B = hh1;
+    int C = hh2;
+    int D = hh3;
+    int E = hh4;
+    int r, T;
+    for (r = 0; r < 16; r++)
+      w[r] =  in[offset++]         << 24
+           | (in[offset++] & 0xFF) << 16
+           | (in[offset++] & 0xFF) << 8
+           | (in[offset++] & 0xFF);
+    for (r = 16; r < 80; r++)
+      {
+        T = w[r - 3] ^ w[r - 8] ^ w[r - 14] ^ w[r - 16];
+        w[r] = T << 1 | T >>> 31;
+      }
+    for (r = 0; r < 20; r++) // rounds 0-19
+      {
+        T = (A << 5 | A >>> 27) + ((B & C) | (~B & D)) + E + w[r] + 0x5A827999;
+        E = D;
+        D = C;
+        C = B << 30 | B >>> 2;
+        B = A;
+        A = T;
+      }
+    for (r = 20; r < 40; r++) // rounds 20-39
+      {
+        T = (A << 5 | A >>> 27) + (B ^ C ^ D) + E + w[r] + 0x6ED9EBA1;
+        E = D;
+        D = C;
+        C = B << 30 | B >>> 2;
+        B = A;
+        A = T;
+      }
+    for (r = 40; r < 60; r++) // rounds 40-59
+      {
+        T = (A << 5 | A >>> 27) + (B & C | B & D | C & D) + E + w[r] + 0x8F1BBCDC;
+        E = D;
+        D = C;
+        C = B << 30 | B >>> 2;
+        B = A;
+        A = T;
+      }
+    for (r = 60; r < 80; r++) // rounds 60-79
+      {
+        T = (A << 5 | A >>> 27) + (B ^ C ^ D) + E + w[r] + 0xCA62C1D6;
+        E = D;
+        D = C;
+        C = B << 30 | B >>> 2;
+        B = A;
+        A = T;
+      }
+    return new int[] { hh0 + A, hh1 + B, hh2 + C, hh3 + D, hh4 + E };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/Sha256.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,252 @@
+/* Sha256.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * Implementation of SHA2-1 [SHA-256] per the IETF Draft Specification.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://ftp.ipv4.heanet.ie/pub/ietf/internet-drafts/draft-ietf-ipsec-ciph-aes-cbc-03.txt">
+ *    Descriptions of SHA-256, SHA-384, and SHA-512</a>,</li>
+ *    <li>http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf</li>
+ * </ol>
+ */
+public class Sha256
+    extends BaseHash
+{
+  private static final int[] k = {
+      0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+      0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+      0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+      0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+      0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+      0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+      0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+      0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+      0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+      0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+      0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+      0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+      0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+      0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+      0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+      0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+  };
+
+  private static final int BLOCK_SIZE = 64; // inner block size in bytes
+
+  private static final String DIGEST0 =
+      "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD";
+
+  private static final int[] w = new int[64];
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /** 256-bit interim result. */
+  private int h0, h1, h2, h3, h4, h5, h6, h7;
+
+  /** Trivial 0-arguments constructor. */
+  public Sha256()
+  {
+    super(Registry.SHA256_HASH, 32, BLOCK_SIZE);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   *
+   * @param md the instance to clone.
+   */
+  private Sha256(Sha256 md)
+  {
+    this();
+
+    this.h0 = md.h0;
+    this.h1 = md.h1;
+    this.h2 = md.h2;
+    this.h3 = md.h3;
+    this.h4 = md.h4;
+    this.h5 = md.h5;
+    this.h6 = md.h6;
+    this.h7 = md.h7;
+    this.count = md.count;
+    this.buffer = (byte[]) md.buffer.clone();
+  }
+
+  public static final int[] G(int hh0, int hh1, int hh2, int hh3, int hh4,
+                              int hh5, int hh6, int hh7, byte[] in, int offset)
+  {
+    return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset);
+  }
+
+  public Object clone()
+  {
+    return new Sha256(this);
+  }
+
+  protected void transform(byte[] in, int offset)
+  {
+    int[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset);
+    h0 = result[0];
+    h1 = result[1];
+    h2 = result[2];
+    h3 = result[3];
+    h4 = result[4];
+    h5 = result[5];
+    h6 = result[6];
+    h7 = result[7];
+  }
+
+  protected byte[] padBuffer()
+  {
+    int n = (int)(count % BLOCK_SIZE);
+    int padding = (n < 56) ? (56 - n) : (120 - n);
+    byte[] result = new byte[padding + 8];
+    // padding is always binary 1 followed by binary 0s
+    result[0] = (byte) 0x80;
+    // save number of bits, casting the long to an array of 8 bytes
+    long bits = count << 3;
+    result[padding++] = (byte)(bits >>> 56);
+    result[padding++] = (byte)(bits >>> 48);
+    result[padding++] = (byte)(bits >>> 40);
+    result[padding++] = (byte)(bits >>> 32);
+    result[padding++] = (byte)(bits >>> 24);
+    result[padding++] = (byte)(bits >>> 16);
+    result[padding++] = (byte)(bits >>> 8);
+    result[padding  ] = (byte) bits;
+    return result;
+  }
+
+  protected byte[] getResult()
+  {
+    return new byte[] {
+        (byte)(h0 >>> 24), (byte)(h0 >>> 16), (byte)(h0 >>> 8), (byte) h0,
+        (byte)(h1 >>> 24), (byte)(h1 >>> 16), (byte)(h1 >>> 8), (byte) h1,
+        (byte)(h2 >>> 24), (byte)(h2 >>> 16), (byte)(h2 >>> 8), (byte) h2,
+        (byte)(h3 >>> 24), (byte)(h3 >>> 16), (byte)(h3 >>> 8), (byte) h3,
+        (byte)(h4 >>> 24), (byte)(h4 >>> 16), (byte)(h4 >>> 8), (byte) h4,
+        (byte)(h5 >>> 24), (byte)(h5 >>> 16), (byte)(h5 >>> 8), (byte) h5,
+        (byte)(h6 >>> 24), (byte)(h6 >>> 16), (byte)(h6 >>> 8), (byte) h6,
+        (byte)(h7 >>> 24), (byte)(h7 >>> 16), (byte)(h7 >>> 8), (byte) h7 };
+  }
+
+  protected void resetContext()
+  {
+    // magic SHA-256 initialisation constants
+    h0 = 0x6a09e667;
+    h1 = 0xbb67ae85;
+    h2 = 0x3c6ef372;
+    h3 = 0xa54ff53a;
+    h4 = 0x510e527f;
+    h5 = 0x9b05688c;
+    h6 = 0x1f83d9ab;
+    h7 = 0x5be0cd19;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        Sha256 md = new Sha256();
+        md.update((byte) 0x61); // a
+        md.update((byte) 0x62); // b
+        md.update((byte) 0x63); // c
+        String result = Util.toString(md.digest());
+        valid = Boolean.valueOf(DIGEST0.equals(result));
+      }
+    return valid.booleanValue();
+  }
+
+  private static synchronized final int[] sha(int hh0, int hh1, int hh2,
+                                              int hh3, int hh4, int hh5,
+                                              int hh6, int hh7, byte[] in,
+                                              int offset)
+  {
+    int A = hh0;
+    int B = hh1;
+    int C = hh2;
+    int D = hh3;
+    int E = hh4;
+    int F = hh5;
+    int G = hh6;
+    int H = hh7;
+    int r, T, T2;
+    for (r = 0; r < 16; r++)
+      w[r] = (in[offset++]         << 24
+           | (in[offset++] & 0xFF) << 16
+           | (in[offset++] & 0xFF) << 8
+           | (in[offset++] & 0xFF));
+    for (r = 16; r < 64; r++)
+      {
+        T =  w[r -  2];
+        T2 = w[r - 15];
+        w[r] = ((((T >>> 17) | (T << 15)) ^ ((T >>> 19) | (T << 13)) ^ (T >>> 10))
+                + w[r - 7]
+                + (((T2 >>> 7) | (T2 << 25))
+                    ^ ((T2 >>> 18) | (T2 << 14))
+                    ^ (T2 >>> 3)) + w[r - 16]);
+      }
+    for (r = 0; r < 64; r++)
+      {
+        T = (H
+             + (((E >>> 6) | (E << 26))
+                 ^ ((E >>> 11) | (E << 21))
+                 ^ ((E >>> 25) | (E << 7)))
+             + ((E & F) ^ (~E & G)) + k[r] + w[r]);
+        T2 = ((((A >>> 2) | (A << 30))
+               ^ ((A >>> 13) | (A << 19))
+               ^ ((A >>> 22) | (A << 10))) + ((A & B) ^ (A & C) ^ (B & C)));
+        H = G;
+        G = F;
+        F = E;
+        E = D + T;
+        D = C;
+        C = B;
+        B = A;
+        A = T + T2;
+      }
+    return new int[] {
+        hh0 + A, hh1 + B, hh2 + C, hh3 + D,
+        hh4 + E, hh5 + F, hh6 + G, hh7 + H };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/Sha384.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,279 @@
+/* Sha384.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * Implementation of SHA2-2 [SHA-384] per the IETF Draft Specification.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://ftp.ipv4.heanet.ie/pub/ietf/internet-drafts/draft-ietf-ipsec-ciph-aes-cbc-03.txt">
+ *    Descriptions of SHA-256, SHA-384, and SHA-512</a>,</li>
+ *    <li>http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf</li>
+ * </ol>
+ */
+public class Sha384
+    extends BaseHash
+{
+  private static final long[] k = {
+      0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL,
+      0xe9b5dba58189dbbcL, 0x3956c25bf348b538L, 0x59f111f1b605d019L,
+      0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L, 0xd807aa98a3030242L,
+      0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
+      0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L,
+      0xc19bf174cf692694L, 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L,
+      0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L, 0x2de92c6f592b0275L,
+      0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
+      0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL,
+      0xbf597fc7beef0ee4L, 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L,
+      0x06ca6351e003826fL, 0x142929670a0e6e70L, 0x27b70a8546d22ffcL,
+      0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
+      0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L,
+      0x92722c851482353bL, 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L,
+      0xc24b8b70d0f89791L, 0xc76c51a30654be30L, 0xd192e819d6ef5218L,
+      0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
+      0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L,
+      0x34b0bcb5e19b48a8L, 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL,
+      0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L, 0x748f82ee5defb2fcL,
+      0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
+      0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L,
+      0xc67178f2e372532bL, 0xca273eceea26619cL, 0xd186b8c721c0c207L,
+      0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L, 0x06f067aa72176fbaL,
+      0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
+      0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL,
+      0x431d67c49c100d4cL, 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL,
+      0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L };
+
+  private static final int BLOCK_SIZE = 128; // inner block size in bytes
+
+  private static final String DIGEST0 =
+      "CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED"
+    + "8086072BA1E7CC2358BAECA134C825A7";
+
+  private static final long[] w = new long[80];
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /** 512-bit interim result. */
+  private long h0, h1, h2, h3, h4, h5, h6, h7;
+
+  /** Trivial 0-arguments constructor. */
+  public Sha384()
+  {
+    super(Registry.SHA384_HASH, 48, BLOCK_SIZE);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   *
+   * @param md the instance to clone.
+   */
+  private Sha384(Sha384 md)
+  {
+    this();
+
+    this.h0 = md.h0;
+    this.h1 = md.h1;
+    this.h2 = md.h2;
+    this.h3 = md.h3;
+    this.h4 = md.h4;
+    this.h5 = md.h5;
+    this.h6 = md.h6;
+    this.h7 = md.h7;
+    this.count = md.count;
+    this.buffer = (byte[]) md.buffer.clone();
+  }
+
+  public static final long[] G(long hh0, long hh1, long hh2, long hh3,
+                               long hh4, long hh5, long hh6, long hh7,
+                               byte[] in, int offset)
+  {
+    return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset);
+  }
+
+  public Object clone()
+  {
+    return new Sha384(this);
+  }
+
+  protected void transform(byte[] in, int offset)
+  {
+    long[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset);
+    h0 = result[0];
+    h1 = result[1];
+    h2 = result[2];
+    h3 = result[3];
+    h4 = result[4];
+    h5 = result[5];
+    h6 = result[6];
+    h7 = result[7];
+  }
+
+  protected byte[] padBuffer()
+  {
+    int n = (int)(count % BLOCK_SIZE);
+    int padding = (n < 112) ? (112 - n) : (240 - n);
+    byte[] result = new byte[padding + 16];
+    // padding is always binary 1 followed by binary 0s
+    result[0] = (byte) 0x80;
+    // save number of bits, casting the long to an array of 8 bytes
+    // TODO: FIX Only ~35 bits of 128 bit counter usable this way
+    long bits = count << 3;
+    padding += 8;
+    result[padding++] = (byte)(bits >>> 56);
+    result[padding++] = (byte)(bits >>> 48);
+    result[padding++] = (byte)(bits >>> 40);
+    result[padding++] = (byte)(bits >>> 32);
+    result[padding++] = (byte)(bits >>> 24);
+    result[padding++] = (byte)(bits >>> 16);
+    result[padding++] = (byte)(bits >>> 8);
+    result[padding  ] = (byte) bits;
+    return result;
+  }
+
+  protected byte[] getResult()
+  {
+    return new byte[] {
+        (byte)(h0 >>> 56), (byte)(h0 >>> 48), (byte)(h0 >>> 40), (byte)(h0 >>> 32),
+        (byte)(h0 >>> 24), (byte)(h0 >>> 16), (byte)(h0 >>>  8), (byte) h0,
+        (byte)(h1 >>> 56), (byte)(h1 >>> 48), (byte)(h1 >>> 40), (byte)(h1 >>> 32),
+        (byte)(h1 >>> 24), (byte)(h1 >>> 16), (byte)(h1 >>>  8), (byte) h1,
+        (byte)(h2 >>> 56), (byte)(h2 >>> 48), (byte)(h2 >>> 40), (byte)(h2 >>> 32),
+        (byte)(h2 >>> 24), (byte)(h2 >>> 16), (byte)(h2 >>>  8), (byte) h2,
+        (byte)(h3 >>> 56), (byte)(h3 >>> 48), (byte)(h3 >>> 40), (byte)(h3 >>> 32),
+        (byte)(h3 >>> 24), (byte)(h3 >>> 16), (byte)(h3 >>>  8), (byte) h3,
+        (byte)(h4 >>> 56), (byte)(h4 >>> 48), (byte)(h4 >>> 40), (byte)(h4 >>> 32),
+        (byte)(h4 >>> 24), (byte)(h4 >>> 16), (byte)(h4 >>>  8), (byte) h4,
+        (byte)(h5 >>> 56), (byte)(h5 >>> 48), (byte)(h5 >>> 40), (byte)(h5 >>> 32),
+        (byte)(h5 >>> 24), (byte)(h5 >>> 16), (byte)(h5 >>>  8), (byte) h5 };
+  }
+
+  protected void resetContext()
+  {
+    // magic SHA-384 initialisation constants
+    h0 = 0xcbbb9d5dc1059ed8L;
+    h1 = 0x629a292a367cd507L;
+    h2 = 0x9159015a3070dd17L;
+    h3 = 0x152fecd8f70e5939L;
+    h4 = 0x67332667ffc00b31L;
+    h5 = 0x8eb44a8768581511L;
+    h6 = 0xdb0c2e0d64f98fa7L;
+    h7 = 0x47b5481dbefa4fa4L;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        Sha384 md = new Sha384();
+        md.update((byte) 0x61); // a
+        md.update((byte) 0x62); // b
+        md.update((byte) 0x63); // c
+        String result = Util.toString(md.digest());
+        valid = Boolean.valueOf(DIGEST0.equals(result));
+      }
+    return valid.booleanValue();
+  }
+
+  private static synchronized final long[] sha(long hh0, long hh1, long hh2,
+                                               long hh3, long hh4, long hh5,
+                                               long hh6, long hh7, byte[] in,
+                                               int offset)
+  {
+    long A = hh0;
+    long B = hh1;
+    long C = hh2;
+    long D = hh3;
+    long E = hh4;
+    long F = hh5;
+    long G = hh6;
+    long H = hh7;
+    long T, T2;
+    int r;
+    for (r = 0; r < 16; r++)
+      w[r] =  (long) in[offset++]         << 56
+           | ((long) in[offset++] & 0xFF) << 48
+           | ((long) in[offset++] & 0xFF) << 40
+           | ((long) in[offset++] & 0xFF) << 32
+           | ((long) in[offset++] & 0xFF) << 24
+           | ((long) in[offset++] & 0xFF) << 16
+           | ((long) in[offset++] & 0xFF) << 8
+           | ((long) in[offset++] & 0xFF);
+    for (r = 16; r < 80; r++)
+      {
+        T = w[r - 2];
+        T2 = w[r - 15];
+        w[r] = (((T >>> 19) | (T << 45)) ^ ((T >>> 61) | (T << 3)) ^ (T >>> 6))
+               + w[r - 7]
+               + (((T2 >>> 1) | (T2 << 63))
+                   ^ ((T2 >>> 8) | (T2 << 56))
+                   ^ (T2 >>> 7))
+               + w[r - 16];
+      }
+    for (r = 0; r < 80; r++)
+      {
+
+        T = H
+            + (((E >>> 14) | (E << 50))
+                ^ ((E >>> 18) | (E << 46))
+                ^ ((E >>> 41) | (E << 23)))
+            + ((E & F) ^ ((~E) & G)) + k[r] + w[r];
+        // T IS INCORRECT SOMEHOW
+        T2 = (((A >>> 28) | (A << 36))
+               ^ ((A >>> 34) | (A << 30))
+               ^ ((A >>> 39) | (A << 25)))
+             + ((A & B) ^ (A & C) ^ (B & C));
+        H = G;
+        G = F;
+        F = E;
+        E = D + T;
+        D = C;
+        C = B;
+        B = A;
+        A = T + T2;
+      }
+    return new long[] {
+        hh0 + A, hh1 + B, hh2 + C, hh3 + D,
+        hh4 + E, hh5 + F, hh6 + G, hh7 + H };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/Sha512.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,281 @@
+/* Sha512.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * Implementation of SHA2-3 [SHA-512] per the IETF Draft Specification.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://ftp.ipv4.heanet.ie/pub/ietf/internet-drafts/draft-ietf-ipsec-ciph-aes-cbc-03.txt">
+ *    Descriptions of SHA-256, SHA-384, and SHA-512</a>,</li>
+ *    <li>http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf</li>
+ * </ol>
+ */
+public class Sha512
+    extends BaseHash
+{
+  private static final long[] k = {
+      0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL,
+      0xe9b5dba58189dbbcL, 0x3956c25bf348b538L, 0x59f111f1b605d019L,
+      0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L, 0xd807aa98a3030242L,
+      0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
+      0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L,
+      0xc19bf174cf692694L, 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L,
+      0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L, 0x2de92c6f592b0275L,
+      0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
+      0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL,
+      0xbf597fc7beef0ee4L, 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L,
+      0x06ca6351e003826fL, 0x142929670a0e6e70L, 0x27b70a8546d22ffcL,
+      0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
+      0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L,
+      0x92722c851482353bL, 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L,
+      0xc24b8b70d0f89791L, 0xc76c51a30654be30L, 0xd192e819d6ef5218L,
+      0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
+      0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L,
+      0x34b0bcb5e19b48a8L, 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL,
+      0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L, 0x748f82ee5defb2fcL,
+      0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
+      0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L,
+      0xc67178f2e372532bL, 0xca273eceea26619cL, 0xd186b8c721c0c207L,
+      0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L, 0x06f067aa72176fbaL,
+      0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
+      0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL,
+      0x431d67c49c100d4cL, 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL,
+      0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L };
+
+  private static final int BLOCK_SIZE = 128; // inner block size in bytes
+
+  private static final String DIGEST0 =
+      "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A"
+    + "2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F";
+
+  private static final long[] w = new long[80];
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /** 512-bit interim result. */
+  private long h0, h1, h2, h3, h4, h5, h6, h7;
+
+  /** Trivial 0-arguments constructor. */
+  public Sha512()
+  {
+    super(Registry.SHA512_HASH, 64, BLOCK_SIZE);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   *
+   * @param md the instance to clone.
+   */
+  private Sha512(Sha512 md)
+  {
+    this();
+
+    this.h0 = md.h0;
+    this.h1 = md.h1;
+    this.h2 = md.h2;
+    this.h3 = md.h3;
+    this.h4 = md.h4;
+    this.h5 = md.h5;
+    this.h6 = md.h6;
+    this.h7 = md.h7;
+    this.count = md.count;
+    this.buffer = (byte[]) md.buffer.clone();
+  }
+
+  public static final long[] G(long hh0, long hh1, long hh2, long hh3,
+                               long hh4, long hh5, long hh6, long hh7,
+                               byte[] in, int offset)
+  {
+    return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset);
+  }
+
+  public Object clone()
+  {
+    return new Sha512(this);
+  }
+
+  protected void transform(byte[] in, int offset)
+  {
+    long[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset);
+    h0 = result[0];
+    h1 = result[1];
+    h2 = result[2];
+    h3 = result[3];
+    h4 = result[4];
+    h5 = result[5];
+    h6 = result[6];
+    h7 = result[7];
+  }
+
+  protected byte[] padBuffer()
+  {
+    int n = (int)(count % BLOCK_SIZE);
+    int padding = (n < 112) ? (112 - n) : (240 - n);
+    byte[] result = new byte[padding + 16];
+    // padding is always binary 1 followed by binary 0s
+    result[0] = (byte) 0x80;
+    // save number of bits, casting the long to an array of 8 bytes
+    // TODO: FIX Only ~35 bits of 128 bit counter usable this way
+    long bits = count << 3;
+    padding += 8;
+    result[padding++] = (byte)(bits >>> 56);
+    result[padding++] = (byte)(bits >>> 48);
+    result[padding++] = (byte)(bits >>> 40);
+    result[padding++] = (byte)(bits >>> 32);
+    result[padding++] = (byte)(bits >>> 24);
+    result[padding++] = (byte)(bits >>> 16);
+    result[padding++] = (byte)(bits >>> 8);
+    result[padding  ] = (byte) bits;
+    return result;
+  }
+
+  protected byte[] getResult()
+  {
+    return new byte[] {
+        (byte)(h0 >>> 56), (byte)(h0 >>> 48), (byte)(h0 >>> 40), (byte)(h0 >>> 32),
+        (byte)(h0 >>> 24), (byte)(h0 >>> 16), (byte)(h0 >>>  8), (byte) h0,
+        (byte)(h1 >>> 56), (byte)(h1 >>> 48), (byte)(h1 >>> 40), (byte)(h1 >>> 32),
+        (byte)(h1 >>> 24), (byte)(h1 >>> 16), (byte)(h1 >>>  8), (byte) h1,
+        (byte)(h2 >>> 56), (byte)(h2 >>> 48), (byte)(h2 >>> 40), (byte)(h2 >>> 32),
+        (byte)(h2 >>> 24), (byte)(h2 >>> 16), (byte)(h2 >>> 8), (byte) h2,
+        (byte)(h3 >>> 56), (byte)(h3 >>> 48), (byte)(h3 >>> 40), (byte)(h3 >>> 32),
+        (byte)(h3 >>> 24), (byte)(h3 >>> 16), (byte)(h3 >>>  8), (byte) h3,
+        (byte)(h4 >>> 56), (byte)(h4 >>> 48), (byte)(h4 >>> 40), (byte)(h4 >>> 32),
+        (byte)(h4 >>> 24), (byte)(h4 >>> 16), (byte)(h4 >>>  8), (byte) h4,
+        (byte)(h5 >>> 56), (byte)(h5 >>> 48), (byte)(h5 >>> 40), (byte)(h5 >>> 32),
+        (byte)(h5 >>> 24), (byte)(h5 >>> 16), (byte)(h5 >>> 8), (byte) h5,
+        (byte)(h6 >>> 56), (byte)(h6 >>> 48), (byte)(h6 >>> 40), (byte)(h6 >>> 32),
+        (byte)(h6 >>> 24), (byte)(h6 >>> 16), (byte)(h6 >>>  8), (byte) h6,
+        (byte)(h7 >>> 56), (byte)(h7 >>> 48), (byte)(h7 >>> 40), (byte)(h7 >>> 32),
+        (byte)(h7 >>> 24), (byte)(h7 >>> 16), (byte)(h7 >>>  8), (byte) h7 };
+  }
+
+  protected void resetContext()
+  {
+    // magic SHA-512 initialisation constants
+    h0 = 0x6a09e667f3bcc908L;
+    h1 = 0xbb67ae8584caa73bL;
+    h2 = 0x3c6ef372fe94f82bL;
+    h3 = 0xa54ff53a5f1d36f1L;
+    h4 = 0x510e527fade682d1L;
+    h5 = 0x9b05688c2b3e6c1fL;
+    h6 = 0x1f83d9abfb41bd6bL;
+    h7 = 0x5be0cd19137e2179L;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        Sha512 md = new Sha512();
+        md.update((byte) 0x61); // a
+        md.update((byte) 0x62); // b
+        md.update((byte) 0x63); // c
+        String result = Util.toString(md.digest());
+        valid = Boolean.valueOf(DIGEST0.equals(result));
+      }
+    return valid.booleanValue();
+  }
+
+  private static synchronized final long[] sha(long hh0, long hh1, long hh2,
+                                               long hh3, long hh4, long hh5,
+                                               long hh6, long hh7, byte[] in,
+                                               int offset)
+  {
+    long A = hh0;
+    long B = hh1;
+    long C = hh2;
+    long D = hh3;
+    long E = hh4;
+    long F = hh5;
+    long G = hh6;
+    long H = hh7;
+    long T, T2;
+    int r;
+    for (r = 0; r < 16; r++)
+      w[r] =  (long) in[offset++]         << 56
+           | ((long) in[offset++] & 0xFF) << 48
+           | ((long) in[offset++] & 0xFF) << 40
+           | ((long) in[offset++] & 0xFF) << 32
+           | ((long) in[offset++] & 0xFF) << 24
+           | ((long) in[offset++] & 0xFF) << 16
+           | ((long) in[offset++] & 0xFF) << 8
+           | ((long) in[offset++] & 0xFF);
+    for (r = 16; r < 80; r++)
+      {
+        T = w[r - 2];
+        T2 = w[r - 15];
+        w[r] = (((T >>> 19) | (T << 45)) ^ ((T >>> 61) | (T << 3)) ^ (T >>> 6))
+               + w[r - 7]
+               + (((T2 >>> 1) | (T2 << 63))
+                   ^ ((T2 >>> 8) | (T2 << 56))
+                   ^ (T2 >>> 7))
+               + w[r - 16];
+      }
+    for (r = 0; r < 80; r++)
+      {
+        T = H
+            + (((E >>> 14) | (E << 50))
+                ^ ((E >>> 18) | (E << 46))
+                ^ ((E >>> 41) | (E << 23)))
+            + ((E & F) ^ ((~E) & G)) + k[r] + w[r];
+        T2 = (((A >>> 28) | (A << 36))
+               ^ ((A >>> 34) | (A << 30))
+               ^ ((A >>> 39) | (A << 25)))
+             + ((A & B) ^ (A & C) ^ (B & C));
+        H = G;
+        G = F;
+        F = E;
+        E = D + T;
+        D = C;
+        C = B;
+        B = A;
+        A = T + T2;
+      }
+    return new long[] {
+        hh0 + A, hh1 + B, hh2 + C, hh3 + D,
+        hh4 + E, hh5 + F, hh6 + G, hh7 + H };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/Tiger.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,864 @@
+/* Tiger.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+/**
+ * The Tiger message digest. Tiger was designed by Ross Anderson and Eli
+ * Biham, with the goal of producing a secure, fast hash function that
+ * performs especially well on next-generation 64-bit architectures, but
+ * is still efficient on 32- and 16-bit architectures.
+ * <p>
+ * Tiger processes data in 512-bit blocks and produces a 192-bit
+ * digest.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cs.technion.ac.il/~biham/Reports/Tiger/">Tiger: A
+ * Fast New Hash Function</a>, Ross Anderson and Eli Biham.</a></li>
+ * </ol>
+ */
+public class Tiger
+    extends BaseHash
+{
+  private static final int HASH_SIZE = 24;
+
+  private static final int BLOCK_SIZE = 64;
+
+  /** Result when no data has been input. */
+  private static final String DIGEST0 =
+      "3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3";
+
+  private static final long A = 0x0123456789ABCDEFL;
+
+  private static final long B = 0xFEDCBA9876543210L;
+
+  private static final long C = 0xF096A5B4C3B2E187L;
+
+  /** S-Box T1. */
+  private static final long[] T1 = {
+      0x02AAB17CF7E90C5EL, 0xAC424B03E243A8ECL, 0x72CD5BE30DD5FCD3L,
+      0x6D019B93F6F97F3AL, 0xCD9978FFD21F9193L, 0x7573A1C9708029E2L,
+      0xB164326B922A83C3L, 0x46883EEE04915870L, 0xEAACE3057103ECE6L,
+      0xC54169B808A3535CL, 0x4CE754918DDEC47CL, 0x0AA2F4DFDC0DF40CL,
+      0x10B76F18A74DBEFAL, 0xC6CCB6235AD1AB6AL, 0x13726121572FE2FFL,
+      0x1A488C6F199D921EL, 0x4BC9F9F4DA0007CAL, 0x26F5E6F6E85241C7L,
+      0x859079DBEA5947B6L, 0x4F1885C5C99E8C92L, 0xD78E761EA96F864BL,
+      0x8E36428C52B5C17DL, 0x69CF6827373063C1L, 0xB607C93D9BB4C56EL,
+      0x7D820E760E76B5EAL, 0x645C9CC6F07FDC42L, 0xBF38A078243342E0L,
+      0x5F6B343C9D2E7D04L, 0xF2C28AEB600B0EC6L, 0x6C0ED85F7254BCACL,
+      0x71592281A4DB4FE5L, 0x1967FA69CE0FED9FL, 0xFD5293F8B96545DBL,
+      0xC879E9D7F2A7600BL, 0x860248920193194EL, 0xA4F9533B2D9CC0B3L,
+      0x9053836C15957613L, 0xDB6DCF8AFC357BF1L, 0x18BEEA7A7A370F57L,
+      0x037117CA50B99066L, 0x6AB30A9774424A35L, 0xF4E92F02E325249BL,
+      0x7739DB07061CCAE1L, 0xD8F3B49CECA42A05L, 0xBD56BE3F51382F73L,
+      0x45FAED5843B0BB28L, 0x1C813D5C11BF1F83L, 0x8AF0E4B6D75FA169L,
+      0x33EE18A487AD9999L, 0x3C26E8EAB1C94410L, 0xB510102BC0A822F9L,
+      0x141EEF310CE6123BL, 0xFC65B90059DDB154L, 0xE0158640C5E0E607L,
+      0x884E079826C3A3CFL, 0x930D0D9523C535FDL, 0x35638D754E9A2B00L,
+      0x4085FCCF40469DD5L, 0xC4B17AD28BE23A4CL, 0xCAB2F0FC6A3E6A2EL,
+      0x2860971A6B943FCDL, 0x3DDE6EE212E30446L, 0x6222F32AE01765AEL,
+      0x5D550BB5478308FEL, 0xA9EFA98DA0EDA22AL, 0xC351A71686C40DA7L,
+      0x1105586D9C867C84L, 0xDCFFEE85FDA22853L, 0xCCFBD0262C5EEF76L,
+      0xBAF294CB8990D201L, 0xE69464F52AFAD975L, 0x94B013AFDF133E14L,
+      0x06A7D1A32823C958L, 0x6F95FE5130F61119L, 0xD92AB34E462C06C0L,
+      0xED7BDE33887C71D2L, 0x79746D6E6518393EL, 0x5BA419385D713329L,
+      0x7C1BA6B948A97564L, 0x31987C197BFDAC67L, 0xDE6C23C44B053D02L,
+      0x581C49FED002D64DL, 0xDD474D6338261571L, 0xAA4546C3E473D062L,
+      0x928FCE349455F860L, 0x48161BBACAAB94D9L, 0x63912430770E6F68L,
+      0x6EC8A5E602C6641CL, 0x87282515337DDD2BL, 0x2CDA6B42034B701BL,
+      0xB03D37C181CB096DL, 0xE108438266C71C6FL, 0x2B3180C7EB51B255L,
+      0xDF92B82F96C08BBCL, 0x5C68C8C0A632F3BAL, 0x5504CC861C3D0556L,
+      0xABBFA4E55FB26B8FL, 0x41848B0AB3BACEB4L, 0xB334A273AA445D32L,
+      0xBCA696F0A85AD881L, 0x24F6EC65B528D56CL, 0x0CE1512E90F4524AL,
+      0x4E9DD79D5506D35AL, 0x258905FAC6CE9779L, 0x2019295B3E109B33L,
+      0xF8A9478B73A054CCL, 0x2924F2F934417EB0L, 0x3993357D536D1BC4L,
+      0x38A81AC21DB6FF8BL, 0x47C4FBF17D6016BFL, 0x1E0FAADD7667E3F5L,
+      0x7ABCFF62938BEB96L, 0xA78DAD948FC179C9L, 0x8F1F98B72911E50DL,
+      0x61E48EAE27121A91L, 0x4D62F7AD31859808L, 0xECEBA345EF5CEAEBL,
+      0xF5CEB25EBC9684CEL, 0xF633E20CB7F76221L, 0xA32CDF06AB8293E4L,
+      0x985A202CA5EE2CA4L, 0xCF0B8447CC8A8FB1L, 0x9F765244979859A3L,
+      0xA8D516B1A1240017L, 0x0BD7BA3EBB5DC726L, 0xE54BCA55B86ADB39L,
+      0x1D7A3AFD6C478063L, 0x519EC608E7669EDDL, 0x0E5715A2D149AA23L,
+      0x177D4571848FF194L, 0xEEB55F3241014C22L, 0x0F5E5CA13A6E2EC2L,
+      0x8029927B75F5C361L, 0xAD139FABC3D6E436L, 0x0D5DF1A94CCF402FL,
+      0x3E8BD948BEA5DFC8L, 0xA5A0D357BD3FF77EL, 0xA2D12E251F74F645L,
+      0x66FD9E525E81A082L, 0x2E0C90CE7F687A49L, 0xC2E8BCBEBA973BC5L,
+      0x000001BCE509745FL, 0x423777BBE6DAB3D6L, 0xD1661C7EAEF06EB5L,
+      0xA1781F354DAACFD8L, 0x2D11284A2B16AFFCL, 0xF1FC4F67FA891D1FL,
+      0x73ECC25DCB920ADAL, 0xAE610C22C2A12651L, 0x96E0A810D356B78AL,
+      0x5A9A381F2FE7870FL, 0xD5AD62EDE94E5530L, 0xD225E5E8368D1427L,
+      0x65977B70C7AF4631L, 0x99F889B2DE39D74FL, 0x233F30BF54E1D143L,
+      0x9A9675D3D9A63C97L, 0x5470554FF334F9A8L, 0x166ACB744A4F5688L,
+      0x70C74CAAB2E4AEADL, 0xF0D091646F294D12L, 0x57B82A89684031D1L,
+      0xEFD95A5A61BE0B6BL, 0x2FBD12E969F2F29AL, 0x9BD37013FEFF9FE8L,
+      0x3F9B0404D6085A06L, 0x4940C1F3166CFE15L, 0x09542C4DCDF3DEFBL,
+      0xB4C5218385CD5CE3L, 0xC935B7DC4462A641L, 0x3417F8A68ED3B63FL,
+      0xB80959295B215B40L, 0xF99CDAEF3B8C8572L, 0x018C0614F8FCB95DL,
+      0x1B14ACCD1A3ACDF3L, 0x84D471F200BB732DL, 0xC1A3110E95E8DA16L,
+      0x430A7220BF1A82B8L, 0xB77E090D39DF210EL, 0x5EF4BD9F3CD05E9DL,
+      0x9D4FF6DA7E57A444L, 0xDA1D60E183D4A5F8L, 0xB287C38417998E47L,
+      0xFE3EDC121BB31886L, 0xC7FE3CCC980CCBEFL, 0xE46FB590189BFD03L,
+      0x3732FD469A4C57DCL, 0x7EF700A07CF1AD65L, 0x59C64468A31D8859L,
+      0x762FB0B4D45B61F6L, 0x155BAED099047718L, 0x68755E4C3D50BAA6L,
+      0xE9214E7F22D8B4DFL, 0x2ADDBF532EAC95F4L, 0x32AE3909B4BD0109L,
+      0x834DF537B08E3450L, 0xFA209DA84220728DL, 0x9E691D9B9EFE23F7L,
+      0x0446D288C4AE8D7FL, 0x7B4CC524E169785BL, 0x21D87F0135CA1385L,
+      0xCEBB400F137B8AA5L, 0x272E2B66580796BEL, 0x3612264125C2B0DEL,
+      0x057702BDAD1EFBB2L, 0xD4BABB8EACF84BE9L, 0x91583139641BC67BL,
+      0x8BDC2DE08036E024L, 0x603C8156F49F68EDL, 0xF7D236F7DBEF5111L,
+      0x9727C4598AD21E80L, 0xA08A0896670A5FD7L, 0xCB4A8F4309EBA9CBL,
+      0x81AF564B0F7036A1L, 0xC0B99AA778199ABDL, 0x959F1EC83FC8E952L,
+      0x8C505077794A81B9L, 0x3ACAAF8F056338F0L, 0x07B43F50627A6778L,
+      0x4A44AB49F5ECCC77L, 0x3BC3D6E4B679EE98L, 0x9CC0D4D1CF14108CL,
+      0x4406C00B206BC8A0L, 0x82A18854C8D72D89L, 0x67E366B35C3C432CL,
+      0xB923DD61102B37F2L, 0x56AB2779D884271DL, 0xBE83E1B0FF1525AFL,
+      0xFB7C65D4217E49A9L, 0x6BDBE0E76D48E7D4L, 0x08DF828745D9179EL,
+      0x22EA6A9ADD53BD34L, 0xE36E141C5622200AL, 0x7F805D1B8CB750EEL,
+      0xAFE5C7A59F58E837L, 0xE27F996A4FB1C23CL, 0xD3867DFB0775F0D0L,
+      0xD0E673DE6E88891AL, 0x123AEB9EAFB86C25L, 0x30F1D5D5C145B895L,
+      0xBB434A2DEE7269E7L, 0x78CB67ECF931FA38L, 0xF33B0372323BBF9CL,
+      0x52D66336FB279C74L, 0x505F33AC0AFB4EAAL, 0xE8A5CD99A2CCE187L,
+      0x534974801E2D30BBL, 0x8D2D5711D5876D90L, 0x1F1A412891BC038EL,
+      0xD6E2E71D82E56648L, 0x74036C3A497732B7L, 0x89B67ED96361F5ABL,
+      0xFFED95D8F1EA02A2L, 0xE72B3BD61464D43DL, 0xA6300F170BDC4820L,
+      0xEBC18760ED78A77AL };
+
+  /** S-Box T2. */
+  private static final long[] T2 = {
+      0xE6A6BE5A05A12138L, 0xB5A122A5B4F87C98L, 0x563C6089140B6990L,
+      0x4C46CB2E391F5DD5L, 0xD932ADDBC9B79434L, 0x08EA70E42015AFF5L,
+      0xD765A6673E478CF1L, 0xC4FB757EAB278D99L, 0xDF11C6862D6E0692L,
+      0xDDEB84F10D7F3B16L, 0x6F2EF604A665EA04L, 0x4A8E0F0FF0E0DFB3L,
+      0xA5EDEEF83DBCBA51L, 0xFC4F0A2A0EA4371EL, 0xE83E1DA85CB38429L,
+      0xDC8FF882BA1B1CE2L, 0xCD45505E8353E80DL, 0x18D19A00D4DB0717L,
+      0x34A0CFEDA5F38101L, 0x0BE77E518887CAF2L, 0x1E341438B3C45136L,
+      0xE05797F49089CCF9L, 0xFFD23F9DF2591D14L, 0x543DDA228595C5CDL,
+      0x661F81FD99052A33L, 0x8736E641DB0F7B76L, 0x15227725418E5307L,
+      0xE25F7F46162EB2FAL, 0x48A8B2126C13D9FEL, 0xAFDC541792E76EEAL,
+      0x03D912BFC6D1898FL, 0x31B1AAFA1B83F51BL, 0xF1AC2796E42AB7D9L,
+      0x40A3A7D7FCD2EBACL, 0x1056136D0AFBBCC5L, 0x7889E1DD9A6D0C85L,
+      0xD33525782A7974AAL, 0xA7E25D09078AC09BL, 0xBD4138B3EAC6EDD0L,
+      0x920ABFBE71EB9E70L, 0xA2A5D0F54FC2625CL, 0xC054E36B0B1290A3L,
+      0xF6DD59FF62FE932BL, 0x3537354511A8AC7DL, 0xCA845E9172FADCD4L,
+      0x84F82B60329D20DCL, 0x79C62CE1CD672F18L, 0x8B09A2ADD124642CL,
+      0xD0C1E96A19D9E726L, 0x5A786A9B4BA9500CL, 0x0E020336634C43F3L,
+      0xC17B474AEB66D822L, 0x6A731AE3EC9BAAC2L, 0x8226667AE0840258L,
+      0x67D4567691CAECA5L, 0x1D94155C4875ADB5L, 0x6D00FD985B813FDFL,
+      0x51286EFCB774CD06L, 0x5E8834471FA744AFL, 0xF72CA0AEE761AE2EL,
+      0xBE40E4CDAEE8E09AL, 0xE9970BBB5118F665L, 0x726E4BEB33DF1964L,
+      0x703B000729199762L, 0x4631D816F5EF30A7L, 0xB880B5B51504A6BEL,
+      0x641793C37ED84B6CL, 0x7B21ED77F6E97D96L, 0x776306312EF96B73L,
+      0xAE528948E86FF3F4L, 0x53DBD7F286A3F8F8L, 0x16CADCE74CFC1063L,
+      0x005C19BDFA52C6DDL, 0x68868F5D64D46AD3L, 0x3A9D512CCF1E186AL,
+      0x367E62C2385660AEL, 0xE359E7EA77DCB1D7L, 0x526C0773749ABE6EL,
+      0x735AE5F9D09F734BL, 0x493FC7CC8A558BA8L, 0xB0B9C1533041AB45L,
+      0x321958BA470A59BDL, 0x852DB00B5F46C393L, 0x91209B2BD336B0E5L,
+      0x6E604F7D659EF19FL, 0xB99A8AE2782CCB24L, 0xCCF52AB6C814C4C7L,
+      0x4727D9AFBE11727BL, 0x7E950D0C0121B34DL, 0x756F435670AD471FL,
+      0xF5ADD442615A6849L, 0x4E87E09980B9957AL, 0x2ACFA1DF50AEE355L,
+      0xD898263AFD2FD556L, 0xC8F4924DD80C8FD6L, 0xCF99CA3D754A173AL,
+      0xFE477BACAF91BF3CL, 0xED5371F6D690C12DL, 0x831A5C285E687094L,
+      0xC5D3C90A3708A0A4L, 0x0F7F903717D06580L, 0x19F9BB13B8FDF27FL,
+      0xB1BD6F1B4D502843L, 0x1C761BA38FFF4012L, 0x0D1530C4E2E21F3BL,
+      0x8943CE69A7372C8AL, 0xE5184E11FEB5CE66L, 0x618BDB80BD736621L,
+      0x7D29BAD68B574D0BL, 0x81BB613E25E6FE5BL, 0x071C9C10BC07913FL,
+      0xC7BEEB7909AC2D97L, 0xC3E58D353BC5D757L, 0xEB017892F38F61E8L,
+      0xD4EFFB9C9B1CC21AL, 0x99727D26F494F7ABL, 0xA3E063A2956B3E03L,
+      0x9D4A8B9A4AA09C30L, 0x3F6AB7D500090FB4L, 0x9CC0F2A057268AC0L,
+      0x3DEE9D2DEDBF42D1L, 0x330F49C87960A972L, 0xC6B2720287421B41L,
+      0x0AC59EC07C00369CL, 0xEF4EAC49CB353425L, 0xF450244EEF0129D8L,
+      0x8ACC46E5CAF4DEB6L, 0x2FFEAB63989263F7L, 0x8F7CB9FE5D7A4578L,
+      0x5BD8F7644E634635L, 0x427A7315BF2DC900L, 0x17D0C4AA2125261CL,
+      0x3992486C93518E50L, 0xB4CBFEE0A2D7D4C3L, 0x7C75D6202C5DDD8DL,
+      0xDBC295D8E35B6C61L, 0x60B369D302032B19L, 0xCE42685FDCE44132L,
+      0x06F3DDB9DDF65610L, 0x8EA4D21DB5E148F0L, 0x20B0FCE62FCD496FL,
+      0x2C1B912358B0EE31L, 0xB28317B818F5A308L, 0xA89C1E189CA6D2CFL,
+      0x0C6B18576AAADBC8L, 0xB65DEAA91299FAE3L, 0xFB2B794B7F1027E7L,
+      0x04E4317F443B5BEBL, 0x4B852D325939D0A6L, 0xD5AE6BEEFB207FFCL,
+      0x309682B281C7D374L, 0xBAE309A194C3B475L, 0x8CC3F97B13B49F05L,
+      0x98A9422FF8293967L, 0x244B16B01076FF7CL, 0xF8BF571C663D67EEL,
+      0x1F0D6758EEE30DA1L, 0xC9B611D97ADEB9B7L, 0xB7AFD5887B6C57A2L,
+      0x6290AE846B984FE1L, 0x94DF4CDEACC1A5FDL, 0x058A5BD1C5483AFFL,
+      0x63166CC142BA3C37L, 0x8DB8526EB2F76F40L, 0xE10880036F0D6D4EL,
+      0x9E0523C9971D311DL, 0x45EC2824CC7CD691L, 0x575B8359E62382C9L,
+      0xFA9E400DC4889995L, 0xD1823ECB45721568L, 0xDAFD983B8206082FL,
+      0xAA7D29082386A8CBL, 0x269FCD4403B87588L, 0x1B91F5F728BDD1E0L,
+      0xE4669F39040201F6L, 0x7A1D7C218CF04ADEL, 0x65623C29D79CE5CEL,
+      0x2368449096C00BB1L, 0xAB9BF1879DA503BAL, 0xBC23ECB1A458058EL,
+      0x9A58DF01BB401ECCL, 0xA070E868A85F143DL, 0x4FF188307DF2239EL,
+      0x14D565B41A641183L, 0xEE13337452701602L, 0x950E3DCF3F285E09L,
+      0x59930254B9C80953L, 0x3BF299408930DA6DL, 0xA955943F53691387L,
+      0xA15EDECAA9CB8784L, 0x29142127352BE9A0L, 0x76F0371FFF4E7AFBL,
+      0x0239F450274F2228L, 0xBB073AF01D5E868BL, 0xBFC80571C10E96C1L,
+      0xD267088568222E23L, 0x9671A3D48E80B5B0L, 0x55B5D38AE193BB81L,
+      0x693AE2D0A18B04B8L, 0x5C48B4ECADD5335FL, 0xFD743B194916A1CAL,
+      0x2577018134BE98C4L, 0xE77987E83C54A4ADL, 0x28E11014DA33E1B9L,
+      0x270CC59E226AA213L, 0x71495F756D1A5F60L, 0x9BE853FB60AFEF77L,
+      0xADC786A7F7443DBFL, 0x0904456173B29A82L, 0x58BC7A66C232BD5EL,
+      0xF306558C673AC8B2L, 0x41F639C6B6C9772AL, 0x216DEFE99FDA35DAL,
+      0x11640CC71C7BE615L, 0x93C43694565C5527L, 0xEA038E6246777839L,
+      0xF9ABF3CE5A3E2469L, 0x741E768D0FD312D2L, 0x0144B883CED652C6L,
+      0xC20B5A5BA33F8552L, 0x1AE69633C3435A9DL, 0x97A28CA4088CFDECL,
+      0x8824A43C1E96F420L, 0x37612FA66EEEA746L, 0x6B4CB165F9CF0E5AL,
+      0x43AA1C06A0ABFB4AL, 0x7F4DC26FF162796BL, 0x6CBACC8E54ED9B0FL,
+      0xA6B7FFEFD2BB253EL, 0x2E25BC95B0A29D4FL, 0x86D6A58BDEF1388CL,
+      0xDED74AC576B6F054L, 0x8030BDBC2B45805DL, 0x3C81AF70E94D9289L,
+      0x3EFF6DDA9E3100DBL, 0xB38DC39FDFCC8847L, 0x123885528D17B87EL,
+      0xF2DA0ED240B1B642L, 0x44CEFADCD54BF9A9L, 0x1312200E433C7EE6L,
+      0x9FFCC84F3A78C748L, 0xF0CD1F72248576BBL, 0xEC6974053638CFE4L,
+      0x2BA7B67C0CEC4E4CL, 0xAC2F4DF3E5CE32EDL, 0xCB33D14326EA4C11L,
+      0xA4E9044CC77E58BCL, 0x5F513293D934FCEFL, 0x5DC9645506E55444L,
+      0x50DE418F317DE40AL, 0x388CB31A69DDE259L, 0x2DB4A83455820A86L,
+      0x9010A91E84711AE9L, 0x4DF7F0B7B1498371L, 0xD62A2EABC0977179L,
+      0x22FAC097AA8D5C0EL };
+
+  /** S-Box T3. */
+  private static final long[] T3 = {
+      0xF49FCC2FF1DAF39BL, 0x487FD5C66FF29281L, 0xE8A30667FCDCA83FL,
+      0x2C9B4BE3D2FCCE63L, 0xDA3FF74B93FBBBC2L, 0x2FA165D2FE70BA66L,
+      0xA103E279970E93D4L, 0xBECDEC77B0E45E71L, 0xCFB41E723985E497L,
+      0xB70AAA025EF75017L, 0xD42309F03840B8E0L, 0x8EFC1AD035898579L,
+      0x96C6920BE2B2ABC5L, 0x66AF4163375A9172L, 0x2174ABDCCA7127FBL,
+      0xB33CCEA64A72FF41L, 0xF04A4933083066A5L, 0x8D970ACDD7289AF5L,
+      0x8F96E8E031C8C25EL, 0xF3FEC02276875D47L, 0xEC7BF310056190DDL,
+      0xF5ADB0AEBB0F1491L, 0x9B50F8850FD58892L, 0x4975488358B74DE8L,
+      0xA3354FF691531C61L, 0x0702BBE481D2C6EEL, 0x89FB24057DEDED98L,
+      0xAC3075138596E902L, 0x1D2D3580172772EDL, 0xEB738FC28E6BC30DL,
+      0x5854EF8F63044326L, 0x9E5C52325ADD3BBEL, 0x90AA53CF325C4623L,
+      0xC1D24D51349DD067L, 0x2051CFEEA69EA624L, 0x13220F0A862E7E4FL,
+      0xCE39399404E04864L, 0xD9C42CA47086FCB7L, 0x685AD2238A03E7CCL,
+      0x066484B2AB2FF1DBL, 0xFE9D5D70EFBF79ECL, 0x5B13B9DD9C481854L,
+      0x15F0D475ED1509ADL, 0x0BEBCD060EC79851L, 0xD58C6791183AB7F8L,
+      0xD1187C5052F3EEE4L, 0xC95D1192E54E82FFL, 0x86EEA14CB9AC6CA2L,
+      0x3485BEB153677D5DL, 0xDD191D781F8C492AL, 0xF60866BAA784EBF9L,
+      0x518F643BA2D08C74L, 0x8852E956E1087C22L, 0xA768CB8DC410AE8DL,
+      0x38047726BFEC8E1AL, 0xA67738B4CD3B45AAL, 0xAD16691CEC0DDE19L,
+      0xC6D4319380462E07L, 0xC5A5876D0BA61938L, 0x16B9FA1FA58FD840L,
+      0x188AB1173CA74F18L, 0xABDA2F98C99C021FL, 0x3E0580AB134AE816L,
+      0x5F3B05B773645ABBL, 0x2501A2BE5575F2F6L, 0x1B2F74004E7E8BA9L,
+      0x1CD7580371E8D953L, 0x7F6ED89562764E30L, 0xB15926FF596F003DL,
+      0x9F65293DA8C5D6B9L, 0x6ECEF04DD690F84CL, 0x4782275FFF33AF88L,
+      0xE41433083F820801L, 0xFD0DFE409A1AF9B5L, 0x4325A3342CDB396BL,
+      0x8AE77E62B301B252L, 0xC36F9E9F6655615AL, 0x85455A2D92D32C09L,
+      0xF2C7DEA949477485L, 0x63CFB4C133A39EBAL, 0x83B040CC6EBC5462L,
+      0x3B9454C8FDB326B0L, 0x56F56A9E87FFD78CL, 0x2DC2940D99F42BC6L,
+      0x98F7DF096B096E2DL, 0x19A6E01E3AD852BFL, 0x42A99CCBDBD4B40BL,
+      0xA59998AF45E9C559L, 0x366295E807D93186L, 0x6B48181BFAA1F773L,
+      0x1FEC57E2157A0A1DL, 0x4667446AF6201AD5L, 0xE615EBCACFB0F075L,
+      0xB8F31F4F68290778L, 0x22713ED6CE22D11EL, 0x3057C1A72EC3C93BL,
+      0xCB46ACC37C3F1F2FL, 0xDBB893FD02AAF50EL, 0x331FD92E600B9FCFL,
+      0xA498F96148EA3AD6L, 0xA8D8426E8B6A83EAL, 0xA089B274B7735CDCL,
+      0x87F6B3731E524A11L, 0x118808E5CBC96749L, 0x9906E4C7B19BD394L,
+      0xAFED7F7E9B24A20CL, 0x6509EADEEB3644A7L, 0x6C1EF1D3E8EF0EDEL,
+      0xB9C97D43E9798FB4L, 0xA2F2D784740C28A3L, 0x7B8496476197566FL,
+      0x7A5BE3E6B65F069DL, 0xF96330ED78BE6F10L, 0xEEE60DE77A076A15L,
+      0x2B4BEE4AA08B9BD0L, 0x6A56A63EC7B8894EL, 0x02121359BA34FEF4L,
+      0x4CBF99F8283703FCL, 0x398071350CAF30C8L, 0xD0A77A89F017687AL,
+      0xF1C1A9EB9E423569L, 0x8C7976282DEE8199L, 0x5D1737A5DD1F7ABDL,
+      0x4F53433C09A9FA80L, 0xFA8B0C53DF7CA1D9L, 0x3FD9DCBC886CCB77L,
+      0xC040917CA91B4720L, 0x7DD00142F9D1DCDFL, 0x8476FC1D4F387B58L,
+      0x23F8E7C5F3316503L, 0x032A2244E7E37339L, 0x5C87A5D750F5A74BL,
+      0x082B4CC43698992EL, 0xDF917BECB858F63CL, 0x3270B8FC5BF86DDAL,
+      0x10AE72BB29B5DD76L, 0x576AC94E7700362BL, 0x1AD112DAC61EFB8FL,
+      0x691BC30EC5FAA427L, 0xFF246311CC327143L, 0x3142368E30E53206L,
+      0x71380E31E02CA396L, 0x958D5C960AAD76F1L, 0xF8D6F430C16DA536L,
+      0xC8FFD13F1BE7E1D2L, 0x7578AE66004DDBE1L, 0x05833F01067BE646L,
+      0xBB34B5AD3BFE586DL, 0x095F34C9A12B97F0L, 0x247AB64525D60CA8L,
+      0xDCDBC6F3017477D1L, 0x4A2E14D4DECAD24DL, 0xBDB5E6D9BE0A1EEBL,
+      0x2A7E70F7794301ABL, 0xDEF42D8A270540FDL, 0x01078EC0A34C22C1L,
+      0xE5DE511AF4C16387L, 0x7EBB3A52BD9A330AL, 0x77697857AA7D6435L,
+      0x004E831603AE4C32L, 0xE7A21020AD78E312L, 0x9D41A70C6AB420F2L,
+      0x28E06C18EA1141E6L, 0xD2B28CBD984F6B28L, 0x26B75F6C446E9D83L,
+      0xBA47568C4D418D7FL, 0xD80BADBFE6183D8EL, 0x0E206D7F5F166044L,
+      0xE258A43911CBCA3EL, 0x723A1746B21DC0BCL, 0xC7CAA854F5D7CDD3L,
+      0x7CAC32883D261D9CL, 0x7690C26423BA942CL, 0x17E55524478042B8L,
+      0xE0BE477656A2389FL, 0x4D289B5E67AB2DA0L, 0x44862B9C8FBBFD31L,
+      0xB47CC8049D141365L, 0x822C1B362B91C793L, 0x4EB14655FB13DFD8L,
+      0x1ECBBA0714E2A97BL, 0x6143459D5CDE5F14L, 0x53A8FBF1D5F0AC89L,
+      0x97EA04D81C5E5B00L, 0x622181A8D4FDB3F3L, 0xE9BCD341572A1208L,
+      0x1411258643CCE58AL, 0x9144C5FEA4C6E0A4L, 0x0D33D06565CF620FL,
+      0x54A48D489F219CA1L, 0xC43E5EAC6D63C821L, 0xA9728B3A72770DAFL,
+      0xD7934E7B20DF87EFL, 0xE35503B61A3E86E5L, 0xCAE321FBC819D504L,
+      0x129A50B3AC60BFA6L, 0xCD5E68EA7E9FB6C3L, 0xB01C90199483B1C7L,
+      0x3DE93CD5C295376CL, 0xAED52EDF2AB9AD13L, 0x2E60F512C0A07884L,
+      0xBC3D86A3E36210C9L, 0x35269D9B163951CEL, 0x0C7D6E2AD0CDB5FAL,
+      0x59E86297D87F5733L, 0x298EF221898DB0E7L, 0x55000029D1A5AA7EL,
+      0x8BC08AE1B5061B45L, 0xC2C31C2B6C92703AL, 0x94CC596BAF25EF42L,
+      0x0A1D73DB22540456L, 0x04B6A0F9D9C4179AL, 0xEFFDAFA2AE3D3C60L,
+      0xF7C8075BB49496C4L, 0x9CC5C7141D1CD4E3L, 0x78BD1638218E5534L,
+      0xB2F11568F850246AL, 0xEDFABCFA9502BC29L, 0x796CE5F2DA23051BL,
+      0xAAE128B0DC93537CL, 0x3A493DA0EE4B29AEL, 0xB5DF6B2C416895D7L,
+      0xFCABBD25122D7F37L, 0x70810B58105DC4B1L, 0xE10FDD37F7882A90L,
+      0x524DCAB5518A3F5CL, 0x3C9E85878451255BL, 0x4029828119BD34E2L,
+      0x74A05B6F5D3CECCBL, 0xB610021542E13ECAL, 0x0FF979D12F59E2ACL,
+      0x6037DA27E4F9CC50L, 0x5E92975A0DF1847DL, 0xD66DE190D3E623FEL,
+      0x5032D6B87B568048L, 0x9A36B7CE8235216EL, 0x80272A7A24F64B4AL,
+      0x93EFED8B8C6916F7L, 0x37DDBFF44CCE1555L, 0x4B95DB5D4B99BD25L,
+      0x92D3FDA169812FC0L, 0xFB1A4A9A90660BB6L, 0x730C196946A4B9B2L,
+      0x81E289AA7F49DA68L, 0x64669A0F83B1A05FL, 0x27B3FF7D9644F48BL,
+      0xCC6B615C8DB675B3L, 0x674F20B9BCEBBE95L, 0x6F31238275655982L,
+      0x5AE488713E45CF05L, 0xBF619F9954C21157L, 0xEABAC46040A8EAE9L,
+      0x454C6FE9F2C0C1CDL, 0x419CF6496412691CL, 0xD3DC3BEF265B0F70L,
+      0x6D0E60F5C3578A9EL };
+
+  /** S-Box T4. */
+  private static final long[] T4 = {
+      0x5B0E608526323C55L, 0x1A46C1A9FA1B59F5L, 0xA9E245A17C4C8FFAL,
+      0x65CA5159DB2955D7L, 0x05DB0A76CE35AFC2L, 0x81EAC77EA9113D45L,
+      0x528EF88AB6AC0A0DL, 0xA09EA253597BE3FFL, 0x430DDFB3AC48CD56L,
+      0xC4B3A67AF45CE46FL, 0x4ECECFD8FBE2D05EL, 0x3EF56F10B39935F0L,
+      0x0B22D6829CD619C6L, 0x17FD460A74DF2069L, 0x6CF8CC8E8510ED40L,
+      0xD6C824BF3A6ECAA7L, 0x61243D581A817049L, 0x048BACB6BBC163A2L,
+      0xD9A38AC27D44CC32L, 0x7FDDFF5BAAF410ABL, 0xAD6D495AA804824BL,
+      0xE1A6A74F2D8C9F94L, 0xD4F7851235DEE8E3L, 0xFD4B7F886540D893L,
+      0x247C20042AA4BFDAL, 0x096EA1C517D1327CL, 0xD56966B4361A6685L,
+      0x277DA5C31221057DL, 0x94D59893A43ACFF7L, 0x64F0C51CCDC02281L,
+      0x3D33BCC4FF6189DBL, 0xE005CB184CE66AF1L, 0xFF5CCD1D1DB99BEAL,
+      0xB0B854A7FE42980FL, 0x7BD46A6A718D4B9FL, 0xD10FA8CC22A5FD8CL,
+      0xD31484952BE4BD31L, 0xC7FA975FCB243847L, 0x4886ED1E5846C407L,
+      0x28CDDB791EB70B04L, 0xC2B00BE2F573417FL, 0x5C9590452180F877L,
+      0x7A6BDDFFF370EB00L, 0xCE509E38D6D9D6A4L, 0xEBEB0F00647FA702L,
+      0x1DCC06CF76606F06L, 0xE4D9F28BA286FF0AL, 0xD85A305DC918C262L,
+      0x475B1D8732225F54L, 0x2D4FB51668CCB5FEL, 0xA679B9D9D72BBA20L,
+      0x53841C0D912D43A5L, 0x3B7EAA48BF12A4E8L, 0x781E0E47F22F1DDFL,
+      0xEFF20CE60AB50973L, 0x20D261D19DFFB742L, 0x16A12B03062A2E39L,
+      0x1960EB2239650495L, 0x251C16FED50EB8B8L, 0x9AC0C330F826016EL,
+      0xED152665953E7671L, 0x02D63194A6369570L, 0x5074F08394B1C987L,
+      0x70BA598C90B25CE1L, 0x794A15810B9742F6L, 0x0D5925E9FCAF8C6CL,
+      0x3067716CD868744EL, 0x910AB077E8D7731BL, 0x6A61BBDB5AC42F61L,
+      0x93513EFBF0851567L, 0xF494724B9E83E9D5L, 0xE887E1985C09648DL,
+      0x34B1D3C675370CFDL, 0xDC35E433BC0D255DL, 0xD0AAB84234131BE0L,
+      0x08042A50B48B7EAFL, 0x9997C4EE44A3AB35L, 0x829A7B49201799D0L,
+      0x263B8307B7C54441L, 0x752F95F4FD6A6CA6L, 0x927217402C08C6E5L,
+      0x2A8AB754A795D9EEL, 0xA442F7552F72943DL, 0x2C31334E19781208L,
+      0x4FA98D7CEAEE6291L, 0x55C3862F665DB309L, 0xBD0610175D53B1F3L,
+      0x46FE6CB840413F27L, 0x3FE03792DF0CFA59L, 0xCFE700372EB85E8FL,
+      0xA7BE29E7ADBCE118L, 0xE544EE5CDE8431DDL, 0x8A781B1B41F1873EL,
+      0xA5C94C78A0D2F0E7L, 0x39412E2877B60728L, 0xA1265EF3AFC9A62CL,
+      0xBCC2770C6A2506C5L, 0x3AB66DD5DCE1CE12L, 0xE65499D04A675B37L,
+      0x7D8F523481BFD216L, 0x0F6F64FCEC15F389L, 0x74EFBE618B5B13C8L,
+      0xACDC82B714273E1DL, 0xDD40BFE003199D17L, 0x37E99257E7E061F8L,
+      0xFA52626904775AAAL, 0x8BBBF63A463D56F9L, 0xF0013F1543A26E64L,
+      0xA8307E9F879EC898L, 0xCC4C27A4150177CCL, 0x1B432F2CCA1D3348L,
+      0xDE1D1F8F9F6FA013L, 0x606602A047A7DDD6L, 0xD237AB64CC1CB2C7L,
+      0x9B938E7225FCD1D3L, 0xEC4E03708E0FF476L, 0xFEB2FBDA3D03C12DL,
+      0xAE0BCED2EE43889AL, 0x22CB8923EBFB4F43L, 0x69360D013CF7396DL,
+      0x855E3602D2D4E022L, 0x073805BAD01F784CL, 0x33E17A133852F546L,
+      0xDF4874058AC7B638L, 0xBA92B29C678AA14AL, 0x0CE89FC76CFAADCDL,
+      0x5F9D4E0908339E34L, 0xF1AFE9291F5923B9L, 0x6E3480F60F4A265FL,
+      0xEEBF3A2AB29B841CL, 0xE21938A88F91B4ADL, 0x57DFEFF845C6D3C3L,
+      0x2F006B0BF62CAAF2L, 0x62F479EF6F75EE78L, 0x11A55AD41C8916A9L,
+      0xF229D29084FED453L, 0x42F1C27B16B000E6L, 0x2B1F76749823C074L,
+      0x4B76ECA3C2745360L, 0x8C98F463B91691BDL, 0x14BCC93CF1ADE66AL,
+      0x8885213E6D458397L, 0x8E177DF0274D4711L, 0xB49B73B5503F2951L,
+      0x10168168C3F96B6BL, 0x0E3D963B63CAB0AEL, 0x8DFC4B5655A1DB14L,
+      0xF789F1356E14DE5CL, 0x683E68AF4E51DAC1L, 0xC9A84F9D8D4B0FD9L,
+      0x3691E03F52A0F9D1L, 0x5ED86E46E1878E80L, 0x3C711A0E99D07150L,
+      0x5A0865B20C4E9310L, 0x56FBFC1FE4F0682EL, 0xEA8D5DE3105EDF9BL,
+      0x71ABFDB12379187AL, 0x2EB99DE1BEE77B9CL, 0x21ECC0EA33CF4523L,
+      0x59A4D7521805C7A1L, 0x3896F5EB56AE7C72L, 0xAA638F3DB18F75DCL,
+      0x9F39358DABE9808EL, 0xB7DEFA91C00B72ACL, 0x6B5541FD62492D92L,
+      0x6DC6DEE8F92E4D5BL, 0x353F57ABC4BEEA7EL, 0x735769D6DA5690CEL,
+      0x0A234AA642391484L, 0xF6F9508028F80D9DL, 0xB8E319A27AB3F215L,
+      0x31AD9C1151341A4DL, 0x773C22A57BEF5805L, 0x45C7561A07968633L,
+      0xF913DA9E249DBE36L, 0xDA652D9B78A64C68L, 0x4C27A97F3BC334EFL,
+      0x76621220E66B17F4L, 0x967743899ACD7D0BL, 0xF3EE5BCAE0ED6782L,
+      0x409F753600C879FCL, 0x06D09A39B5926DB6L, 0x6F83AEB0317AC588L,
+      0x01E6CA4A86381F21L, 0x66FF3462D19F3025L, 0x72207C24DDFD3BFBL,
+      0x4AF6B6D3E2ECE2EBL, 0x9C994DBEC7EA08DEL, 0x49ACE597B09A8BC4L,
+      0xB38C4766CF0797BAL, 0x131B9373C57C2A75L, 0xB1822CCE61931E58L,
+      0x9D7555B909BA1C0CL, 0x127FAFDD937D11D2L, 0x29DA3BADC66D92E4L,
+      0xA2C1D57154C2ECBCL, 0x58C5134D82F6FE24L, 0x1C3AE3515B62274FL,
+      0xE907C82E01CB8126L, 0xF8ED091913E37FCBL, 0x3249D8F9C80046C9L,
+      0x80CF9BEDE388FB63L, 0x1881539A116CF19EL, 0x5103F3F76BD52457L,
+      0x15B7E6F5AE47F7A8L, 0xDBD7C6DED47E9CCFL, 0x44E55C410228BB1AL,
+      0xB647D4255EDB4E99L, 0x5D11882BB8AAFC30L, 0xF5098BBB29D3212AL,
+      0x8FB5EA14E90296B3L, 0x677B942157DD025AL, 0xFB58E7C0A390ACB5L,
+      0x89D3674C83BD4A01L, 0x9E2DA4DF4BF3B93BL, 0xFCC41E328CAB4829L,
+      0x03F38C96BA582C52L, 0xCAD1BDBD7FD85DB2L, 0xBBB442C16082AE83L,
+      0xB95FE86BA5DA9AB0L, 0xB22E04673771A93FL, 0x845358C9493152D8L,
+      0xBE2A488697B4541EL, 0x95A2DC2DD38E6966L, 0xC02C11AC923C852BL,
+      0x2388B1990DF2A87BL, 0x7C8008FA1B4F37BEL, 0x1F70D0C84D54E503L,
+      0x5490ADEC7ECE57D4L, 0x002B3C27D9063A3AL, 0x7EAEA3848030A2BFL,
+      0xC602326DED2003C0L, 0x83A7287D69A94086L, 0xC57A5FCB30F57A8AL,
+      0xB56844E479EBE779L, 0xA373B40F05DCBCE9L, 0xD71A786E88570EE2L,
+      0x879CBACDBDE8F6A0L, 0x976AD1BCC164A32FL, 0xAB21E25E9666D78BL,
+      0x901063AAE5E5C33CL, 0x9818B34448698D90L, 0xE36487AE3E1E8ABBL,
+      0xAFBDF931893BDCB4L, 0x6345A0DC5FBBD519L, 0x8628FE269B9465CAL,
+      0x1E5D01603F9C51ECL, 0x4DE44006A15049B7L, 0xBF6C70E5F776CBB1L,
+      0x411218F2EF552BEDL, 0xCB0C0708705A36A3L, 0xE74D14754F986044L,
+      0xCD56D9430EA8280EL, 0xC12591D7535F5065L, 0xC83223F1720AEF96L,
+      0xC3A0396F7363A51FL };
+
+  // The cached self-test result.
+  private static Boolean valid;
+
+  // The context.
+  private long a, b, c;
+
+  /**
+   * Trivial 0-arguments constructor.
+   */
+  public Tiger()
+  {
+    super(Registry.TIGER_HASH, HASH_SIZE, BLOCK_SIZE);
+  }
+
+  /**
+   * Private copying constructor for cloning.
+   *
+   * @param that The instance being cloned.
+   */
+  private Tiger(Tiger that)
+  {
+    this();
+    this.a = that.a;
+    this.b = that.b;
+    this.c = that.c;
+    this.count = that.count;
+    this.buffer = (that.buffer != null) ? (byte[]) that.buffer.clone() : null;
+  }
+
+  public Object clone()
+  {
+    return new Tiger(this);
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        String d = Util.toString(new Tiger().digest());
+        valid = Boolean.valueOf(DIGEST0.equals(d));
+      }
+    return valid.booleanValue();
+  }
+
+  protected byte[] padBuffer()
+  {
+    int n = (int)(count % BLOCK_SIZE);
+    int padding = (n < 56) ? (56 - n) : (120 - n);
+    byte[] pad = new byte[padding + 8];
+    pad[0] = 1;
+    long bits = count << 3;
+    pad[padding++] = (byte) bits;
+    pad[padding++] = (byte)(bits >>> 8);
+    pad[padding++] = (byte)(bits >>> 16);
+    pad[padding++] = (byte)(bits >>> 24);
+    pad[padding++] = (byte)(bits >>> 32);
+    pad[padding++] = (byte)(bits >>> 40);
+    pad[padding++] = (byte)(bits >>> 48);
+    pad[padding  ] = (byte)(bits >>> 56);
+    return pad;
+  }
+
+  protected byte[] getResult()
+  {
+    return new byte[] {
+        (byte) a,         (byte)(a >>>  8), (byte)(a >>> 16), (byte)(a >>> 24),
+        (byte)(a >>> 32), (byte)(a >>> 40), (byte)(a >>> 48), (byte)(a >>> 56),
+        (byte) b,         (byte)(b >>>  8), (byte)(b >>> 16), (byte)(b >>> 24),
+        (byte)(b >>> 32), (byte)(b >>> 40), (byte)(b >>> 48), (byte)(b >>> 56),
+        (byte) c,         (byte)(c >>>  8), (byte)(c >>> 16), (byte)(c >>> 24),
+        (byte)(c >>> 32), (byte)(c >>> 40), (byte)(c >>> 48), (byte)(c >>> 56) };
+  }
+
+  protected void resetContext()
+  {
+    a = A;
+    b = B;
+    c = C;
+  }
+
+  protected void transform(byte[] in, int offset)
+  {
+    long x0, x1, x2, x3, x4, x5, x6, x7;
+    x0 = ((long)  in[offset++] & 0xFF)
+       | ((long) (in[offset++] & 0xFF) << 8)
+       | ((long) (in[offset++] & 0xFF) << 16)
+       | ((long) (in[offset++] & 0xFF) << 24)
+       | ((long) (in[offset++] & 0xFF) << 32)
+       | ((long) (in[offset++] & 0xFF) << 40)
+       | ((long) (in[offset++] & 0xFF) << 48)
+       | ((long) (in[offset++] & 0xFF) << 56);
+    x1 = ((long)  in[offset++] & 0xFF)
+       | ((long) (in[offset++] & 0xFF) << 8)
+       | ((long) (in[offset++] & 0xFF) << 16)
+       | ((long) (in[offset++] & 0xFF) << 24)
+       | ((long) (in[offset++] & 0xFF) << 32)
+       | ((long) (in[offset++] & 0xFF) << 40)
+       | ((long) (in[offset++] & 0xFF) << 48)
+       | ((long) (in[offset++] & 0xFF) << 56);
+    x2 = ((long)  in[offset++] & 0xFF)
+       | ((long) (in[offset++] & 0xFF) << 8)
+       | ((long) (in[offset++] & 0xFF) << 16)
+       | ((long) (in[offset++] & 0xFF) << 24)
+       | ((long) (in[offset++] & 0xFF) << 32)
+       | ((long) (in[offset++] & 0xFF) << 40)
+       | ((long) (in[offset++] & 0xFF) << 48)
+       | ((long) (in[offset++] & 0xFF) << 56);
+    x3 = ((long)  in[offset++] & 0xFF)
+       | ((long) (in[offset++] & 0xFF) << 8)
+       | ((long) (in[offset++] & 0xFF) << 16)
+       | ((long) (in[offset++] & 0xFF) << 24)
+       | ((long) (in[offset++] & 0xFF) << 32)
+       | ((long) (in[offset++] & 0xFF) << 40)
+       | ((long) (in[offset++] & 0xFF) << 48)
+       | ((long) (in[offset++] & 0xFF) << 56);
+    x4 = ((long)  in[offset++] & 0xFF)
+       | ((long) (in[offset++] & 0xFF) << 8)
+       | ((long) (in[offset++] & 0xFF) << 16)
+       | ((long) (in[offset++] & 0xFF) << 24)
+       | ((long) (in[offset++] & 0xFF) << 32)
+       | ((long) (in[offset++] & 0xFF) << 40)
+       | ((long) (in[offset++] & 0xFF) << 48)
+       | ((long) (in[offset++] & 0xFF) << 56);
+    x5 = ((long)  in[offset++] & 0xFF)
+       | ((long) (in[offset++] & 0xFF) << 8)
+       | ((long) (in[offset++] & 0xFF) << 16)
+       | ((long) (in[offset++] & 0xFF) << 24)
+       | ((long) (in[offset++] & 0xFF) << 32)
+       | ((long) (in[offset++] & 0xFF) << 40)
+       | ((long) (in[offset++] & 0xFF) << 48)
+       | ((long) (in[offset++] & 0xFF) << 56);
+    x6 = ((long)  in[offset++] & 0xFF)
+       | ((long) (in[offset++] & 0xFF) << 8)
+       | ((long) (in[offset++] & 0xFF) << 16)
+       | ((long) (in[offset++] & 0xFF) << 24)
+       | ((long) (in[offset++] & 0xFF) << 32)
+       | ((long) (in[offset++] & 0xFF) << 40)
+       | ((long) (in[offset++] & 0xFF) << 48)
+       | ((long) (in[offset++] & 0xFF) << 56);
+    x7 = ((long)  in[offset++] & 0xFF)
+       | ((long) (in[offset++] & 0xFF) << 8)
+       | ((long) (in[offset++] & 0xFF) << 16)
+       | ((long) (in[offset++] & 0xFF) << 24)
+       | ((long) (in[offset++] & 0xFF) << 32)
+       | ((long) (in[offset++] & 0xFF) << 40)
+       | ((long) (in[offset++] & 0xFF) << 48)
+       | ((long) (in[offset  ] & 0xFF) << 56);
+    // save_abc ::=
+    long aa = a, bb = b, cc = c;
+    // pass(aa, bb, cc, 5) ::=
+    cc ^= x0;
+    aa -= T1[(int) cc        & 0xff]
+        ^ T2[(int)(cc >> 16) & 0xff]
+        ^ T3[(int)(cc >> 32) & 0xff]
+        ^ T4[(int)(cc >> 48) & 0xff];
+    bb += T4[(int)(cc >>  8) & 0xff]
+        ^ T3[(int)(cc >> 24) & 0xff]
+        ^ T2[(int)(cc >> 40) & 0xff]
+        ^ T1[(int)(cc >> 56) & 0xff];
+    bb *= 5;
+    aa ^= x1;
+    bb -= T1[(int) aa        & 0xff]
+        ^ T2[(int)(aa >> 16) & 0xff]
+        ^ T3[(int)(aa >> 32) & 0xff]
+        ^ T4[(int)(aa >> 48) & 0xff];
+    cc += T4[(int)(aa >>  8) & 0xff]
+        ^ T3[(int)(aa >> 24) & 0xff]
+        ^ T2[(int)(aa >> 40) & 0xff]
+        ^ T1[(int)(aa >> 56) & 0xff];
+    cc *= 5;
+    bb ^= x2;
+    cc -= T1[(int) bb        & 0xff]
+        ^ T2[(int)(bb >> 16) & 0xff]
+        ^ T3[(int)(bb >> 32) & 0xff]
+        ^ T4[(int)(bb >> 48) & 0xff];
+    aa += T4[(int)(bb >>  8) & 0xff]
+        ^ T3[(int)(bb >> 24) & 0xff]
+        ^ T2[(int)(bb >> 40) & 0xff]
+        ^ T1[(int)(bb >> 56) & 0xff];
+    aa *= 5;
+    cc ^= x3;
+    aa -= T1[(int) cc        & 0xff]
+        ^ T2[(int)(cc >> 16) & 0xff]
+        ^ T3[(int)(cc >> 32) & 0xff]
+        ^ T4[(int)(cc >> 48) & 0xff];
+    bb += T4[(int)(cc >>  8) & 0xff]
+        ^ T3[(int)(cc >> 24) & 0xff]
+        ^ T2[(int)(cc >> 40) & 0xff]
+        ^ T1[(int)(cc >> 56) & 0xff];
+    bb *= 5;
+    aa ^= x4;
+    bb -= T1[(int) aa        & 0xff]
+        ^ T2[(int)(aa >> 16) & 0xff]
+        ^ T3[(int)(aa >> 32) & 0xff]
+        ^ T4[(int)(aa >> 48) & 0xff];
+    cc += T4[(int)(aa >>  8) & 0xff]
+        ^ T3[(int)(aa >> 24) & 0xff]
+        ^ T2[(int)(aa >> 40) & 0xff]
+        ^ T1[(int)(aa >> 56) & 0xff];
+    cc *= 5;
+    bb ^= x5;
+    cc -= T1[(int) bb        & 0xff]
+        ^ T2[(int)(bb >> 16) & 0xff]
+        ^ T3[(int)(bb >> 32) & 0xff]
+        ^ T4[(int)(bb >> 48) & 0xff];
+    aa += T4[(int)(bb >>  8) & 0xff]
+        ^ T3[(int)(bb >> 24) & 0xff]
+        ^ T2[(int)(bb >> 40) & 0xff]
+        ^ T1[(int)(bb >> 56) & 0xff];
+    aa *= 5;
+    cc ^= x6;
+    aa -= T1[(int) cc        & 0xff]
+        ^ T2[(int)(cc >> 16) & 0xff]
+        ^ T3[(int)(cc >> 32) & 0xff]
+        ^ T4[(int)(cc >> 48) & 0xff];
+    bb += T4[(int)(cc >>  8) & 0xff]
+        ^ T3[(int)(cc >> 24) & 0xff]
+        ^ T2[(int)(cc >> 40) & 0xff]
+        ^ T1[(int)(cc >> 56) & 0xff];
+    bb *= 5;
+    aa ^= x7;
+    bb -= T1[(int) aa        & 0xff]
+        ^ T2[(int)(aa >> 16) & 0xff]
+        ^ T3[(int)(aa >> 32) & 0xff]
+        ^ T4[(int)(aa >> 48) & 0xff];
+    cc += T4[(int)(aa >>  8) & 0xff]
+        ^ T3[(int)(aa >> 24) & 0xff]
+        ^ T2[(int)(aa >> 40) & 0xff]
+        ^ T1[(int)(aa >> 56) & 0xff];
+    cc *= 5;
+    // key_schedule ::=
+    x0 -= x7 ^ 0xA5A5A5A5A5A5A5A5L;
+    x1 ^= x0;
+    x2 += x1;
+    x3 -= x2 ^ ((~x1) << 19);
+    x4 ^= x3;
+    x5 += x4;
+    x6 -= x5 ^ ((~x4) >>> 23);
+    x7 ^= x6;
+    x0 += x7;
+    x1 -= x0 ^ ((~x7) << 19);
+    x2 ^= x1;
+    x3 += x2;
+    x4 -= x3 ^ ((~x2) >>> 23);
+    x5 ^= x4;
+    x6 += x5;
+    x7 -= x6 ^ 0x0123456789ABCDEFL;
+    // pass(cc, aa, bb, 7) ::=
+    bb ^= x0;
+    cc -= T1[(int) bb        & 0xff]
+        ^ T2[(int)(bb >> 16) & 0xff]
+        ^ T3[(int)(bb >> 32) & 0xff]
+        ^ T4[(int)(bb >> 48) & 0xff];
+    aa += T4[(int)(bb >>  8) & 0xff]
+        ^ T3[(int)(bb >> 24) & 0xff]
+        ^ T2[(int)(bb >> 40) & 0xff]
+        ^ T1[(int)(bb >> 56) & 0xff];
+    aa *= 7;
+    cc ^= x1;
+    aa -= T1[(int) cc        & 0xff]
+        ^ T2[(int)(cc >> 16) & 0xff]
+        ^ T3[(int)(cc >> 32) & 0xff]
+        ^ T4[(int)(cc >> 48) & 0xff];
+    bb += T4[(int)(cc >>  8) & 0xff]
+        ^ T3[(int)(cc >> 24) & 0xff]
+        ^ T2[(int)(cc >> 40) & 0xff]
+        ^ T1[(int)(cc >> 56) & 0xff];
+    bb *= 7;
+    aa ^= x2;
+    bb -= T1[(int) aa        & 0xff]
+        ^ T2[(int)(aa >> 16) & 0xff]
+        ^ T3[(int)(aa >> 32) & 0xff]
+        ^ T4[(int)(aa >> 48) & 0xff];
+    cc += T4[(int)(aa >>  8) & 0xff]
+        ^ T3[(int)(aa >> 24) & 0xff]
+        ^ T2[(int)(aa >> 40) & 0xff]
+        ^ T1[(int)(aa >> 56) & 0xff];
+    cc *= 7;
+    bb ^= x3;
+    cc -= T1[(int) bb        & 0xff]
+        ^ T2[(int)(bb >> 16) & 0xff]
+        ^ T3[(int)(bb >> 32) & 0xff]
+        ^ T4[(int)(bb >> 48) & 0xff];
+    aa += T4[(int)(bb >>  8) & 0xff]
+        ^ T3[(int)(bb >> 24) & 0xff]
+        ^ T2[(int)(bb >> 40) & 0xff]
+        ^ T1[(int)(bb >> 56) & 0xff];
+    aa *= 7;
+    cc ^= x4;
+    aa -= T1[(int) cc        & 0xff]
+        ^ T2[(int)(cc >> 16) & 0xff]
+        ^ T3[(int)(cc >> 32) & 0xff]
+        ^ T4[(int)(cc >> 48) & 0xff];
+    bb += T4[(int)(cc >>  8) & 0xff]
+        ^ T3[(int)(cc >> 24) & 0xff]
+        ^ T2[(int)(cc >> 40) & 0xff]
+        ^ T1[(int)(cc >> 56) & 0xff];
+    bb *= 7;
+    aa ^= x5;
+    bb -= T1[(int) aa        & 0xff]
+        ^ T2[(int)(aa >> 16) & 0xff]
+        ^ T3[(int)(aa >> 32) & 0xff]
+        ^ T4[(int)(aa >> 48) & 0xff];
+    cc += T4[(int)(aa >>  8) & 0xff]
+        ^ T3[(int)(aa >> 24) & 0xff]
+        ^ T2[(int)(aa >> 40) & 0xff]
+        ^ T1[(int)(aa >> 56) & 0xff];
+    cc *= 7;
+    bb ^= x6;
+    cc -= T1[(int) bb        & 0xff]
+        ^ T2[(int)(bb >> 16) & 0xff]
+        ^ T3[(int)(bb >> 32) & 0xff]
+        ^ T4[(int)(bb >> 48) & 0xff];
+    aa += T4[(int)(bb >>  8) & 0xff]
+        ^ T3[(int)(bb >> 24) & 0xff]
+        ^ T2[(int)(bb >> 40) & 0xff]
+        ^ T1[(int)(bb >> 56) & 0xff];
+    aa *= 7;
+    cc ^= x7;
+    aa -= T1[(int) cc        & 0xff]
+        ^ T2[(int)(cc >> 16) & 0xff]
+        ^ T3[(int)(cc >> 32) & 0xff]
+        ^ T4[(int)(cc >> 48) & 0xff];
+    bb += T4[(int)(cc >>  8) & 0xff]
+        ^ T3[(int)(cc >> 24) & 0xff]
+        ^ T2[(int)(cc >> 40) & 0xff]
+        ^ T1[(int)(cc >> 56) & 0xff];
+    bb *= 7;
+    // key_schedule ::=
+    x0 -= x7 ^ 0xA5A5A5A5A5A5A5A5L;
+    x1 ^= x0;
+    x2 += x1;
+    x3 -= x2 ^ ((~x1) << 19);
+    x4 ^= x3;
+    x5 += x4;
+    x6 -= x5 ^ ((~x4) >>> 23);
+    x7 ^= x6;
+    x0 += x7;
+    x1 -= x0 ^ ((~x7) << 19);
+    x2 ^= x1;
+    x3 += x2;
+    x4 -= x3 ^ ((~x2) >>> 23);
+    x5 ^= x4;
+    x6 += x5;
+    x7 -= x6 ^ 0x0123456789ABCDEFL;
+    // pass(bb,cc,aa,9) ::=
+    aa ^= x0;
+    bb -= T1[(int) aa        & 0xff]
+        ^ T2[(int)(aa >> 16) & 0xff]
+        ^ T3[(int)(aa >> 32) & 0xff]
+        ^ T4[(int)(aa >> 48) & 0xff];
+    cc += T4[(int)(aa >>  8) & 0xff]
+        ^ T3[(int)(aa >> 24) & 0xff]
+        ^ T2[(int)(aa >> 40) & 0xff]
+        ^ T1[(int)(aa >> 56) & 0xff];
+    cc *= 9;
+    bb ^= x1;
+    cc -= T1[(int) bb        & 0xff]
+        ^ T2[(int)(bb >> 16) & 0xff]
+        ^ T3[(int)(bb >> 32) & 0xff]
+        ^ T4[(int)(bb >> 48) & 0xff];
+    aa += T4[(int)(bb >>  8) & 0xff]
+        ^ T3[(int)(bb >> 24) & 0xff]
+        ^ T2[(int)(bb >> 40) & 0xff]
+        ^ T1[(int)(bb >> 56) & 0xff];
+    aa *= 9;
+    cc ^= x2;
+    aa -= T1[(int) cc        & 0xff]
+        ^ T2[(int)(cc >> 16) & 0xff]
+        ^ T3[(int)(cc >> 32) & 0xff]
+        ^ T4[(int)(cc >> 48) & 0xff];
+    bb += T4[(int)(cc >>  8) & 0xff]
+        ^ T3[(int)(cc >> 24) & 0xff]
+        ^ T2[(int)(cc >> 40) & 0xff]
+        ^ T1[(int)(cc >> 56) & 0xff];
+    bb *= 9;
+    aa ^= x3;
+    bb -= T1[(int) aa        & 0xff]
+        ^ T2[(int)(aa >> 16) & 0xff]
+        ^ T3[(int)(aa >> 32) & 0xff]
+        ^ T4[(int)(aa >> 48) & 0xff];
+    cc += T4[(int)(aa >>  8) & 0xff]
+        ^ T3[(int)(aa >> 24) & 0xff]
+        ^ T2[(int)(aa >> 40) & 0xff]
+        ^ T1[(int)(aa >> 56) & 0xff];
+    cc *= 9;
+    bb ^= x4;
+    cc -= T1[(int) bb        & 0xff]
+        ^ T2[(int)(bb >> 16) & 0xff]
+        ^ T3[(int)(bb >> 32) & 0xff]
+        ^ T4[(int)(bb >> 48) & 0xff];
+    aa += T4[(int)(bb >>  8) & 0xff]
+        ^ T3[(int)(bb >> 24) & 0xff]
+        ^ T2[(int)(bb >> 40) & 0xff]
+        ^ T1[(int)(bb >> 56) & 0xff];
+    aa *= 9;
+    cc ^= x5;
+    aa -= T1[(int) cc        & 0xff]
+        ^ T2[(int)(cc >> 16) & 0xff]
+        ^ T3[(int)(cc >> 32) & 0xff]
+        ^ T4[(int)(cc >> 48) & 0xff];
+    bb += T4[(int)(cc >>  8) & 0xff]
+        ^ T3[(int)(cc >> 24) & 0xff]
+        ^ T2[(int)(cc >> 40) & 0xff]
+        ^ T1[(int)(cc >> 56) & 0xff];
+    bb *= 9;
+    aa ^= x6;
+    bb -= T1[(int) aa        & 0xff]
+        ^ T2[(int)(aa >> 16) & 0xff]
+        ^ T3[(int)(aa >> 32) & 0xff]
+        ^ T4[(int)(aa >> 48) & 0xff];
+    cc += T4[(int)(aa >>  8) & 0xff]
+        ^ T3[(int)(aa >> 24) & 0xff]
+        ^ T2[(int)(aa >> 40) & 0xff]
+        ^ T1[(int)(aa >> 56) & 0xff];
+    cc *= 9;
+    bb ^= x7;
+    cc -= T1[(int) bb        & 0xff]
+        ^ T2[(int)(bb >> 16) & 0xff]
+        ^ T3[(int)(bb >> 32) & 0xff]
+        ^ T4[(int)(bb >> 48) & 0xff];
+    aa += T4[(int)(bb >>  8) & 0xff]
+        ^ T3[(int)(bb >> 24) & 0xff]
+        ^ T2[(int)(bb >> 40) & 0xff]
+        ^ T1[(int)(bb >> 56) & 0xff];
+    aa *= 9;
+    // feedforward ::=
+    a ^= aa;
+    b = bb - b;
+    c += cc;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/hash/Whirlpool.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,606 @@
+/* Whirlpool.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.hash;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.util.logging.Logger;
+
+/**
+ * Whirlpool, a new 512-bit hashing function operating on messages less than
+ * 2 ** 256 bits in length. The function structure is designed according to the
+ * Wide Trail strategy and permits a wide variety of implementation trade-offs.
+ * <p>
+ * This implementation is of Whirlpool Version 3, described in [1] last revised
+ * on May 24th, 2003.
+ * <p>
+ * <b>IMPORTANT</b>: This implementation is not thread-safe.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html">
+ *    The WHIRLPOOL Hashing Function</a>.<br>
+ *    <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and
+ *    <a href="mailto:vincent.rijmen@iaik.tugraz.at">Vincent Rijmen</a>.</li>
+ * </ol>
+ */
+public final class Whirlpool
+    extends BaseHash
+{
+  private static final Logger log = Logger.getLogger(Whirlpool.class.getName());
+  private static final int BLOCK_SIZE = 64; // inner block size in bytes
+
+  /** The digest of the 0-bit long message. */
+  private static final String DIGEST0 =
+      "19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A7"
+    + "3E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3";
+
+  /** Default number of rounds. */
+  private static final int R = 10;
+
+  /** Whirlpool S-box; p. 19. */
+  private static final String S_box = // p. 19 [WHIRLPOOL]
+      "\u1823\uc6E8\u87B8\u014F\u36A6\ud2F5\u796F\u9152"
+    + "\u60Bc\u9B8E\uA30c\u7B35\u1dE0\ud7c2\u2E4B\uFE57"
+    + "\u1577\u37E5\u9FF0\u4AdA\u58c9\u290A\uB1A0\u6B85"
+    + "\uBd5d\u10F4\ucB3E\u0567\uE427\u418B\uA77d\u95d8"
+    + "\uFBEE\u7c66\udd17\u479E\ucA2d\uBF07\uAd5A\u8333"
+    + "\u6302\uAA71\uc819\u49d9\uF2E3\u5B88\u9A26\u32B0"
+    + "\uE90F\ud580\uBEcd\u3448\uFF7A\u905F\u2068\u1AAE"
+    + "\uB454\u9322\u64F1\u7312\u4008\uc3Ec\udBA1\u8d3d"
+    + "\u9700\ucF2B\u7682\ud61B\uB5AF\u6A50\u45F3\u30EF"
+    + "\u3F55\uA2EA\u65BA\u2Fc0\udE1c\uFd4d\u9275\u068A"
+    + "\uB2E6\u0E1F\u62d4\uA896\uF9c5\u2559\u8472\u394c"
+    + "\u5E78\u388c\ud1A5\uE261\uB321\u9c1E\u43c7\uFc04"
+    + "\u5199\u6d0d\uFAdF\u7E24\u3BAB\ucE11\u8F4E\uB7EB"
+    + "\u3c81\u94F7\uB913\u2cd3\uE76E\uc403\u5644\u7FA9"
+    + "\u2ABB\uc153\udc0B\u9d6c\u3174\uF646\uAc89\u14E1"
+    + "\u163A\u6909\u70B6\ud0Ed\ucc42\u98A4\u285c\uF886";
+
+  /** The 64-bit lookup tables; section 7.1 p. 13. */
+  private static final long[] T0 = new long[256];
+  private static final long[] T1 = new long[256];
+  private static final long[] T2 = new long[256];
+  private static final long[] T3 = new long[256];
+  private static final long[] T4 = new long[256];
+  private static final long[] T5 = new long[256];
+  private static final long[] T6 = new long[256];
+  private static final long[] T7 = new long[256];
+
+  /** The round constants. */
+  private static final long[] rc = new long[R];
+
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  /** The 512-bit context as 8 longs. */
+  private long H0, H1, H2, H3, H4, H5, H6, H7;
+
+  /** Work area for computing the round key schedule. */
+  private long k00, k01, k02, k03, k04, k05, k06, k07;
+  private long Kr0, Kr1, Kr2, Kr3, Kr4, Kr5, Kr6, Kr7;
+
+  /** work area for transforming the 512-bit buffer. */
+  private long n0, n1, n2, n3, n4, n5, n6, n7;
+  private long nn0, nn1, nn2, nn3, nn4, nn5, nn6, nn7;
+
+  /** work area for holding block cipher's intermediate values. */
+  private long w0, w1, w2, w3, w4, w5, w6, w7;
+
+  static
+    {
+      long time = System.currentTimeMillis();
+      int ROOT = 0x11D; // para. 2.1 [WHIRLPOOL]
+      int i, r, j;
+      long s1, s2, s4, s5, s8, s9, t;
+      char c;
+      final byte[] S = new byte[256];
+      for (i = 0; i < 256; i++)
+        {
+          c = S_box.charAt(i >>> 1);
+
+          s1 = ((i & 1) == 0 ? c >>> 8 : c) & 0xFFL;
+          s2 = s1 << 1;
+          if (s2 > 0xFFL)
+            s2 ^= ROOT;
+
+          s4 = s2 << 1;
+          if (s4 > 0xFFL)
+            s4 ^= ROOT;
+
+          s5 = s4 ^ s1;
+          s8 = s4 << 1;
+          if (s8 > 0xFFL)
+            s8 ^= ROOT;
+
+          s9 = s8 ^ s1;
+
+          T0[i] = t = s1 << 56 | s1 << 48 | s4 << 40 | s1 << 32
+                    | s8 << 24 | s5 << 16 | s2 <<  8 | s9;
+          T1[i] = t >>>  8 | t << 56;
+          T2[i] = t >>> 16 | t << 48;
+          T3[i] = t >>> 24 | t << 40;
+          T4[i] = t >>> 32 | t << 32;
+          T5[i] = t >>> 40 | t << 24;
+          T6[i] = t >>> 48 | t << 16;
+          T7[i] = t >>> 56 | t <<  8;
+        }
+      for (r = 0, i = 0; r < R; )
+        rc[r++] = (T0[i++] & 0xFF00000000000000L)
+                ^ (T1[i++] & 0x00FF000000000000L)
+                ^ (T2[i++] & 0x0000FF0000000000L)
+                ^ (T3[i++] & 0x000000FF00000000L)
+                ^ (T4[i++] & 0x00000000FF000000L)
+                ^ (T5[i++] & 0x0000000000FF0000L)
+                ^ (T6[i++] & 0x000000000000FF00L)
+                ^ (T7[i++] & 0x00000000000000FFL);
+      time = System.currentTimeMillis() - time;
+      if (Configuration.DEBUG)
+        {
+          log.fine("Static data");
+          log.fine("T0[]:");
+          StringBuilder sb;
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T0[i * 4 + j])).append(", ");
+
+              log.fine(sb.toString());
+            }
+          log.fine("T1[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T1[i * 4 + j])).append(", ");
+
+              log.fine(sb.toString());
+            }
+          log.fine("T2[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T2[i * 4 + j])).append(", ");
+
+              log.fine(sb.toString());
+            }
+          log.fine("T3[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T3[i * 4 + j])).append(", ");
+
+              log.fine(sb.toString());
+            }
+          log.fine("\nT4[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T4[i * 4 + j])).append(", ");
+
+              log.fine(sb.toString());
+            }
+          log.fine("T5[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", ");
+
+              log.fine(sb.toString());
+            }
+          log.fine("T6[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", ");
+
+              log.fine(sb.toString());
+            }
+          log.fine("T7[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", ");
+
+              log.fine(sb.toString());
+            }
+          log.fine("rc[]:");
+          for (i = 0; i < R; i++)
+            log.fine("0x" + Util.toString(rc[i]));
+
+          log.fine("Total initialization time: " + time + " ms.");
+        }
+    }
+
+  /** Trivial 0-arguments constructor. */
+  public Whirlpool()
+  {
+    super(Registry.WHIRLPOOL_HASH, 20, BLOCK_SIZE);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   *
+   * @param md the instance to clone.
+   */
+  private Whirlpool(Whirlpool md)
+  {
+    this();
+
+    this.H0 = md.H0;
+    this.H1 = md.H1;
+    this.H2 = md.H2;
+    this.H3 = md.H3;
+    this.H4 = md.H4;
+    this.H5 = md.H5;
+    this.H6 = md.H6;
+    this.H7 = md.H7;
+    this.count = md.count;
+    this.buffer = (byte[]) md.buffer.clone();
+  }
+
+  public Object clone()
+  {
+    return (new Whirlpool(this));
+  }
+
+  protected void transform(byte[] in, int offset)
+  {
+    // apply mu to the input
+    n0 = (in[offset++] & 0xFFL) << 56
+       | (in[offset++] & 0xFFL) << 48
+       | (in[offset++] & 0xFFL) << 40
+       | (in[offset++] & 0xFFL) << 32
+       | (in[offset++] & 0xFFL) << 24
+       | (in[offset++] & 0xFFL) << 16
+       | (in[offset++] & 0xFFL) <<  8
+       | (in[offset++] & 0xFFL);
+    n1 = (in[offset++] & 0xFFL) << 56
+       | (in[offset++] & 0xFFL) << 48
+       | (in[offset++] & 0xFFL) << 40
+       | (in[offset++] & 0xFFL) << 32
+       | (in[offset++] & 0xFFL) << 24
+       | (in[offset++] & 0xFFL) << 16
+       | (in[offset++] & 0xFFL) <<  8
+       | (in[offset++] & 0xFFL);
+    n2 = (in[offset++] & 0xFFL) << 56
+       | (in[offset++] & 0xFFL) << 48
+       | (in[offset++] & 0xFFL) << 40
+       | (in[offset++] & 0xFFL) << 32
+       | (in[offset++] & 0xFFL) << 24
+       | (in[offset++] & 0xFFL) << 16
+       | (in[offset++] & 0xFFL) <<  8
+       | (in[offset++] & 0xFFL);
+    n3 = (in[offset++] & 0xFFL) << 56
+       | (in[offset++] & 0xFFL) << 48
+       | (in[offset++] & 0xFFL) << 40
+       | (in[offset++] & 0xFFL) << 32
+       | (in[offset++] & 0xFFL) << 24
+       | (in[offset++] & 0xFFL) << 16
+       | (in[offset++] & 0xFFL) <<  8
+       | (in[offset++] & 0xFFL);
+    n4 = (in[offset++] & 0xFFL) << 56
+       | (in[offset++] & 0xFFL) << 48
+       | (in[offset++] & 0xFFL) << 40
+       | (in[offset++] & 0xFFL) << 32
+       | (in[offset++] & 0xFFL) << 24
+       | (in[offset++] & 0xFFL) << 16
+       | (in[offset++] & 0xFFL) <<  8
+       | (in[offset++] & 0xFFL);
+    n5 = (in[offset++] & 0xFFL) << 56
+       | (in[offset++] & 0xFFL) << 48
+       | (in[offset++] & 0xFFL) << 40
+       | (in[offset++] & 0xFFL) << 32
+       | (in[offset++] & 0xFFL) << 24
+       | (in[offset++] & 0xFFL) << 16
+       | (in[offset++] & 0xFFL) <<  8
+       | (in[offset++] & 0xFFL);
+    n6 = (in[offset++] & 0xFFL) << 56
+       | (in[offset++] & 0xFFL) << 48
+       | (in[offset++] & 0xFFL) << 40
+       | (in[offset++] & 0xFFL) << 32
+       | (in[offset++] & 0xFFL) << 24
+       | (in[offset++] & 0xFFL) << 16
+       | (in[offset++] & 0xFFL) <<  8
+       | (in[offset++] & 0xFFL);
+    n7 = (in[offset++] & 0xFFL) << 56
+       | (in[offset++] & 0xFFL) << 48
+       | (in[offset++] & 0xFFL) << 40
+       | (in[offset++] & 0xFFL) << 32
+       | (in[offset++] & 0xFFL) << 24
+       | (in[offset++] & 0xFFL) << 16
+       | (in[offset++] & 0xFFL) <<  8
+       | (in[offset++] & 0xFFL);
+    // transform K into the key schedule Kr; 0 <= r <= R
+    k00 = H0;
+    k01 = H1;
+    k02 = H2;
+    k03 = H3;
+    k04 = H4;
+    k05 = H5;
+    k06 = H6;
+    k07 = H7;
+    nn0 = n0 ^ k00;
+    nn1 = n1 ^ k01;
+    nn2 = n2 ^ k02;
+    nn3 = n3 ^ k03;
+    nn4 = n4 ^ k04;
+    nn5 = n5 ^ k05;
+    nn6 = n6 ^ k06;
+    nn7 = n7 ^ k07;
+    // intermediate cipher output
+    w0 = w1 = w2 = w3 = w4 = w5 = w6 = w7 = 0L;
+    for (int r = 0; r < R; r++)
+      {
+        // 1. compute intermediate round key schedule by applying ro[rc]
+        // to the previous round key schedule --rc being the round constant
+        Kr0 = T0[(int)((k00 >> 56) & 0xFFL)]
+            ^ T1[(int)((k07 >> 48) & 0xFFL)]
+            ^ T2[(int)((k06 >> 40) & 0xFFL)]
+            ^ T3[(int)((k05 >> 32) & 0xFFL)]
+            ^ T4[(int)((k04 >> 24) & 0xFFL)]
+            ^ T5[(int)((k03 >> 16) & 0xFFL)]
+            ^ T6[(int)((k02 >>  8) & 0xFFL)]
+            ^ T7[(int)( k01        & 0xFFL)] ^ rc[r];
+        Kr1 = T0[(int)((k01 >> 56) & 0xFFL)]
+            ^ T1[(int)((k00 >> 48) & 0xFFL)]
+            ^ T2[(int)((k07 >> 40) & 0xFFL)]
+            ^ T3[(int)((k06 >> 32) & 0xFFL)]
+            ^ T4[(int)((k05 >> 24) & 0xFFL)]
+            ^ T5[(int)((k04 >> 16) & 0xFFL)]
+            ^ T6[(int)((k03 >>  8) & 0xFFL)]
+            ^ T7[(int)( k02        & 0xFFL)];
+        Kr2 = T0[(int)((k02 >> 56) & 0xFFL)]
+            ^ T1[(int)((k01 >> 48) & 0xFFL)]
+            ^ T2[(int)((k00 >> 40) & 0xFFL)]
+            ^ T3[(int)((k07 >> 32) & 0xFFL)]
+            ^ T4[(int)((k06 >> 24) & 0xFFL)]
+            ^ T5[(int)((k05 >> 16) & 0xFFL)]
+            ^ T6[(int)((k04 >>  8) & 0xFFL)]
+            ^ T7[(int)( k03        & 0xFFL)];
+        Kr3 = T0[(int)((k03 >> 56) & 0xFFL)]
+            ^ T1[(int)((k02 >> 48) & 0xFFL)]
+            ^ T2[(int)((k01 >> 40) & 0xFFL)]
+            ^ T3[(int)((k00 >> 32) & 0xFFL)]
+            ^ T4[(int)((k07 >> 24) & 0xFFL)]
+            ^ T5[(int)((k06 >> 16) & 0xFFL)]
+            ^ T6[(int)((k05 >>  8) & 0xFFL)]
+            ^ T7[(int)( k04        & 0xFFL)];
+        Kr4 = T0[(int)((k04 >> 56) & 0xFFL)]
+            ^ T1[(int)((k03 >> 48) & 0xFFL)]
+            ^ T2[(int)((k02 >> 40) & 0xFFL)]
+            ^ T3[(int)((k01 >> 32) & 0xFFL)]
+            ^ T4[(int)((k00 >> 24) & 0xFFL)]
+            ^ T5[(int)((k07 >> 16) & 0xFFL)]
+            ^ T6[(int)((k06 >>  8) & 0xFFL)]
+            ^ T7[(int)( k05        & 0xFFL)];
+        Kr5 = T0[(int)((k05 >> 56) & 0xFFL)]
+            ^ T1[(int)((k04 >> 48) & 0xFFL)]
+            ^ T2[(int)((k03 >> 40) & 0xFFL)]
+            ^ T3[(int)((k02 >> 32) & 0xFFL)]
+            ^ T4[(int)((k01 >> 24) & 0xFFL)]
+            ^ T5[(int)((k00 >> 16) & 0xFFL)]
+            ^ T6[(int)((k07 >>  8) & 0xFFL)]
+            ^ T7[(int)( k06        & 0xFFL)];
+        Kr6 = T0[(int)((k06 >> 56) & 0xFFL)]
+            ^ T1[(int)((k05 >> 48) & 0xFFL)]
+            ^ T2[(int)((k04 >> 40) & 0xFFL)]
+            ^ T3[(int)((k03 >> 32) & 0xFFL)]
+            ^ T4[(int)((k02 >> 24) & 0xFFL)]
+            ^ T5[(int)((k01 >> 16) & 0xFFL)]
+            ^ T6[(int)((k00 >>  8) & 0xFFL)]
+            ^ T7[(int)( k07        & 0xFFL)];
+        Kr7 = T0[(int)((k07 >> 56) & 0xFFL)]
+            ^ T1[(int)((k06 >> 48) & 0xFFL)]
+            ^ T2[(int)((k05 >> 40) & 0xFFL)]
+            ^ T3[(int)((k04 >> 32) & 0xFFL)]
+            ^ T4[(int)((k03 >> 24) & 0xFFL)]
+            ^ T5[(int)((k02 >> 16) & 0xFFL)]
+            ^ T6[(int)((k01 >>  8) & 0xFFL)]
+            ^ T7[(int)( k00        & 0xFFL)];
+        k00 = Kr0;
+        k01 = Kr1;
+        k02 = Kr2;
+        k03 = Kr3;
+        k04 = Kr4;
+        k05 = Kr5;
+        k06 = Kr6;
+        k07 = Kr7;
+        // 2. incrementally compute the cipher output
+        w0 = T0[(int)((nn0 >> 56) & 0xFFL)]
+           ^ T1[(int)((nn7 >> 48) & 0xFFL)]
+           ^ T2[(int)((nn6 >> 40) & 0xFFL)]
+           ^ T3[(int)((nn5 >> 32) & 0xFFL)]
+           ^ T4[(int)((nn4 >> 24) & 0xFFL)]
+           ^ T5[(int)((nn3 >> 16) & 0xFFL)]
+           ^ T6[(int)((nn2 >>  8) & 0xFFL)]
+           ^ T7[(int)( nn1        & 0xFFL)] ^ Kr0;
+        w1 = T0[(int)((nn1 >> 56) & 0xFFL)]
+           ^ T1[(int)((nn0 >> 48) & 0xFFL)]
+           ^ T2[(int)((nn7 >> 40) & 0xFFL)]
+           ^ T3[(int)((nn6 >> 32) & 0xFFL)]
+           ^ T4[(int)((nn5 >> 24) & 0xFFL)]
+           ^ T5[(int)((nn4 >> 16) & 0xFFL)]
+           ^ T6[(int)((nn3 >>  8) & 0xFFL)]
+           ^ T7[(int)( nn2        & 0xFFL)] ^ Kr1;
+        w2 = T0[(int)((nn2 >> 56) & 0xFFL)]
+           ^ T1[(int)((nn1 >> 48) & 0xFFL)]
+           ^ T2[(int)((nn0 >> 40) & 0xFFL)]
+           ^ T3[(int)((nn7 >> 32) & 0xFFL)]
+           ^ T4[(int)((nn6 >> 24) & 0xFFL)]
+           ^ T5[(int)((nn5 >> 16) & 0xFFL)]
+           ^ T6[(int)((nn4 >>  8) & 0xFFL)]
+           ^ T7[(int)( nn3        & 0xFFL)] ^ Kr2;
+        w3 = T0[(int)((nn3 >> 56) & 0xFFL)]
+           ^ T1[(int)((nn2 >> 48) & 0xFFL)]
+           ^ T2[(int)((nn1 >> 40) & 0xFFL)]
+           ^ T3[(int)((nn0 >> 32) & 0xFFL)]
+           ^ T4[(int)((nn7 >> 24) & 0xFFL)]
+           ^ T5[(int)((nn6 >> 16) & 0xFFL)]
+           ^ T6[(int)((nn5 >>  8) & 0xFFL)]
+           ^ T7[(int)( nn4        & 0xFFL)] ^ Kr3;
+        w4 = T0[(int)((nn4 >> 56) & 0xFFL)]
+           ^ T1[(int)((nn3 >> 48) & 0xFFL)]
+           ^ T2[(int)((nn2 >> 40) & 0xFFL)]
+           ^ T3[(int)((nn1 >> 32) & 0xFFL)]
+           ^ T4[(int)((nn0 >> 24) & 0xFFL)]
+           ^ T5[(int)((nn7 >> 16) & 0xFFL)]
+           ^ T6[(int)((nn6 >>  8) & 0xFFL)]
+           ^ T7[(int)( nn5        & 0xFFL)] ^ Kr4;
+        w5 = T0[(int)((nn5 >> 56) & 0xFFL)]
+           ^ T1[(int)((nn4 >> 48) & 0xFFL)]
+           ^ T2[(int)((nn3 >> 40) & 0xFFL)]
+           ^ T3[(int)((nn2 >> 32) & 0xFFL)]
+           ^ T4[(int)((nn1 >> 24) & 0xFFL)]
+           ^ T5[(int)((nn0 >> 16) & 0xFFL)]
+           ^ T6[(int)((nn7 >>  8) & 0xFFL)]
+           ^ T7[(int)( nn6        & 0xFFL)] ^ Kr5;
+        w6 = T0[(int)((nn6 >> 56) & 0xFFL)]
+           ^ T1[(int)((nn5 >> 48) & 0xFFL)]
+           ^ T2[(int)((nn4 >> 40) & 0xFFL)]
+           ^ T3[(int)((nn3 >> 32) & 0xFFL)]
+           ^ T4[(int)((nn2 >> 24) & 0xFFL)]
+           ^ T5[(int)((nn1 >> 16) & 0xFFL)]
+           ^ T6[(int)((nn0 >>  8) & 0xFFL)]
+           ^ T7[(int)( nn7        & 0xFFL)] ^ Kr6;
+        w7 = T0[(int)((nn7 >> 56) & 0xFFL)]
+           ^ T1[(int)((nn6 >> 48) & 0xFFL)]
+           ^ T2[(int)((nn5 >> 40) & 0xFFL)]
+           ^ T3[(int)((nn4 >> 32) & 0xFFL)]
+           ^ T4[(int)((nn3 >> 24) & 0xFFL)]
+           ^ T5[(int)((nn2 >> 16) & 0xFFL)]
+           ^ T6[(int)((nn1 >>  8) & 0xFFL)]
+           ^ T7[(int)( nn0        & 0xFFL)] ^ Kr7;
+        nn0 = w0;
+        nn1 = w1;
+        nn2 = w2;
+        nn3 = w3;
+        nn4 = w4;
+        nn5 = w5;
+        nn6 = w6;
+        nn7 = w7;
+      }
+    // apply the Miyaguchi-Preneel hash scheme
+    H0 ^= w0 ^ n0;
+    H1 ^= w1 ^ n1;
+    H2 ^= w2 ^ n2;
+    H3 ^= w3 ^ n3;
+    H4 ^= w4 ^ n4;
+    H5 ^= w5 ^ n5;
+    H6 ^= w6 ^ n6;
+    H7 ^= w7 ^ n7;
+  }
+
+  protected byte[] padBuffer()
+  {
+    // [WHIRLPOOL] p. 6:
+    // "...padded with a 1-bit, then with as few 0-bits as necessary to
+    // obtain a bit string whose length is an odd multiple of 256, and
+    // finally with the 256-bit right-justified binary representation of L."
+    // in this implementation we use 'count' as the number of bytes hashed
+    // so far. hence the minimal number of bytes added to the message proper
+    // are 33 (1 for the 1-bit followed by the 0-bits and the encoding of
+    // the count framed in a 256-bit block). our formula is then:
+    //		count + 33 + padding = 0 (mod BLOCK_SIZE)
+    int n = (int)((count + 33) % BLOCK_SIZE);
+    int padding = n == 0 ? 33 : BLOCK_SIZE - n + 33;
+    byte[] result = new byte[padding];
+    // padding is always binary 1 followed by binary 0s
+    result[0] = (byte) 0x80;
+    // save (right justified) the number of bits hashed
+    long bits = count * 8;
+    int i = padding - 8;
+    result[i++] = (byte)(bits >>> 56);
+    result[i++] = (byte)(bits >>> 48);
+    result[i++] = (byte)(bits >>> 40);
+    result[i++] = (byte)(bits >>> 32);
+    result[i++] = (byte)(bits >>> 24);
+    result[i++] = (byte)(bits >>> 16);
+    result[i++] = (byte)(bits >>>  8);
+    result[i  ] = (byte) bits;
+    return result;
+  }
+
+  protected byte[] getResult()
+  {
+    // apply inverse mu to the context
+    return new byte[] {
+      (byte)(H0 >>> 56), (byte)(H0 >>> 48), (byte)(H0 >>> 40), (byte)(H0 >>> 32),
+      (byte)(H0 >>> 24), (byte)(H0 >>> 16), (byte)(H0 >>>  8), (byte) H0,
+      (byte)(H1 >>> 56), (byte)(H1 >>> 48), (byte)(H1 >>> 40), (byte)(H1 >>> 32),
+      (byte)(H1 >>> 24), (byte)(H1 >>> 16), (byte)(H1 >>>  8), (byte) H1,
+      (byte)(H2 >>> 56), (byte)(H2 >>> 48), (byte)(H2 >>> 40), (byte)(H2 >>> 32),
+      (byte)(H2 >>> 24), (byte)(H2 >>> 16), (byte)(H2 >>>  8), (byte) H2,
+      (byte)(H3 >>> 56), (byte)(H3 >>> 48), (byte)(H3 >>> 40), (byte)(H3 >>> 32),
+      (byte)(H3 >>> 24), (byte)(H3 >>> 16), (byte)(H3 >>>  8), (byte) H3,
+      (byte)(H4 >>> 56), (byte)(H4 >>> 48), (byte)(H4 >>> 40), (byte)(H4 >>> 32),
+      (byte)(H4 >>> 24), (byte)(H4 >>> 16), (byte)(H4 >>>  8), (byte) H4,
+      (byte)(H5 >>> 56), (byte)(H5 >>> 48), (byte)(H5 >>> 40), (byte)(H5 >>> 32),
+      (byte)(H5 >>> 24), (byte)(H5 >>> 16), (byte)(H5 >>>  8), (byte) H5,
+      (byte)(H6 >>> 56), (byte)(H6 >>> 48), (byte)(H6 >>> 40), (byte)(H6 >>> 32),
+      (byte)(H6 >>> 24), (byte)(H6 >>> 16), (byte)(H6 >>>  8), (byte) H6,
+      (byte)(H7 >>> 56), (byte)(H7 >>> 48), (byte)(H7 >>> 40), (byte)(H7 >>> 32),
+      (byte)(H7 >>> 24), (byte)(H7 >>> 16), (byte)(H7 >>>  8), (byte) H7 };
+
+  }
+
+  protected void resetContext()
+  {
+    H0 = H1 = H2 = H3 = H4 = H5 = H6 = H7 = 0L;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        String d = Util.toString(new Whirlpool().digest());
+        valid = Boolean.valueOf(DIGEST0.equals(d));
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/HavalSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HavalSpi.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HAVAL <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class HavalSpi
+    extends MessageDigestAdapter
+{
+  public HavalSpi()
+  {
+    super(Registry.HAVAL_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/MD2Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,55 @@
+/* MD2Spi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the MD2 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * adapter.
+ */
+public class MD2Spi
+    extends MessageDigestAdapter
+{
+  /** Trivial 0-arguments constructor. */
+  public MD2Spi()
+  {
+    super(Registry.MD2_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/MD4Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,55 @@
+/* MD4Spi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the MD4 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * adapter.
+ */
+public class MD4Spi
+    extends MessageDigestAdapter
+{
+  /** Trivial 0-arguments constructor. */
+  public MD4Spi()
+  {
+    super(Registry.MD4_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/MD5Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* MD5Spi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the MD5 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * adapter.
+ */
+public class MD5Spi
+    extends MessageDigestAdapter
+{
+  public MD5Spi()
+  {
+    super(Registry.MD5_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/MessageDigestAdapter.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,133 @@
+/* MessageDigestAdapter.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.hash.HashFactory;
+
+import java.security.DigestException;
+import java.security.MessageDigestSpi;
+
+/**
+ * The implementation of a generic {@link java.security.MessageDigest} adapter
+ * class to wrap GNU hash instances.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link java.security.MessageDigest} class, which provides the
+ * functionality of a message digest algorithm, such as MD5 or SHA. Message
+ * digests are secure one-way hash functions that take arbitrary-sized data and
+ * output a fixed-length hash value.
+ * <p>
+ * All the abstract methods in the {@link MessageDigestSpi} class are
+ * implemented by this class and all its sub-classes.
+ * <p>
+ * All the implementations which subclass this object, and which are serviced by
+ * the GNU provider implement the {@link Cloneable} interface.
+ */
+class MessageDigestAdapter
+    extends MessageDigestSpi
+    implements Cloneable
+{
+  /** Our underlying hash instance. */
+  private IMessageDigest adaptee;
+
+  /**
+   * Trivial protected constructor.
+   * 
+   * @param mdName the canonical name of the hash algorithm.
+   */
+  protected MessageDigestAdapter(String mdName)
+  {
+    this(HashFactory.getInstance(mdName));
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   * 
+   * @param adaptee a clone of the underlying hash algorithm instance.
+   */
+  private MessageDigestAdapter(IMessageDigest adaptee)
+  {
+    super();
+
+    this.adaptee = adaptee;
+  }
+
+  public Object clone()
+  {
+    return new MessageDigestAdapter((IMessageDigest) adaptee.clone());
+  }
+
+  public int engineGetDigestLength()
+  {
+    return adaptee.hashSize();
+  }
+
+  public void engineUpdate(byte input)
+  {
+    adaptee.update(input);
+  }
+
+  public void engineUpdate(byte[] input, int offset, int len)
+  {
+    adaptee.update(input, offset, len);
+  }
+
+  public byte[] engineDigest()
+  {
+    return adaptee.digest();
+  }
+
+  public int engineDigest(byte[] buf, int offset, int len)
+      throws DigestException
+  {
+    int result = adaptee.hashSize();
+    if (len < result)
+      throw new DigestException();
+
+    byte[] md = adaptee.digest();
+    System.arraycopy(md, 0, buf, offset, result);
+    return result;
+  }
+
+  public void engineReset()
+  {
+    adaptee.reset();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/RipeMD128Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* RipeMD128Spi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the RIPEMD-128 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class RipeMD128Spi
+    extends MessageDigestAdapter
+{
+  public RipeMD128Spi()
+  {
+    super(Registry.RIPEMD128_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/RipeMD160Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* RipeMD160Spi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the RIPEMD-160 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class RipeMD160Spi
+    extends MessageDigestAdapter
+{
+  public RipeMD160Spi()
+  {
+    super(Registry.RIPEMD160_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/Sha160Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* Sha160Spi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the SHA-1 (160-bit) <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class Sha160Spi
+    extends MessageDigestAdapter
+{
+  public Sha160Spi()
+  {
+    super(Registry.SHA160_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/Sha256Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* Sha256Spi.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the SHA-2-1 (256-bit) <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class Sha256Spi
+    extends MessageDigestAdapter
+{
+  public Sha256Spi()
+  {
+    super(Registry.SHA256_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/Sha384Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* Sha384Spi.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the SHA-2-2 (384-bit) <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class Sha384Spi
+    extends MessageDigestAdapter
+{
+  public Sha384Spi()
+  {
+    super(Registry.SHA384_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/Sha512Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* Sha512Spi.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the SHA-2-3 (512-bit) <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class Sha512Spi
+    extends MessageDigestAdapter
+{
+  public Sha512Spi()
+  {
+    super(Registry.SHA512_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/TigerSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,55 @@
+/* TigerSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Tiger <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class TigerSpi
+    extends MessageDigestAdapter
+{
+  /** Trivial 0-arguments constructor. */
+  public TigerSpi()
+  {
+    super(Registry.TIGER_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/hash/WhirlpoolSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* WhirlpoolSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.hash;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Whirlpool <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class WhirlpoolSpi
+    extends MessageDigestAdapter
+{
+  public WhirlpoolSpi()
+  {
+    super(Registry.WHIRLPOOL_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/HavalRandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HavalRandomSpi.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HAVAL-based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class HavalRandomSpi
+    extends SecureRandomAdapter
+{
+  public HavalRandomSpi()
+  {
+    super(Registry.HAVAL_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/MD2RandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* MD2RandomSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the MD2-based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class MD2RandomSpi
+    extends SecureRandomAdapter
+{
+  public MD2RandomSpi()
+  {
+    super(Registry.MD2_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/MD4RandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* MD4RandomSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the MD4-based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class MD4RandomSpi
+    extends SecureRandomAdapter
+{
+  public MD4RandomSpi()
+  {
+    super(Registry.MD4_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/MD5RandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* MD5RandomSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the MD5-based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class MD5RandomSpi
+    extends SecureRandomAdapter
+{
+  public MD5RandomSpi()
+  {
+    super(Registry.MD5_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/RipeMD128RandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* RipeMD128RandomSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the RIPEMD128-based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class RipeMD128RandomSpi
+    extends SecureRandomAdapter
+{
+  public RipeMD128RandomSpi()
+  {
+    super(Registry.RIPEMD128_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/RipeMD160RandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* RipeMD160RandomSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the RIPEMD160-based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class RipeMD160RandomSpi
+    extends SecureRandomAdapter
+{
+  public RipeMD160RandomSpi()
+  {
+    super(Registry.RIPEMD160_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/SecureRandomAdapter.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,107 @@
+/* SecureRandomAdapter.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.prng.MDGenerator;
+
+import java.security.SecureRandomSpi;
+import java.util.Collections;
+
+/**
+ * The implementation of a generic {@link java.security.SecureRandom} adapter
+ * class to wrap GNU PRNG instances based on Message Digest algorithms.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link java.security.SecureRandom} class, which provides the
+ * functionality of a cryptographically strong pseudo-random number generator.
+ * <p>
+ * All the abstract methods in the {@link SecureRandomSpi} class are implemented
+ * by this class and all its sub-classes.
+ */
+abstract class SecureRandomAdapter
+    extends SecureRandomSpi
+{
+  /** Our underlying prng instance. */
+  private MDGenerator adaptee = new MDGenerator();
+
+  /** The name of the message digest algorithm used by the adaptee. */
+  private String mdName;
+
+  /**
+   * Trivial protected constructor.
+   * 
+   * @param mdName the canonical name of the underlying hash algorithm.
+   */
+  protected SecureRandomAdapter(String mdName)
+  {
+    super();
+
+    this.mdName = mdName;
+    adaptee.init(Collections.singletonMap(MDGenerator.MD_NAME, mdName));
+  }
+
+  public byte[] engineGenerateSeed(int numBytes)
+  {
+    if (numBytes < 1)
+      return new byte[0];
+
+    byte[] result = new byte[numBytes];
+    this.engineNextBytes(result);
+    return result;
+  }
+
+  public void engineNextBytes(byte[] bytes)
+  {
+    if (! adaptee.isInitialised())
+      this.engineSetSeed(new byte[0]);
+    try
+      {
+        adaptee.nextBytes(bytes, 0, bytes.length);
+      }
+    catch (LimitReachedException ignored)
+      {
+      }
+  }
+
+  public void engineSetSeed(byte[] seed)
+  {
+    adaptee.addRandomBytes(seed);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/Sha160RandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* Sha160RandomSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the SHA1-based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class Sha160RandomSpi
+    extends SecureRandomAdapter
+{
+  public Sha160RandomSpi()
+  {
+    super(Registry.SHA160_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/Sha256RandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* Sha256RandomSpi.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the SHA-256 based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class Sha256RandomSpi
+    extends SecureRandomAdapter
+{
+  public Sha256RandomSpi()
+  {
+    super(Registry.SHA256_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/Sha384RandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* Sha384RandomSpi.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the SHA-384 based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class Sha384RandomSpi
+    extends SecureRandomAdapter
+{
+  public Sha384RandomSpi()
+  {
+    super(Registry.SHA384_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/Sha512RandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* Sha512RandomSpi.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the SHA-512 based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class Sha512RandomSpi
+    extends SecureRandomAdapter
+{
+  public Sha512RandomSpi()
+  {
+    super(Registry.SHA512_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/TigerRandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* TigerRandomSpi.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Tiger based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class TigerRandomSpi
+    extends SecureRandomAdapter
+{
+  public TigerRandomSpi()
+  {
+    super(Registry.TIGER_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* WhirlpoolRandomSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.prng;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Whirlpool-based SecureRandom <i>Service Provider
+ * Interface</i> (<b>SPI</b>) adapter.
+ */
+public class WhirlpoolRandomSpi
+    extends SecureRandomAdapter
+{
+  public WhirlpoolRandomSpi()
+  {
+    super(Registry.WHIRLPOOL_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/DSSKeyFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,221 @@
+/* DSSKeyFactory.java -- JCE DSA key factory Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec;
+import gnu.java.security.key.dss.DSSKeyPairX509Codec;
+import gnu.java.security.key.dss.DSSPrivateKey;
+import gnu.java.security.key.dss.DSSPublicKey;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * DSA key factory.
+ * 
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class DSSKeyFactory
+    extends KeyFactorySpi
+{
+  // implicit 0-arguments constructor
+
+  protected PublicKey engineGeneratePublic(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (keySpec instanceof DSAPublicKeySpec)
+      {
+        DSAPublicKeySpec spec = (DSAPublicKeySpec) keySpec;
+        BigInteger p = spec.getP();
+        BigInteger q = spec.getQ();
+        BigInteger g = spec.getG();
+        BigInteger y = spec.getY();
+        return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y);
+      }
+    if (keySpec instanceof X509EncodedKeySpec)
+      {
+        X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec;
+        byte[] encoded = spec.getEncoded();
+        PublicKey result;
+        try
+          {
+            result = new DSSKeyPairX509Codec().decodePublicKey(encoded);
+            return result;
+          }
+        catch (RuntimeException x)
+          {
+            throw new InvalidKeySpecException(x.getMessage(), x);
+          }
+      }
+    throw new InvalidKeySpecException("Unsupported (public) key specification");
+  }
+
+  protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (keySpec instanceof DSAPrivateKeySpec)
+      {
+        DSAPrivateKeySpec spec = (DSAPrivateKeySpec) keySpec;
+        BigInteger p = spec.getP();
+        BigInteger q = spec.getQ();
+        BigInteger g = spec.getG();
+        BigInteger x = spec.getX();
+        return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);
+      }
+    if (keySpec instanceof PKCS8EncodedKeySpec)
+      {
+        PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec;
+        byte[] encoded = spec.getEncoded();
+        PrivateKey result;
+        try
+          {
+            result = new DSSKeyPairPKCS8Codec().decodePrivateKey(encoded);
+            return result;
+          }
+        catch (RuntimeException x)
+          {
+            throw new InvalidKeySpecException(x.getMessage(), x);
+          }
+      }
+    throw new InvalidKeySpecException("Unsupported (private) key specification");
+  }
+
+  protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+      throws InvalidKeySpecException
+  {
+    if (key instanceof DSAPublicKey)
+      {
+        if (keySpec.isAssignableFrom(DSAPublicKeySpec.class))
+          {
+            DSAPublicKey dsaKey = (DSAPublicKey) key;
+            BigInteger p = dsaKey.getParams().getP();
+            BigInteger q = dsaKey.getParams().getQ();
+            BigInteger g = dsaKey.getParams().getG();
+            BigInteger y = dsaKey.getY();
+            return new DSAPublicKeySpec(y, p, q, g);
+          }
+        if (keySpec.isAssignableFrom(X509EncodedKeySpec.class))
+          {
+            if (key instanceof DSSPublicKey)
+              {
+                DSSPublicKey dssKey = (DSSPublicKey) key;
+                byte[] encoded = dssKey.getEncoded(Registry.X509_ENCODING_ID);
+                return new X509EncodedKeySpec(encoded);
+              }
+            if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat()))
+              {
+                byte[] encoded = key.getEncoded();
+                return new X509EncodedKeySpec(encoded);
+              }
+            throw new InvalidKeySpecException(
+                "Wrong key type or unsupported (public) key specification");
+          }
+        throw new InvalidKeySpecException("Unsupported (public) key specification");
+      }
+    if (key instanceof DSAPrivateKey)
+      {
+        if (keySpec.isAssignableFrom(DSAPrivateKeySpec.class))
+          {
+            DSAPrivateKey dsaKey = (DSAPrivateKey) key;
+            BigInteger p = dsaKey.getParams().getP();
+            BigInteger q = dsaKey.getParams().getQ();
+            BigInteger g = dsaKey.getParams().getG();
+            BigInteger x = dsaKey.getX();
+            return new DSAPrivateKeySpec(x, p, q, g);
+          }
+        if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class))
+          {
+            if (key instanceof DSSPrivateKey)
+              {
+                DSSPrivateKey dssKey = (DSSPrivateKey) key;
+                byte[] encoded = dssKey.getEncoded(Registry.PKCS8_ENCODING_ID);
+                return new PKCS8EncodedKeySpec(encoded);
+              }
+            if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat()))
+              {
+                byte[] encoded = key.getEncoded();
+                return new PKCS8EncodedKeySpec(encoded);
+              }
+            throw new InvalidKeySpecException(
+                "Wrong key type or unsupported (private) key specification");
+          }
+        throw new InvalidKeySpecException("Unsupported (private) key specification");
+      }
+    throw new InvalidKeySpecException("Wrong key type or unsupported key specification");
+  }
+
+  protected Key engineTranslateKey(Key key) throws InvalidKeyException
+  {
+    if ((key instanceof DSSPublicKey) || (key instanceof DSSPrivateKey))
+      return key;
+
+    if (key instanceof DSAPublicKey)
+      {
+        DSAPublicKey dsaKey = (DSAPublicKey) key;
+        BigInteger p = dsaKey.getParams().getP();
+        BigInteger q = dsaKey.getParams().getQ();
+        BigInteger g = dsaKey.getParams().getG();
+        BigInteger y = dsaKey.getY();
+        return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y);
+      }
+    if (key instanceof DSAPrivateKey)
+      {
+        DSAPrivateKey dsaKey = (DSAPrivateKey) key;
+        BigInteger p = dsaKey.getParams().getP();
+        BigInteger q = dsaKey.getParams().getQ();
+        BigInteger g = dsaKey.getParams().getG();
+        BigInteger x = dsaKey.getX();
+        return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);
+      }
+    throw new InvalidKeyException("Wrong key type");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,146 @@
+/* DSSKeyPairGeneratorSpi.java -- 
+   Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.dss.DSSKeyPairGenerator;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.interfaces.DSAKeyPairGenerator;
+import java.security.interfaces.DSAParams;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.util.HashMap;
+
+/**
+ * The implementation of a {@link java.security.KeyPairGenerator} adapter class
+ * to wrap GNU DSS keypair generator instances.
+ * <p>
+ * In case the client does not explicitly initialize the KeyPairGenerator (via a
+ * call to an <code>initialize()</code> method), the GNU provider uses a
+ * default <i>modulus</i> size (keysize) of 1024 bits.
+ */
+public class DSSKeyPairGeneratorSpi
+    extends KeyPairGeneratorAdapter
+    implements DSAKeyPairGenerator
+{
+  public DSSKeyPairGeneratorSpi()
+  {
+    super(Registry.DSS_KPG);
+  }
+
+  public void initialize(int keysize, SecureRandom random)
+  {
+    this.initialize(keysize, false, random);
+  }
+
+  public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+      throws InvalidAlgorithmParameterException
+  {
+    HashMap attributes = new HashMap();
+    if (params != null)
+      {
+        if (! (params instanceof DSAParameterSpec))
+          throw new InvalidAlgorithmParameterException(
+              "Parameters argument is not a non-null instance, or "
+              + "sub-instance, of java.security.spec.DSAParameterSpec");
+        attributes.put(DSSKeyPairGenerator.DSS_PARAMETERS, params);
+      }
+    if (random != null)
+      attributes.put(DSSKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
+
+    attributes.put(DSSKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   Integer.valueOf(Registry.ASN1_ENCODING_ID));
+    try
+      {
+        adaptee.setup(attributes);
+      }
+    catch (IllegalArgumentException x)
+      {
+        throw new InvalidAlgorithmParameterException(x.getMessage(), x);
+      }
+  }
+
+  public void initialize(DSAParams params, SecureRandom random)
+      throws InvalidParameterException
+  {
+    if (params == null || !(params instanceof DSAParameterSpec))
+      throw new InvalidParameterException(
+          "Parameters argument is either null or is not an instance, or "
+          + "sub-instance, of java.security.spec.DSAParameterSpec");
+    DSAParameterSpec spec = (DSAParameterSpec) params;
+    try
+      {
+        this.initialize((AlgorithmParameterSpec) spec, random);
+      }
+    catch (InvalidAlgorithmParameterException x)
+      {
+        InvalidParameterException y = new InvalidParameterException(x.getMessage());
+        y.initCause(x);
+        throw y;
+      }
+  }
+
+  public void initialize(int modlen, boolean genParams, SecureRandom random)
+      throws InvalidParameterException
+  {
+    HashMap attributes = new HashMap();
+    attributes.put(DSSKeyPairGenerator.MODULUS_LENGTH, Integer.valueOf(modlen));
+    if (random != null)
+      attributes.put(DSSKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
+
+    attributes.put(DSSKeyPairGenerator.USE_DEFAULTS,
+                   Boolean.valueOf(! genParams));
+    attributes.put(DSSKeyPairGenerator.STRICT_DEFAULTS, Boolean.TRUE);
+    attributes.put(DSSKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   Integer.valueOf(Registry.ASN1_ENCODING_ID));
+    try
+      {
+        adaptee.setup(attributes);
+      }
+    catch (IllegalArgumentException x)
+      {
+        InvalidParameterException y = new InvalidParameterException(x.getMessage());
+        y.initCause(x);
+        throw y;
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/DSSParameters.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,218 @@
+/* DSSParameters.java -- DSS parameters DAO
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.util.DerUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.ArrayList;
+
+/**
+ * A JCE-specific Data Access Object (DAO) for DSS parameters.
+ */
+public class DSSParameters
+    extends AlgorithmParametersSpi
+{
+  /**
+   * A prime modulus, where <code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code>
+   * for <code>512 &lt;= L &lt;= 1024</code> and <code>L</code> a multiple of
+   * <code>64</code>.
+   */
+  private BigInteger p;
+
+  /**
+   * A prime divisor of <code>p - 1</code>, where <code>2<sup>159</sup> &lt; q
+   * &lt; 2<sup>160</sup></code>.
+   */
+  private BigInteger q;
+
+  /**
+   * <code>g = h<sup>(p-1)</sup>/q mod p</code>, where <code>h</code> is any
+   * integer with <code>1 &lt; h &lt; p - 1</code> such that <code>h<sup>
+   * (p-1)</sup>/q mod p > 1</code> (<code>g</code> has order <code>q mod p
+   * </code>).
+   */
+  private BigInteger g;
+
+  // default 0-arguments constructor
+
+  protected void engineInit(AlgorithmParameterSpec spec)
+      throws InvalidParameterSpecException
+  {
+    if (! (spec instanceof DSAParameterSpec))
+      throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: "
+                                              + spec.getClass().getName());
+    DSAParameterSpec dsaSpec = (DSAParameterSpec) spec;
+    p = dsaSpec.getP();
+    q = dsaSpec.getQ();
+    g = dsaSpec.getG();
+  }
+
+  /**
+   * Decodes the set of DSS parameters as per RFC-2459; i.e. the DER-encoded
+   * form of the following ASN.1 construct: 
+   * 
+   * <pre>
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * </pre>
+   */
+  protected void engineInit(byte[] params) throws IOException
+  {
+    DERReader der = new DERReader(params);
+
+    DERValue derParams = der.read();
+    DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
+
+    DERValue val = der.read();
+    DerUtil.checkIsBigInteger(val, "Wrong P field");
+    p = (BigInteger) val.getValue();
+    val = der.read();
+    DerUtil.checkIsBigInteger(val, "Wrong Q field");
+    q = (BigInteger) val.getValue();
+    val = der.read();
+    DerUtil.checkIsBigInteger(val, "Wrong G field");
+    g = (BigInteger) val.getValue();
+  }
+
+  protected void engineInit(byte[] params, String format) throws IOException
+  {
+    if (format != null)
+      {
+        format = format.trim();
+        if (format.length() == 0)
+          throw new IOException("Format MUST NOT be an empty string");
+
+        if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME))
+          throw new IOException("Unknown or unsupported format: " + format);
+      }
+    engineInit(params);
+  }
+
+  protected AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec)
+      throws InvalidParameterSpecException
+  {
+    if (! paramSpec.isAssignableFrom(DSAParameterSpec.class))
+      throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: "
+                                              + paramSpec.getName());
+    return new DSAParameterSpec(p, q, g);
+  }
+
+  /**
+   * Encodes the set of DSS parameters as per RFC-2459; i.e. as the DER-encoded
+   * form of the following ASN.1 construct: 
+   * 
+   * <pre>
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * </pre>
+   */
+  protected byte[] engineGetEncoded() throws IOException
+  {
+    DERValue derP = new DERValue(DER.INTEGER, p);
+    DERValue derQ = new DERValue(DER.INTEGER, q);
+    DERValue derG = new DERValue(DER.INTEGER, g);
+
+    ArrayList params = new ArrayList(3);
+    params.add(derP);
+    params.add(derQ);
+    params.add(derG);
+    DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    DERWriter.write(baos, derParams);
+    byte[] result = baos.toByteArray();
+
+    return result;
+  }
+
+  protected byte[] engineGetEncoded(String format) throws IOException
+  {
+    if (format != null)
+      {
+        format = format.trim();
+        if (format.length() == 0)
+          throw new IOException("Format MUST NOT be an empty string");
+
+        if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME))
+          throw new IOException("Unknown or unsupported format: " + format);
+      }
+    return engineGetEncoded();
+  }
+
+  protected String engineToString()
+  {
+    StringBuffer sb = new StringBuffer("p=");
+    if (p == null)
+      sb.append("???");
+    else
+      sb.append("0x").append(p.toString(16));
+
+    sb.append(", q=");
+    if (q == null)
+      sb.append("???");
+    else
+      sb.append("0x").append(q.toString(16));
+
+    sb.append(", g=");
+    if (g == null)
+      sb.append("???");
+    else
+      sb.append("0x").append(g.toString(16));
+
+    return sb.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/DSSParametersGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,125 @@
+/* DSSParametersGenerator.java -- JCE Adapter for a generator of DSS parameters
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.dss.DSSKeyPairGenerator;
+import gnu.java.security.key.dss.FIPS186;
+import gnu.java.security.provider.Gnu;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * A JCE Adapter for a generator of DSS parameters.
+ */
+public class DSSParametersGenerator
+    extends AlgorithmParameterGeneratorSpi
+{
+  private static final Provider GNU = new Gnu();
+
+  /** Size of the public modulus in bits. */
+  private int modulusLength = -1;
+
+  /** User specified source of randomness. */
+  private SecureRandom rnd;
+
+  /** Our concrete DSS parameters generator. */
+  private FIPS186 fips;
+
+  // default 0-arguments constructor
+
+  protected void engineInit(int size, SecureRandom random)
+  {
+    if ((size % 64) != 0 || size < 512 || size > 1024)
+      throw new InvalidParameterException("Modulus size/length (in bits) MUST "
+                                          + "be a multiple of 64, greater than "
+                                          + "or equal to 512, and less than or "
+                                          + "equal to 1024");
+    this.modulusLength = size;
+    this.rnd = random;
+  }
+
+  protected void engineInit(AlgorithmParameterSpec spec, SecureRandom random)
+      throws InvalidAlgorithmParameterException
+  {
+    if (! (spec instanceof DSAParameterSpec))
+      throw new InvalidAlgorithmParameterException("Wrong AlgorithmParameterSpec type: "
+                                                   + spec.getClass().getName());
+    DSAParameterSpec dsaSpec = (DSAParameterSpec) spec;
+    BigInteger p = dsaSpec.getP();
+    int size = p.bitLength();
+    this.engineInit(size, random);
+  }
+
+  protected AlgorithmParameters engineGenerateParameters()
+  {
+    if (modulusLength < 1)
+      modulusLength = DSSKeyPairGenerator.DEFAULT_MODULUS_LENGTH;
+
+    fips = new FIPS186(modulusLength, rnd);
+    BigInteger[] params = fips.generateParameters();
+    BigInteger p = params[3];
+    BigInteger q = params[2];
+    BigInteger g = params[5];
+    DSAParameterSpec spec = new DSAParameterSpec(p, q, g);
+    AlgorithmParameters result = null;
+    try
+      {
+        result = AlgorithmParameters.getInstance(Registry.DSS_KPG, GNU);
+        result.init(spec);
+      }
+    catch (NoSuchAlgorithmException ignore)
+      {
+      }
+    catch (InvalidParameterSpecException ignore)
+      {
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/DSSRawSignatureSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,56 @@
+/* DSSRawSignatureSpi.java -- 
+   Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.dss.DSSSignatureRawCodec;
+
+/**
+ * The implementation of <i>Service Provider Interface</i> (<b>SPI</b>)
+ * adapter for the DSS (Digital Signature Standard) signature scheme, encoded
+ * and/or decoded in RAW format.
+ */
+public class DSSRawSignatureSpi
+    extends SignatureAdapter
+{
+  public DSSRawSignatureSpi()
+  {
+    super(Registry.DSS_SIG, new DSSSignatureRawCodec());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/EncodedKeyFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,430 @@
+/* EncodedKeyFactory.java -- JCE Encoded key factory Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.key.dss.DSSPrivateKey;
+import gnu.java.security.key.dss.DSSPublicKey;
+import gnu.java.security.key.rsa.GnuRSAPrivateKey;
+import gnu.java.security.key.rsa.GnuRSAPublicKey;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+/**
+ * A factory for keys encoded in either the X.509 format (for public keys) or
+ * the PKCS#8 format (for private keys).
+ */
+public class EncodedKeyFactory
+    extends KeyFactorySpi
+{
+  private static final Logger log = Logger.getLogger(EncodedKeyFactory.class.getName());
+
+  private static Object invokeConstructor(String className, Object[] params)
+      throws InvalidKeySpecException
+  {
+    Class clazz = getConcreteClass(className);
+    try
+      {
+        Constructor ctor = getConcreteCtor(clazz);
+        Object result = ctor.newInstance(params);
+        return result;
+      }
+    catch (InstantiationException x)
+      {
+        throw new InvalidKeySpecException(x.getMessage(), x);
+      }
+    catch (IllegalAccessException x)
+      {
+        throw new InvalidKeySpecException(x.getMessage(), x);
+      }
+    catch (InvocationTargetException x)
+      {
+        throw new InvalidKeySpecException(x.getMessage(), x);
+      }
+  }
+
+  private static Class getConcreteClass(String className)
+      throws InvalidKeySpecException
+  {
+    try
+      {
+        Class result = Class.forName(className);
+        return result;
+      }
+    catch (ClassNotFoundException x)
+      {
+        throw new InvalidKeySpecException(x.getMessage(), x);
+      }
+  }
+
+  private static Constructor getConcreteCtor(Class clazz)
+      throws InvalidKeySpecException
+  {
+    try
+      {
+        Constructor result = clazz.getConstructor(new Class[] {int.class,
+                                                               BigInteger.class,
+                                                               BigInteger.class,
+                                                               BigInteger.class,
+                                                               BigInteger.class});
+        return result;
+      }
+    catch (NoSuchMethodException x)
+      {
+        throw new InvalidKeySpecException(x.getMessage(), x);
+      }
+  }
+
+  private static Object invokeValueOf(String className, byte[] encoded)
+      throws InvalidKeySpecException
+  {
+    Class clazz = getConcreteClass(className);
+    try
+      {
+        Method valueOf = getValueOfMethod(clazz);
+        Object result = valueOf.invoke(null, new Object[] { encoded });
+        return result;
+      }
+    catch (IllegalAccessException x)
+      {
+        throw new InvalidKeySpecException(x.getMessage(), x);
+      }
+    catch (InvocationTargetException x)
+      {
+        throw new InvalidKeySpecException(x.getMessage(), x);
+      }
+  }
+
+  private static Method getValueOfMethod(Class clazz)
+      throws InvalidKeySpecException
+  {
+    try
+      {
+        Method result = clazz.getMethod("valueOf", new Class[] {byte[].class});
+        return result;
+      }
+    catch (NoSuchMethodException x)
+      {
+        throw new InvalidKeySpecException(x.getMessage(), x);
+      }
+  }
+
+  protected PublicKey engineGeneratePublic(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineGeneratePublic()", keySpec);
+    PublicKey result = null;
+    if (keySpec instanceof DSAPublicKeySpec)
+      result = decodeDSSPublicKey((DSAPublicKeySpec) keySpec);
+    else if (keySpec instanceof RSAPublicKeySpec)
+      result = decodeRSAPublicKey((RSAPublicKeySpec) keySpec);
+    else if (keySpec instanceof DHPublicKeySpec)
+      result = decodeDHPublicKey((DHPublicKeySpec) keySpec);
+    else
+      {
+        if (! (keySpec instanceof X509EncodedKeySpec))
+          throw new InvalidKeySpecException("Unsupported key specification");
+
+        byte[] input = ((X509EncodedKeySpec) keySpec).getEncoded();
+        boolean ok = false;
+        // try DSS
+        try
+          {
+            result = DSSPublicKey.valueOf(input);
+            ok = true;
+          }
+        catch (InvalidParameterException ignored)
+          {
+            if (Configuration.DEBUG)
+              log.log(Level.FINE, "Exception in DSSPublicKey.valueOf(). Ignore",
+                      ignored);
+          }
+        if (! ok) // try RSA
+          try
+            {
+              result = GnuRSAPublicKey.valueOf(input);
+              ok = true;
+            }
+          catch (InvalidParameterException ignored)
+            {
+              if (Configuration.DEBUG)
+                log.log(Level.FINE,
+                        "Exception in GnuRSAPublicKey.valueOf(). Ignore",
+                        ignored);
+            }
+          if (! ok) // try DH
+            result = decodeDHPublicKey(input);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineGeneratePublic()", result);
+    return result;
+  }
+
+  protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineGeneratePrivate()", keySpec);
+    PrivateKey result = null;
+    if (keySpec instanceof DSAPrivateKeySpec)
+      result = decodeDSSPrivateKey((DSAPrivateKeySpec) keySpec);
+    else if (keySpec instanceof RSAPrivateCrtKeySpec)
+      result = decodeRSAPrivateKey((RSAPrivateCrtKeySpec) keySpec);
+    else if (keySpec instanceof DHPrivateKeySpec)
+      result = decodeDHPrivateKey((DHPrivateKeySpec) keySpec);
+    else
+      {
+        if (! (keySpec instanceof PKCS8EncodedKeySpec))
+          throw new InvalidKeySpecException("Unsupported key specification");
+
+        byte[] input = ((PKCS8EncodedKeySpec) keySpec).getEncoded();
+        boolean ok = false;
+        // try DSS
+        try
+          {
+            result = DSSPrivateKey.valueOf(input);
+            ok = true;
+          }
+        catch (InvalidParameterException ignored)
+          {
+            if (Configuration.DEBUG)
+              log.log(Level.FINE, "Exception in DSSPrivateKey.valueOf(). Ignore",
+                      ignored);
+          }
+        if (! ok) // try RSA
+          try
+            {
+              result = GnuRSAPrivateKey.valueOf(input);
+              ok = true;
+            }
+          catch (InvalidParameterException ignored)
+            {
+              if (Configuration.DEBUG)
+                log.log(Level.FINE,
+                        "Exception in GnuRSAPrivateKey.valueOf(). Ignore",
+                        ignored);
+            }
+        if (! ok) // try DH
+          result = decodeDHPrivateKey(input);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineGeneratePrivate()", result);
+    return result;
+  }
+
+  protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+      throws InvalidKeySpecException
+  {
+    if (key instanceof PublicKey
+        && Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat())
+        && keySpec.isAssignableFrom(X509EncodedKeySpec.class))
+      return new X509EncodedKeySpec(key.getEncoded());
+
+    if (key instanceof PrivateKey
+        && Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())
+        && keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class))
+      return new PKCS8EncodedKeySpec(key.getEncoded());
+
+    throw new InvalidKeySpecException("Unsupported format or invalid key spec class");
+  }
+
+  protected Key engineTranslateKey(Key key) throws InvalidKeyException
+  {
+    throw new InvalidKeyException("Key translation not supported");
+  }
+
+  /**
+   * @param spec an instance of {@link DSAPublicKeySpec} to decode.
+   * @return an instance of {@link DSSPublicKey} constructed from the
+   *         information in the designated key-specification.
+   */
+  private DSSPublicKey decodeDSSPublicKey(DSAPublicKeySpec spec)
+  {
+    BigInteger p = spec.getP();
+    BigInteger q = spec.getQ();
+    BigInteger g = spec.getG();
+    BigInteger y = spec.getY();
+    return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y);
+  }
+
+  /**
+   * @param spec an instance of {@link RSAPublicKeySpec} to decode.
+   * @return an instance of {@link GnuRSAPublicKey} constructed from the
+   *         information in the designated key-specification.
+   */
+  private GnuRSAPublicKey decodeRSAPublicKey(RSAPublicKeySpec spec)
+  {
+    BigInteger n = spec.getModulus();
+    BigInteger e = spec.getPublicExponent();
+    return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e);
+  }
+
+  /**
+   * @param spec an instance of {@link DHPublicKeySpec} to decode.
+   * @return an instance of a {@link DHPublicKey} constructed from the
+   *         information in the designated key-specification.
+   * @throws InvalidKeySpecException if no concrete implementation of the
+   *           {@link DHPublicKey} interface exists at run-time, or if an
+   *           exception occurs during its instantiation.
+   */
+  private DHPublicKey decodeDHPublicKey(DHPublicKeySpec spec)
+      throws InvalidKeySpecException
+  {
+    BigInteger p = spec.getP();
+    BigInteger g = spec.getG();
+    BigInteger y = spec.getY();
+    Object[] params = new Object[] {Integer.valueOf(Registry.X509_ENCODING_ID),
+                                    null, p, g, y};
+    Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPublicKey",
+                                   params);
+    return (DHPublicKey) obj;
+  }
+
+  /**
+   * @param encoded the bytes to decode.
+   * @return an instance of a {@link DHPublicKey} constructed from the
+   *         information in the designated key-specification.
+   * @throws InvalidKeySpecException if no concrete implementation of the
+   *           {@link DHPublicKey} interface exists at run-time, or if an
+   *           exception occurs during its instantiation.
+   */
+  private DHPublicKey decodeDHPublicKey(byte[] encoded)
+      throws InvalidKeySpecException
+  {
+    Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPublicKey",
+                               encoded);
+    return (DHPublicKey) obj;
+  }
+
+  /**
+   * @param spec an instance of {@link DSAPrivateKeySpec} to decode.
+   * @return an instance of {@link DSSPrivateKey} constructed from the
+   *         information in the designated key-specification.
+   */
+  private PrivateKey decodeDSSPrivateKey(DSAPrivateKeySpec spec)
+  {
+    BigInteger p = spec.getP();
+    BigInteger q = spec.getQ();
+    BigInteger g = spec.getG();
+    BigInteger x = spec.getX();
+    return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);
+  }
+
+  /**
+   * @param spec an instance of {@link RSAPrivateCrtKeySpec} to decode.
+   * @return an instance of {@link GnuRSAPrivateKey} constructed from the
+   *         information in the designated key-specification.
+   */
+  private PrivateKey decodeRSAPrivateKey(RSAPrivateCrtKeySpec spec)
+  {
+    BigInteger n = spec.getModulus();
+    BigInteger e = spec.getPublicExponent();
+    BigInteger d = spec.getPrivateExponent();
+    BigInteger p = spec.getPrimeP();
+    BigInteger q = spec.getPrimeQ();
+    BigInteger dP = spec.getPrimeExponentP();
+    BigInteger dQ = spec.getPrimeExponentQ();
+    BigInteger qInv = spec.getCrtCoefficient();
+    return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID,
+                                n, e, d, p, q, dP, dQ, qInv);
+  }
+
+  /**
+   * @param spec an instance of {@link DHPrivateKeySpec} to decode.
+   * @return an instance of a {@link DHPrivateKey} constructed from the
+   *         information in the designated key-specification.
+   * @throws InvalidKeySpecException if no concrete implementation of the
+   *           {@link DHPrivateKey} interface exists at run-time, or if an
+   *           exception occurs during its instantiation.
+   */
+  private DHPrivateKey decodeDHPrivateKey(DHPrivateKeySpec spec)
+      throws InvalidKeySpecException
+  {
+    BigInteger p = spec.getP();
+    BigInteger g = spec.getG();
+    BigInteger x = spec.getX();
+    Object[] params = new Object[] {Integer.valueOf(Registry.PKCS8_ENCODING_ID),
+                                    null, p, g, x};
+    Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPrivateKey",
+                                   params);
+    return (DHPrivateKey) obj;
+  }
+
+  /**
+   * @param encoded the bytes to decode.
+   * @return an instance of a {@link DHPrivateKey} constructed from the
+   *         information in the designated key-specification.
+   * @throws InvalidKeySpecException if no concrete implementation of the
+   *           {@link DHPrivateKey} interface exists at run-time, or if an
+   *           exception occurs during its instantiation.
+   */
+  private DHPrivateKey decodeDHPrivateKey(byte[] encoded)
+      throws InvalidKeySpecException
+  {
+    Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPrivateKey",
+                               encoded);
+    return (DHPrivateKey) obj;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,95 @@
+/* KeyPairGeneratorAdapter.java -- 
+   Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.java.security.key.KeyPairGeneratorFactory;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * The implementation of a generic {@link java.security.KeyPairGenerator}
+ * adapter class to wrap GNU keypair generator instances.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link java.security.KeyPairGenerator} class, which is used to generate
+ * pairs of public and private keys.
+ * <p>
+ * All the abstract methods in the {@link java.security.KeyPairGeneratorSpi}
+ * class are implemented by this class and all its sub-classes.
+ * <p>
+ * In case the client does not explicitly initialize the KeyPairGenerator (via a
+ * call to an <code>initialize()</code> method), the GNU provider supplies
+ * (and document) default values to be used. For example, the GNU provider uses
+ * a default <i>modulus</i> size (keysize) of 1024 bits for the DSS (Digital
+ * Signature Standard) a.k.a <i>DSA</i>.
+ */
+public abstract class KeyPairGeneratorAdapter
+    extends KeyPairGenerator
+{
+  /** Our underlying keypair instance. */
+  protected IKeyPairGenerator adaptee;
+
+  /**
+   * Trivial protected constructor.
+   * 
+   * @param kpgName the canonical name of the keypair generator algorithm.
+   */
+  protected KeyPairGeneratorAdapter(String kpgName)
+  {
+    super(kpgName);
+
+    this.adaptee = KeyPairGeneratorFactory.getInstance(kpgName);
+  }
+
+  public abstract void initialize(int keysize, SecureRandom random);
+
+  public abstract void initialize(AlgorithmParameterSpec params,
+                                  SecureRandom random)
+      throws InvalidAlgorithmParameterException;
+
+  public KeyPair generateKeyPair()
+  {
+    return adaptee.generate();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/MD2withRSA.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,56 @@
+/* MD2WithRSA.java -- RSA PKCS1 with MD2 JCE signature Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
+
+/**
+ * A JCE Adapter for the RSA PKCS1 (v1.5) signature with MD2 hash and X.509
+ * encoding format.
+ */
+public class MD2withRSA
+    extends SignatureAdapter
+{
+  public MD2withRSA()
+  {
+    super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD2_HASH,
+          new RSAPKCS1V1_5SignatureX509Codec());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/MD5withRSA.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,56 @@
+/* MD5withRSA.java -- RSA PKCS1 with MD5 JCE signature Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
+
+/**
+ * A JCE Adapter for the RSA PKCS1 (v1.5) signature with MD5 hash and X.509
+ * encoding format.
+ */
+public class MD5withRSA
+    extends SignatureAdapter
+{
+  public MD5withRSA()
+  {
+    super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD5_HASH,
+          new RSAPKCS1V1_5SignatureX509Codec());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/RSAKeyFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,231 @@
+/* RSAKeyFactory.java -- RSA key-factory JCE Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.rsa.GnuRSAPrivateKey;
+import gnu.java.security.key.rsa.GnuRSAPublicKey;
+import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec;
+import gnu.java.security.key.rsa.RSAKeyPairX509Codec;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+public class RSAKeyFactory
+    extends KeyFactorySpi
+{
+  // implicit 0-arguments constructor
+
+  protected PublicKey engineGeneratePublic(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (keySpec instanceof RSAPublicKeySpec)
+      {
+        RSAPublicKeySpec spec = (RSAPublicKeySpec) keySpec;
+        BigInteger n = spec.getModulus();
+        BigInteger e = spec.getPublicExponent();
+        return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e);
+      }
+    if (keySpec instanceof X509EncodedKeySpec)
+      {
+        X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec;
+        byte[] encoded = spec.getEncoded();
+        PublicKey result;
+        try
+          {
+            return new RSAKeyPairX509Codec().decodePublicKey(encoded);
+          }
+        catch (RuntimeException x)
+          {
+            throw new InvalidKeySpecException(x.getMessage(), x);
+          }
+      }
+    throw new InvalidKeySpecException("Unsupported (public) key specification");
+  }
+
+  protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (keySpec instanceof RSAPrivateCrtKeySpec)
+      {
+        RSAPrivateCrtKeySpec spec = (RSAPrivateCrtKeySpec) keySpec;
+        BigInteger n = spec.getModulus();
+        BigInteger e = spec.getPublicExponent();
+        BigInteger d = spec.getPrivateExponent();
+        BigInteger p = spec.getPrimeP();
+        BigInteger q = spec.getPrimeQ();
+        BigInteger dP = spec.getPrimeExponentP();
+        BigInteger dQ = spec.getPrimeExponentQ();
+        BigInteger qInv = spec.getCrtCoefficient();
+        return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID,
+                                    n, e, d, p, q, dP, dQ, qInv);
+      }
+    if (keySpec instanceof PKCS8EncodedKeySpec)
+      {
+        PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec;
+        byte[] encoded = spec.getEncoded();
+        PrivateKey result;
+        try
+          {
+            return new RSAKeyPairPKCS8Codec().decodePrivateKey(encoded);
+          }
+        catch (RuntimeException x)
+          {
+            throw new InvalidKeySpecException(x.getMessage(), x);
+          }
+      }
+    throw new InvalidKeySpecException("Unsupported (private) key specification");
+  }
+
+  protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+      throws InvalidKeySpecException
+  {
+    if (key instanceof RSAPublicKey)
+      {
+        if (keySpec.isAssignableFrom(RSAPublicKeySpec.class))
+        {
+          RSAPublicKey rsaKey = (RSAPublicKey) key;
+          BigInteger n = rsaKey.getModulus();
+          BigInteger e = rsaKey.getPublicExponent();
+          return new RSAPublicKeySpec(n, e);
+        }
+        if (keySpec.isAssignableFrom(X509EncodedKeySpec.class))
+          {
+            if (key instanceof GnuRSAPublicKey)
+              {
+                GnuRSAPublicKey rsaKey = (GnuRSAPublicKey) key;
+                byte[] encoded = rsaKey.getEncoded(Registry.X509_ENCODING_ID);
+                return new X509EncodedKeySpec(encoded);
+              }
+
+            if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat()))
+              {
+                byte[] encoded = key.getEncoded();
+                return new X509EncodedKeySpec(encoded);
+              }
+            throw new InvalidKeySpecException(
+                "Wrong key type or unsupported (public) key specification");
+          }
+        throw new InvalidKeySpecException("Unsupported (public) key specification");
+      }
+    if ((key instanceof RSAPrivateCrtKey)
+        && keySpec.isAssignableFrom(RSAPrivateCrtKeySpec.class))
+      {
+        RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;
+        BigInteger n = rsaKey.getModulus();
+        BigInteger e = rsaKey.getPublicExponent();
+        BigInteger d = rsaKey.getPrivateExponent();
+        BigInteger p = rsaKey.getPrimeP();
+        BigInteger q = rsaKey.getPrimeQ();
+        BigInteger dP = rsaKey.getPrimeExponentP();
+        BigInteger dQ = rsaKey.getPrimeExponentQ();
+        BigInteger qInv = rsaKey.getCrtCoefficient();
+        return new RSAPrivateCrtKeySpec(n, e, d, p, q, dP, dQ, qInv);
+      }
+    if ((key instanceof RSAPrivateKey)
+        && keySpec.isAssignableFrom(RSAPrivateKeySpec.class))
+      {
+        RSAPrivateKey rsaKey = (RSAPrivateKey) key;
+        BigInteger n = rsaKey.getModulus();
+        BigInteger d = rsaKey.getPrivateExponent();
+        return new RSAPrivateKeySpec(n, d);
+      }
+    if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class))
+      {
+        if (key instanceof GnuRSAPrivateKey)
+          {
+            GnuRSAPrivateKey rsaKey = (GnuRSAPrivateKey) key;
+            byte[] encoded = rsaKey.getEncoded(Registry.PKCS8_ENCODING_ID);
+            return new PKCS8EncodedKeySpec(encoded);
+          }
+        if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat()))
+          {
+            byte[] encoded = key.getEncoded();
+            return new PKCS8EncodedKeySpec(encoded);
+          }
+        throw new InvalidKeySpecException(
+            "Wrong key type or unsupported (private) key specification");
+      }
+    throw new InvalidKeySpecException(
+        "Wrong key type or unsupported key specification");
+  }
+
+  protected Key engineTranslateKey(Key key) throws InvalidKeyException
+  {
+    if ((key instanceof GnuRSAPublicKey) || (key instanceof GnuRSAPrivateKey))
+      return key;
+
+    if (key instanceof RSAPublicKey)
+      {
+        RSAPublicKey rsaKey = (RSAPublicKey) key;
+        BigInteger n = rsaKey.getModulus();
+        BigInteger e = rsaKey.getPublicExponent();
+        return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e);
+      }
+    if (key instanceof RSAPrivateCrtKey)
+      {
+        RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;
+        BigInteger n = rsaKey.getModulus();
+        BigInteger e = rsaKey.getPublicExponent();
+        BigInteger d = rsaKey.getPrivateExponent();
+        BigInteger p = rsaKey.getPrimeP();
+        BigInteger q = rsaKey.getPrimeQ();
+        BigInteger dP = rsaKey.getPrimeExponentP();
+        BigInteger dQ = rsaKey.getPrimeExponentQ();
+        BigInteger qInv = rsaKey.getCrtCoefficient();
+        return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID,
+                                    n, e, d, p, q, dP, dQ, qInv);
+      }
+    throw new InvalidKeyException("Unsupported key type");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,96 @@
+/* RSAKeyPairGeneratorSpi.java -- JCE RSA KeyPairGenerator Adapter
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.rsa.RSAKeyPairGenerator;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+import java.util.HashMap;
+
+/**
+ * The implementation of a {@link java.security.KeyPairGenerator} adapter class
+ * to wrap GNU RSA keypair generator instances.
+ * <p>
+ * In case the client does not explicitly initialize the KeyPairGenerator (via a
+ * call to an <code>initialize()</code> method), the GNU provider uses a
+ * default <i>modulus</i> size (keysize) of 1024 bits.
+ */
+public class RSAKeyPairGeneratorSpi
+    extends KeyPairGeneratorAdapter
+{
+  public RSAKeyPairGeneratorSpi()
+  {
+    super(Registry.RSA_KPG);
+  }
+
+  public void initialize(int keysize, SecureRandom random)
+  {
+    HashMap attributes = new HashMap();
+    attributes.put(RSAKeyPairGenerator.MODULUS_LENGTH, Integer.valueOf(keysize));
+    if (random != null)
+      attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
+
+    attributes.put(RSAKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   Integer.valueOf(Registry.ASN1_ENCODING_ID));
+    adaptee.setup(attributes);
+  }
+
+  public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+      throws InvalidAlgorithmParameterException
+  {
+    HashMap attributes = new HashMap();
+    if (params != null)
+      {
+        if (! (params instanceof RSAKeyGenParameterSpec))
+          throw new InvalidAlgorithmParameterException("params");
+
+        attributes.put(RSAKeyPairGenerator.RSA_PARAMETERS, params);
+      }
+    if (random != null)
+      attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
+
+    attributes.put(RSAKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   Integer.valueOf(Registry.ASN1_ENCODING_ID));
+    adaptee.setup(attributes);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,56 @@
+/* RSAPSSRawSignatureSpi.java -- 
+   Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.rsa.RSAPSSSignatureRawCodec;
+
+/**
+ * The implementation of <i>Service Provider Interface</i> (<b>SPI</b>)
+ * adapter for the RSA-PSS signature scheme, encoded and/or decoded in RAW
+ * format.
+ */
+public class RSAPSSRawSignatureSpi
+    extends SignatureAdapter
+{
+  public RSAPSSRawSignatureSpi()
+  {
+    super(Registry.RSA_PSS_SIG, new RSAPSSSignatureRawCodec());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/SHA160withDSS.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* SHA160withDSS.java -- JCE Adapter for DSS with SHA1 signatures
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.dss.DSSSignatureX509Codec;
+
+/**
+ * A JCE Adapter for providing X.509 formatted DSS with SHA1 signatures.
+ */
+public class SHA160withDSS
+    extends SignatureAdapter
+{
+  public SHA160withDSS()
+  {
+    super(Registry.DSS_SIG, new DSSSignatureX509Codec());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/SHA160withRSA.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,56 @@
+/* SHA160withRSA.java -- RSA PKCS1 with SHA160 JCE signature Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
+
+/**
+ * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA160 hash and X.509
+ * encoding format.
+ */
+public class SHA160withRSA
+    extends SignatureAdapter
+{
+  public SHA160withRSA()
+  {
+    super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA160_HASH,
+          new RSAPKCS1V1_5SignatureX509Codec());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/SHA256withRSA.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,56 @@
+/* SHA256withRSA.java -- RSA PKCS1 with SHA256 JCE signature Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
+
+/**
+ * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA256 hash and X.509
+ * encoding format.
+ */
+public class SHA256withRSA
+    extends SignatureAdapter
+{
+  public SHA256withRSA()
+  {
+    super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA256_HASH,
+          new RSAPKCS1V1_5SignatureX509Codec());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/SHA384withRSA.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,56 @@
+/* SHA384withRSA.java -- RSA PKCS1 with SHA384 JCE signature Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
+
+/**
+ * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA384 hash and X.509
+ * encoding format.
+ */
+public class SHA384withRSA
+    extends SignatureAdapter
+{
+  public SHA384withRSA()
+  {
+    super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA384_HASH,
+          new RSAPKCS1V1_5SignatureX509Codec());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/SHA512withRSA.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,56 @@
+/* SHA512withRSA.java -- RSA PKCS1 with SHA512 JCE signature Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
+
+/**
+ * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA512 hash and X.509
+ * encoding format.
+ */
+public class SHA512withRSA
+    extends SignatureAdapter
+{
+  public SHA512withRSA()
+  {
+    super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA512_HASH,
+          new RSAPKCS1V1_5SignatureX509Codec());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/jce/sig/SignatureAdapter.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,250 @@
+/* SignatureAdapter.java -- 
+   Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.jce.sig;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.sig.BaseSignature;
+import gnu.java.security.sig.ISignature;
+import gnu.java.security.sig.ISignatureCodec;
+import gnu.java.security.sig.SignatureFactory;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.logging.Logger;
+
+/**
+ * The implementation of a generic {@link java.security.Signature} adapter class
+ * to wrap GNU signature instances.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link java.security.Signature} class, which provides the functionality
+ * of a digital signature algorithm. Digital signatures are used for
+ * authentication and integrity assurance of digital data.
+ * <p>
+ * All the abstract methods in the {@link SignatureSpi} class are implemented by
+ * this class and all its sub-classes.
+ * <p>
+ * All the implementations which subclass this object, and which are serviced by
+ * the GNU provider implement the {@link Cloneable} interface.
+ */
+class SignatureAdapter
+    extends SignatureSpi
+    implements Cloneable
+{
+  private static final Logger log = Logger.getLogger(SignatureAdapter.class.getName());
+
+  /** Our underlying signature instance. */
+  private ISignature adaptee;
+
+  /** Our underlying signature encoder/decoder engine. */
+  private ISignatureCodec codec;
+
+  /**
+   * Trivial protected constructor.
+   * 
+   * @param sigName the canonical name of the signature scheme.
+   * @param codec the signature codec engine to use with this scheme.
+   */
+  protected SignatureAdapter(String sigName, ISignatureCodec codec)
+  {
+    this(SignatureFactory.getInstance(sigName), codec);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   * 
+   * @param adaptee a clone of the underlying signature scheme instance.
+   * @param codec the signature codec engine to use with this scheme.
+   */
+  private SignatureAdapter(ISignature adaptee, ISignatureCodec codec)
+  {
+    super();
+
+    this.adaptee = adaptee;
+    this.codec = codec;
+  }
+
+  public Object clone()
+  {
+    return new SignatureAdapter((ISignature) adaptee.clone(), codec);
+  }
+
+  public void engineInitVerify(PublicKey publicKey) throws InvalidKeyException
+  {
+    HashMap attributes = new HashMap();
+    attributes.put(BaseSignature.VERIFIER_KEY, publicKey);
+    try
+      {
+        adaptee.setupVerify(attributes);
+      }
+    catch (IllegalArgumentException x)
+      {
+        throw new InvalidKeyException(x.getMessage(), x);
+      }
+  }
+
+  public void engineInitSign(PrivateKey privateKey) throws InvalidKeyException
+  {
+    HashMap attributes = new HashMap();
+    attributes.put(BaseSignature.SIGNER_KEY, privateKey);
+    try
+      {
+        adaptee.setupSign(attributes);
+      }
+    catch (IllegalArgumentException x)
+      {
+        throw new InvalidKeyException(x.getMessage(), x);
+      }
+  }
+
+  public void engineInitSign(PrivateKey privateKey, SecureRandom random)
+      throws InvalidKeyException
+  {
+    HashMap attributes = new HashMap();
+    attributes.put(BaseSignature.SIGNER_KEY, privateKey);
+    attributes.put(BaseSignature.SOURCE_OF_RANDOMNESS, random);
+    try
+      {
+        adaptee.setupSign(attributes);
+      }
+    catch (IllegalArgumentException x)
+      {
+        throw new InvalidKeyException(x.getMessage(), x);
+      }
+  }
+
+  public void engineUpdate(byte b) throws SignatureException
+  {
+    try
+      {
+        adaptee.update(b);
+      }
+    catch (IllegalStateException x)
+      {
+        throw new SignatureException(x.getMessage(), x);
+      }
+  }
+
+  public void engineUpdate(byte[] b, int off, int len)
+      throws SignatureException
+  {
+    try
+      {
+        adaptee.update(b, off, len);
+      }
+    catch (IllegalStateException x)
+      {
+        throw new SignatureException(x.getMessage(), x);
+      }
+  }
+
+  public byte[] engineSign() throws SignatureException
+  {
+    Object signature = null;
+    try
+      {
+        signature = adaptee.sign();
+      }
+    catch (IllegalStateException x)
+      {
+        throw new SignatureException(x.getMessage(), x);
+      }
+    byte[] result = codec.encodeSignature(signature);
+    return result;
+  }
+
+  public int engineSign(byte[] outbuf, int offset, int len)
+      throws SignatureException
+  {
+    byte[] signature = this.engineSign();
+    int result = signature.length;
+    if (result > len)
+      throw new SignatureException("Not enough room to store signature");
+
+    System.arraycopy(signature, 0, outbuf, offset, result);
+    return result;
+  }
+
+  public boolean engineVerify(byte[] sigBytes) throws SignatureException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineVerify");
+    Object signature = codec.decodeSignature(sigBytes);
+    boolean result = false;
+    try
+      {
+        result = adaptee.verify(signature);
+      }
+    catch (IllegalStateException x)
+      {
+        throw new SignatureException(x.getMessage(), x);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineVerify",
+                  Boolean.valueOf(result));
+    return result;
+  }
+
+  // Deprecated. Replaced by engineSetParameter.
+  public void engineSetParameter(String param, Object value)
+      throws InvalidParameterException
+  {
+    throw new InvalidParameterException("deprecated");
+  }
+
+  public void engineSetParameter(AlgorithmParameterSpec params)
+      throws InvalidAlgorithmParameterException
+  {
+  }
+
+  // Deprecated
+  public Object engineGetParameter(String param)
+      throws InvalidParameterException
+  {
+    throw new InvalidParameterException("deprecated");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/IKeyPairCodec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,124 @@
+/* IKeyPairCodec.java -- 
+   Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key;
+
+import gnu.java.security.Registry;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * The visible methods of an object that knows how to encode and decode
+ * cryptographic asymmetric keypairs. Codecs are useful for (a) externalising
+ * public and private keys for storage and on-the-wire transmission, as well as
+ * (b) re-creating their internal Java representation from external sources.
+ */
+public interface IKeyPairCodec
+{
+  /** Constant identifying the <i>Raw</i> encoding format. */
+  int RAW_FORMAT = Registry.RAW_ENCODING_ID;
+
+  /** Constant identifying the <i>X.509</i> encoding format. */
+  int X509_FORMAT = Registry.X509_ENCODING_ID;
+
+  /** Constant identifying the <i>PKCS#8</i> encoding format. */
+  int PKCS8_FORMAT = Registry.PKCS8_ENCODING_ID;
+
+  /**
+   * Constant identifying the <i>ASN.1</i> encoding format: a combined encoding
+   * of <i>X.509</i> for public keys, and <i>PKCS#8</i> for private ones.
+   */
+  int ASN1_FORMAT = Registry.ASN1_ENCODING_ID;
+
+  /**
+   * Returns the unique identifier (within this library) of the format used to
+   * externalise public and private keys.
+   * 
+   * @return the identifier of the format, the object supports.
+   */
+  int getFormatID();
+
+  /**
+   * Encodes an instance of a public key for storage or transmission purposes.
+   * 
+   * @param key the non-null key to encode.
+   * @return a byte sequence representing the encoding of the designated key
+   *         according to the format supported by this codec.
+   * @exception IllegalArgumentException if the designated key is not supported
+   *              by this codec.
+   */
+  byte[] encodePublicKey(PublicKey key);
+
+  /**
+   * Encodes an instance of a private key for storage or transmission purposes.
+   * 
+   * @param key the non-null key to encode.
+   * @return a byte sequence representing the encoding of the designated key
+   *         according to the format supported by this codec.
+   * @exception IllegalArgumentException if the designated key is not supported
+   *              by this codec.
+   */
+  byte[] encodePrivateKey(PrivateKey key);
+
+  /**
+   * Decodes an instance of an external public key into its native Java
+   * representation.
+   * 
+   * @param input the source of the externalised key to decode.
+   * @return a concrete instance of a public key, reconstructed from the
+   *         designated input.
+   * @exception IllegalArgumentException if the designated input does not
+   *              contain a known representation of a public key for the format
+   *              supported by the concrete codec.
+   */
+  PublicKey decodePublicKey(byte[] input);
+
+  /**
+   * Decodes an instance of an external private key into its native Java
+   * representation.
+   * 
+   * @param input the source of the externalised key to decode.
+   * @return a concrete instance of a private key, reconstructed from the
+   *         designated input.
+   * @exception IllegalArgumentException if the designated input does not
+   *              contain a known representation of a private key for the format
+   *              supported by the concrete codec.
+   */
+  PrivateKey decodePrivateKey(byte[] input);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/IKeyPairGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,73 @@
+/* IKeyPairGenerator.java -- 
+   Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key;
+
+import java.security.KeyPair;
+import java.util.Map;
+
+/**
+ * The visible methods of every asymmetric keypair generator.
+ */
+public interface IKeyPairGenerator
+{
+  /**
+   * Returns the canonical name of this keypair generator.
+   * 
+   * @return the canonical name of this instance.
+   */
+  String name();
+
+  /**
+   * [Re]-initialises this instance for use with a given set of attributes.
+   * 
+   * @param attributes a map of name/value pairs to use for setting up the
+   *          instance.
+   * @exception IllegalArgumentException if at least one of the mandatory
+   *              attributes is missing or an invalid value was specified.
+   */
+  void setup(Map attributes);
+
+  /**
+   * Generates a new keypair based on the attributes used to configure the
+   * instance.
+   * 
+   * @return a new keypair.
+   */
+  KeyPair generate();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/KeyPairCodecFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,360 @@
+/* KeyPairCodecFactory.java -- 
+   Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec;
+import gnu.java.security.key.dss.DSSKeyPairRawCodec;
+import gnu.java.security.key.dss.DSSKeyPairX509Codec;
+import gnu.java.security.key.dss.DSSPrivateKey;
+import gnu.java.security.key.dss.DSSPublicKey;
+import gnu.java.security.key.rsa.GnuRSAPrivateKey;
+import gnu.java.security.key.rsa.GnuRSAPublicKey;
+import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec;
+import gnu.java.security.key.rsa.RSAKeyPairRawCodec;
+import gnu.java.security.key.rsa.RSAKeyPairX509Codec;
+import gnu.java.security.util.FormatUtil;
+
+import java.lang.reflect.Constructor;
+import java.security.Key;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A <i>Factory</i> class to instantiate key encoder/decoder instances.
+ */
+public class KeyPairCodecFactory
+{
+  private static Set names;
+
+  /** Trivial constructor to enforce Singleton pattern. */
+  private KeyPairCodecFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns the appropriate codec given a composed key-pair generator algorithm
+   * and an encoding format. A composed name is formed by the concatenation of
+   * the canonical key-pair algorithm name, the forward slash character
+   * <code>/</code> and the canonical name of the encoding format.
+   * <p>
+   * <b>IMPORTANT</b>: For backward compatibility, when the encoding format
+   * name is missing, the Raw encoding format is assumed. When this is the case
+   * the trailing forward slash is discarded from the name.
+   * 
+   * @param name the case-insensitive key codec name.
+   * @return an instance of the keypair codec, or <code>null</code> if none
+   *         found.
+   */
+  public static IKeyPairCodec getInstance(String name)
+  {
+    if (name == null)
+      return null;
+
+    name = name.trim();
+    if (name.length() == 0)
+      return null;
+
+    if (name.startsWith("/"))
+      return null;
+
+    if (name.endsWith("/"))
+      return getInstance(name.substring(0, name.length() - 1),
+                         Registry.RAW_ENCODING_ID);
+
+    int i = name.indexOf("/");
+    if (i == -1)
+      return getInstance(name, Registry.RAW_ENCODING_ID);
+
+    String kpgName = name.substring(0, i);
+    String formatName = name.substring(i + 1);
+    return getInstance(kpgName, formatName);
+  }
+
+  /**
+   * Returns an instance of a keypair codec given the canonical name of the
+   * key-pair algorithm, and the name of the encoding format to use when
+   * externalizing the keys.
+   * 
+   * @param name the case-insensitive key-pair algorithm name.
+   * @param format the name of the encoding format to use when externalizing the
+   *          keys generated by the key-pair algorithm.
+   * @return an instance of the key-pair codec, or <code>null</code> if none
+   *         found.
+   */
+  public static IKeyPairCodec getInstance(String name, String format)
+  {
+    int formatID = FormatUtil.getFormatID(format);
+    if (formatID == 0)
+      return null;
+
+    return getInstance(name, formatID);
+  }
+
+  /**
+   * Returns an instance of a keypair codec given the canonical name of the
+   * key-pair algorithm, and the identifier of the format to use when
+   * externalizing the keys.
+   * 
+   * @param name the case-insensitive key-pair algorithm name.
+   * @param formatID the identifier of the format to use when externalizing the
+   *          keys generated by the key-pair algorithm.
+   * @return an instance of the key-pair codec, or <code>null</code> if none
+   *         found.
+   */
+  public static IKeyPairCodec getInstance(String name, int formatID)
+  {
+    if (name == null)
+      return null;
+
+    name = name.trim();
+    switch (formatID)
+      {
+      case Registry.RAW_ENCODING_ID:
+        return getRawCodec(name);
+      case Registry.X509_ENCODING_ID:
+        return getX509Codec(name);
+      case Registry.PKCS8_ENCODING_ID:
+        return getPKCS8Codec(name);
+      }
+
+    return null;
+  }
+
+  /**
+   * Returns an instance of a keypair codec given a key.
+   * 
+   * @param key the key to encode.
+   * @return an instance of the keypair codec, or <code>null</code> if none
+   *         found.
+   */
+  public static IKeyPairCodec getInstance(Key key)
+  {
+    if (key == null)
+      return null;
+
+    String format = key.getFormat();
+    int formatID = FormatUtil.getFormatID(format);
+    if (formatID == 0)
+      return null;
+
+    switch (formatID)
+      {
+      case Registry.RAW_ENCODING_ID:
+        return getRawCodec(key);
+      case Registry.X509_ENCODING_ID:
+        return getX509Codec(key);
+      case Registry.PKCS8_ENCODING_ID:
+        return getPKCS8Codec(key);
+      }
+
+    return null;
+  }
+
+  /**
+   * Returns a {@link Set} of supported key-pair codec names.
+   *
+   * @return a {@link Set} of the names of supported key-pair codec (Strings).
+   */
+  public static synchronized final Set getNames()
+  {
+    if (names == null)
+      {
+        HashSet hs = new HashSet();
+        hs.add(Registry.DSS_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME);
+        hs.add(Registry.DSS_KPG + "/" + Registry.X509_ENCODING_SORT_NAME);
+        hs.add(Registry.DSS_KPG + "/" + Registry.PKCS8_ENCODING_SHORT_NAME);
+        hs.add(Registry.RSA_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME);
+        hs.add(Registry.RSA_KPG + "/" + Registry.X509_ENCODING_SORT_NAME);
+        hs.add(Registry.RSA_KPG + "/" + Registry.PKCS8_ENCODING_SHORT_NAME);
+        hs.add(Registry.DH_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME);
+        hs.add(Registry.SRP_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME);
+        names = Collections.unmodifiableSet(hs);
+      }
+    return names;
+  }
+
+  private static IKeyPairCodec makeInstance (String clazz)
+  {
+    try
+      {
+        Class c = Class.forName (clazz);
+        Constructor ctor = c.getConstructor (new Class[0]);
+        return (IKeyPairCodec) ctor.newInstance (new Object[0]);
+      }
+    catch (Exception x)
+      {
+        IllegalArgumentException iae =
+          new IllegalArgumentException ("strong crypto key codec not available: "
+                                        + clazz);
+        iae.initCause (x);
+        throw iae;
+      }
+  }
+
+  private static boolean matches (Object o, String clazz)
+  {
+    try
+      {
+        Class c = Class.forName (clazz);
+        return c.isAssignableFrom (o.getClass ());
+      }
+    catch (Exception x)
+      {
+        // Can't match.
+        return false;
+      }
+  }
+
+  /**
+   * @param name the trimmed name of a key-pair algorithm.
+   * @return a Raw format codec for the designated key-pair algorithm, or
+   *         <code>null</code> if none exists.
+   */
+  private static IKeyPairCodec getRawCodec(String name)
+  {
+    IKeyPairCodec result = null;
+    if (name.equalsIgnoreCase(Registry.DSA_KPG)
+        || name.equals(Registry.DSS_KPG))
+      result = new DSSKeyPairRawCodec();
+    else if (name.equalsIgnoreCase(Registry.RSA_KPG))
+      result = new RSAKeyPairRawCodec();
+    else if (name.equalsIgnoreCase(Registry.DH_KPG))
+      result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairRawCodec");
+    else if (name.equalsIgnoreCase(Registry.SRP_KPG))
+      result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec");
+
+    return result;
+  }
+
+  /**
+   * @param name the trimmed name of a key-pair algorithm.
+   * @return a X.509 format codec for the designated key-pair algorithm, or
+   *         <code>null</code> if none exists.
+   */
+  private static IKeyPairCodec getX509Codec(String name)
+  {
+    IKeyPairCodec result = null;
+    if (name.equalsIgnoreCase(Registry.DSA_KPG)
+        || name.equals(Registry.DSS_KPG))
+      result = new DSSKeyPairX509Codec();
+    else if (name.equalsIgnoreCase(Registry.RSA_KPG))
+      result = new RSAKeyPairX509Codec();
+    else if (name.equalsIgnoreCase(Registry.DH_KPG))
+      result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairX509Codec");
+
+    return result;
+  }
+
+  /**
+   * @param name the trimmed name of a key-pair algorithm.
+   * @return a PKCS#8 format codec for the designated key-pair algorithm, or
+   *         <code>null</code> if none exists.
+   */
+  private static IKeyPairCodec getPKCS8Codec(String name)
+  {
+    IKeyPairCodec result = null;
+    if (name.equalsIgnoreCase(Registry.DSA_KPG)
+        || name.equals(Registry.DSS_KPG))
+      result = new DSSKeyPairPKCS8Codec();
+    else if (name.equalsIgnoreCase(Registry.RSA_KPG))
+      result = new RSAKeyPairPKCS8Codec();
+    else if (name.equalsIgnoreCase(Registry.DH_KPG))
+      result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec");
+
+    return result;
+  }
+
+  /**
+   * @param key a {@link Key} for which we want to return a Raw codec.
+   * @return the Raw codec corresponding to the key, or <code>null</code> if
+   *         none exists for this key.
+   */
+  private static IKeyPairCodec getRawCodec(Key key)
+  {
+    IKeyPairCodec result = null;
+    if ((key instanceof DSSPublicKey) || (key instanceof DSSPrivateKey))
+      result = new DSSKeyPairRawCodec();
+    else if ((key instanceof GnuRSAPublicKey)
+             || (key instanceof GnuRSAPrivateKey))
+      result = new RSAKeyPairRawCodec();
+    else if (matches(key, "gnu.javax.crypto.key.dh.GnuDHPublicKey")
+             || matches(key, "gnu.javax.crypto.key.dh.GnuDHPrivateKey"))
+      result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairRawCodec");
+    else if (matches(key, "gnu.javax.crypto.key.srp6.SRPPublicKey")
+             || matches(key, "gnu.javax.crypto.key.srp6.SRPPrivateKey"))
+      result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec");
+
+    return result;
+  }
+
+  /**
+   * @param key a {@link Key} for which we want to return an X.509 codec.
+   * @return the X.509 codec corresponding to the key, or <code>null</code> if
+   *         none exists for this key.
+   */
+  private static IKeyPairCodec getX509Codec(Key key)
+  {
+    IKeyPairCodec result = null;
+    if (key instanceof DSSPublicKey)
+      result = new DSSKeyPairX509Codec();
+    else if (key instanceof GnuRSAPublicKey)
+      result = new RSAKeyPairX509Codec();
+
+    return result;
+  }
+
+  /**
+   * @param key a {@link Key} for which we want to return a PKCS#8 codec.
+   * @return the PKCS#8 codec corresponding to the key, or <code>null</code> if
+   *         none exists for this key.
+   */
+  private static IKeyPairCodec getPKCS8Codec(Key key)
+  {
+    IKeyPairCodec result = null;
+    if (key instanceof DSSPrivateKey)
+      result = new DSSKeyPairPKCS8Codec();
+    else if (key instanceof GnuRSAPrivateKey)
+      result = new RSAKeyPairPKCS8Codec();
+
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/KeyPairGeneratorFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,120 @@
+/* KeyPairGeneratorFactory.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.dss.DSSKeyPairGenerator;
+import gnu.java.security.key.rsa.RSAKeyPairGenerator;
+
+import java.lang.reflect.Constructor;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A Factory to instantiate asymmetric keypair generators.
+ */
+public class KeyPairGeneratorFactory
+{
+  /** Trivial constructor to enforce Singleton pattern. */
+  private KeyPairGeneratorFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a keypair generator given its name.
+   * 
+   * @param name the case-insensitive key generator name.
+   * @return an instance of the keypair generator, or <code>null</code> if
+   *         none found.
+   */
+  public static IKeyPairGenerator getInstance(String name)
+  {
+    if (name == null)
+      return null;
+
+    name = name.trim();
+    IKeyPairGenerator result = null;
+    if (name.equalsIgnoreCase(Registry.DSA_KPG)
+        || name.equalsIgnoreCase(Registry.DSS_KPG))
+      result = new DSSKeyPairGenerator();
+    else if (name.equalsIgnoreCase(Registry.RSA_KPG))
+      result = new RSAKeyPairGenerator();
+    else if (name.equalsIgnoreCase(Registry.DH_KPG))
+      result = makeInstance("gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator");
+    else if (name.equalsIgnoreCase(Registry.SRP_KPG))
+      result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairGenerator");
+
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of keypair generator names supported by this
+   * <i>Factory</i>. Those keypair generators may be used in conjunction with
+   * the digital signature schemes with appendix supported by this library.
+   * 
+   * @return a {@link Set} of keypair generator names (Strings).
+   */
+  public static final Set getNames()
+  {
+    HashSet hs = new HashSet();
+    hs.add(Registry.DSS_KPG);
+    hs.add(Registry.DSA_KPG);
+    hs.add(Registry.RSA_KPG);
+    hs.add(Registry.DH_KPG);
+    hs.add(Registry.SRP_KPG);
+    return Collections.unmodifiableSet(hs);
+  }
+
+  private static IKeyPairGenerator makeInstance(String clazz)
+  {
+    try
+      {
+        Class c = Class.forName(clazz);
+        Constructor ctor = c.getConstructor(new Class[0]);
+        return (IKeyPairGenerator) ctor.newInstance(new Object[0]);
+      }
+    catch (Exception x)
+      {
+        throw new IllegalArgumentException(
+            "strong crypto key pair generator not available: " + clazz, x);
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/dss/DSSKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,211 @@
+/* DSSKey.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.util.FormatUtil;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.Key;
+import java.security.interfaces.DSAKey;
+import java.security.interfaces.DSAParams;
+import java.security.spec.DSAParameterSpec;
+
+/**
+ * A base asbtract class for both public and private DSS (Digital Signature
+ * Standard) keys. It encapsulates the three DSS numbers: <code>p</code>,
+ * <code>q</code> and <code>g</code>.
+ * <p>
+ * According to the JDK, cryptographic <i>Keys</i> all have a <i>format</i>.
+ * The format used in this implementation is called <i>Raw</i>, and basically
+ * consists of the raw byte sequences of algorithm parameters. The exact order
+ * of the byte sequences and the implementation details are given in each of the
+ * relevant <code>getEncoded()</code> methods of each of the private and
+ * public keys.
+ * <p>
+ * <b>IMPORTANT</b>: Under certain circumstances (e.g. in an X.509 certificate
+ * with inherited AlgorithmIdentifier's parameters of a SubjectPublicKeyInfo
+ * element) these three MPIs may be <code>null</code>.
+ * 
+ * @see DSSPrivateKey#getEncoded
+ * @see DSSPublicKey#getEncoded
+ */
+public abstract class DSSKey
+    implements Key, DSAKey
+{
+  /**
+   * A prime modulus, where
+   * <code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code> for
+   * <code>512 &lt;= L &lt;= 1024</code> and <code>L</code> a multiple of
+   * <code>64</code>.
+   */
+  protected final BigInteger p;
+
+  /**
+   * A prime divisor of <code>p - 1</code>, where
+   * <code>2<sup>159</sup> &lt; q
+   * &lt; 2<sup>160</sup></code>.
+   */
+  protected final BigInteger q;
+
+  /**
+   * <code>g = h<sup>(p-1)</sup>/q mod p</code>, where <code>h</code> is
+   * any integer with <code>1 &lt; h &lt; p - 1</code> such that <code>h<sup>
+   * (p-1)</sup>/q mod p > 1</code> (<code>g</code>
+   * has order <code>q mod p
+   * </code>).
+   */
+  protected final BigInteger g;
+
+  /**
+   * Identifier of the default encoding format to use when externalizing the key
+   * material.
+   */
+  protected final int defaultFormat;
+
+  /** String representation of this key. Cached for speed. */
+  private transient String str;
+
+  /**
+   * Trivial protected constructor.
+   * 
+   * @param defaultFormat the identifier of the encoding format to use by
+   *          default when externalizing the key.
+   * @param p the DSS parameter <code>p</code>.
+   * @param q the DSS parameter <code>q</code>.
+   * @param g the DSS parameter <code>g</code>.
+   */
+  protected DSSKey(int defaultFormat, BigInteger p, BigInteger q, BigInteger g)
+  {
+    super();
+
+    this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID
+                                            : defaultFormat;
+    this.p = p;
+    this.q = q;
+    this.g = g;
+  }
+
+  public DSAParams getParams()
+  {
+    return new DSAParameterSpec(p, q, g);
+  }
+
+  public String getAlgorithm()
+  {
+    return Registry.DSS_KPG;
+  }
+
+  /** @deprecated see getEncoded(int). */
+  public byte[] getEncoded()
+  {
+    return getEncoded(defaultFormat);
+  }
+
+  public String getFormat()
+  {
+    return FormatUtil.getEncodingShortName(defaultFormat);
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * {@link DSAKey} and has the same DSS (Digital Signature Standard) parameter
+   * values as this one.
+   * <p>
+   * Always returns <code>false</code> if the MPIs of this key are
+   * <i>inherited</i>. This may be the case when the key is re-constructed from
+   * an X.509 certificate with absent or NULL AlgorithmIdentifier's parameters
+   * field.
+   * 
+   * @param obj the other non-null DSS key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(Object obj)
+  {
+    if (hasInheritedParameters())
+      return false;
+
+    if (obj == null)
+      return false;
+
+    if (! (obj instanceof DSAKey))
+      return false;
+
+    DSAKey that = (DSAKey) obj;
+    return p.equals(that.getParams().getP())
+           && q.equals(that.getParams().getQ())
+           && g.equals(that.getParams().getG());
+  }
+
+  public String toString()
+  {
+    if (str == null)
+      {
+        String ls = (String) AccessController.doPrivileged(new GetPropertyAction("line.separator"));
+        StringBuilder sb = new StringBuilder(ls)
+            .append("defaultFormat=").append(defaultFormat).append(",")
+            .append(ls);
+        if (hasInheritedParameters())
+          sb.append("p=inherited,").append(ls)
+              .append("q=inherited,").append(ls)
+              .append("g=inherited");
+        else
+          sb.append("p=0x").append(p.toString(16)).append(",").append(ls)
+              .append("q=0x").append(q.toString(16)).append(",").append(ls)
+              .append("g=0x").append(g.toString(16));
+        str = sb.toString();
+      }
+    return str;
+  }
+
+  public abstract byte[] getEncoded(int format);
+
+  /**
+   * @return <code>true</code> if <code>p</code>, <code>q</code> and
+   *         <code>g</code> are all <code>null</code>. Returns
+   *         <code>false</code> otherwise.
+   */
+  public boolean hasInheritedParameters()
+  {
+    return p == null && q == null && g == null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/dss/DSSKeyPairGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,382 @@
+/* DSSKeyPairGenerator.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.DSAParameterSpec;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * A key-pair generator for asymetric keys to use in conjunction with the DSS
+ * (Digital Signature Standard).
+ * <p>
+ * References:
+ * <p>
+ * <a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
+ * Standard (DSS)</a>, Federal Information Processing Standards Publication
+ * 186. National Institute of Standards and Technology.
+ */
+public class DSSKeyPairGenerator
+    implements IKeyPairGenerator
+{
+  private static final Logger log = Logger.getLogger(DSSKeyPairGenerator.class.getName());
+
+  /** The BigInteger constant 2. */
+  private static final BigInteger TWO = BigInteger.valueOf(2L);
+
+  /** Property name of the length (Integer) of the modulus (p) of a DSS key. */
+  public static final String MODULUS_LENGTH = "gnu.crypto.dss.L";
+
+  /**
+   * Property name of the Boolean indicating wether or not to use default pre-
+   * computed values of <code>p</code>, <code>q</code> and <code>g</code>
+   * for a given modulus length. The ultimate behaviour of this generator with
+   * regard to using pre-computed parameter sets will depend on the value of
+   * this property and of the following one {@link #STRICT_DEFAULTS}:
+   * <ol>
+   * <li>If this property is {@link Boolean#FALSE} then this generator will
+   * accept being setup for generating parameters for any modulus length
+   * provided the modulus length is between <code>512</code> and
+   * <code>1024</code>, and is of the form <code>512 + 64 * n</code>. In
+   * addition, a new paramter set will always be generated; i.e. no pre-
+   * computed values are used.</li>
+   * <li>If this property is {@link Boolean#TRUE} and the value of
+   * {@link #STRICT_DEFAULTS} is also {@link Boolean#TRUE} then this generator
+   * will only accept being setup for generating parameters for modulus lengths
+   * of <code>512</code>, <code>768</code> and <code>1024</code>. Any
+   * other value, of the modulus length, even if between <code>512</code> and
+   * <code>1024</code>, and of the form <code>512 + 64 * n</code>, will
+   * cause an {@link IllegalArgumentException} to be thrown. When those modulus
+   * length (<code>512</code>, <code>768</code>, and <code>1024</code>)
+   * are specified, the paramter set is always the same.</li>
+   * <li>Finally, if this property is {@link Boolean#TRUE} and the value of
+   * {@link #STRICT_DEFAULTS} is {@link Boolean#FALSE} then this generator will
+   * behave as in point 1 above, except that it will use pre-computed values
+   * when possible; i.e. the modulus length is one of <code>512</code>,
+   * <code>768</code>, or <code>1024</code>.</li>
+   * </ol>
+   * The default value of this property is {@link Boolean#TRUE}.
+   */
+  public static final String USE_DEFAULTS = "gnu.crypto.dss.use.defaults";
+
+  /**
+   * Property name of the Boolean indicating wether or not to generate new
+   * parameters, even if the modulus length <i>L</i> is not one of the pre-
+   * computed defaults (value {@link Boolean#FALSE}), or throw an exception
+   * (value {@link Boolean#TRUE}) -- the exception in this case is an
+   * {@link IllegalArgumentException}. The default value for this property is
+   * {@link Boolean#FALSE}. The ultimate behaviour of this generator will
+   * depend on the values of this and {@link #USE_DEFAULTS} properties -- see
+   * {@link #USE_DEFAULTS} for more information.
+   */
+  public static final String STRICT_DEFAULTS = "gnu.crypto.dss.strict.defaults";
+
+  /**
+   * Property name of an optional {@link SecureRandom} instance to use. The
+   * default is to use a classloader singleton from {@link PRNG}.
+   */
+  public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dss.prng";
+
+  /**
+   * Property name of an optional {@link DSAParameterSpec} instance to use for
+   * this generator's <code>p</code>, <code>q</code>, and <code>g</code>
+   * values. The default is to generate these values or use pre-computed ones,
+   * depending on the value of the <code>USE_DEFAULTS</code> attribute.
+   */
+  public static final String DSS_PARAMETERS = "gnu.crypto.dss.params";
+
+  /**
+   * Property name of the preferred encoding format to use when externalizing
+   * generated instance of key-pairs from this generator. The property is taken
+   * to be an {@link Integer} that encapsulates an encoding format identifier.
+   */
+  public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dss.encoding";
+
+  /** Default value for the modulus length. */
+  public static final int DEFAULT_MODULUS_LENGTH = 1024;
+
+  /** Default encoding format to use when none was specified. */
+  private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
+
+  /** Initial SHS context. */
+  private static final int[] T_SHS = new int[] {
+      0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
+  };
+
+  // from jdk1.3.1/docs/guide/security/CryptoSpec.html#AppB
+  public static final DSAParameterSpec KEY_PARAMS_512 = new DSAParameterSpec(
+      new BigInteger(
+          "fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae"
+        + "01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16),
+      new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16),
+      new BigInteger(
+          "678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e"
+        + "35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16));
+  public static final DSAParameterSpec KEY_PARAMS_768 = new DSAParameterSpec(
+      new BigInteger(
+          "e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d8901419"
+        + "22d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d77"
+        + "7d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16),
+      new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", 16),
+      new BigInteger(
+          "30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4"
+        + "dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d8"
+        + "3c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16));
+  public static final DSAParameterSpec KEY_PARAMS_1024 = new DSAParameterSpec(
+      new BigInteger(
+          "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669"
+        + "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7"
+        + "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb"
+        + "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16),
+      new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16),
+      new BigInteger(
+          "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267"
+        + "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1"
+        + "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b"
+        + "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16));
+
+  private static final BigInteger TWO_POW_160 = TWO.pow(160);
+
+  /** The length of the modulus of DSS keys generated by this instance. */
+  private int L;
+
+  /** The optional {@link SecureRandom} instance to use. */
+  private SecureRandom rnd = null;
+
+  private BigInteger seed;
+
+  private BigInteger counter;
+
+  private BigInteger p;
+
+  private BigInteger q;
+
+  private BigInteger e;
+
+  private BigInteger g;
+
+  private BigInteger XKEY;
+
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+
+  /** Preferred encoding format of generated keys. */
+  private int preferredFormat;
+
+  public String name()
+  {
+    return Registry.DSS_KPG;
+  }
+
+  /**
+   * Configures this instance.
+   * 
+   * @param attributes the map of name/value pairs to use.
+   * @exception IllegalArgumentException if the designated MODULUS_LENGTH value
+   *              is not greater than 512, less than 1024 and not of the form
+   *              <code>512 + 64j</code>.
+   */
+  public void setup(Map attributes)
+  {
+    // find out the modulus length
+    Integer l = (Integer) attributes.get(MODULUS_LENGTH);
+    L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue());
+    if ((L % 64) != 0 || L < 512 || L > 1024)
+      throw new IllegalArgumentException(MODULUS_LENGTH);
+
+    // should we use the default pre-computed params?
+    Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS);
+    if (useDefaults == null)
+      useDefaults = Boolean.TRUE;
+
+    Boolean strictDefaults = (Boolean) attributes.get(STRICT_DEFAULTS);
+    if (strictDefaults == null)
+      strictDefaults = Boolean.FALSE;
+
+    // are we given a set of DSA params or we shall use/generate our own?
+    DSAParameterSpec params = (DSAParameterSpec) attributes.get(DSS_PARAMETERS);
+    if (params != null)
+      {
+        p = params.getP();
+        q = params.getQ();
+        g = params.getG();
+      }
+    else if (useDefaults.equals(Boolean.TRUE))
+      {
+        switch (L)
+          {
+          case 512:
+            p = KEY_PARAMS_512.getP();
+            q = KEY_PARAMS_512.getQ();
+            g = KEY_PARAMS_512.getG();
+            break;
+          case 768:
+            p = KEY_PARAMS_768.getP();
+            q = KEY_PARAMS_768.getQ();
+            g = KEY_PARAMS_768.getG();
+            break;
+          case 1024:
+            p = KEY_PARAMS_1024.getP();
+            q = KEY_PARAMS_1024.getQ();
+            g = KEY_PARAMS_1024.getG();
+            break;
+          default:
+            if (strictDefaults.equals(Boolean.TRUE))
+              throw new IllegalArgumentException(
+                  "Does not provide default parameters for " + L
+                  + "-bit modulus length");
+            else
+              {
+                p = null;
+                q = null;
+                g = null;
+              }
+          }
+      }
+    else
+      {
+        p = null;
+        q = null;
+        g = null;
+      }
+    // do we have a SecureRandom, or should we use our own?
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    // what is the preferred encoding format
+    Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
+    preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
+                                       : formatID.intValue();
+    // set the seed-key
+    byte[] kb = new byte[20]; // we need 160 bits of randomness
+    nextRandomBytes(kb);
+    XKEY = new BigInteger(1, kb).setBit(159).setBit(0);
+  }
+
+  public KeyPair generate()
+  {
+    if (p == null)
+      {
+        BigInteger[] params = new FIPS186(L, rnd).generateParameters();
+        seed = params[FIPS186.DSA_PARAMS_SEED];
+        counter = params[FIPS186.DSA_PARAMS_COUNTER];
+        q = params[FIPS186.DSA_PARAMS_Q];
+        p = params[FIPS186.DSA_PARAMS_P];
+        e = params[FIPS186.DSA_PARAMS_E];
+        g = params[FIPS186.DSA_PARAMS_G];
+        if (Configuration.DEBUG)
+          {
+            log.fine("seed: " + seed.toString(16));
+            log.fine("counter: " + counter.intValue());
+            log.fine("q: " + q.toString(16));
+            log.fine("p: " + p.toString(16));
+            log.fine("e: " + e.toString(16));
+            log.fine("g: " + g.toString(16));
+          }
+      }
+    BigInteger x = nextX();
+    BigInteger y = g.modPow(x, p);
+    PublicKey pubK = new DSSPublicKey(preferredFormat, p, q, g, y);
+    PrivateKey secK = new DSSPrivateKey(preferredFormat, p, q, g, x);
+    return new KeyPair(pubK, secK);
+  }
+
+  /**
+   * This method applies the following algorithm described in 3.1 of FIPS-186:
+   * <ol>
+   * <li>XSEED = optional user input.</li>
+   * <li>XVAL = (XKEY + XSEED) mod 2<sup>b</sup>.</li>
+   * <li>x = G(t, XVAL) mod q.</li>
+   * <li>XKEY = (1 + XKEY + x) mod 2<sup>b</sup>.</li>
+   * </ol>
+   * <p>
+   * Where <code>b</code> is the length of a secret b-bit seed-key (XKEY).
+   * <p>
+   * Note that in this implementation, XSEED, the optional user input, is always
+   * zero.
+   */
+  private synchronized BigInteger nextX()
+  {
+    byte[] xk = XKEY.toByteArray();
+    byte[] in = new byte[64]; // 512-bit block for SHS
+    System.arraycopy(xk, 0, in, 0, xk.length);
+    int[] H = Sha160.G(T_SHS[0], T_SHS[1], T_SHS[2], T_SHS[3], T_SHS[4], in, 0);
+    byte[] h = new byte[20];
+    for (int i = 0, j = 0; i < 5; i++)
+      {
+        h[j++] = (byte)(H[i] >>> 24);
+        h[j++] = (byte)(H[i] >>> 16);
+        h[j++] = (byte)(H[i] >>> 8);
+        h[j++] = (byte) H[i];
+      }
+    BigInteger result = new BigInteger(1, h).mod(q);
+    XKEY = XKEY.add(result).add(BigInteger.ONE).mod(TWO_POW_160);
+    return result;
+  }
+
+  /**
+   * Fills the designated byte array with random data.
+   * 
+   * @param buffer the byte array to fill with random data.
+   */
+  private void nextRandomBytes(byte[] buffer)
+  {
+    if (rnd != null)
+      rnd.nextBytes(buffer);
+    else
+      getDefaultPRNG().nextBytes(buffer);
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,249 @@
+/* DSSKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+import gnu.java.security.util.Util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+/**
+ * An implementation of an {@link IKeyPairCodec} that knows how to encode /
+ * decode PKCS#8 ASN.1 external representation of DSS private keys.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class DSSKeyPairPKCS8Codec
+    implements IKeyPairCodec
+{
+  private static final Logger log = Logger.getLogger(DSSKeyPairPKCS8Codec.class.getName());
+  private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
+
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return PKCS8_FORMAT;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    throw new InvalidParameterException("Wrong format for public keys");
+  }
+
+  /**
+   * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of a DSA
+   * private key. The ASN.1 specification is as follows:
+   * 
+   * <pre>
+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * </pre>
+   * 
+   * @return the DER encoded form of the ASN.1 representation of the
+   *         <i>PrivateKeyInfo</i> field in an X.509 certificate.
+   * @throw InvalidParameterException if an error occurs during the marshalling
+   *        process.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    if (! (key instanceof DSSPrivateKey))
+      throw new InvalidParameterException("Wrong key type");
+
+    DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
+
+    DSSPrivateKey pk = (DSSPrivateKey) key;
+    BigInteger p = pk.getParams().getP();
+    BigInteger q = pk.getParams().getQ();
+    BigInteger g = pk.getParams().getG();
+    BigInteger x = pk.getX();
+
+    ArrayList params = new ArrayList(3);
+    params.add(new DERValue(DER.INTEGER, p));
+    params.add(new DERValue(DER.INTEGER, q));
+    params.add(new DERValue(DER.INTEGER, g));
+    DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+
+    ArrayList algorithmID = new ArrayList(2);
+    algorithmID.add(derOID);
+    algorithmID.add(derParams);
+    DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                           algorithmID);
+
+    // The OCTET STRING is the DER encoding of an INTEGER.
+    DERValue derX = new DERValue(DER.INTEGER, x);
+    DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, derX.getEncoded());
+
+    ArrayList pki = new ArrayList(3);
+    pki.add(derVersion);
+    pki.add(derAlgorithmID);
+    pki.add(derPrivateKey);
+    DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
+
+    byte[] result;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try
+      {
+        DERWriter.write(baos, derPKI);
+        result = baos.toByteArray();
+      }
+    catch (IOException e)
+      {
+        InvalidParameterException y = new InvalidParameterException(e.getMessage());
+        y.initCause(e);
+        throw y;
+      }
+    return result;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public PublicKey decodePublicKey(byte[] input)
+  {
+    throw new InvalidParameterException("Wrong format for public keys");
+  }
+
+  /**
+   * @param input the byte array to unmarshall into a valid DSS
+   *          {@link PrivateKey} instance. MUST NOT be null.
+   * @return a new instance of a {@link DSSPrivateKey} decoded from the
+   *         <i>PrivateKeyInfo</i> material fed as <code>input</code>.
+   * @throw InvalidParameterException if an exception occurs during the
+   *        unmarshalling process.
+   */
+  public PrivateKey decodePrivateKey(byte[] input)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "decodePrivateKey");
+    if (input == null)
+      throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+    BigInteger version, p, q, g, x;
+    DERReader der = new DERReader(input);
+    try
+      {
+        DERValue derPKI = der.read();
+        DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
+
+        DERValue derVersion = der.read();
+        if (! (derVersion.getValue() instanceof BigInteger))
+          throw new InvalidParameterException("Wrong Version field");
+
+        version = (BigInteger) derVersion.getValue();
+        if (version.compareTo(BigInteger.ZERO) != 0)
+          throw new InvalidParameterException("Unexpected Version: " + version);
+
+        DERValue derAlgoritmID = der.read();
+        DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
+
+        DERValue derOID = der.read();
+        OID algOID = (OID) derOID.getValue();
+        if (! algOID.equals(DSA_ALG_OID))
+          throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+        DERValue derParams = der.read();
+        DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
+
+        DERValue val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong P field");
+        p = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong Q field");
+        q = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong G field");
+        g = (BigInteger) val.getValue();
+
+        val = der.read();
+        if (Configuration.DEBUG)
+          log.fine("val = " + val);
+        byte[] xBytes = (byte[]) val.getValue();
+        if (Configuration.DEBUG)
+          log.fine(Util.dumpString(xBytes, "xBytes: "));
+        DERReader der2 = new DERReader(xBytes);
+        val = der2.read();
+        DerUtil.checkIsBigInteger(val, "Wrong X field");
+        x = (BigInteger) val.getValue();
+      }
+    catch (IOException e)
+      {
+        InvalidParameterException y = new InvalidParameterException(e.getMessage());
+        y.initCause(e);
+        throw y;
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "decodePrivateKey");
+    return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/dss/DSSKeyPairRawCodec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,347 @@
+/* DSSKeyPairRawCodec.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * An object that implements the {@link IKeyPairCodec} operations for the
+ * <i>Raw</i> format to use with DSS keypairs.
+ */
+public class DSSKeyPairRawCodec
+    implements IKeyPairCodec
+{
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return RAW_FORMAT;
+  }
+
+  /**
+   * Returns the encoded form of the designated DSS (Digital Signature Standard)
+   * public key according to the <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for a DSA public key, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_DSS_PUBLIC_KEY},
+   * <li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the DSA parameter
+   * <code>p</code> in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSA parameter <code>p</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DSA parameter
+   * <code>q</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSA parameter <code>q</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DSA parameter
+   * <code>g</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSA parameter <code>g</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DSA parameter
+   * <code>y</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSA parameter <code>y</code>,
+   * </li>
+   * </ol>
+   * 
+   * @param key the key to encode.
+   * @return the <i>Raw</i> format encoding of the designated key.
+   * @throws IllegalArgumentException if the designated key is not a DSS
+   *           (Digital Signature Standard) one.
+   * @see Registry#MAGIC_RAW_DSS_PUBLIC_KEY
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    if (! (key instanceof DSSPublicKey))
+      throw new IllegalArgumentException("key");
+
+    DSSPublicKey dssKey = (DSSPublicKey) key;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]);
+    baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1]);
+    baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2]);
+    baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3]);
+    // version
+    baos.write(0x01);
+    // p
+    byte[] buffer = dssKey.getParams().getP().toByteArray();
+    int length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // q
+    buffer = dssKey.getParams().getQ().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // g
+    buffer = dssKey.getParams().getG().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // y
+    buffer = dssKey.getY().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    return baos.toByteArray();
+  }
+
+  public PublicKey decodePublicKey(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]
+        || k[1] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1]
+        || k[2] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2]
+        || k[3] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3])
+      throw new IllegalArgumentException("magic");
+
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+
+    int i = 5;
+    int l;
+    byte[] buffer;
+    // p
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger p = new BigInteger(1, buffer);
+    // q
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger q = new BigInteger(1, buffer);
+    // g
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger g = new BigInteger(1, buffer);
+    // y
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger y = new BigInteger(1, buffer);
+    return new DSSPublicKey(p, q, g, y);
+  }
+
+  /**
+   * Returns the encoded form of the designated DSS (Digital Signature Standard)
+   * private key according to the <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for a DSA private key, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_DSS_PRIVATE_KEY},
+   * <li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the DSA parameter
+   * <code>p</code> in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSA parameter <code>p</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DSA parameter
+   * <code>q</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSA parameter <code>q</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DSA parameter
+   * <code>g</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSA parameter <code>g</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DSA parameter
+   * <code>x</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSA parameter <code>x</code>,
+   * </li>
+   * </ol>
+   * 
+   * @param key the key to encode.
+   * @return the <i>Raw</i> format encoding of the designated key.
+   * @throws IllegalArgumentException if the designated key is not a DSS
+   *           (Digital Signature Standard) one.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    if (! (key instanceof DSSPrivateKey))
+      throw new IllegalArgumentException("key");
+
+    DSSPrivateKey dssKey = (DSSPrivateKey) key;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]);
+    baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1]);
+    baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2]);
+    baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3]);
+    // version
+    baos.write(0x01);
+    // p
+    byte[] buffer = dssKey.getParams().getP().toByteArray();
+    int length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // q
+    buffer = dssKey.getParams().getQ().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // g
+    buffer = dssKey.getParams().getG().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // x
+    buffer = dssKey.getX().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    return baos.toByteArray();
+  }
+
+  public PrivateKey decodePrivateKey(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]
+        || k[1] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1]
+        || k[2] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2]
+        || k[3] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3])
+      throw new IllegalArgumentException("magic");
+
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+
+    int i = 5;
+    int l;
+    byte[] buffer;
+    // p
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger p = new BigInteger(1, buffer);
+    // q
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger q = new BigInteger(1, buffer);
+    // g
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger g = new BigInteger(1, buffer);
+    // x
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger x = new BigInteger(1, buffer);
+    return new DSSPrivateKey(p, q, g, x);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/dss/DSSKeyPairX509Codec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,276 @@
+/* DSSKeyPairX509Codec.java -- X.509 Encoding/Decoding handler
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+
+/**
+ * An implementation of an {@link IKeyPairCodec} that knows how to encode /
+ * decode X.509 ASN.1 external representation of DSS public keys.
+ */
+public class DSSKeyPairX509Codec
+    implements IKeyPairCodec
+{
+  private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
+
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return X509_FORMAT;
+  }
+
+  /**
+   * Returns the X.509 ASN.1 <i>SubjectPublicKeyInfo</i> representation of a
+   * DSA public key. The ASN.1 specification, as defined in RFC-3280, and
+   * RFC-2459, is as follows:
+   *
+   * <pre>
+   *   SubjectPublicKeyInfo ::= SEQUENCE {
+   *     algorithm         AlgorithmIdentifier,
+   *     subjectPublicKey  BIT STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * </pre>
+   * <p>
+   * Note that RFC-3280 (page 79) implies that some certificates MAY have an
+   * absent, or NULL, parameters field in their AlgorithmIdentifier element,
+   * implying that those parameters MUST be <i>inherited</i> from another
+   * certificate. This implementation, encodes a <i>NULL</i> element as the DER
+   * value of the parameters field when such is the case.
+   * <p>
+   * The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+   * DER-encoded form of the DSA public key as an INTEGER.
+   * 
+   * <pre>
+   *       DSAPublicKey ::= INTEGER -- public key, Y
+   * </pre>
+   * 
+   * @param key the {@link PublicKey} instance to encode. MUST be an instance of
+   *          {@link DSSPublicKey}.
+   * @return the ASN.1 representation of the <i>SubjectPublicKeyInfo</i> in an
+   *         X.509 certificate.
+   * @throw InvalidParameterException if <code>key</code> is not an instance
+   *        of {@link DSSPublicKey} or if an exception occurs during the
+   *        marshalling process.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    if (! (key instanceof DSSPublicKey))
+      throw new InvalidParameterException("key");
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
+
+    DSSPublicKey dssKey = (DSSPublicKey) key;
+    DERValue derParams;
+    if (dssKey.hasInheritedParameters())
+      derParams = new DERValue(DER.NULL, null);
+    else
+      {
+        BigInteger p = dssKey.getParams().getP();
+        BigInteger q = dssKey.getParams().getQ();
+        BigInteger g = dssKey.getParams().getG();
+
+        DERValue derP = new DERValue(DER.INTEGER, p);
+        DERValue derQ = new DERValue(DER.INTEGER, q);
+        DERValue derG = new DERValue(DER.INTEGER, g);
+
+        ArrayList params = new ArrayList(3);
+        params.add(derP);
+        params.add(derQ);
+        params.add(derG);
+        derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+      }
+
+    ArrayList algorithmID = new ArrayList(2);
+    algorithmID.add(derOID);
+    algorithmID.add(derParams);
+    DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                           algorithmID);
+
+    BigInteger y = dssKey.getY();
+    DERValue derDSAPublicKey = new DERValue(DER.INTEGER, y);
+    byte[] yBytes = derDSAPublicKey.getEncoded();
+    DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes));
+
+    ArrayList spki = new ArrayList(2);
+    spki.add(derAlgorithmID);
+    spki.add(derSPK);
+    DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki);
+
+    byte[] result;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try
+      {
+        DERWriter.write(baos, derSPKI);
+        result = baos.toByteArray();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException e = new InvalidParameterException(x.getMessage());
+        e.initCause(x);
+        throw e;
+      }
+    return result;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    throw new InvalidParameterException("Wrong format for private keys");
+  }
+
+  /**
+   * @param input the byte array to unmarshall into a valid DSS
+   *          {@link PublicKey} instance. MUST NOT be null.
+   * @return a new instance of a {@link DSSPublicKey} decoded from the
+   *         <i>SubjectPublicKeyInfo</i> material in an X.509 certificate.
+   * @throw InvalidParameterException if an exception occurs during the
+   *        unmarshalling process.
+   */
+  public PublicKey decodePublicKey(byte[] input)
+  {
+    if (input == null)
+      throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+    BigInteger p = null;
+    BigInteger g = null;
+    BigInteger q = null;
+    BigInteger y;
+    DERReader der = new DERReader(input);
+    try
+      {
+        DERValue derSPKI = der.read();
+        DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field");
+
+        DERValue derAlgorithmID = der.read();
+        DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field");
+
+        DERValue derOID = der.read();
+        if (! (derOID.getValue() instanceof OID))
+          throw new InvalidParameterException("Wrong Algorithm field");
+
+        OID algOID = (OID) derOID.getValue();
+        if (! algOID.equals(DSA_ALG_OID))
+          throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+        DERValue val = der.read();
+        // RFC-3280, page 79 states: "If the subjectPublicKeyInfo field of the
+        // certificate contains an algorithm field with null parameters or
+        // parameters are omitted, compare the certificate subjectPublicKey
+        // algorithm to the working_public_key_algorithm.  If the certificate
+        // subjectPublicKey algorithm and the working_public_key_algorithm are
+        // different, set the working_public_key_parameters to null."
+        // in other words, the parameters field of an AlgorithmIdentifier
+        // element MAY NOT be present at all, or if present MAY be NULL!
+        // the Mauve test ValidDSAParameterInheritenceTest5, in
+        // gnu.testlet.java.security.cert.pkix.pkits, is/was failing because
+        // of this.
+        if (val.getTag() == DER.NULL)
+          val = der.read();
+        else if (val.isConstructed())
+          {
+            val = der.read();
+            DerUtil.checkIsBigInteger(val, "Wrong P field");
+            p = (BigInteger) val.getValue();
+            val = der.read();
+            DerUtil.checkIsBigInteger(val, "Wrong Q field");
+            q = (BigInteger) val.getValue();
+            val = der.read();
+            DerUtil.checkIsBigInteger(val, "Wrong G field");
+            g = (BigInteger) val.getValue();
+
+            val = der.read();
+          }
+
+        if (! (val.getValue() instanceof BitString))
+          throw new InvalidParameterException("Wrong SubjectPublicKey field");
+
+        byte[] yBytes = ((BitString) val.getValue()).toByteArray();
+
+        DERReader dsaPub = new DERReader(yBytes);
+        val = dsaPub.read();
+        DerUtil.checkIsBigInteger(val, "Wrong Y field");
+        y = (BigInteger) val.getValue();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException e = new InvalidParameterException(x.getMessage());
+        e.initCause(x);
+        throw e;
+      }
+    return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y);
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public PrivateKey decodePrivateKey(byte[] input)
+  {
+    throw new InvalidParameterException("Wrong format for private keys");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/dss/DSSPrivateKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,203 @@
+/* DSSPrivateKey.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.PrivateKey;
+import java.security.interfaces.DSAPrivateKey;
+
+/**
+ * An object that embodies a DSS (Digital Signature Standard) private key.
+ * 
+ * @see #getEncoded
+ */
+public class DSSPrivateKey
+    extends DSSKey
+    implements PrivateKey, DSAPrivateKey
+{
+  /**
+   * A randomly or pseudorandomly generated integer with <code>0 &lt; x &lt;
+   * q</code>.
+   */
+  private final BigInteger x;
+
+  /** String representation of this key. Cached for speed. */
+  private transient String str;
+
+  /**
+   * Convenience constructor. Calls the constructor with 5 arguments passing
+   * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred
+   * encoding format.
+   * 
+   * @param p the public modulus.
+   * @param q the public prime divisor of <code>p-1</code>.
+   * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+   *          <sub>p</sub></code>.
+   * @param x the private key part.
+   */
+  public DSSPrivateKey(BigInteger p, BigInteger q, BigInteger g, BigInteger x)
+  {
+    this(Registry.RAW_ENCODING_ID, p, q, g, x);
+  }
+
+  /**
+   * Constructs a new instance of a <code>DSSPrivateKey</code> given the
+   * designated arguments.
+   * 
+   * @param preferredFormat the indetifier of the preferred encoding format to
+   *          use when externalizing this key.
+   * @param p the public modulus.
+   * @param q the public prime divisor of <code>p-1</code>.
+   * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+   *          <sub>p</sub></code>.
+   * @param x the private key part.
+   */
+  public DSSPrivateKey(int preferredFormat, BigInteger p, BigInteger q,
+                       BigInteger g, BigInteger x)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID
+                                                       : preferredFormat,
+          p, q, g);
+    this.x = x;
+  }
+
+  /**
+   * A class method that takes the output of the <code>encodePrivateKey()</code>
+   * method of a DSS keypair codec object (an instance implementing
+   * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs
+   * an instance of this object.
+   * 
+   * @param k the contents of a previously encoded instance of this object.
+   * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
+   *              <code>k</code>, to represent a valid encoding of an
+   *              instance of this object.
+   * @exception IllegalArgumentException if the byte sequence does not represent
+   *              a valid encoding of an instance of this object.
+   */
+  public static DSSPrivateKey valueOf(byte[] k)
+  {
+    // try RAW codec
+    if (k[0] == Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0])
+      try
+        {
+          return (DSSPrivateKey) new DSSKeyPairRawCodec().decodePrivateKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+    // try PKCS#8 codec
+    return (DSSPrivateKey) new DSSKeyPairPKCS8Codec().decodePrivateKey(k);
+  }
+
+  public BigInteger getX()
+  {
+    return x;
+  }
+
+  /**
+   * Returns the encoded form of this private key according to the designated
+   * format.
+   * 
+   * @param format the desired format identifier of the resulting encoding.
+   * @return the byte sequence encoding this key according to the designated
+   *         format.
+   * @exception IllegalArgumentException if the format is not supported.
+   * @see DSSKeyPairRawCodec
+   */
+  public byte[] getEncoded(int format)
+  {
+    byte[] result;
+    switch (format)
+      {
+      case IKeyPairCodec.RAW_FORMAT:
+        result = new DSSKeyPairRawCodec().encodePrivateKey(this);
+        break;
+      case IKeyPairCodec.PKCS8_FORMAT:
+        result = new DSSKeyPairPKCS8Codec().encodePrivateKey(this);
+        break;
+      default:
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
+      }
+    return result;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * {@link DSAPrivateKey} and has the same DSS (Digital Signature Standard)
+   * parameter values as this one.
+   * 
+   * @param obj the other non-null DSS key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(Object obj)
+  {
+    if (obj == null)
+      return false;
+
+    if (! (obj instanceof DSAPrivateKey))
+      return false;
+
+    DSAPrivateKey that = (DSAPrivateKey) obj;
+    return super.equals(that) && x.equals(that.getX());
+  }
+
+  public String toString()
+  {
+    if (str == null)
+      {
+        String ls = (String) AccessController.doPrivileged
+            (new GetPropertyAction("line.separator"));
+        str = new StringBuilder(this.getClass().getName()).append("(")
+            .append(super.toString()).append(",").append(ls)
+            .append("x=0x").append(Configuration.DEBUG ? x.toString(16)
+                                                       : "**...*").append(ls)
+            .append(")")
+            .toString();
+      }
+    return str;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/dss/DSSPublicKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,201 @@
+/* DSSPublicKey.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPublicKey;
+
+/**
+ * An object that embodies a DSS (Digital Signature Standard) public key.
+ * 
+ * @see #getEncoded
+ */
+public class DSSPublicKey
+    extends DSSKey
+    implements PublicKey, DSAPublicKey
+{
+  /**
+   * <code>y = g<sup>x</sup> mod p</code> where <code>x</code> is the
+   * private part of the DSA key.
+   */
+  private final BigInteger y;
+
+  /** String representation of this key. Cached for speed. */
+  private transient String str;
+
+  /**
+   * Conveience constructor. Calls the constructor with 5 arguments passing
+   * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred
+   * encoding format.
+   * 
+   * @param p the public modulus.
+   * @param q the public prime divisor of <code>p-1</code>.
+   * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+   *          <sub>p</sub></code>.
+   * @param y the public key part.
+   */
+  public DSSPublicKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y)
+  {
+    this(Registry.RAW_ENCODING_ID, p, q, g, y);
+  }
+
+  /**
+   * Constructs a new instance of <code>DSSPublicKey</code> given the
+   * designated arguments.
+   * 
+   * @param preferredFormat the identifier of the preferred encoding format to
+   *          use when externalizing this key.
+   * @param p the public modulus.
+   * @param q the public prime divisor of <code>p-1</code>.
+   * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+   *          <sub>p</sub></code>.
+   * @param y the public key part.
+   */
+  public DSSPublicKey(int preferredFormat, BigInteger p, BigInteger q,
+                      BigInteger g, BigInteger y)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID
+                                                       : preferredFormat,
+          p, q, g);
+    this.y = y;
+  }
+
+  /**
+   * A class method that takes the output of the <code>encodePublicKey()</code>
+   * method of a DSS keypair codec object (an instance implementing
+   * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs
+   * an instance of this object.
+   * 
+   * @param k the contents of a previously encoded instance of this object.
+   * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
+   *              <code>k</code>, to represent a valid encoding of an
+   *              instance of this object.
+   * @exception IllegalArgumentException if the byte sequence does not represent
+   *              a valid encoding of an instance of this object.
+   */
+  public static DSSPublicKey valueOf(byte[] k)
+  {
+    // try RAW codec
+    if (k[0] == Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0])
+      try
+        {
+          return (DSSPublicKey) new DSSKeyPairRawCodec().decodePublicKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+    // try X.509 codec
+    return (DSSPublicKey) new DSSKeyPairX509Codec().decodePublicKey(k);
+  }
+
+  public BigInteger getY()
+  {
+    return y;
+  }
+
+  /**
+   * Returns the encoded form of this public key according to the designated
+   * format.
+   * 
+   * @param format the desired format identifier of the resulting encoding.
+   * @return the byte sequence encoding this key according to the designated
+   *         format.
+   * @exception IllegalArgumentException if the format is not supported.
+   * @see DSSKeyPairRawCodec
+   */
+  public byte[] getEncoded(int format)
+  {
+    byte[] result;
+    switch (format)
+      {
+      case IKeyPairCodec.RAW_FORMAT:
+        result = new DSSKeyPairRawCodec().encodePublicKey(this);
+        break;
+      case IKeyPairCodec.X509_FORMAT:
+        result = new DSSKeyPairX509Codec().encodePublicKey(this);
+        break;
+      default:
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
+      }
+    return result;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * {@link DSAPublicKey} and has the same DSS (Digital Signature Standard)
+   * parameter values as this one.
+   * 
+   * @param obj the other non-null DSS key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(Object obj)
+  {
+    if (obj == null)
+      return false;
+
+    if (! (obj instanceof DSAPublicKey))
+      return false;
+
+    DSAPublicKey that = (DSAPublicKey) obj;
+    return super.equals(that) && y.equals(that.getY());
+  }
+
+  public String toString()
+  {
+    if (str == null)
+      {
+        String ls = (String) AccessController.doPrivileged
+            (new GetPropertyAction("line.separator"));
+        str = new StringBuilder(this.getClass().getName()).append("(")
+            .append(super.toString()).append(",").append(ls)
+            .append("y=0x").append(y.toString(16)).append(ls)
+            .append(")")
+            .toString();
+      }
+    return str;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/dss/FIPS186.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,262 @@
+/* FIPS186.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * An implementation of the DSA parameters generation as described in FIPS-186.
+ * <p>
+ * References:
+ * <p>
+ * <a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
+ * Standard (DSS)</a>, Federal Information Processing Standards Publication
+ * 186. National Institute of Standards and Technology.
+ */
+public class FIPS186
+{
+  public static final int DSA_PARAMS_SEED = 0;
+
+  public static final int DSA_PARAMS_COUNTER = 1;
+
+  public static final int DSA_PARAMS_Q = 2;
+
+  public static final int DSA_PARAMS_P = 3;
+
+  public static final int DSA_PARAMS_E = 4;
+
+  public static final int DSA_PARAMS_G = 5;
+
+  /** The BigInteger constant 2. */
+  private static final BigInteger TWO = BigInteger.valueOf(2L);
+
+  private static final BigInteger TWO_POW_160 = TWO.pow(160);
+
+  /** The SHA instance to use. */
+  private Sha160 sha = new Sha160();
+
+  /** The length of the modulus of DSS keys generated by this instance. */
+  private int L;
+
+  /** The optional {@link SecureRandom} instance to use. */
+  private SecureRandom rnd = null;
+
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+
+  public FIPS186(int L, SecureRandom rnd)
+  {
+    super();
+
+    this.L = L;
+    this.rnd = rnd;
+  }
+
+  /**
+   * This method generates the DSS <code>p</code>, <code>q</code>, and
+   * <code>g</code> parameters only when <code>L</code> (the modulus length)
+   * is not one of the following: <code>512</code>, <code>768</code> and
+   * <code>1024</code>. For those values of <code>L</code>, this
+   * implementation uses pre-computed values of <code>p</code>,
+   * <code>q</code>, and <code>g</code> given in the document <i>CryptoSpec</i>
+   * included in the security guide documentation of the standard JDK
+   * distribution.
+   * <p>
+   * The DSS requires two primes , <code>p</code> and <code>q</code>,
+   * satisfying the following three conditions:
+   * <ul>
+   * <li><code>2<sup>159</sup> &lt; q &lt; 2<sup>160</sup></code></li>
+   * <li><code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code> for a
+   * specified <code>L</code>, where <code>L = 512 + 64j</code> for some
+   * <code>0 &lt;= j &lt;= 8</code></li>
+   * <li>q divides p - 1.</li>
+   * </ul>
+   * The algorithm used to find these primes is as described in FIPS-186,
+   * section 2.2: GENERATION OF PRIMES. This prime generation scheme starts by
+   * using the {@link Sha160} and a user supplied <i>SEED</i> to construct a
+   * prime, <code>q</code>, in the range 2<sup>159</sup> &lt; q &lt; 2<sup>160</sup>.
+   * Once this is accomplished, the same <i>SEED</i> value is used to construct
+   * an <code>X</code> in the range <code>2<sup>L-1
+   * </sup> &lt; X &lt; 2<sup>L</sup>. The prime, <code>p</code>, is then
+   * formed by rounding <code>X</code> to a number congruent to <code>1 mod
+   * 2q</code>. In this implementation we use the same <i>SEED</i> value given
+   * in FIPS-186, Appendix 5.
+   */
+  public BigInteger[] generateParameters()
+  {
+    int counter, offset;
+    BigInteger SEED, alpha, U, q, OFFSET, SEED_PLUS_OFFSET, W, X, p, c, g;
+    byte[] a, u;
+    byte[] kb = new byte[20]; // to hold 160 bits of randomness
+
+    // Let L-1 = n*160 + b, where b and n are integers and 0 <= b < 160.
+    int b = (L - 1) % 160;
+    int n = (L - 1 - b) / 160;
+    BigInteger[] V = new BigInteger[n + 1];
+    algorithm: while (true)
+      {
+        step1: while (true)
+          {
+            // 1. Choose an arbitrary sequence of at least 160 bits and
+            // call it SEED.
+            nextRandomBytes(kb);
+            SEED = new BigInteger(1, kb).setBit(159).setBit(0);
+            // Let g be the length of SEED in bits. here always 160
+            // 2. Compute: U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g]
+            alpha = SEED.add(BigInteger.ONE).mod(TWO_POW_160);
+            synchronized (sha)
+              {
+                a = SEED.toByteArray();
+                sha.update(a, 0, a.length);
+                a = sha.digest();
+                u = alpha.toByteArray();
+                sha.update(u, 0, u.length);
+                u = sha.digest();
+              }
+            for (int i = 0; i < a.length; i++)
+              a[i] ^= u[i];
+
+            U = new BigInteger(1, a);
+            // 3. Form q from U by setting the most significant bit (the
+            // 2**159 bit) and the least significant bit to 1. In terms of
+            // boolean operations, q = U OR 2**159 OR 1. Note that
+            // 2**159 < q < 2**160.
+            q = U.setBit(159).setBit(0);
+            // 4. Use a robust primality testing algorithm to test whether
+            // q is prime(1). A robust primality test is one where the
+            // probability of a non-prime number passing the test is at
+            // most 1/2**80.
+            // 5. If q is not prime, go to step 1.
+            if (q.isProbablePrime(80))
+              break step1;
+          } // step1
+        // 6. Let counter = 0 and offset = 2.
+        counter = 0;
+        offset = 2;
+        step7: while (true)
+          {
+            OFFSET = BigInteger.valueOf(offset & 0xFFFFFFFFL);
+            SEED_PLUS_OFFSET = SEED.add(OFFSET);
+            // 7. For k = 0,...,n let V[k] = SHA[(SEED + offset + k) mod 2**g].
+            synchronized (sha)
+              {
+                for (int k = 0; k <= n; k++)
+                  {
+                    a = SEED_PLUS_OFFSET
+                        .add(BigInteger.valueOf(k & 0xFFFFFFFFL))
+                        .mod(TWO_POW_160).toByteArray();
+                    sha.update(a, 0, a.length);
+                    V[k] = new BigInteger(1, sha.digest());
+                  }
+              }
+            // 8. Let W be the integer:
+            // V[0]+V[1]*2**160+...+V[n-1]*2**((n-1)*160)+(V[n]mod2**b)*2**(n*160)
+            // and let : X = W + 2**(L-1).
+            // Note that 0 <= W < 2**(L-1) and hence 2**(L-1) <= X < 2**L.
+            W = V[0];
+            for (int k = 1; k < n; k++)
+              W = W.add(V[k].multiply(TWO.pow(k * 160)));
+
+            W = W.add(V[n].mod(TWO.pow(b)).multiply(TWO.pow(n * 160)));
+            X = W.add(TWO.pow(L - 1));
+            // 9. Let c = X mod 2q and set p = X - (c - 1).
+            // Note that p is congruent to 1 mod 2q.
+            c = X.mod(TWO.multiply(q));
+            p = X.subtract(c.subtract(BigInteger.ONE));
+            // 10. If p < 2**(L-1), then go to step 13.
+            if (p.compareTo(TWO.pow(L - 1)) >= 0)
+              {
+                // 11. Perform a robust primality test on p.
+                // 12. If p passes the test performed in step 11, go to step 15.
+                if (p.isProbablePrime(80))
+                  break algorithm;
+              }
+            // 13. Let counter = counter + 1 and offset = offset + n + 1.
+            counter++;
+            offset += n + 1;
+            // 14. If counter >= 4096 go to step 1, otherwise go to step 7.
+            if (counter >= 4096)
+              continue algorithm;
+          } // step7
+      } // algorithm
+    // compute g. from FIPS-186, Appendix 4:
+    // 1. Generate p and q as specified in Appendix 2.
+    // 2. Let e = (p - 1) / q
+    BigInteger e = p.subtract(BigInteger.ONE).divide(q);
+    BigInteger h = TWO;
+    BigInteger p_minus_1 = p.subtract(BigInteger.ONE);
+    g = TWO;
+    // 3. Set h = any integer, where 1 < h < p - 1 and
+    // h differs from any value previously tried
+    for (; h.compareTo(p_minus_1) < 0; h = h.add(BigInteger.ONE))
+      {
+        // 4. Set g = h**e mod p
+        g = h.modPow(e, p);
+        // 5. If g = 1, go to step 3
+        if (! g.equals(BigInteger.ONE))
+          break;
+      }
+    return new BigInteger[] { SEED, BigInteger.valueOf(counter), q, p, e, g };
+  }
+
+  /**
+   * Fills the designated byte array with random data.
+   * 
+   * @param buffer the byte array to fill with random data.
+   */
+  private void nextRandomBytes(byte[] buffer)
+  {
+    if (rnd != null)
+      rnd.nextBytes(buffer);
+    else
+      getDefaultPRNG().nextBytes(buffer);
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/rsa/GnuRSAKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,176 @@
+/* GnuRSAKey.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.rsa;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.util.FormatUtil;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.Key;
+import java.security.interfaces.RSAKey;
+
+/**
+ * A base asbtract class for both public and private RSA keys.
+ */
+public abstract class GnuRSAKey
+    implements Key, RSAKey
+{
+  /** The public modulus of an RSA key pair. */
+  private final BigInteger n;
+
+  /** The public exponent of an RSA key pair. */
+  private final BigInteger e;
+
+  /**
+   * Identifier of the default encoding format to use when externalizing the key
+   * material.
+   */
+  protected final int defaultFormat;
+
+  /** String representation of this key. Cached for speed. */
+  private transient String str;
+
+  /**
+   * Trivial protected constructor.
+   * 
+   * @param defaultFormat the identifier of the encoding format to use by
+   *          default when externalizing the key.
+   * @param n the public modulus <code>n</code>.
+   * @param e the public exponent <code>e</code>.
+   */
+  protected GnuRSAKey(int defaultFormat, BigInteger n, BigInteger e)
+  {
+    super();
+
+    this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID
+                                            : defaultFormat;
+    this.n = n;
+    this.e = e;
+  }
+
+  public BigInteger getModulus()
+  {
+    return getN();
+  }
+
+  public String getAlgorithm()
+  {
+    return Registry.RSA_KPG;
+  }
+
+  /** @deprecated see getEncoded(int). */
+  public byte[] getEncoded()
+  {
+    return getEncoded(defaultFormat);
+  }
+
+  public String getFormat()
+  {
+    return FormatUtil.getEncodingShortName(defaultFormat);
+  }
+
+  /**
+   * Returns the modulus <code>n</code>.
+   * 
+   * @return the modulus <code>n</code>.
+   */
+  public BigInteger getN()
+  {
+    return n;
+  }
+
+  /**
+   * Returns the public exponent <code>e</code>.
+   * 
+   * @return the public exponent <code>e</code>.
+   */
+  public BigInteger getPublicExponent()
+  {
+    return getE();
+  }
+
+  /**
+   * Same as {@link #getPublicExponent()}.
+   * 
+   * @return the public exponent <code>e</code>.
+   */
+  public BigInteger getE()
+  {
+    return e;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * {@link RSAKey} and has the same RSA parameter values as this one.
+   * 
+   * @param obj the other non-null RSA key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(final Object obj)
+  {
+    if (obj == null)
+      return false;
+
+    if (! (obj instanceof RSAKey))
+      return false;
+
+    final RSAKey that = (RSAKey) obj;
+    return n.equals(that.getModulus());
+  }
+
+  public String toString()
+  {
+    if (str == null)
+      {
+        String ls = (String) AccessController.doPrivileged
+            (new GetPropertyAction("line.separator"));
+        str = new StringBuilder(ls)
+            .append("defaultFormat=").append(defaultFormat).append(",").append(ls)
+            .append("n=0x").append(n.toString(16)).append(",").append(ls)
+            .append("e=0x").append(e.toString(16))
+            .toString();
+      }
+    return str;
+  }
+
+  public abstract byte[] getEncoded(int format);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/rsa/GnuRSAPrivateKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,311 @@
+/* GnuRSAPrivateKey.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.rsa;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.PrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+
+/**
+ * An object that embodies an RSA private key.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+public class GnuRSAPrivateKey
+    extends GnuRSAKey
+    implements PrivateKey, RSAPrivateCrtKey
+{
+  /** The first prime divisor of the modulus. */
+  private final BigInteger p;
+
+  /** The second prime divisor of the modulus. */
+  private final BigInteger q;
+
+  /** The private exponent of an RSA private key. */
+  private final BigInteger d;
+
+  /** The first factor's exponent. */
+  private final BigInteger dP;
+
+  /** The second factor's exponent. */
+  private final BigInteger dQ;
+
+  /** The CRT (Chinese Remainder Theorem) coefficient. */
+  private final BigInteger qInv;
+
+  /** String representation of this key. Cached for speed. */
+  private transient String str;
+
+  /**
+   * Convenience constructor. Calls the constructor with 5 arguments passing
+   * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred
+   * encoding format.
+   * 
+   * @param p the modulus first prime divisor.
+   * @param q the modulus second prime divisor.
+   * @param e the public exponent.
+   * @param d the private exponent.
+   */
+  public GnuRSAPrivateKey(BigInteger p, BigInteger q, BigInteger e, BigInteger d)
+  {
+    this(Registry.RAW_ENCODING_ID, p, q, e, d);
+  }
+
+  /**
+   * Constructs a new instance of a <code>GnuRSAPrivateKey</code> given the
+   * designated arguments.
+   * 
+   * @param preferredFormat the indetifier of the preferred encoding format to
+   *          use when externalizing this key.
+   * @param p the modulus first prime divisor.
+   * @param q the modulus second prime divisor.
+   * @param e the public exponent.
+   * @param d the private exponent.
+   */
+  public GnuRSAPrivateKey(int preferredFormat, BigInteger p, BigInteger q,
+                          BigInteger e, BigInteger d)
+  {
+    this(preferredFormat,
+         p.multiply(q),
+         e, d, p, q,
+         e.modInverse(p.subtract(BigInteger.ONE)),
+         e.modInverse(q.subtract(BigInteger.ONE)),
+         q.modInverse(p));
+  }
+
+  /**
+   * Constructs a new instance of a <code>GnuRSAPrivateKey</code> given the
+   * designated arguments.
+   * 
+   * @param preferredFormat the indetifier of the preferred encoding format to
+   *          use when externalizing this key.
+   * @param n the public modulus, which is also the product of <code>p</code>
+   *          and <code>q</code>.
+   * @param e the public exponent.
+   * @param d the private exponent.
+   * @param p the modulus first prime divisor.
+   * @param q the modulus second prime divisor.
+   * @param dP the first prime's exponen. A positive integer less than
+   *          <code>p</code> and <code>q</code>, satisfying
+   *          <code>e * dP = 1 (mod p-1)</code>.
+   * @param dQ the second prime's exponent. A positive integer less than
+   *          <code>p</code> and <code>q</code>, satisfying
+   *          <code>e * dQ = 1 (mod p-1)</code>.
+   * @param qInv the Chinese Remainder Theorem coefiicient. A positive integer
+   *          less than <code>p</code>, satisfying
+   *          <code>q * qInv = 1 (mod p)</code>.
+   */
+  public GnuRSAPrivateKey(int preferredFormat, BigInteger n, BigInteger e,
+                          BigInteger d, BigInteger p, BigInteger q,
+                          BigInteger dP, BigInteger dQ, BigInteger qInv)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID
+                                                       : preferredFormat,
+          n, e);
+    this.d = d;
+    this.p = p;
+    this.q = q;
+    // the exponents dP and dQ are positive integers less than p and q
+    // respectively satisfying
+    // e * dP = 1 (mod p-1);
+    // e * dQ = 1 (mod q-1),
+    this.dP = dP;
+    this.dQ = dQ;
+    // the CRT coefficient qInv is a positive integer less than p satisfying
+    // q * qInv = 1 (mod p).
+    this.qInv = qInv;
+  }
+
+  /**
+   * A class method that takes the output of the <code>encodePrivateKey()</code>
+   * method of an RSA keypair codec object (an instance implementing
+   * {@link IKeyPairCodec} for RSA keys, and re-constructs an instance of this
+   * object.
+   * 
+   * @param k the contents of a previously encoded instance of this object.
+   * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in
+   *           <code>k</code>, to represent a valid encoding of an instance
+   *           of this object.
+   * @throws IllegalArgumentException if the byte sequence does not represent a
+   *           valid encoding of an instance of this object.
+   */
+  public static GnuRSAPrivateKey valueOf(final byte[] k)
+  {
+    // try RAW codec
+    if (k[0] == Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0])
+      try
+        {
+          return (GnuRSAPrivateKey) new RSAKeyPairRawCodec().decodePrivateKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+    // try PKCS#8 codec
+    return (GnuRSAPrivateKey) new RSAKeyPairPKCS8Codec().decodePrivateKey(k);
+  }
+
+  public BigInteger getPrimeP()
+  {
+    return p;
+  }
+
+  public BigInteger getPrimeQ()
+  {
+    return q;
+  }
+
+  public BigInteger getPrimeExponentP()
+  {
+    return dP;
+  }
+
+  public BigInteger getPrimeExponentQ()
+  {
+    return dQ;
+  }
+
+  public BigInteger getCrtCoefficient()
+  {
+    return qInv;
+  }
+
+  public BigInteger getPrivateExponent()
+  {
+    return d;
+  }
+
+  /**
+   * Returns the encoded form of this private key according to the designated
+   * format.
+   * 
+   * @param format the desired format identifier of the resulting encoding.
+   * @return the byte sequence encoding this key according to the designated
+   *         format.
+   * @throws IllegalArgumentException if the format is not supported.
+   * @see RSAKeyPairRawCodec
+   * @see RSAKeyPairPKCS8Codec
+   */
+  public byte[] getEncoded(int format)
+  {
+    final byte[] result;
+    switch (format)
+      {
+      case IKeyPairCodec.RAW_FORMAT:
+        result = new RSAKeyPairRawCodec().encodePrivateKey(this);
+        break;
+      case IKeyPairCodec.PKCS8_FORMAT:
+        result = new RSAKeyPairPKCS8Codec().encodePrivateKey(this);
+        break;
+      default:
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
+      }
+    return result;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of this
+   * class and has the same RSA parameter values as this one.
+   * 
+   * @param obj the other non-null RSA key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(final Object obj)
+  {
+    if (obj == null)
+      return false;
+
+    if (obj instanceof RSAPrivateKey)
+      {
+        final RSAPrivateKey that = (RSAPrivateKey) obj;
+        return super.equals(that) && d.equals(that.getPrivateExponent());
+      }
+    if (obj instanceof RSAPrivateCrtKey)
+      {
+        final RSAPrivateCrtKey that = (RSAPrivateCrtKey) obj;
+        return super.equals(that) && p.equals(that.getPrimeP())
+               && q.equals(that.getPrimeQ())
+               && dP.equals(that.getPrimeExponentP())
+               && dQ.equals(that.getPrimeExponentQ())
+               && qInv.equals(that.getCrtCoefficient());
+      }
+    return false;
+  }
+
+  public String toString()
+  {
+    if (str == null)
+      {
+        String ls = (String) AccessController.doPrivileged
+            (new GetPropertyAction("line.separator"));
+        str = new StringBuilder(this.getClass().getName()).append("(")
+            .append(super.toString()).append(",").append(ls)
+            .append("d=0x").append(Configuration.DEBUG ? d.toString(16)
+                                                       : "**...*").append(ls)
+            .append("p=0x").append(Configuration.DEBUG ? p.toString(16)
+                                                       : "**...*").append(ls)
+            .append("q=0x").append(Configuration.DEBUG ? q.toString(16)
+                                                       : "**...*").append(ls)
+            .append("dP=0x").append(Configuration.DEBUG ? dP.toString(16)
+                                                        : "**...*").append(ls)
+            .append("dQ=0x").append(Configuration.DEBUG ? dQ.toString(16)
+                                                        : "**...*").append(ls)
+            .append("qInv=0x").append(Configuration.DEBUG ? qInv.toString(16)
+                                                          : "**...*").append(ls)
+            .append(")")
+            .toString();
+      }
+    return str;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/rsa/GnuRSAPublicKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,188 @@
+/* GnuRSAPublicKey.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.rsa;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPublicKey;
+
+/**
+ * An object that encapsulates an RSA public key.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+public class GnuRSAPublicKey
+    extends GnuRSAKey
+    implements PublicKey, RSAPublicKey
+{
+  /** String representation of this key. Cached for speed. */
+  private transient String str;
+
+  /**
+   * Conveience constructor. Calls the constructor with 3 arguments passing
+   * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred
+   * encoding format.
+   * 
+   * @param n the modulus.
+   * @param e the public exponent.
+   */
+  public GnuRSAPublicKey(final BigInteger n, final BigInteger e)
+  {
+    this(Registry.RAW_ENCODING_ID, n, e);
+  }
+
+  /**
+   * Constructs a new instance of <code>GnuRSAPublicKey</code> given the
+   * designated arguments.
+   * 
+   * @param preferredFormat the identifier of the preferred encoding format to
+   *          use when externalizing this key.
+   * @param n the modulus.
+   * @param e the public exponent.
+   */
+  public GnuRSAPublicKey(int preferredFormat, BigInteger n, BigInteger e)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID
+                                                       : preferredFormat,
+          n, e);
+  }
+
+  /**
+   * A class method that takes the output of the <code>encodePublicKey()</code>
+   * method of an RSA keypair codec object (an instance implementing
+   * {@link IKeyPairCodec} for RSA keys, and re-constructs an instance of this
+   * object.
+   * 
+   * @param k the contents of a previously encoded instance of this object.
+   * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in
+   *           <code>k</code>, to represent a valid encoding of an instance
+   *           of this object.
+   * @throws IllegalArgumentException if the byte sequence does not represent a
+   *           valid encoding of an instance of this object.
+   */
+  public static GnuRSAPublicKey valueOf(final byte[] k)
+  {
+    // try RAW codec
+    if (k[0] == Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0])
+      try
+        {
+          return (GnuRSAPublicKey) new RSAKeyPairRawCodec().decodePublicKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+    // try X.509 codec
+    return (GnuRSAPublicKey) new RSAKeyPairX509Codec().decodePublicKey(k);
+  }
+
+  /**
+   * Returns the encoded form of this public key according to the designated
+   * format.
+   * 
+   * @param format the desired format identifier of the resulting encoding.
+   * @return the byte sequence encoding this key according to the designated
+   *         format.
+   * @throws IllegalArgumentException if the format is not supported.
+   * @see RSAKeyPairRawCodec
+   */
+  public byte[] getEncoded(final int format)
+  {
+    final byte[] result;
+    switch (format)
+      {
+      case IKeyPairCodec.RAW_FORMAT:
+        result = new RSAKeyPairRawCodec().encodePublicKey(this);
+        break;
+      case IKeyPairCodec.X509_FORMAT:
+        result = new RSAKeyPairX509Codec().encodePublicKey(this);
+        break;
+      default:
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
+      }
+    return result;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of this
+   * class and has the same RSA parameter values as this one.
+   * 
+   * @param obj the other non-null RSA key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(final Object obj)
+  {
+    if (obj == null)
+      return false;
+
+    if (! (obj instanceof RSAPublicKey))
+      return false;
+
+    final RSAPublicKey that = (RSAPublicKey) obj;
+    return super.equals(that)
+           && getPublicExponent().equals(that.getPublicExponent());
+  }
+
+  public String toString()
+  {
+    if (str == null)
+      {
+        String ls = (String) AccessController.doPrivileged
+            (new GetPropertyAction("line.separator"));
+        str = new StringBuilder(this.getClass().getName()).append("(")
+            .append(super.toString()).append(",").append(ls)
+            .append(")")
+            .toString();
+      }
+    return str;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/rsa/RSAKeyPairGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,246 @@
+/* RSAKeyPairGenerator.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.rsa;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.RSAKeyGenParameterSpec;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * A key-pair generator for asymetric keys to use in conjunction with the RSA
+ * scheme.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix</a>, part B. Primitive specification
+ * and supporting documentation. Jakob Jonsson and Burt Kaliski. </li>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac/">Handbook of Applied
+ * Cryptography</a>, Alfred J. Menezes, Paul C. van Oorschot and Scott A.
+ * Vanstone. Section 11.3 RSA and related signature schemes.</li>
+ * </ol>
+ */
+public class RSAKeyPairGenerator
+    implements IKeyPairGenerator
+{
+  private static final Logger log = Logger.getLogger(RSAKeyPairGenerator.class.getName());
+
+  /** The BigInteger constant 1. */
+  private static final BigInteger ONE = BigInteger.ONE;
+
+  /** The BigInteger constant 2. */
+  private static final BigInteger TWO = BigInteger.valueOf(2L);
+
+  /** Property name of the length (Integer) of the modulus of an RSA key. */
+  public static final String MODULUS_LENGTH = "gnu.crypto.rsa.L";
+
+  /**
+   * Property name of an optional {@link SecureRandom} instance to use. The
+   * default is to use a classloader singleton from {@link PRNG}.
+   */
+  public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.rsa.prng";
+
+  /**
+   * Property name of an optional {@link RSAKeyGenParameterSpec} instance to use
+   * for this generator's <code>n</code>, and <code>e</code> values. The
+   * default is to generate <code>n</code> and use a fixed value for
+   * <code>e</.code> (Fermat's F4 number).
+   */
+  public static final String RSA_PARAMETERS = "gnu.crypto.rsa.params";
+
+  /**
+   * Property name of the preferred encoding format to use when externalizing
+   * generated instance of key-pairs from this generator. The property is taken
+   * to be an {@link Integer} that encapsulates an encoding format identifier.
+   */
+  public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.rsa.encoding";
+
+  /** Default value for the modulus length. */
+  private static final int DEFAULT_MODULUS_LENGTH = 1024;
+
+  /** Default encoding format to use when none was specified. */
+  private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
+
+  /** The desired bit length of the modulus. */
+  private int L;
+
+  /**
+   * This implementation uses, by default, Fermat's F4 number as the public
+   * exponent.
+   */
+  private BigInteger e = BigInteger.valueOf(65537L);
+
+  /** The optional {@link SecureRandom} instance to use. */
+  private SecureRandom rnd = null;
+
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+
+  /** Preferred encoding format of generated keys. */
+  private int preferredFormat;
+
+  // implicit 0-arguments constructor
+
+  public String name()
+  {
+    return Registry.RSA_KPG;
+  }
+
+  /**
+   * Configures this instance.
+   * 
+   * @param attributes the map of name/value pairs to use.
+   * @exception IllegalArgumentException if the designated MODULUS_LENGTH value
+   *              is less than 1024.
+   */
+  public void setup(Map attributes)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "setup", attributes);
+    // do we have a SecureRandom, or should we use our own?
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    // are we given a set of RSA params or we shall use our own?
+    RSAKeyGenParameterSpec params = (RSAKeyGenParameterSpec) attributes.get(RSA_PARAMETERS);
+    // find out the modulus length
+    if (params != null)
+      {
+        L = params.getKeysize();
+        e = params.getPublicExponent();
+      }
+    else
+      {
+        Integer l = (Integer) attributes.get(MODULUS_LENGTH);
+        L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue());
+      }
+    if (L < 1024)
+      throw new IllegalArgumentException(MODULUS_LENGTH);
+
+    // what is the preferred encoding format
+    Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
+    preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
+                                       : formatID.intValue();
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "setup");
+  }
+
+  /**
+   * <p>
+   * The algorithm used here is described in <i>nessie-pss-B.pdf</i> document
+   * which is part of the RSA-PSS submission to NESSIE.
+   * </p>
+   * 
+   * @return an RSA keypair.
+   */
+  public KeyPair generate()
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "generate");
+    BigInteger p, q, n, d;
+    // 1. Generate a prime p in the interval [2**(M-1), 2**M - 1], where
+    // M = CEILING(L/2), and such that GCD(p, e) = 1
+    int M = (L + 1) / 2;
+    BigInteger lower = TWO.pow(M - 1);
+    BigInteger upper = TWO.pow(M).subtract(ONE);
+    byte[] kb = new byte[(M + 7) / 8]; // enough bytes to frame M bits
+    step1: while (true)
+      {
+        nextRandomBytes(kb);
+        p = new BigInteger(1, kb).setBit(0);
+        if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0
+            && p.isProbablePrime(80) && p.gcd(e).equals(ONE))
+          break step1;
+      }
+    // 2. Generate a prime q such that the product of p and q is an L-bit
+    // number, and such that GCD(q, e) = 1
+    step2: while (true)
+      {
+        nextRandomBytes(kb);
+        q = new BigInteger(1, kb).setBit(0);
+        n = p.multiply(q);
+        if (n.bitLength() == L && q.isProbablePrime(80) && q.gcd(e).equals(ONE))
+          break step2;
+        // TODO: test for p != q
+      }
+    // TODO: ensure p < q
+    // 3. Put n = pq. The public key is (n, e).
+    // 4. Compute the parameters necessary for the private key K (see
+    // Section 2.2).
+    BigInteger phi = p.subtract(ONE).multiply(q.subtract(ONE));
+    d = e.modInverse(phi);
+    // 5. Output the public key and the private key.
+    PublicKey pubK = new GnuRSAPublicKey(preferredFormat, n, e);
+    PrivateKey secK = new GnuRSAPrivateKey(preferredFormat, p, q, e, d);
+    KeyPair result = new KeyPair(pubK, secK);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "generate", result);
+    return result;
+  }
+
+  /**
+   * Fills the designated byte array with random data.
+   * 
+   * @param buffer the byte array to fill with random data.
+   */
+  private void nextRandomBytes(byte[] buffer)
+  {
+    if (rnd != null)
+      rnd.nextBytes(buffer);
+    else
+      getDefaultPRNG().nextBytes(buffer);
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,299 @@
+/* RSAKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.rsa;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+/**
+ * An implementation of an {@link IKeyPairCodec} that knows how to encode /
+ * decode PKCS#8 ASN.1 external representation of RSA private keys.
+ */
+public class RSAKeyPairPKCS8Codec
+    implements IKeyPairCodec
+{
+  private static final Logger log = Logger.getLogger(RSAKeyPairPKCS8Codec.class.getName());
+  private static final OID RSA_ALG_OID = new OID(Registry.RSA_OID_STRING);
+
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return PKCS8_FORMAT;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    throw new InvalidParameterException("Wrong format for public keys");
+  }
+
+  /**
+   * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of an RSA
+   * private key. The ASN.1 specification is as follows:
+   * <pre>
+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   * </pre>
+   * <p>
+   * As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL
+   * for this algorithm identifier.".
+   * <p>
+   * The <i>privateKey</i> field, which is an OCTET STRING, contains the
+   * DER-encoded form of the RSA private key defined as:
+   * <pre>
+   *   RSAPrivateKey ::= SEQUENCE {
+   *     version                 INTEGER, -- MUST be 0
+   *     modulus                 INTEGER, -- n
+   *     publicExponent          INTEGER, -- e
+   *     privateExponent         INTEGER, -- d
+   *     prime1                  INTEGER, -- p
+   *     prime2                  INTEGER, -- q
+   *     exponent1               INTEGER, -- d mod (p-1)
+   *     exponent2               INTEGER, -- d mod (q-1)
+   *     coefficient             INTEGER, -- (inverse of q) mod p
+   *   }
+   * </pre>
+   * 
+   * @return the DER encoded form of the ASN.1 representation of the
+   *         <i>PrivateKeyInfo</i> field for an RSA {@link PrivateKey}..
+   * @throw InvalidParameterException if an error occurs during the marshalling
+   *        process.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "encodePrivateKey()", key);
+    if (! (key instanceof GnuRSAPrivateKey))
+      throw new InvalidParameterException("Wrong key type");
+
+    GnuRSAPrivateKey pk = (GnuRSAPrivateKey) key;
+    BigInteger n = pk.getN();
+    BigInteger e = pk.getE();
+    BigInteger d = pk.getPrivateExponent();
+    BigInteger p = pk.getPrimeP();
+    BigInteger q = pk.getPrimeQ();
+    BigInteger dP = pk.getPrimeExponentP();
+    BigInteger dQ = pk.getPrimeExponentQ();
+    BigInteger qInv = pk.getCrtCoefficient();
+
+    DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, RSA_ALG_OID);
+
+    ArrayList algorithmID = new ArrayList(2);
+    algorithmID.add(derOID);
+    algorithmID.add(new DERValue(DER.NULL, null));
+    DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                           algorithmID);
+
+    DERValue derRSAVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+    DERValue derN = new DERValue(DER.INTEGER, n);
+    DERValue derE = new DERValue(DER.INTEGER, e);
+    DERValue derD = new DERValue(DER.INTEGER, d);
+    DERValue derP = new DERValue(DER.INTEGER, p);
+    DERValue derQ = new DERValue(DER.INTEGER, q);
+    DERValue derDP = new DERValue(DER.INTEGER, dP);
+    DERValue derDQ = new DERValue(DER.INTEGER, dQ);
+    DERValue derQInv = new DERValue(DER.INTEGER, qInv);
+
+    ArrayList rsaPrivateKey = new ArrayList();
+    rsaPrivateKey.add(derRSAVersion);
+    rsaPrivateKey.add(derN);
+    rsaPrivateKey.add(derE);
+    rsaPrivateKey.add(derD);
+    rsaPrivateKey.add(derP);
+    rsaPrivateKey.add(derQ);
+    rsaPrivateKey.add(derDP);
+    rsaPrivateKey.add(derDQ);
+    rsaPrivateKey.add(derQInv);
+    DERValue derRSAPrivateKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                             rsaPrivateKey);
+    byte[] pkBytes = derRSAPrivateKey.getEncoded();
+    DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, pkBytes);
+
+    ArrayList pki = new ArrayList(3);
+    pki.add(derVersion);
+    pki.add(derAlgorithmID);
+    pki.add(derPrivateKey);
+    DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
+
+    byte[] result;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try
+      {
+        DERWriter.write(baos, derPKI);
+        result = baos.toByteArray();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(x);
+        throw y;
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "encodePrivateKey()", result);
+    return result;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public PublicKey decodePublicKey(byte[] input)
+  {
+    throw new InvalidParameterException("Wrong format for public keys");
+  }
+
+  /**
+   * @param input the byte array to unmarshall into a valid RSA
+   *          {@link PrivateKey} instance. MUST NOT be null.
+   * @return a new instance of a {@link GnuRSAPrivateKey} decoded from the
+   *         <i>PrivateKeyInfo</i> material fed as <code>input</code>.
+   * @throw InvalidParameterException if an exception occurs during the
+   *        unmarshalling process.
+   */
+  public PrivateKey decodePrivateKey(byte[] input)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "decodePrivateKey()", input);
+    if (input == null)
+      throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+    BigInteger version, n, e, d, p, q, dP, dQ, qInv;
+    DERReader der = new DERReader(input);
+    try
+      {
+        DERValue derPKI = der.read();
+        DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
+
+        DERValue derVersion = der.read();
+        DerUtil.checkIsBigInteger(derVersion, "Wrong Version field");
+        version = (BigInteger) derVersion.getValue();
+        if (version.compareTo(BigInteger.ZERO) != 0)
+          throw new InvalidParameterException("Unexpected Version: " + version);
+
+        DERValue derAlgoritmID = der.read();
+        DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
+
+        DERValue derOID = der.read();
+        OID algOID = (OID) derOID.getValue();
+        if (! algOID.equals(RSA_ALG_OID))
+          throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+        // rfc-2459 states that this field is OPTIONAL but NULL if/when present
+        DERValue val = der.read();
+        if (val.getTag() == DER.NULL)
+          val = der.read();
+
+        byte[] pkBytes = (byte[]) val.getValue();
+        der = new DERReader(pkBytes);
+        DERValue derRSAPrivateKey = der.read();
+        DerUtil.checkIsConstructed(derRSAPrivateKey, "Wrong RSAPrivateKey field");
+        
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong RSAPrivateKey Version field");
+        version = (BigInteger) val.getValue();
+        if (version.compareTo(BigInteger.ZERO) != 0)
+          throw new InvalidParameterException("Unexpected RSAPrivateKey Version: "
+                                              + version);
+
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong modulus field");
+        n = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong publicExponent field");
+        e = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong privateExponent field");
+        d = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong prime1 field");
+        p = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong prime2 field");
+        q = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong exponent1 field");
+        dP = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong exponent2 field");
+        dQ = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong coefficient field");
+        qInv = (BigInteger) val.getValue();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(x);
+        throw y;
+      }
+    PrivateKey result = new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID,
+                                             n, e, d, p, q, dP, dQ, qInv);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "decodePrivateKey()", result);
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,300 @@
+/* RSAKeyPairRawCodec.java -- 
+   Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.key.rsa;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * An object that implements the {@link IKeyPairCodec} interface for the <i>Raw</i>
+ * format to use with RSA keypairs.
+ */
+public class RSAKeyPairRawCodec
+    implements IKeyPairCodec
+{
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return RAW_FORMAT;
+  }
+
+  /**
+   * Returns the encoded form of the designated RSA public key according to the
+   * <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for an RSA public key, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_RSA_PUBLIC_KEY},</li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the RSA parameter
+   * <code>n</code> (the modulus) in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the RSA parameter <code>n</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the RSA parameter
+   * <code>e</code> (the public exponent) in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the RSA parameter <code>e</code>.
+   * </li>
+   * </ol>
+   *
+   * @param key the key to encode.
+   * @return the <i>Raw</i> format encoding of the designated key.
+   * @exception IllegalArgumentException if the designated key is not an RSA
+   *                                     one.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    if (! (key instanceof GnuRSAPublicKey))
+      throw new IllegalArgumentException("key");
+
+    GnuRSAPublicKey rsaKey = (GnuRSAPublicKey) key;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0]);
+    baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[1]);
+    baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[2]);
+    baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[3]);
+    // version
+    baos.write(0x01);
+    // n
+    byte[] buffer = rsaKey.getModulus().toByteArray();
+    int length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // e
+    buffer = rsaKey.getPublicExponent().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    return baos.toByteArray();
+  }
+
+  public PublicKey decodePublicKey(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0]
+        || k[1] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[1]
+        || k[2] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[2]
+        || k[3] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[3])
+      throw new IllegalArgumentException("magic");
+
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+
+    int i = 5;
+    int l;
+    byte[] buffer;
+    // n
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger n = new BigInteger(1, buffer);
+    // e
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger e = new BigInteger(1, buffer);
+    return new GnuRSAPublicKey(n, e);
+  }
+
+  /**
+   * Returns the encoded form of the designated RSA private key according to the
+   * <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for an RSA private key, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_RSA_PRIVATE_KEY},</li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the RSA parameter
+   * <code>p</code> (the first prime factor of the modulus) in internet order,
+   * </li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the RSA parameter <code>p</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the RSA parameter
+   * <code>q</code> (the second prime factor of the modulus) in internet
+   * order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the RSA parameter <code>q</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the RSA parameter
+   * <code>e</code> (the public exponent) in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the RSA parameter <code>e</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the RSA parameter
+   * <code>d</code> (the private exponent) in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the RSA parameter <code>d</code>,
+   * </li>
+   * </ol>
+   * 
+   * @param key the key to encode.
+   * @return the <i>Raw</i> format encoding of the designated key.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    if (! (key instanceof GnuRSAPrivateKey))
+      throw new IllegalArgumentException("key");
+
+    GnuRSAPrivateKey rsaKey = (GnuRSAPrivateKey) key;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0]);
+    baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[1]);
+    baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[2]);
+    baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[3]);
+    // version
+    baos.write(0x01);
+    // p
+    byte[] buffer = rsaKey.getPrimeP().toByteArray();
+    int length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // q
+    buffer = rsaKey.getPrimeQ().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // e
+    buffer = rsaKey.getPublicExponent().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // d
+    buffer = rsaKey.getPrivateExponent().toByteArray();
+    length = buffer.length;
+    baos.write(length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    return baos.toByteArray();
+  }
+
+  public PrivateKey decodePrivateKey(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0]
+        || k[1] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[1]
+        || k[2] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[2]
+        || k[3] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[3])
+      throw new IllegalArgumentException("magic");
+
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+
+    int i = 5;
+    int l;
+    byte[] buffer;
+    // p
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger p = new BigInteger(1, buffer);
+    // q
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger q = new BigInteger(1, buffer);
+    // e
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger e = new BigInteger(1, buffer);
+    // d
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger d = new BigInteger(1, buffer);
+    return new GnuRSAPrivateKey(p, q, e, d);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,250 @@
+/* RSAKeyPairX509Codec.java -- X.509 Encoding/Decoding handler
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.rsa;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+/**
+ * An implementation of an {@link IKeyPairCodec} that knows how to encode /
+ * decode X.509 ASN.1 external representation of RSA public keys.
+ */
+public class RSAKeyPairX509Codec
+    implements IKeyPairCodec
+{
+  private static final Logger log = Logger.getLogger(RSAKeyPairX509Codec.class.getName());
+  private static final OID RSA_ALG_OID = new OID(Registry.RSA_OID_STRING);
+
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return X509_FORMAT;
+  }
+
+  /**
+   * Returns the X.509 ASN.1 <i>SubjectPublicKeyInfo</i> representation of an
+   * RSA public key. The ASN.1 specification, as defined in RFC-3280, and
+   * RFC-2459, is as follows:
+   *
+   * <pre>
+   *   SubjectPublicKeyInfo ::= SEQUENCE {
+   *     algorithm         AlgorithmIdentifier,
+   *     subjectPublicKey  BIT STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   * </pre>
+   * <p>
+   * As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL
+   * for this algorithm identifier.".
+   * <p>
+   * The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+   * DER-encoded form of the RSA public key defined as:
+   * 
+   * <pre>
+   *   RSAPublicKey ::= SEQUENCE {
+   *     modulus         INTEGER, -- n
+   *     publicExponent  INTEGER  -- e
+   *   }
+   * </pre>
+   * 
+   * @param key the {@link PublicKey} instance to encode. MUST be an instance of
+   *          {@link GnuRSAPublicKey}.
+   * @return the ASN.1 representation of the <i>SubjectPublicKeyInfo</i> in an
+   *         X.509 certificate.
+   * @throw InvalidParameterException if <code>key</code> is not an instance
+   *        of {@link GnuRSAPublicKey} or if an exception occurs during the
+   *        marshalling process.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "encodePublicKey()", key);
+    if (! (key instanceof GnuRSAPublicKey))
+      throw new InvalidParameterException("key");
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, RSA_ALG_OID);
+
+    GnuRSAPublicKey rsaKey = (GnuRSAPublicKey) key;
+    BigInteger n = rsaKey.getN();
+    BigInteger e = rsaKey.getE();
+
+    DERValue derN = new DERValue(DER.INTEGER, n);
+    DERValue derE = new DERValue(DER.INTEGER, e);
+
+    ArrayList algorithmID = new ArrayList(2);
+    algorithmID.add(derOID);
+    algorithmID.add(new DERValue(DER.NULL, null));
+    DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                           algorithmID);
+
+    ArrayList publicKey = new ArrayList(2);
+    publicKey.add(derN);
+    publicKey.add(derE);
+    DERValue derPublicKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                         publicKey);
+    byte[] spkBytes = derPublicKey.getEncoded();
+    DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(spkBytes));
+
+    ArrayList spki = new ArrayList(2);
+    spki.add(derAlgorithmID);
+    spki.add(derSPK);
+    DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki);
+
+    byte[] result;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try
+      {
+        DERWriter.write(baos, derSPKI);
+        result = baos.toByteArray();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException y = new InvalidParameterException(x.getMessage());
+        y.initCause(x);
+        throw y;
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "encodePublicKey()", result);
+    return result;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    throw new InvalidParameterException("Wrong format for private keys");
+  }
+
+  /**
+   * @param input the byte array to unmarshall into a valid RSA
+   *          {@link PublicKey} instance. MUST NOT be null.
+   * @return a new instance of a {@link GnuRSAPublicKey} decoded from the
+   *         <i>SubjectPublicKeyInfo</i> material in an X.509 certificate.
+   * @throw InvalidParameterException if an exception occurs during the
+   *        unmarshalling process.
+   */
+  public PublicKey decodePublicKey(byte[] input)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "decodePublicKey()", input);
+    if (input == null)
+      throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+    BigInteger n, e;
+    DERReader der = new DERReader(input);
+    try
+      {
+        DERValue derSPKI = der.read();
+        DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field");
+
+        DERValue derAlgorithmID = der.read();
+        DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field");
+
+        DERValue derOID = der.read();
+        if (! (derOID.getValue() instanceof OID))
+          throw new InvalidParameterException("Wrong Algorithm field");
+
+        OID algOID = (OID) derOID.getValue();
+        if (! algOID.equals(RSA_ALG_OID))
+          throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+        // rfc-2459 states that this field is OPTIONAL but NULL if/when present
+        DERValue val = der.read();
+        if (val.getTag() == DER.NULL)
+          val = der.read();
+
+        if (! (val.getValue() instanceof BitString))
+          throw new InvalidParameterException("Wrong SubjectPublicKey field");
+
+        byte[] spkBytes = ((BitString) val.getValue()).toByteArray();
+
+        der = new DERReader(spkBytes);
+        val = der.read();
+        DerUtil.checkIsConstructed(derAlgorithmID, "Wrong subjectPublicKey field");
+
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong modulus field");
+        n = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong publicExponent field");
+        e = (BigInteger) val.getValue();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException y = new InvalidParameterException(x.getMessage());
+        y.initCause(x);
+        throw y;
+      }
+    PublicKey result = new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "decodePublicKey()", result);
+    return result;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public PrivateKey decodePrivateKey(byte[] input)
+  {
+    throw new InvalidParameterException("Wrong format for private keys");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/prng/BasePRNG.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,178 @@
+/* BasePRNG.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.prng;
+
+import java.util.Map;
+
+/**
+ * An abstract class to facilitate implementing PRNG algorithms.
+ */
+public abstract class BasePRNG
+    implements IRandom
+{
+  /** The canonical name prefix of the PRNG algorithm. */
+  protected String name;
+
+  /** Indicate if this instance has already been initialised or not. */
+  protected boolean initialised;
+
+  /** A temporary buffer to serve random bytes. */
+  protected byte[] buffer;
+
+  /** The index into buffer of where the next byte will come from. */
+  protected int ndx;
+
+  /**
+   * Trivial constructor for use by concrete subclasses.
+   * 
+   * @param name the canonical name of this instance.
+   */
+  protected BasePRNG(String name)
+  {
+    super();
+
+    this.name = name;
+    initialised = false;
+    buffer = new byte[0];
+  }
+
+  public String name()
+  {
+    return name;
+  }
+
+  public void init(Map attributes)
+  {
+    this.setup(attributes);
+
+    ndx = 0;
+    initialised = true;
+  }
+
+  public byte nextByte() throws IllegalStateException, LimitReachedException
+  {
+    if (! initialised)
+      throw new IllegalStateException();
+
+    return nextByteInternal();
+  }
+
+  public void nextBytes(byte[] out) throws IllegalStateException,
+      LimitReachedException
+  {
+    nextBytes(out, 0, out.length);
+  }
+
+  public void nextBytes(byte[] out, int offset, int length)
+      throws IllegalStateException, LimitReachedException
+  {
+    if (! initialised)
+      throw new IllegalStateException("not initialized");
+
+    if (length == 0)
+      return;
+
+    if (offset < 0 || length < 0 || offset + length > out.length)
+      throw new ArrayIndexOutOfBoundsException("offset=" + offset + " length="
+                                               + length + " limit="
+                                               + out.length);
+    if (ndx >= buffer.length)
+      {
+        fillBlock();
+        ndx = 0;
+      }
+    int count = 0;
+    while (count < length)
+      {
+        int amount = Math.min(buffer.length - ndx, length - count);
+        System.arraycopy(buffer, ndx, out, offset + count, amount);
+        count += amount;
+        ndx += amount;
+        if (ndx >= buffer.length)
+          {
+            fillBlock();
+            ndx = 0;
+          }
+      }
+  }
+
+  public void addRandomByte(byte b)
+  {
+    throw new UnsupportedOperationException("random state is non-modifiable");
+  }
+
+  public void addRandomBytes(byte[] buffer)
+  {
+    addRandomBytes(buffer, 0, buffer.length);
+  }
+
+  public void addRandomBytes(byte[] buffer, int offset, int length)
+  {
+    throw new UnsupportedOperationException("random state is non-modifiable");
+  }
+
+  public boolean isInitialised()
+  {
+    return initialised;
+  }
+
+  private byte nextByteInternal() throws LimitReachedException
+  {
+    if (ndx >= buffer.length)
+      {
+        this.fillBlock();
+        ndx = 0;
+      }
+
+    return buffer[ndx++];
+  }
+
+  public Object clone() throws CloneNotSupportedException
+  {
+    BasePRNG result = (BasePRNG) super.clone();
+    if (this.buffer != null)
+      result.buffer = (byte[]) this.buffer.clone();
+
+    return result;
+  }
+
+  public abstract void setup(Map attributes);
+
+  public abstract void fillBlock() throws LimitReachedException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/prng/EntropySource.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,61 @@
+/* EntropySource.java -- 
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.prng;
+
+/**
+ * A generic interface for adding random bytes to an entropy pool.
+ */
+public interface EntropySource
+{
+  /**
+   * Returns the estimated quality of this source. This value should be
+   * between 0 and 100 (the running quality is computed as a percentage,
+   * 100 percent being perfect-quality).
+   *
+   * @return The quality.
+   */
+  double quality();
+
+  /**
+   * Returns a new buffer with the next random bytes to add.
+   *
+   * @return The next random bytes.
+   */
+  byte[] nextBytes();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/prng/IRandom.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,174 @@
+/* IRandom.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.prng;
+
+import java.util.Map;
+
+/**
+ * The basic visible methods of any pseudo-random number generator.
+ * <p>
+ * The [HAC] defines a PRNG (as implemented in this library) as follows:
+ * <ul>
+ * <li>"5.6 Definition: A pseudorandom bit generator (PRBG) is said to pass the
+ * <em>next-bit test</em> if there is no polynomial-time algorithm which, on
+ * input of the first <code>L</code> bits of an output sequence <code>S</code>,
+ * can predict the <code>(L+1)</code><sup>st</sup> bit of <code>S</code> with a
+ * probability significantly greater than <code>1/2</code>."</li>
+ * <li>"5.8 Definition: A PRBG that passes the <em>next-bit test</em>
+ * (possibly under some plausible but unproved mathematical assumption such as
+ * the intractability of factoring integers) is called a <em>cryptographically
+ * secure pseudorandom bit generator</em> (CSPRBG)."</li>
+ * </ul>
+ * <p>
+ * <b>IMPLEMENTATION NOTE</b>: Although all the concrete classes in this
+ * package implement the {@link Cloneable} interface, it is important to note
+ * here that such an operation, for those algorithms that use an underlying
+ * symmetric key block cipher, <b>DOES NOT</b> clone any session key material
+ * that may have been used in initialising the source PRNG (the instance to be
+ * cloned). Instead a clone of an already initialised PRNG, that uses an
+ * underlying symmetric key block cipher, is another instance with a clone of
+ * the same cipher that operates with the <b>same block size</b> but without
+ * any knowledge of neither key material nor key size.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+public interface IRandom
+    extends Cloneable
+{
+  /**
+   * Returns the canonical name of this instance.
+   * 
+   * @return the canonical name of this instance.
+   */
+  String name();
+
+  /**
+   * Initialises the pseudo-random number generator scheme with the appropriate
+   * attributes.
+   * 
+   * @param attributes a set of name-value pairs that describe the desired
+   *          future instance behaviour.
+   * @exception IllegalArgumentException if at least one of the defined name/
+   *              value pairs contains invalid data.
+   */
+  void init(Map attributes);
+
+  /**
+   * Returns the next 8 bits of random data generated from this instance.
+   * 
+   * @return the next 8 bits of random data generated from this instance.
+   * @exception IllegalStateException if the instance is not yet initialised.
+   * @exception LimitReachedException if this instance has reached its
+   *              theoretical limit for generating non-repetitive pseudo-random
+   *              data.
+   */
+  byte nextByte() throws IllegalStateException, LimitReachedException;
+
+  /**
+   * Fills the designated byte array, starting from byte at index
+   * <code>offset</code>, for a maximum of <code>length</code> bytes with
+   * the output of this generator instance.
+   * 
+   * @param out the placeholder to contain the generated random bytes.
+   * @param offset the starting index in <i>out</i> to consider. This method
+   *          does nothing if this parameter is not within <code>0</code> and
+   *          <code>out.length</code>.
+   * @param length the maximum number of required random bytes. This method does
+   *          nothing if this parameter is less than <code>1</code>.
+   * @exception IllegalStateException if the instance is not yet initialised.
+   * @exception LimitReachedException if this instance has reached its
+   *              theoretical limit for generating non-repetitive pseudo-random
+   *              data.
+   */
+  void nextBytes(byte[] out, int offset, int length)
+      throws IllegalStateException, LimitReachedException;
+
+  /**
+   * Supplement, or possibly replace, the random state of this PRNG with a
+   * random byte.
+   * <p>
+   * Implementations are not required to implement this method in any meaningful
+   * way; this may be a no-operation, and implementations may throw an
+   * {@link UnsupportedOperationException}.
+   * 
+   * @param b The byte to add.
+   */
+  void addRandomByte(byte b);
+
+  /**
+   * Supplement, or possibly replace, the random state of this PRNG with a
+   * sequence of new random bytes.
+   * <p>
+   * Implementations are not required to implement this method in any meaningful
+   * way; this may be a no-operation, and implementations may throw an
+   * {@link UnsupportedOperationException}.
+   * 
+   * @param in The buffer of new random bytes to add.
+   */
+  void addRandomBytes(byte[] in);
+
+  /**
+   * Supplement, or possibly replace, the random state of this PRNG with a
+   * sequence of new random bytes.
+   * <p>
+   * Implementations are not required to implement this method in any meaningful
+   * way; this may be a no-operation, and implementations may throw an
+   * {@link UnsupportedOperationException}.
+   * 
+   * @param in The buffer of new random bytes to add.
+   * @param offset The offset from whence to begin reading random bytes.
+   * @param length The number of random bytes to add.
+   * @exception IndexOutOfBoundsException If <i>offset</i>, <i>length</i>, or
+   *              <i>offset</i>+<i>length</i> is out of bounds.
+   */
+  void addRandomBytes(byte[] in, int offset, int length);
+
+  /**
+   * Returns a clone copy of this instance.
+   * 
+   * @return a clone copy of this instance.
+   */
+  Object clone() throws CloneNotSupportedException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/prng/LimitReachedException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,57 @@
+/* LimitReachedException.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.prng;
+
+/**
+ * A checked exception that indicates that a pseudo random number generated has
+ * reached its theoretical limit in generating random bytes.
+ */
+public class LimitReachedException
+    extends Exception
+{
+  public LimitReachedException()
+  {
+    super();
+  }
+
+  public LimitReachedException(String msg)
+  {
+    super(msg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/prng/MDGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,127 @@
+/* MDGenerator.java -- 
+   Copyright (C) 2001, 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.prng;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+
+import java.util.Map;
+
+/**
+ * A simple pseudo-random number generator that relies on a hash algorithm, that
+ * (a) starts its operation by hashing a <code>seed</code>, and then (b)
+ * continuously re-hashing its output. If no hash algorithm name is specified in
+ * the {@link Map} of attributes used to initialise the instance then the
+ * SHA-160 algorithm is used as the underlying hash function. Also, if no
+ * <code>seed</code> is given, an empty octet sequence is used.
+ */
+public class MDGenerator
+    extends BasePRNG
+    implements Cloneable
+{
+  /** Property name of underlying hash algorithm for this generator. */
+  public static final String MD_NAME = "gnu.crypto.prng.md.hash.name";
+
+  /** Property name of seed material. */
+  public static final String SEEED = "gnu.crypto.prng.md.seed";
+
+  /** The underlying hash instance. */
+  private IMessageDigest md;
+
+  /** Trivial 0-arguments constructor. */
+  public MDGenerator()
+  {
+    super(Registry.MD_PRNG);
+  }
+
+  public void setup(Map attributes)
+  {
+    // find out which hash to use
+    String underlyingMD = (String) attributes.get(MD_NAME);
+    if (underlyingMD == null)
+      {
+        if (md == null)
+          { // happy birthday
+            // ensure we have a reliable implementation of this hash
+            md = HashFactory.getInstance(Registry.SHA160_HASH);
+          }
+        else // a clone. reset it for reuse
+          md.reset();
+      }
+    else // ensure we have a reliable implementation of this hash
+      md = HashFactory.getInstance(underlyingMD);
+    // get the seeed
+    byte[] seed = (byte[]) attributes.get(SEEED);
+    if (seed == null)
+      seed = new byte[0];
+
+    md.update(seed, 0, seed.length);
+  }
+
+  public void fillBlock() throws LimitReachedException
+  {
+    IMessageDigest mdc = (IMessageDigest) md.clone();
+    buffer = mdc.digest();
+    md.update(buffer, 0, buffer.length);
+  }
+
+  public void addRandomByte(final byte b)
+  {
+    if (md == null)
+      throw new IllegalStateException("not initialized");
+    md.update(b);
+  }
+
+  public void addRandomBytes(final byte[] buf, final int off, final int len)
+  {
+    if (md == null)
+      throw new IllegalStateException("not initialized");
+    md.update(buf, off, len);
+  }
+
+  public Object clone() throws CloneNotSupportedException
+  {
+    MDGenerator result = (MDGenerator) super.clone();
+    if (this.md != null)
+      result.md = (IMessageDigest) this.md.clone();
+
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/prng/PRNGFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,92 @@
+/* PRNGFactory.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.prng;
+
+import gnu.java.security.Registry;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A Factory to instantiate pseudo random number generators.
+ */
+public class PRNGFactory
+    implements Registry
+{
+  /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+  protected PRNGFactory()
+  {
+  }
+
+  /**
+   * Returns an instance of a padding algorithm given its name.
+   * 
+   * @param prng the case-insensitive name of the PRNG.
+   * @return an instance of the pseudo-random number generator.
+   * @exception InternalError if the implementation does not pass its self-
+   *              test.
+   */
+  public static final IRandom getInstance(String prng)
+  {
+    if (prng == null)
+      return null;
+
+    prng = prng.trim();
+    IRandom result = null;
+    if (prng.equalsIgnoreCase(MD_PRNG))
+      result = new MDGenerator();
+
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of names of padding algorithms supported by this
+   * <i>Factory</i>.
+   * 
+   * @return a {@link Set} of pseudo-random number generator algorithm names
+   *         (Strings).
+   */
+  public static final Set getNames()
+  {
+    HashSet hs = new HashSet();
+    hs.add(MD_PRNG);
+    return Collections.unmodifiableSet(hs);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/prng/RandomEvent.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,81 @@
+/* RandomEvent.java -- an event with random data.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.prng;
+
+import java.util.EventObject;
+
+/**
+ * A type for entropy accumulators that will be notified of random events.
+ */
+public class RandomEvent
+    extends EventObject
+{
+  private final byte sourceNumber;
+
+  private final byte poolNumber;
+
+  private final byte[] data;
+
+  public RandomEvent(Object source, byte sourceNumber, byte poolNumber,
+                     byte[] data)
+  {
+    super(source);
+    this.sourceNumber = sourceNumber;
+    this.poolNumber = poolNumber;
+    if (data.length == 0 || data.length > 32)
+      throw new IllegalArgumentException(
+          "random events take between 1 and 32 bytes of data");
+    this.data = (byte[]) data.clone();
+  }
+
+  public byte getSourceNumber()
+  {
+    return sourceNumber;
+  }
+
+  public byte getPoolNumber()
+  {
+    return poolNumber;
+  }
+
+  public byte[] getData()
+  {
+    return data;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/prng/RandomEventListener.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* RandomEventListener.java -- 
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.prng;
+
+import java.util.EventListener;
+
+/**
+ * An interface for entropy accumulators that will be notified of random events.
+ */
+public interface RandomEventListener
+    extends EventListener
+{
+  void addRandomEvent(RandomEvent event);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/provider/CollectionCertStoreImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,102 @@
+/* CollectionCertStore.java -- Collection-based cert store.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRL;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.security.cert.Certificate;
+import java.security.cert.CollectionCertStoreParameters;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+public final class CollectionCertStoreImpl extends CertStoreSpi
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private final Collection store;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public CollectionCertStoreImpl(CertStoreParameters params)
+    throws InvalidAlgorithmParameterException
+  {
+    super(params);
+    if (! (params instanceof CollectionCertStoreParameters))
+      throw new InvalidAlgorithmParameterException("not a CollectionCertStoreParameters object");
+    store = ((CollectionCertStoreParameters) params).getCollection();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public Collection engineGetCertificates(CertSelector selector)
+    throws CertStoreException
+  {
+    LinkedList result = new LinkedList();
+    for (Iterator it = store.iterator(); it.hasNext(); )
+      {
+        Object o = it.next();
+        if ((o instanceof Certificate) && selector.match((Certificate) o))
+          result.add(o);
+      }
+    return result;
+  }
+
+  public Collection engineGetCRLs(CRLSelector selector)
+    throws CertStoreException
+  {
+    LinkedList result = new LinkedList();
+    for (Iterator it = store.iterator(); it.hasNext(); )
+      {
+        Object o = it.next();
+        if ((o instanceof CRL) && selector.match((CRL) o))
+          result.add(o);
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/provider/DefaultPolicy.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,68 @@
+/* DefaultPolicy.java --
+   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.security.provider;
+
+import java.security.AllPermission;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+
+/** 
+  * This is just a stub policy implementation which grants all permissions
+  * to any code source. FIXME: This should be replaced with a real
+  * implementation that reads the policy configuration from a file, like
+  * $JAVA_HOME/jre/lib/security/java.security.
+  */
+public class DefaultPolicy extends Policy
+{
+  static Permission allPermission = new AllPermission();
+
+  public PermissionCollection getPermissions(CodeSource codesource)
+  {
+    Permissions perms = new Permissions();
+    perms.add(allPermission);
+    return perms;
+  }
+  
+  public void refresh()
+  {
+    // Nothing.
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/provider/Gnu.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,306 @@
+/* Gnu.java --- Gnu provider main class
+   Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.provider;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+
+public final class Gnu
+    extends Provider
+{
+  public Gnu()
+  {
+    super("GNU", 1.0,
+          "GNU provider v1.0 implementing SHA-1, MD5, DSA, RSA, X.509 "
+          + "Certificates and CRLs, PKIX certificate path validators, "
+          + "Collection cert stores, Diffie-Hellman key agreement and "
+          + "key pair generator");
+    AccessController.doPrivileged (new PrivilegedAction()
+    {
+      public Object run()
+      {
+        // Note that all implementation class names are referenced by using
+        // Class.getName(). That way when we staticly link the Gnu provider
+        // we automatically get all the implementation classes.
+
+        // Signature
+        put("Signature.SHA160withDSS",
+            gnu.java.security.jce.sig.SHA160withDSS.class.getName());
+        put("Alg.Alias.Signature.SHA1withDSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.DSS", "SHA160withDSS");
+        put("Alg.Alias.Signature.DSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.SHAwithDSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.DSAwithSHA", "SHA160withDSS");
+        put("Alg.Alias.Signature.DSAwithSHA1", "SHA160withDSS");
+        put("Alg.Alias.Signature.SHA/DSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.SHA-1/DSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.SHA1/DSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", "SHA160withDSS");
+        put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA160withDSS");
+        put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA160withDSS");
+        put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA160withDSS");
+
+        put("Signature.MD2withRSA",
+            gnu.java.security.jce.sig.MD2withRSA.class.getName());
+        put("Signature.MD2withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.md2WithRSAEncryption", "MD2withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", "MD2withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA");
+
+        put("Signature.MD5withRSA",
+            gnu.java.security.jce.sig.MD5withRSA.class.getName());
+        put("Signature.MD5withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.md5WithRSAEncryption", "MD5withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA");
+        put("Alg.Alias.Signature.RSA", "MD5withRSA");
+
+        put("Signature.SHA160withRSA",
+            gnu.java.security.jce.sig.SHA160withRSA.class.getName());
+        put("Signature.SHA160withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.sha-1WithRSAEncryption", "SHA160withRSA");
+        put("Alg.Alias.Signature.sha-160WithRSAEncryption", "SHA160withRSA");
+        put("Alg.Alias.Signature.sha1WithRSAEncryption", "SHA160withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA160withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA160withRSA");
+        put("Alg.Alias.Signature.SHA1withRSA", "SHA160withRSA");
+
+        put("Signature.SHA256withRSA",
+            gnu.java.security.jce.sig.SHA256withRSA.class.getName());
+        put("Signature.SHA160withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.sha256WithRSAEncryption", "SHA256withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA");
+
+        put("Signature.SHA384withRSA",
+            gnu.java.security.jce.sig.SHA384withRSA.class.getName());
+        put("Signature.SHA160withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.sha384WithRSAEncryption", "SHA384withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA");
+
+        put("Signature.SHA512withRSA",
+            gnu.java.security.jce.sig.SHA512withRSA.class.getName());
+        put("Signature.SHA160withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.sha512WithRSAEncryption", "SHA512withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA");
+
+        put("Signature.DSS/RAW",
+            gnu.java.security.jce.sig.DSSRawSignatureSpi.class.getName());
+        put("Signature.DSS/RAW KeySize", "1024");
+        put("Signature.DSS/RAW ImplementedIn", "Software");
+
+        put("Signature.RSA-PSS/RAW",
+            gnu.java.security.jce.sig.RSAPSSRawSignatureSpi.class.getName());
+        put("Signature.RSA-PSS/RAW KeySize", "1024");
+        put("Signature.RSA-PSS/RAW ImplementedIn", "Software");
+
+        // Key Pair Generator
+        put("KeyPairGenerator.DSS",
+            gnu.java.security.jce.sig.DSSKeyPairGeneratorSpi.class.getName());
+        put("KeyPairGenerator.DSS KeySize", "1024");
+        put("KeyPairGenerator.DSS ImplementedIn", "Software");
+        put("Alg.Alias.KeyPairGenerator.DSA", "DSS");
+        put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSS");
+        put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSS");
+        put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSS");
+
+        put("KeyPairGenerator.RSA",
+            gnu.java.security.jce.sig.RSAKeyPairGeneratorSpi.class.getName());
+        put("KeyPairGenerator.RSA KeySize", "1024");
+        put("KeyPairGenerator.RSA ImplementedIn", "Software");
+
+        // Key Factory
+        put("KeyFactory.DSS",
+            gnu.java.security.jce.sig.DSSKeyFactory.class.getName());
+        put("Alg.Alias.KeyFactory.DSA", "DSS");
+        put("Alg.Alias.KeyFactory.OID.1.2.840.10040.4.1", "DSS");
+        put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSS");
+        put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSS");
+
+        put("KeyFactory.RSA",
+            gnu.java.security.jce.sig.RSAKeyFactory.class.getName());
+
+        put("KeyFactory.Encoded",
+            gnu.java.security.jce.sig.EncodedKeyFactory.class.getName());
+        put("KeyFactory.Encoded ImplementedIn", "Software");
+        put("Alg.Alias.KeyFactory.X.509", "Encoded");
+        put("Alg.Alias.KeyFactory.X509", "Encoded");
+        put("Alg.Alias.KeyFactory.PKCS#8", "Encoded");
+        put("Alg.Alias.KeyFactory.PKCS8", "Encoded");
+
+        put("MessageDigest.HAVAL",
+            gnu.java.security.jce.hash.HavalSpi.class.getName());
+        put("MessageDigest.HAVAL ImplementedIn", "Software");
+        put("MessageDigest.MD2",
+            gnu.java.security.jce.hash.MD2Spi.class.getName());
+        put("MessageDigest.MD2 ImplementedIn", "Software");
+        put("MessageDigest.MD4",
+            gnu.java.security.jce.hash.MD4Spi.class.getName());
+        put("MessageDigest.MD4 ImplementedIn", "Software");
+        put("MessageDigest.MD5",
+            gnu.java.security.jce.hash.MD5Spi.class.getName());
+        put("MessageDigest.MD5 ImplementedIn", "Software");
+        put("MessageDigest.RIPEMD128",
+            gnu.java.security.jce.hash.RipeMD128Spi.class.getName());
+        put("MessageDigest.RIPEMD128 ImplementedIn", "Software");
+        put("MessageDigest.RIPEMD160",
+            gnu.java.security.jce.hash.RipeMD160Spi.class.getName());
+        put("MessageDigest.RIPEMD160 ImplementedIn", "Software");
+        put("MessageDigest.SHA-160",
+            gnu.java.security.jce.hash.Sha160Spi.class.getName());
+        put("MessageDigest.SHA-160 ImplementedIn", "Software");
+        put("MessageDigest.SHA-256",
+            gnu.java.security.jce.hash.Sha256Spi.class.getName());
+        put("MessageDigest.SHA-256 ImplementedIn", "Software");
+        put("MessageDigest.SHA-384",
+            gnu.java.security.jce.hash.Sha384Spi.class.getName());
+        put("MessageDigest.SHA-384 ImplementedIn", "Software");
+        put("MessageDigest.SHA-512",
+            gnu.java.security.jce.hash.Sha512Spi.class.getName());
+        put("MessageDigest.SHA-512 ImplementedIn", "Software");
+        put("MessageDigest.TIGER",
+            gnu.java.security.jce.hash.TigerSpi.class.getName());
+        put("MessageDigest.TIGER ImplementedIn", "Software");
+        put("MessageDigest.WHIRLPOOL",
+            gnu.java.security.jce.hash.WhirlpoolSpi.class.getName());
+        put("MessageDigest.WHIRLPOOL ImplementedIn", "Software");
+
+        put("Alg.Alias.MessageDigest.SHS", "SHA-160");
+        put("Alg.Alias.MessageDigest.SHA", "SHA-160");
+        put("Alg.Alias.MessageDigest.SHA1", "SHA-160");
+        put("Alg.Alias.MessageDigest.SHA-1", "SHA-160");
+        put("Alg.Alias.MessageDigest.SHA2-256", "SHA-256");
+        put("Alg.Alias.MessageDigest.SHA2-384", "SHA-384");
+        put("Alg.Alias.MessageDigest.SHA2-512", "SHA-512");
+        put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
+        put("Alg.Alias.MessageDigest.SHA384", "SHA-384");
+        put("Alg.Alias.MessageDigest.SHA512", "SHA-512");
+        put("Alg.Alias.MessageDigest.RIPEMD-160", "RIPEMD160");
+        put("Alg.Alias.MessageDigest.RIPEMD-128", "RIPEMD128");
+        put("Alg.Alias.MessageDigest.OID.1.2.840.11359.2.2", "MD2");
+        put("Alg.Alias.MessageDigest.1.2.840.11359.2.2", "MD2");
+        put("Alg.Alias.MessageDigest.OID.1.2.840.11359.2.5", "MD5");
+        put("Alg.Alias.MessageDigest.1.2.840.11359.2.5", "MD5");
+        put("Alg.Alias.MessageDigest.OID.1.3.14.3.2.26", "SHA1");
+        put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA1");
+
+        // Algorithm Parameters
+        put("AlgorithmParameters.DSS",
+            gnu.java.security.jce.sig.DSSParameters.class.getName());
+        put("Alg.Alias.AlgorithmParameters.DSA", "DSS");
+        put("Alg.Alias.AlgorithmParameters.SHAwithDSA", "DSS");
+        put("Alg.Alias.AlgorithmParameters.OID.1.2.840.10040.4.3", "DSS");
+        put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.3", "DSS");
+
+        // Algorithm Parameter Generator
+        put("AlgorithmParameterGenerator.DSA",
+            gnu.java.security.jce.sig.DSSParametersGenerator.class.getName());
+        put("Alg.Alias.AlgorithmParameterGenerator.DSA", "DSS");
+
+        // SecureRandom
+        put("SecureRandom.SHA1PRNG",
+            gnu.java.security.jce.prng.Sha160RandomSpi.class.getName());
+
+        put("SecureRandom.MD2PRNG",
+            gnu.java.security.jce.prng.MD2RandomSpi.class.getName());
+        put("SecureRandom.MD2PRNG ImplementedIn", "Software");
+        put("SecureRandom.MD4PRNG",
+            gnu.java.security.jce.prng.MD4RandomSpi.class.getName());
+        put("SecureRandom.MD4PRNG ImplementedIn", "Software");
+        put("SecureRandom.MD5PRNG",
+            gnu.java.security.jce.prng.MD5RandomSpi.class.getName());
+        put("SecureRandom.MD5PRNG ImplementedIn", "Software");
+        put("SecureRandom.RIPEMD128PRNG",
+            gnu.java.security.jce.prng.RipeMD128RandomSpi.class.getName());
+        put("SecureRandom.RIPEMD128PRNG ImplementedIn", "Software");
+        put("SecureRandom.RIPEMD160PRNG",
+            gnu.java.security.jce.prng.RipeMD160RandomSpi.class.getName());
+        put("SecureRandom.RIPEMD160PRNG ImplementedIn", "Software");
+        put("SecureRandom.SHA-160PRNG",
+            gnu.java.security.jce.prng.Sha160RandomSpi.class.getName());
+        put("SecureRandom.SHA-160PRNG ImplementedIn", "Software");
+        put("SecureRandom.SHA-256PRNG",
+            gnu.java.security.jce.prng.Sha256RandomSpi.class.getName());
+        put("SecureRandom.SHA-256PRNG ImplementedIn", "Software");
+        put("SecureRandom.SHA-384PRNG",
+            gnu.java.security.jce.prng.Sha384RandomSpi.class.getName());
+        put("SecureRandom.SHA-384PRNG ImplementedIn", "Software");
+        put("SecureRandom.SHA-512PRNG",
+            gnu.java.security.jce.prng.Sha512RandomSpi.class.getName());
+        put("SecureRandom.SHA-512PRNG ImplementedIn", "Software");
+        put("SecureRandom.TIGERPRNG",
+            gnu.java.security.jce.prng.TigerRandomSpi.class.getName());
+        put("SecureRandom.TIGERPRNG ImplementedIn", "Software");
+        put("SecureRandom.HAVALPRNG",
+            gnu.java.security.jce.prng.HavalRandomSpi.class.getName());
+        put("SecureRandom.HAVALPRNG ImplementedIn", "Software");
+        put("SecureRandom.WHIRLPOOLPRNG",
+            gnu.java.security.jce.prng.WhirlpoolRandomSpi.class.getName());
+        put("SecureRandom.WHIRLPOOLPRNG ImplementedIn", "Software");
+
+        put("Alg.Alias.SecureRandom.SHA-1PRNG", "SHA-160PRNG");
+        put("Alg.Alias.SecureRandom.SHA1PRNG", "SHA-160PRNG");
+        put("Alg.Alias.SecureRandom.SHAPRNG", "SHA-160PRNG");
+        put("Alg.Alias.SecureRandom.SHA-256PRNG", "SHA-256PRNG");
+        put("Alg.Alias.SecureRandom.SHA-2-1PRNG", "SHA-256PRNG");
+        put("Alg.Alias.SecureRandom.SHA-384PRNG", "SHA-384PRNG");
+        put("Alg.Alias.SecureRandom.SHA-2-2PRNG", "SHA-384PRNG");
+        put("Alg.Alias.SecureRandom.SHA-512PRNG", "SHA-512PRNG");
+        put("Alg.Alias.SecureRandom.SHA-2-3PRNG", "SHA-512PRNG");
+
+        // CertificateFactory
+        put("CertificateFactory.X509", X509CertificateFactory.class.getName());
+        put("CertificateFactory.X509 ImplementedIn", "Software");
+        put("Alg.Alias.CertificateFactory.X.509", "X509");
+
+        // CertPathValidator
+        put("CertPathValidator.PKIX", PKIXCertPathValidatorImpl.class.getName());
+        put("CertPathValidator.PKIX ImplementedIn", "Software");
+
+        // CertStore
+        put("CertStore.Collection", CollectionCertStoreImpl.class.getName());
+
+        return null;
+      }
+    });
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/provider/PKIXCertPathValidatorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,693 @@
+/* PKIXCertPathValidatorImpl.java -- PKIX certificate path validator.
+   Copyright (C) 2004, 2005, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.provider;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.key.dss.DSSPublicKey;
+import gnu.java.security.x509.GnuPKIExtension;
+import gnu.java.security.x509.PolicyNodeImpl;
+import gnu.java.security.x509.X509CRLSelectorImpl;
+import gnu.java.security.x509.X509CertSelectorImpl;
+import gnu.java.security.x509.ext.BasicConstraints;
+import gnu.java.security.x509.ext.CertificatePolicies;
+import gnu.java.security.x509.ext.Extension;
+import gnu.java.security.x509.ext.KeyUsage;
+import gnu.java.security.x509.ext.PolicyConstraint;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.PublicKey;
+import java.security.cert.CRL;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorResult;
+import java.security.cert.CertPathValidatorSpi;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertificateException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * An implementation of the Public Key Infrastructure's X.509 certificate path
+ * validation algorithm.
+ * <p>
+ * See <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
+ * Public Key Infrastructure Certificate and Certificate Revocation List (CRL)
+ * Profile</a>.
+ * 
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class PKIXCertPathValidatorImpl
+    extends CertPathValidatorSpi
+{
+  private static final Logger log = Logger.getLogger(PKIXCertPathValidatorImpl.class.getName());
+
+  public static final String ANY_POLICY = "2.5.29.32.0";
+
+  public PKIXCertPathValidatorImpl()
+  {
+    super();
+  }
+
+  public CertPathValidatorResult engineValidate(CertPath path,
+                                                CertPathParameters params)
+      throws CertPathValidatorException, InvalidAlgorithmParameterException
+  {
+    if (! (params instanceof PKIXParameters))
+      throw new InvalidAlgorithmParameterException("not a PKIXParameters object");
+    // First check if the certificate path is valid.
+    //
+    // This means that:
+    //
+    // (a) for all x in {1, ..., n-1}, the subject of certificate x is
+    // the issuer of certificate x+1;
+    //
+    // (b) for all x in {1, ..., n}, the certificate was valid at the
+    // time in question.
+    //
+    // Because this is the X.509 algorithm, we also check if all
+    // cerificates are of type X509Certificate.
+    PolicyNodeImpl rootNode = new PolicyNodeImpl();
+    Set initPolicies = ((PKIXParameters) params).getInitialPolicies();
+    rootNode.setValidPolicy(ANY_POLICY);
+    rootNode.setCritical(false);
+    rootNode.setDepth(0);
+    if (initPolicies != null)
+      rootNode.addAllExpectedPolicies(initPolicies);
+    else
+      rootNode.addExpectedPolicy(ANY_POLICY);
+    List checks = ((PKIXParameters) params).getCertPathCheckers();
+    List l = path.getCertificates();
+    if (l == null || l.size() == 0)
+      throw new CertPathValidatorException();
+    X509Certificate[] p = null;
+    try
+      {
+        p = (X509Certificate[]) l.toArray(new X509Certificate[l.size()]);
+      }
+    catch (ClassCastException cce)
+      {
+        throw new CertPathValidatorException("invalid certificate path");
+      }
+    String sigProvider = ((PKIXParameters) params).getSigProvider();
+    PublicKey prevKey = null;
+    Date now = ((PKIXParameters) params).getDate();
+    if (now == null)
+      now = new Date();
+    LinkedList policyConstraints = new LinkedList();
+    for (int i = p.length - 1; i >= 0; i--)
+      {
+        try
+          {
+            p[i].checkValidity(now);
+          }
+        catch (CertificateException ce)
+          {
+            throw new CertPathValidatorException(ce.toString());
+          }
+        Set uce = getCritExts(p[i]);
+        for (Iterator check = checks.iterator(); check.hasNext();)
+          {
+            try
+              {
+                ((PKIXCertPathChecker) check.next()).check(p[i], uce);
+              }
+            catch (Exception x)
+              {
+              }
+          }
+        PolicyConstraint constr = null;
+        if (p[i] instanceof GnuPKIExtension)
+          {
+            Extension pcx = ((GnuPKIExtension) p[i]).getExtension(PolicyConstraint.ID);
+            if (pcx != null)
+              constr = (PolicyConstraint) pcx.getValue();
+          }
+        else
+          {
+            byte[] pcx = p[i].getExtensionValue(PolicyConstraint.ID.toString());
+            if (pcx != null)
+              {
+                try
+                  {
+                    constr = new PolicyConstraint(pcx);
+                  }
+                catch (Exception x)
+                  {
+                  }
+              }
+          }
+        if (constr != null && constr.getRequireExplicitPolicy() >= 0)
+          policyConstraints.add(new int[] { p.length - i,
+                                            constr.getRequireExplicitPolicy() });
+        updatePolicyTree(p[i], rootNode, p.length - i, (PKIXParameters) params,
+                         checkExplicitPolicy(p.length - i, policyConstraints));
+        // The rest of the tests involve this cert's relationship with the
+        // next in the path. If this cert is the end entity, we can stop.
+        if (i == 0)
+          break;
+
+        basicSanity(p, i);
+        PublicKey pubKey = null;
+        try
+          {
+            pubKey = p[i].getPublicKey();
+            if (pubKey instanceof DSAPublicKey)
+              {
+                DSAParams dsa = ((DSAPublicKey) pubKey).getParams();
+                // If the DSA public key is missing its parameters, use those
+                // from the previous cert's key.
+                if (dsa == null || dsa.getP() == null || dsa.getG() == null
+                    || dsa.getQ() == null)
+                  {
+                    if (prevKey == null)
+                      throw new InvalidKeyException("DSA keys not chainable");
+                    if (! (prevKey instanceof DSAPublicKey))
+                      throw new InvalidKeyException("DSA keys not chainable");
+                    dsa = ((DSAPublicKey) prevKey).getParams();
+                    pubKey = new DSSPublicKey(Registry.X509_ENCODING_ID,
+                                              dsa.getP(), dsa.getQ(),
+                                              dsa.getG(),
+                                              ((DSAPublicKey) pubKey).getY());
+                  }
+              }
+            if (sigProvider == null)
+              p[i - 1].verify(pubKey);
+            else
+              p[i - 1].verify(pubKey, sigProvider);
+            prevKey = pubKey;
+          }
+        catch (Exception e)
+          {
+            throw new CertPathValidatorException(e.toString());
+          }
+        if (! p[i].getSubjectDN().equals(p[i - 1].getIssuerDN()))
+          throw new CertPathValidatorException("issuer DN mismatch");
+        boolean[] issuerUid = p[i - 1].getIssuerUniqueID();
+        boolean[] subjectUid = p[i].getSubjectUniqueID();
+        if (issuerUid != null && subjectUid != null)
+          if (! Arrays.equals(issuerUid, subjectUid))
+            throw new CertPathValidatorException("UID mismatch");
+
+        // Check the certificate against the revocation lists.
+        if (((PKIXParameters) params).isRevocationEnabled())
+          {
+            X509CRLSelectorImpl selector = new X509CRLSelectorImpl();
+            try
+              {
+                selector.addIssuerName(p[i].getSubjectDN());
+              }
+            catch (IOException ioe)
+              {
+                throw new CertPathValidatorException("error selecting CRLs");
+              }
+            List certStores = ((PKIXParameters) params).getCertStores();
+            List crls = new LinkedList();
+            for (Iterator it = certStores.iterator(); it.hasNext();)
+              {
+                CertStore cs = (CertStore) it.next();
+                try
+                  {
+                    Collection c = cs.getCRLs(selector);
+                    crls.addAll(c);
+                  }
+                catch (CertStoreException cse)
+                  {
+                  }
+              }
+            if (crls.isEmpty())
+              throw new CertPathValidatorException("no CRLs for issuer");
+            boolean certOk = false;
+            for (Iterator it = crls.iterator(); it.hasNext();)
+              {
+                CRL crl = (CRL) it.next();
+                if (! (crl instanceof X509CRL))
+                  continue;
+                X509CRL xcrl = (X509CRL) crl;
+                if (! checkCRL(xcrl, p, now, p[i], pubKey, certStores))
+                  continue;
+                if (xcrl.isRevoked(p[i - 1]))
+                  throw new CertPathValidatorException("certificate is revoked");
+                else
+                  certOk = true;
+              }
+            if (! certOk)
+              throw new CertPathValidatorException(
+                  "certificate's validity could not be determined");
+          }
+      }
+    rootNode.setReadOnly();
+    // Now ensure that the first certificate in the chain was issued
+    // by a trust anchor.
+    Exception cause = null;
+    Set anchors = ((PKIXParameters) params).getTrustAnchors();
+    for (Iterator i = anchors.iterator(); i.hasNext();)
+      {
+        TrustAnchor anchor = (TrustAnchor) i.next();
+        X509Certificate anchorCert = null;
+        PublicKey anchorKey = null;
+        if (anchor.getTrustedCert() != null)
+          {
+            anchorCert = anchor.getTrustedCert();
+            anchorKey = anchorCert.getPublicKey();
+          }
+        else
+          anchorKey = anchor.getCAPublicKey();
+        if (anchorKey == null)
+          continue;
+        try
+          {
+            if (anchorCert != null)
+              anchorCert.checkValidity(now);
+            p[p.length - 1].verify(anchorKey);
+            if (anchorCert != null && anchorCert.getBasicConstraints() >= 0
+                && anchorCert.getBasicConstraints() < p.length)
+              continue;
+
+            if (((PKIXParameters) params).isRevocationEnabled())
+              {
+                X509CRLSelectorImpl selector = new X509CRLSelectorImpl();
+                if (anchorCert != null)
+                  try
+                    {
+                      selector.addIssuerName(anchorCert.getSubjectDN());
+                    }
+                  catch (IOException ioe)
+                    {
+                    }
+                else
+                  selector.addIssuerName(anchor.getCAName());
+                List certStores = ((PKIXParameters) params).getCertStores();
+                List crls = new LinkedList();
+                for (Iterator it = certStores.iterator(); it.hasNext();)
+                  {
+                    CertStore cs = (CertStore) it.next();
+                    try
+                      {
+                        Collection c = cs.getCRLs(selector);
+                        crls.addAll(c);
+                      }
+                    catch (CertStoreException cse)
+                      {
+                      }
+                  }
+                if (crls.isEmpty())
+                  continue;
+                for (Iterator it = crls.iterator(); it.hasNext();)
+                  {
+                    CRL crl = (CRL) it.next();
+                    if (! (crl instanceof X509CRL))
+                      continue;
+                    X509CRL xcrl = (X509CRL) crl;
+                    try
+                      {
+                        xcrl.verify(anchorKey);
+                      }
+                    catch (Exception x)
+                      {
+                        continue;
+                      }
+                    Date nextUpdate = xcrl.getNextUpdate();
+                    if (nextUpdate != null && nextUpdate.compareTo(now) < 0)
+                      continue;
+                    if (xcrl.isRevoked(p[p.length - 1]))
+                      throw new CertPathValidatorException("certificate is revoked");
+                  }
+              }
+            // The chain is valid; return the result.
+            return new PKIXCertPathValidatorResult(anchor, rootNode,
+                                                   p[0].getPublicKey());
+          }
+        catch (Exception ignored)
+          {
+            cause = ignored;
+            continue;
+          }
+      }
+    // The path is not valid.
+    CertPathValidatorException cpve =
+        new CertPathValidatorException("path validation failed");
+    if (cause != null)
+      cpve.initCause(cause);
+    throw cpve;
+  }
+
+  /**
+   * Check if a given CRL is acceptable for checking the revocation status of
+   * certificates in the path being checked.
+   * <p>
+   * The CRL is accepted iff:
+   * <ol>
+   * <li>The <i>nextUpdate</i> field (if present) is in the future.</li>
+   * <li>The CRL does not contain any unsupported critical extensions.</li>
+   * <li>The CRL is signed by one of the certificates in the path, or,</li>
+   * <li>The CRL is signed by the given public key and was issued by the public
+   * key's subject, or,</li>
+   * <li>The CRL is signed by a certificate in the given cert stores, and that
+   * cert is signed by one of the certificates in the path.</li>
+   * </ol>
+   * 
+   * @param crl The CRL being checked.
+   * @param path The path this CRL is being checked against.
+   * @param now The value to use as 'now'.
+   * @param pubKeyCert The certificate authenticating the public key.
+   * @param pubKey The public key to check.
+   * @return True if the CRL is acceptable.
+   */
+  private static boolean checkCRL(X509CRL crl, X509Certificate[] path,
+                                  Date now, X509Certificate pubKeyCert,
+                                  PublicKey pubKey, List certStores)
+  {
+    Date nextUpdate = crl.getNextUpdate();
+    if (nextUpdate != null && nextUpdate.compareTo(now) < 0)
+      return false;
+    if (crl.hasUnsupportedCriticalExtension())
+      return false;
+    for (int i = 0; i < path.length; i++)
+      {
+        if (! path[i].getSubjectDN().equals(crl.getIssuerDN()))
+          continue;
+        boolean[] keyUsage = path[i].getKeyUsage();
+        if (keyUsage != null)
+          {
+            if (! keyUsage[KeyUsage.CRL_SIGN])
+              continue;
+          }
+        try
+          {
+            crl.verify(path[i].getPublicKey());
+            return true;
+          }
+        catch (Exception x)
+          {
+          }
+      }
+    if (crl.getIssuerDN().equals(pubKeyCert.getSubjectDN()))
+      {
+        try
+          {
+            boolean[] keyUsage = pubKeyCert.getKeyUsage();
+            if (keyUsage != null)
+              {
+                if (! keyUsage[KeyUsage.CRL_SIGN])
+                  throw new Exception();
+              }
+            crl.verify(pubKey);
+            return true;
+          }
+        catch (Exception x)
+          {
+          }
+      }
+    try
+      {
+        X509CertSelectorImpl select = new X509CertSelectorImpl();
+        select.addSubjectName(crl.getIssuerDN());
+        List certs = new LinkedList();
+        for (Iterator it = certStores.iterator(); it.hasNext();)
+          {
+            CertStore cs = (CertStore) it.next();
+            try
+              {
+                certs.addAll(cs.getCertificates(select));
+              }
+            catch (CertStoreException cse)
+              {
+              }
+          }
+        for (Iterator it = certs.iterator(); it.hasNext();)
+          {
+            X509Certificate c = (X509Certificate) it.next();
+            for (int i = 0; i < path.length; i++)
+              {
+                if (! c.getIssuerDN().equals(path[i].getSubjectDN()))
+                  continue;
+                boolean[] keyUsage = c.getKeyUsage();
+                if (keyUsage != null)
+                  {
+                    if (! keyUsage[KeyUsage.CRL_SIGN])
+                      continue;
+                  }
+                try
+                  {
+                    c.verify(path[i].getPublicKey());
+                    crl.verify(c.getPublicKey());
+                    return true;
+                  }
+                catch (Exception x)
+                  {
+                  }
+              }
+            if (c.getIssuerDN().equals(pubKeyCert.getSubjectDN()))
+              {
+                c.verify(pubKey);
+                crl.verify(c.getPublicKey());
+              }
+          }
+      }
+    catch (Exception x)
+      {
+      }
+    return false;
+  }
+
+  private static Set getCritExts(X509Certificate cert)
+  {
+    HashSet s = new HashSet();
+    if (cert instanceof GnuPKIExtension)
+      {
+        Collection exts = ((GnuPKIExtension) cert).getExtensions();
+        for (Iterator it = exts.iterator(); it.hasNext();)
+          {
+            Extension ext = (Extension) it.next();
+            if (ext.isCritical() && ! ext.isSupported())
+              s.add(ext.getOid().toString());
+          }
+      }
+    else
+      s.addAll(cert.getCriticalExtensionOIDs());
+    return s;
+  }
+
+  /**
+   * Perform a basic sanity check on the CA certificate at <code>index</code>.
+   */
+  private static void basicSanity(X509Certificate[] path, int index)
+      throws CertPathValidatorException
+  {
+    X509Certificate cert = path[index];
+    int pathLen = 0;
+    for (int i = index - 1; i > 0; i--)
+      {
+        if (! path[i].getIssuerDN().equals(path[i].getSubjectDN()))
+          pathLen++;
+      }
+    Extension e = null;
+    if (cert instanceof GnuPKIExtension)
+      {
+        e = ((GnuPKIExtension) cert).getExtension(BasicConstraints.ID);
+      }
+    else
+      {
+        try
+          {
+            e = new Extension(cert.getExtensionValue(BasicConstraints.ID.toString()));
+          }
+        catch (Exception x)
+          {
+          }
+      }
+    if (e == null)
+      throw new CertPathValidatorException("no basicConstraints");
+    BasicConstraints bc = (BasicConstraints) e.getValue();
+    if (! bc.isCA())
+      throw new CertPathValidatorException(
+          "certificate cannot be used to verify signatures");
+    if (bc.getPathLengthConstraint() >= 0
+        && bc.getPathLengthConstraint() < pathLen)
+      throw new CertPathValidatorException("path is too long");
+
+    boolean[] keyUsage = cert.getKeyUsage();
+    if (keyUsage != null)
+      {
+        if (! keyUsage[KeyUsage.KEY_CERT_SIGN])
+          throw new CertPathValidatorException(
+              "certificate cannot be used to sign certificates");
+      }
+  }
+
+  private static void updatePolicyTree(X509Certificate cert,
+                                       PolicyNodeImpl root, int depth,
+                                       PKIXParameters params,
+                                       boolean explicitPolicy)
+      throws CertPathValidatorException
+  {
+    if (Configuration.DEBUG)
+      log.fine("updatePolicyTree depth == " + depth);
+    Set nodes = new HashSet();
+    LinkedList stack = new LinkedList();
+    Iterator current = null;
+    stack.addLast(Collections.singleton(root).iterator());
+    do
+      {
+        current = (Iterator) stack.removeLast();
+        while (current.hasNext())
+          {
+            PolicyNodeImpl p = (PolicyNodeImpl) current.next();
+            if (Configuration.DEBUG)
+              log.fine("visiting node == " + p);
+            if (p.getDepth() == depth - 1)
+              {
+                if (Configuration.DEBUG)
+                  log.fine("added node");
+                nodes.add(p);
+              }
+            else
+              {
+                if (Configuration.DEBUG)
+                  log.fine("skipped node");
+                stack.addLast(current);
+                current = p.getChildren();
+              }
+          }
+      }
+    while (! stack.isEmpty());
+
+    Extension e = null;
+    CertificatePolicies policies = null;
+    List qualifierInfos = null;
+    if (cert instanceof GnuPKIExtension)
+      {
+        e = ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID);
+        if (e != null)
+          policies = (CertificatePolicies) e.getValue();
+      }
+
+    List cp = null;
+    if (policies != null)
+      cp = policies.getPolicies();
+    else
+      cp = Collections.EMPTY_LIST;
+    boolean match = false;
+    if (Configuration.DEBUG)
+      {
+        log.fine("nodes are == " + nodes);
+        log.fine("cert policies are == " + cp);
+      }
+    for (Iterator it = nodes.iterator(); it.hasNext();)
+      {
+        PolicyNodeImpl parent = (PolicyNodeImpl) it.next();
+        if (Configuration.DEBUG)
+          log.fine("adding policies to " + parent);
+        for (Iterator it2 = cp.iterator(); it2.hasNext();)
+          {
+            OID policy = (OID) it2.next();
+            if (Configuration.DEBUG)
+              log.fine("trying to add policy == " + policy);
+            if (policy.toString().equals(ANY_POLICY)
+                && params.isAnyPolicyInhibited())
+              continue;
+            PolicyNodeImpl child = new PolicyNodeImpl();
+            child.setValidPolicy(policy.toString());
+            child.addExpectedPolicy(policy.toString());
+            if (parent.getExpectedPolicies().contains(policy.toString()))
+              {
+                parent.addChild(child);
+                match = true;
+              }
+            else if (parent.getExpectedPolicies().contains(ANY_POLICY))
+              {
+                parent.addChild(child);
+                match = true;
+              }
+            else if (ANY_POLICY.equals(policy.toString()))
+              {
+                parent.addChild(child);
+                match = true;
+              }
+            if (match && policies != null)
+              {
+                List qualifiers = policies.getPolicyQualifierInfos(policy);
+                if (qualifiers != null)
+                  child.addAllPolicyQualifiers(qualifiers);
+              }
+          }
+      }
+    if (! match && (params.isExplicitPolicyRequired() || explicitPolicy))
+      throw new CertPathValidatorException("policy tree building failed");
+  }
+
+  private boolean checkExplicitPolicy(int depth, List explicitPolicies)
+  {
+    if (Configuration.DEBUG)
+      log.fine("checkExplicitPolicy depth=" + depth);
+    for (Iterator it = explicitPolicies.iterator(); it.hasNext();)
+      {
+        int[] i = (int[]) it.next();
+        int caDepth = i[0];
+        int limit = i[1];
+        if (Configuration.DEBUG)
+          log.fine("  caDepth=" + caDepth + " limit=" + limit);
+        if (depth - caDepth >= limit)
+          return true;
+      }
+    return false;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/provider/X509CertificateFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,294 @@
+/* X509CertificateFactory.java -- generates X.509 certificates.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.provider;
+
+import gnu.java.io.Base64InputStream;
+import gnu.java.security.x509.X509CRL;
+import gnu.java.security.x509.X509CertPath;
+import gnu.java.security.x509.X509Certificate;
+
+import java.io.BufferedInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+public class X509CertificateFactory
+    extends CertificateFactorySpi
+{
+  public static final String BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----";
+
+  public static final String END_CERTIFICATE = "-----END CERTIFICATE-----";
+
+  public static final String BEGIN_X509_CRL = "-----BEGIN X509 CRL-----";
+
+  public static final String END_X509_CRL = "-----END X509 CRL-----";
+
+  public X509CertificateFactory()
+  {
+    super();
+  }
+
+  public Certificate engineGenerateCertificate(InputStream inStream)
+      throws CertificateException
+  {
+    try
+      {
+        return generateCert(inStream);
+      }
+    catch (IOException ioe)
+      {
+        CertificateException ce = new CertificateException(ioe.getMessage());
+        ce.initCause(ioe);
+        throw ce;
+      }
+  }
+
+  public Collection engineGenerateCertificates(InputStream inStream)
+      throws CertificateException
+  {
+    LinkedList certs = new LinkedList();
+    while (true)
+      {
+        try
+          {
+            certs.add(generateCert(inStream));
+          }
+        catch (EOFException eof)
+          {
+            break;
+          }
+        catch (IOException ioe)
+          {
+            CertificateException ce = new CertificateException(ioe.getMessage());
+            ce.initCause(ioe);
+            throw ce;
+          }
+      }
+    return certs;
+  }
+
+  public CRL engineGenerateCRL(InputStream inStream) throws CRLException
+  {
+    try
+      {
+        return generateCRL(inStream);
+      }
+    catch (IOException ioe)
+      {
+        CRLException crle = new CRLException(ioe.getMessage());
+        crle.initCause(ioe);
+        throw crle;
+      }
+  }
+
+  public Collection engineGenerateCRLs(InputStream inStream)
+      throws CRLException
+  {
+    LinkedList crls = new LinkedList();
+    while (true)
+      {
+        try
+          {
+            crls.add(generateCRL(inStream));
+          }
+        catch (EOFException eof)
+          {
+            break;
+          }
+        catch (IOException ioe)
+          {
+            CRLException crle = new CRLException(ioe.getMessage());
+            crle.initCause(ioe);
+            throw crle;
+          }
+      }
+    return crls;
+  }
+
+  public CertPath engineGenerateCertPath(List certs)
+  {
+    return new X509CertPath(certs);
+  }
+
+  public CertPath engineGenerateCertPath(InputStream in)
+      throws CertificateEncodingException
+  {
+    return new X509CertPath(in);
+  }
+
+  public CertPath engineGenerateCertPath(InputStream in, String encoding)
+      throws CertificateEncodingException
+  {
+    return new X509CertPath(in, encoding);
+  }
+
+  public Iterator engineGetCertPathEncodings()
+  {
+    return X509CertPath.ENCODINGS.iterator();
+  }
+
+  private X509Certificate generateCert(InputStream inStream)
+      throws IOException, CertificateException
+  {
+    if (inStream == null)
+      throw new CertificateException("missing input stream");
+    if (! inStream.markSupported())
+      inStream = new BufferedInputStream(inStream, 8192);
+    inStream.mark(20);
+    int i = inStream.read();
+    if (i == -1)
+      throw new EOFException();
+    // If the input is in binary DER format, the first byte MUST be
+    // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the
+    // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set.
+    //
+    // So if we do not see 0x30 here we will assume it is in Base-64.
+    if (i != 0x30)
+      {
+        inStream.reset();
+        StringBuffer line = new StringBuffer(80);
+        do
+          {
+            line.setLength(0);
+            do
+              {
+                i = inStream.read();
+                if (i == -1)
+                  throw new EOFException();
+                if (i != '\n' && i != '\r')
+                  line.append((char) i);
+              }
+            while (i != '\n' && i != '\r');
+          }
+        while (! line.toString().equals(BEGIN_CERTIFICATE));
+        X509Certificate ret = new X509Certificate(
+            new BufferedInputStream(new Base64InputStream(inStream), 8192));
+        line.setLength(0);
+        line.append('-'); // Base64InputStream will eat this.
+        do
+          {
+            i = inStream.read();
+            if (i == -1)
+              throw new EOFException();
+            if (i != '\n' && i != '\r')
+              line.append((char) i);
+          }
+        while (i != '\n' && i != '\r');
+        // XXX ???
+        if (! line.toString().equals(END_CERTIFICATE))
+          throw new CertificateException("no end-of-certificate marker");
+        return ret;
+      }
+    else
+      {
+        inStream.reset();
+        return new X509Certificate(inStream);
+      }
+  }
+
+  private X509CRL generateCRL(InputStream inStream) throws IOException,
+      CRLException
+  {
+    if (inStream == null)
+      throw new CRLException("missing input stream");
+    if (! inStream.markSupported())
+      inStream = new BufferedInputStream(inStream, 8192);
+    inStream.mark(20);
+    int i = inStream.read();
+    if (i == -1)
+      throw new EOFException();
+    // If the input is in binary DER format, the first byte MUST be
+    // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the
+    // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set.
+    //
+    // So if we do not see 0x30 here we will assume it is in Base-64.
+    if (i != 0x30)
+      {
+        inStream.reset();
+        StringBuffer line = new StringBuffer(80);
+        do
+          {
+            line.setLength(0);
+            do
+              {
+                i = inStream.read();
+                if (i == -1)
+                  throw new EOFException();
+                if (i != '\n' && i != '\r')
+                  line.append((char) i);
+              }
+            while (i != '\n' && i != '\r');
+          }
+        while (! line.toString().startsWith(BEGIN_X509_CRL));
+        X509CRL ret = new X509CRL(
+            new BufferedInputStream(new Base64InputStream(inStream), 8192));
+        line.setLength(0);
+        line.append('-'); // Base64InputStream will eat this.
+        do
+          {
+            i = inStream.read();
+            if (i == -1)
+              throw new EOFException();
+            if (i != '\n' && i != '\r')
+              line.append((char) i);
+          }
+        while (i != '\n' && i != '\r');
+        // XXX ???
+        if (! line.toString().startsWith(END_X509_CRL))
+          throw new CRLException("no end-of-CRL marker");
+        return ret;
+      }
+    else
+      {
+        inStream.reset();
+        return new X509CRL(inStream);
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/provider/package.html	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.provider package.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.security.provider</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/BaseSignature.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,219 @@
+/* BaseSignature.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.PRNG;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * A base abstract class to facilitate implementations of concrete Signatures.
+ */
+public abstract class BaseSignature
+    implements ISignature
+{
+  /** The canonical name of this signature scheme. */
+  protected String schemeName;
+
+  /** The underlying message digest instance for this signature scheme. */
+  protected IMessageDigest md;
+
+  /** The public key to use when verifying signatures. */
+  protected PublicKey publicKey;
+
+  /** The private key to use when generating signatures (signing). */
+  protected PrivateKey privateKey;
+
+  /** The optional {@link Random} instance to use. */
+  private Random rnd;
+
+  /** The optional {@link IRandom} instance to use. */
+  private IRandom irnd;
+
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+
+  /**
+   * Trivial constructor.
+   * 
+   * @param schemeName the name of this signature scheme.
+   * @param md the underlying instance of the message digest algorithm.
+   * @throws IllegalArgumentException if the designated hash instance is
+   *           <code>null</code>.
+   */
+  protected BaseSignature(String schemeName, IMessageDigest md)
+  {
+    super();
+
+    this.schemeName = schemeName;
+    if (md == null)
+      throw new IllegalArgumentException("Message digest MUST NOT be null");
+
+    this.md = md;
+  }
+
+  public String name()
+  {
+    return schemeName + "-" + md.name();
+  }
+
+  public void setupVerify(Map attributes) throws IllegalArgumentException
+  {
+    setup(attributes);
+    // do we have a public key?
+    PublicKey key = (PublicKey) attributes.get(VERIFIER_KEY);
+    if (key != null)
+      setupForVerification(key);
+  }
+
+  public void setupSign(Map attributes) throws IllegalArgumentException
+  {
+    setup(attributes);
+    // do we have a private key?
+    PrivateKey key = (PrivateKey) attributes.get(SIGNER_KEY);
+    if (key != null)
+      setupForSigning(key);
+  }
+
+  public void update(byte b)
+  {
+    if (md == null)
+      throw new IllegalStateException();
+
+    md.update(b);
+  }
+
+  public void update(byte[] b, int off, int len)
+  {
+    if (md == null)
+      throw new IllegalStateException();
+
+    md.update(b, off, len);
+  }
+
+  public Object sign()
+  {
+    if (md == null || privateKey == null)
+      throw new IllegalStateException();
+
+    return generateSignature();
+  }
+
+  public boolean verify(Object sig)
+  {
+    if (md == null || publicKey == null)
+      throw new IllegalStateException();
+
+    return verifySignature(sig);
+  }
+
+  public abstract Object clone();
+
+  protected abstract void setupForVerification(PublicKey key)
+      throws IllegalArgumentException;
+
+  protected abstract void setupForSigning(PrivateKey key)
+      throws IllegalArgumentException;
+
+  protected abstract Object generateSignature() throws IllegalStateException;
+
+  protected abstract boolean verifySignature(Object signature)
+      throws IllegalStateException;
+
+  /** Initialises the internal fields of this instance. */
+  protected void init()
+  {
+    md.reset();
+    rnd = null;
+    irnd = null;
+    publicKey = null;
+    privateKey = null;
+  }
+
+  /**
+   * Fills the designated byte array with random data.
+   * 
+   * @param buffer the byte array to fill with random data.
+   */
+  protected void nextRandomBytes(byte[] buffer)
+  {
+    if (rnd != null)
+      rnd.nextBytes(buffer);
+    else if (irnd != null)
+      try
+        {
+          irnd.nextBytes(buffer, 0, buffer.length);
+        }
+      catch (IllegalStateException x)
+        {
+          throw new RuntimeException("nextRandomBytes(): " + x);
+        }
+      catch (LimitReachedException x)
+        {
+          throw new RuntimeException("nextRandomBytes(): " + x);
+        }
+    else
+      getDefaultPRNG().nextBytes(buffer);
+  }
+
+  private void setup(Map attributes)
+  {
+    init();
+    // do we have a Random or SecureRandom, or should we use our own?
+    Object obj = attributes.get(SOURCE_OF_RANDOMNESS);
+    if (obj instanceof Random)
+      rnd = (Random) obj;
+    else if (obj instanceof IRandom)
+      irnd = (IRandom) obj;
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/ISignature.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,160 @@
+/* ISignature.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig;
+
+import java.util.Map;
+
+/**
+ * The visible methods of every signature-with-appendix scheme.
+ * <p>
+ * The Handbook of Applied Cryptography (HAC), by A. Menezes &amp; al. states:
+ * "Digital signature schemes which require the message as input to the
+ * verification algorithm are called <i>digital signature schemes with appendix</i>.
+ * ... They rely on cryptographic hash functions rather than customised
+ * redundancy functions, and are less prone to existential forgery attacks."
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac/">Handbook of Applied
+ * Cryptography</a>, Alfred J. Menezes, Paul C. van Oorschot and Scott A.
+ * Vanstone. Section 11.2.2 Digital signature schemes with appendix.</li>
+ * </ol>
+ */
+public interface ISignature
+    extends Cloneable
+{
+  /** Property name of the verifier's public key. */
+  public static final String VERIFIER_KEY = "gnu.crypto.sig.public.key";
+
+  /** Property name of the signer's private key. */
+  public static final String SIGNER_KEY = "gnu.crypto.sig.private.key";
+
+  /**
+   * Property name of an optional {@link java.security.SecureRandom},
+   * {@link java.util.Random}, or {@link gnu.java.security.prng.IRandom}
+   * instance to use. The default is to use a classloader singleton from
+   * {@link gnu.java.security.util.PRNG}.
+   */
+  public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.sig.prng";
+
+  /**
+   * Returns the canonical name of this signature scheme.
+   * 
+   * @return the canonical name of this instance.
+   */
+  String name();
+
+  /**
+   * Initialises this instance for signature verification.
+   * 
+   * @param attributes the attributes to use for setting up this instance.
+   * @throws IllegalArgumentException if the designated public key is not
+   *           appropriate for this signature scheme.
+   * @see #SOURCE_OF_RANDOMNESS
+   * @see #VERIFIER_KEY
+   */
+  void setupVerify(Map attributes) throws IllegalArgumentException;
+
+  /**
+   * Initialises this instance for signature generation.
+   * 
+   * @param attributes the attributes to use for setting up this instance.
+   * @throws IllegalArgumentException if the designated private key is not
+   *           appropriate for this signature scheme.
+   * @see #SOURCE_OF_RANDOMNESS
+   * @see #SIGNER_KEY
+   */
+  void setupSign(Map attributes) throws IllegalArgumentException;
+
+  /**
+   * Digests one byte of a message for signing or verification purposes.
+   * 
+   * @param b the message byte to digest.
+   * @throws IllegalStateException if this instance was not setup for signature
+   *           generation/verification.
+   */
+  void update(byte b) throws IllegalStateException;
+
+  /**
+   * Digests a sequence of bytes from a message for signing or verification
+   * purposes.
+   * 
+   * @param buffer the byte sequence to consider.
+   * @param offset the byte poisition in <code>buffer</code> of the first byte
+   *          to consider.
+   * @param length the number of bytes in <code>buffer</code> starting from
+   *          the byte at index <code>offset</code> to digest.
+   * @throws IllegalStateException if this instance was not setup for signature
+   *           generation/verification.
+   */
+  void update(byte[] buffer, int offset, int length)
+      throws IllegalStateException;
+
+  /**
+   * Terminates a signature generation phase by digesting and processing the
+   * context of the underlying message digest algorithm instance.
+   * 
+   * @return a {@link Object} representing the native output of the signature
+   *         scheme implementation.
+   * @throws IllegalStateException if this instance was not setup for signature
+   *           generation.
+   */
+  Object sign() throws IllegalStateException;
+
+  /**
+   * Terminates a signature verification phase by digesting and processing the
+   * context of the underlying message digest algorithm instance.
+   * 
+   * @param signature a native signature object previously generated by an
+   *          invocation of the <code>sign()</code> method.
+   * @return <code>true</code> iff the outpout of the verification phase
+   *         confirms that the designated signature object has been generated
+   *         using the corresponding public key of the recepient.
+   * @throws IllegalStateException if this instance was not setup for signature
+   *           verification.
+   */
+  boolean verify(Object signature) throws IllegalStateException;
+
+  /**
+   * Returns a clone copy of this instance.
+   * 
+   * @return a clone copy of this instance.
+   */
+  Object clone();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/ISignatureCodec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,59 @@
+/* ISignatureCodec.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig;
+
+import gnu.java.security.Registry;
+
+/**
+ * The visible methods of an object that knows how to encode and decode
+ * cryptographic signatures. Codecs are useful for (a) externalising signature
+ * output data for storage and on-the-wire transmission, as well as (b) re-
+ * creating their internal Java representation from external sources.
+ */
+public interface ISignatureCodec
+{
+  /** Constant identifying the <i>Raw</i> encoding format. */
+  int RAW_FORMAT = Registry.RAW_ENCODING_ID;
+
+  int getFormatID();
+
+  byte[] encodeSignature(Object signature);
+
+  Object decodeSignature(byte[] input);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/SignatureCodecFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,226 @@
+/* SignatureCodecFactory.java -- Factory to instantiate Signature codecs
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.sig.dss.DSSSignatureRawCodec;
+import gnu.java.security.sig.dss.DSSSignatureX509Codec;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureRawCodec;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
+import gnu.java.security.sig.rsa.RSAPSSSignatureRawCodec;
+import gnu.java.security.util.FormatUtil;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A <i>Factory</i> class to instantiate Signature codecs.
+ */
+public class SignatureCodecFactory
+{
+  private static Set names;
+
+  /** Trivial constructor to enforce Singleton pattern. */
+  private SignatureCodecFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns the appropriate codec given a composed signature algorithm and an
+   * encoding format. A composed name is formed by the concatenation of the
+   * canonical signature algorithm name, the forward slash character
+   * <code>/</code> and the canonical name of the encoding format.
+   * <p>
+   * When the encoding format name is missing, the Raw encoding format is
+   * assumed. When this is the case the trailing forward slash is discarded from
+   * the name.
+   * 
+   * @param name the case-insensitive, possibly composed, signature codec name.
+   * @return an instance of the signaturecodec, or <code>null</code> if none
+   *         found.
+   */
+  public static ISignatureCodec getInstance(String name)
+  {
+    if (name == null)
+      return null;
+
+    name = name.trim();
+    if (name.length() == 0)
+      return null;
+
+    if (name.startsWith("/"))
+      return null;
+
+    if (name.endsWith("/"))
+      return getInstance(name.substring(0, name.length() - 1),
+                         Registry.RAW_ENCODING_ID);
+
+    int i = name.indexOf("/");
+    if (i == - 1)
+      return getInstance(name, Registry.RAW_ENCODING_ID);
+
+    String sigName = name.substring(0, i);
+    String formatName = name.substring(i + 1);
+    return getInstance(sigName, formatName);
+  }
+
+  /**
+   * Returns an instance of a signature codec given the canonical name of the
+   * signature algorithm, and that of the encoding format.
+   * 
+   * @param name the case-insensitive signature algorithm name.
+   * @param format the name of the format to use when encodigng/decoding
+   *          signatures generated by the named algorithm.
+   * @return an instance of the signature codec, or <code>null</code> if none
+   *         found.
+   */
+  public static ISignatureCodec getInstance(String name, String format)
+  {
+    int formatID = FormatUtil.getFormatID(format);
+    if (formatID == 0)
+      return null;
+
+    return getInstance(name, formatID);
+  }
+
+  /**
+   * Returns an instance of a signature codec given the canonical name of the
+   * signature algorithm, and the identifier of the format to use when
+   * encoding/decoding signatures generated by that algorithm.
+   * 
+   * @param name the case-insensitive signature algorithm name.
+   * @param formatID the identifier of the format to use when encoding /
+   *          decoding signatures generated by the designated algorithm.
+   * @return an instance of the signature codec, or <code>null</code> if none
+   *         found.
+   */
+  public static ISignatureCodec getInstance(String name, int formatID)
+  {
+    if (name == null)
+      return null;
+
+    name = name.trim();
+    switch (formatID)
+      {
+      case Registry.RAW_ENCODING_ID:
+        return getRawCodec(name);
+      case Registry.X509_ENCODING_ID:
+        return getX509Codec(name);
+      }
+
+    return null;
+  }
+
+  /**
+   * Returns a {@link Set} of supported signature codec names.
+   *
+   * @return a {@link Set} of the names of supported signature codec (Strings).
+   */
+  public static synchronized final Set getNames()
+  {
+    if (names == null)
+      {
+        HashSet hs = new HashSet();
+        hs.add(Registry.DSS_SIG + "/" + Registry.RAW_ENCODING_SHORT_NAME);
+        hs.add(Registry.DSS_SIG + "/" + Registry.X509_ENCODING_SORT_NAME);
+        Set hashNames = HashFactory.getNames();
+        for (Iterator it = hashNames.iterator(); it.hasNext();)
+          {
+            String mdName = (String) it.next();
+            String name = Registry.RSA_PKCS1_V1_5_SIG + "-" + mdName;
+            hs.add(name + "/" + Registry.RAW_ENCODING_SHORT_NAME);
+            hs.add(name + "/" + Registry.X509_ENCODING_SORT_NAME);
+            name = Registry.RSA_PSS_SIG + "-" + mdName;
+            hs.add(name + "/" + Registry.RAW_ENCODING_SHORT_NAME);
+          }
+
+        names = Collections.unmodifiableSet(hs);
+      }
+
+    return names;
+  }
+
+  /**
+   * @param name the trimmed name of a signature algorithm.
+   * @return a Raw format codec for the designated signature algorithm, or
+   *         <code>null</code> if none exists.
+   */
+  private static ISignatureCodec getRawCodec(String name)
+  {
+    ISignatureCodec result = null;
+    if (name.equalsIgnoreCase(Registry.DSA_SIG)
+        || name.equalsIgnoreCase(Registry.DSS_SIG))
+      result = new DSSSignatureRawCodec();
+    else
+      {
+        name = name.toLowerCase();
+        if (name.startsWith(Registry.RSA_PKCS1_V1_5_SIG))
+          result = new RSAPKCS1V1_5SignatureRawCodec();
+        else if (name.startsWith(Registry.RSA_PSS_SIG))
+          result = new RSAPSSSignatureRawCodec();
+      }
+
+    return result;
+  }
+
+  /**
+   * @param name the trimmed name of a signature algorithm.
+   * @return a X.509 format codec for the designated signature algorithm, or
+   *         <code>null</code> if none exists.
+   */
+  private static ISignatureCodec getX509Codec(String name)
+  {
+    ISignatureCodec result = null;
+    if (name.equalsIgnoreCase(Registry.DSA_SIG)
+        || name.equalsIgnoreCase(Registry.DSS_SIG))
+      result = new DSSSignatureX509Codec();
+    else
+      {
+        name = name.toLowerCase();
+        if (name.startsWith(Registry.RSA_PKCS1_V1_5_SIG))
+          result = new RSAPKCS1V1_5SignatureX509Codec();
+      }
+
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/SignatureFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,101 @@
+/* SignatureFactory.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.dss.DSSSignature;
+import gnu.java.security.sig.rsa.RSASignatureFactory;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A Factory to instantiate signature-with-appendix handlers.
+ */
+public class SignatureFactory
+{
+  private static Set names;
+
+  /** Trivial constructor to enforce Singleton pattern. */
+  private SignatureFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a signature-with-appendix scheme given its name.
+   * 
+   * @param ssa the case-insensitive signature-with-appendix scheme name.
+   * @return an instance of the scheme, or <code>null</code> if none found.
+   */
+  public static final ISignature getInstance(String ssa)
+  {
+    if (ssa == null)
+      return null;
+
+    ssa = ssa.trim();
+    ssa = ssa.toLowerCase();
+    ISignature result = null;
+    if (ssa.equalsIgnoreCase(Registry.DSA_SIG) || ssa.equals(Registry.DSS_SIG))
+      result = new DSSSignature();
+    else if (ssa.startsWith(Registry.RSA_SIG_PREFIX))
+      result = RSASignatureFactory.getInstance(ssa);
+
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of signature-with-appendix scheme names supported by
+   * this <i>Factory</i>.
+   * 
+   * @return a {@link Set} of signature-with-appendix scheme names (Strings).
+   */
+  public static synchronized final Set getNames()
+  {
+    if (names == null)
+      {
+        HashSet hs = new HashSet();
+        hs.add(Registry.DSS_SIG);
+        hs.addAll(RSASignatureFactory.getNames());
+        names = Collections.unmodifiableSet(hs);
+      }
+    return names;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/dss/DSSSignature.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,275 @@
+/* DSSSignature.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig.dss;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.sig.BaseSignature;
+import gnu.java.security.sig.ISignature;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * The DSS (Digital Signature Standard) algorithm makes use of the following
+ * parameters:
+ * <ol>
+ * <li>p: A prime modulus, where
+ * <code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup> </code> for <code>512 &lt;= L
+ * &lt;= 1024</code> and <code>L</code> a multiple of <code>64</code>.</li>
+ * <li>q: A prime divisor of <code>p - 1</code>, where <code>2<sup>159</sup>
+ *    &lt; q &lt; 2<sup>160</sup></code>.</li>
+ * <li>g: Where <code>g = h<sup>(p-1)</sup>/q mod p</code>, where
+ * <code>h</code> is any integer with <code>1 &lt; h &lt; p - 1</code> such
+ * that <code>h<sup> (p-1)</sup>/q mod p > 1</code> (<code>g</code> has order
+ * <code>q mod p</code>).</li>
+ * <li>x: A randomly or pseudorandomly generated integer with <code>0 &lt; x
+ *    &lt; q</code>.</li>
+ * <li>y: <code>y = g<sup>x</sup> mod p</code>.</li>
+ * <li>k: A randomly or pseudorandomly generated integer with <code>0 &lt; k
+ *    &lt; q</code>.</li>
+ * </ol>
+ * <p>
+ * The integers <code>p</code>, <code>q</code>, and <code>g</code> can be
+ * public and can be common to a group of users. A user's private and public
+ * keys are <code>x</code> and <code>y</code>, respectively. They are
+ * normally fixed for a period of time. Parameters <code>x</code> and
+ * <code>k</code> are used for signature generation only, and must be kept
+ * secret. Parameter <code>k</code> must be regenerated for each signature.
+ * <p>
+ * The signature of a message <code>M</code> is the pair of numbers
+ * <code>r</code> and <code>s</code> computed according to the equations below:
+ * <ul>
+ * <li><code>r = (g<sup>k</sup> mod p) mod q</code> and</li>
+ * <li><code>s = (k<sup>-1</sup>(SHA(M) + xr)) mod q</code>.</li>
+ * </ul>
+ * <p>
+ * In the above, <code>k<sup>-1</sup></code> is the multiplicative inverse of
+ * <code>k</code>, <code>mod q</code>; i.e., <code>(k<sup>-1</sup> k) mod q =
+ * 1</code> and <code>0 &lt; k-1 &lt; q</code>. The value of <code>SHA(M)</code>
+ * is a 160-bit string output by the Secure Hash Algorithm specified in FIPS
+ * 180. For use in computing <code>s</code>, this string must be converted to
+ * an integer.
+ * <p>
+ * As an option, one may wish to check if <code>r == 0</code> or <code>s == 0
+ * </code>.
+ * If either <code>r == 0</code> or <code>s == 0</code>, a new value of
+ * <code>k</code> should be generated and the signature should be recalculated
+ * (it is extremely unlikely that <code>r == 0</code> or <code>s == 0</code> if
+ * signatures are generated properly).
+ * <p>
+ * The signature is transmitted along with the message to the verifier.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
+ * Standard (DSS)</a>, Federal Information Processing Standards Publication
+ * 186. National Institute of Standards and Technology.</li>
+ * </ol>
+ */
+public class DSSSignature
+    extends BaseSignature
+{
+  /** Trivial 0-arguments constructor. */
+  public DSSSignature()
+  {
+    super(Registry.DSS_SIG, new Sha160());
+  }
+
+  /** Private constructor for cloning purposes. */
+  private DSSSignature(DSSSignature that)
+  {
+    this();
+
+    this.publicKey = that.publicKey;
+    this.privateKey = that.privateKey;
+    this.md = (IMessageDigest) that.md.clone();
+  }
+
+  public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h)
+  {
+    final DSSSignature sig = new DSSSignature();
+    final Map attributes = new HashMap();
+    attributes.put(ISignature.SIGNER_KEY, k);
+    sig.setupSign(attributes);
+    return sig.computeRS(h);
+  }
+
+  public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h,
+                                        Random rnd)
+  {
+    final DSSSignature sig = new DSSSignature();
+    final Map attributes = new HashMap();
+    attributes.put(ISignature.SIGNER_KEY, k);
+    if (rnd != null)
+      attributes.put(ISignature.SOURCE_OF_RANDOMNESS, rnd);
+
+    sig.setupSign(attributes);
+    return sig.computeRS(h);
+  }
+
+  public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h,
+                                        IRandom irnd)
+  {
+    final DSSSignature sig = new DSSSignature();
+    final Map attributes = new HashMap();
+    attributes.put(ISignature.SIGNER_KEY, k);
+    if (irnd != null)
+      attributes.put(ISignature.SOURCE_OF_RANDOMNESS, irnd);
+
+    sig.setupSign(attributes);
+    return sig.computeRS(h);
+  }
+
+  public static final boolean verify(final DSAPublicKey k, final byte[] h,
+                                     final BigInteger[] rs)
+  {
+    final DSSSignature sig = new DSSSignature();
+    final Map attributes = new HashMap();
+    attributes.put(ISignature.VERIFIER_KEY, k);
+    sig.setupVerify(attributes);
+    return sig.checkRS(rs, h);
+  }
+
+  public Object clone()
+  {
+    return new DSSSignature(this);
+  }
+
+  protected void setupForVerification(PublicKey k)
+      throws IllegalArgumentException
+  {
+    if (! (k instanceof DSAPublicKey))
+      throw new IllegalArgumentException();
+
+    this.publicKey = k;
+  }
+
+  protected void setupForSigning(PrivateKey k) throws IllegalArgumentException
+  {
+    if (! (k instanceof DSAPrivateKey))
+      throw new IllegalArgumentException();
+
+    this.privateKey = k;
+  }
+
+  protected Object generateSignature() throws IllegalStateException
+  {
+    final BigInteger[] rs = computeRS(md.digest());
+    return encodeSignature(rs[0], rs[1]);
+  }
+
+  protected boolean verifySignature(Object sig) throws IllegalStateException
+  {
+    final BigInteger[] rs = decodeSignature(sig);
+    return checkRS(rs, md.digest());
+  }
+
+  /**
+   * Returns the output of a signature generation phase.
+   * 
+   * @return an object encapsulating the DSS signature pair <code>r</code> and
+   *         <code>s</code>.
+   */
+  private Object encodeSignature(BigInteger r, BigInteger s)
+  {
+    return new BigInteger[] { r, s };
+  }
+
+  /**
+   * Returns the output of a previously generated signature object as a pair of
+   * {@link java.math.BigInteger}.
+   * 
+   * @return the DSS signature pair <code>r</code> and <code>s</code>.
+   */
+  private BigInteger[] decodeSignature(Object signature)
+  {
+    return (BigInteger[]) signature;
+  }
+
+  private BigInteger[] computeRS(final byte[] digestBytes)
+  {
+    final BigInteger p = ((DSAPrivateKey) privateKey).getParams().getP();
+    final BigInteger q = ((DSAPrivateKey) privateKey).getParams().getQ();
+    final BigInteger g = ((DSAPrivateKey) privateKey).getParams().getG();
+    final BigInteger x = ((DSAPrivateKey) privateKey).getX();
+    final BigInteger m = new BigInteger(1, digestBytes);
+    BigInteger k, r, s;
+    final byte[] kb = new byte[20]; // we'll use 159 bits only
+    while (true)
+      {
+        this.nextRandomBytes(kb);
+        k = new BigInteger(1, kb);
+        k.clearBit(159);
+        r = g.modPow(k, p).mod(q);
+        if (r.equals(BigInteger.ZERO))
+          continue;
+
+        s = m.add(x.multiply(r)).multiply(k.modInverse(q)).mod(q);
+        if (s.equals(BigInteger.ZERO))
+          continue;
+
+        break;
+      }
+    return new BigInteger[] { r, s };
+  }
+
+  private boolean checkRS(final BigInteger[] rs, final byte[] digestBytes)
+  {
+    final BigInteger r = rs[0];
+    final BigInteger s = rs[1];
+    final BigInteger g = ((DSAPublicKey) publicKey).getParams().getG();
+    final BigInteger p = ((DSAPublicKey) publicKey).getParams().getP();
+    final BigInteger q = ((DSAPublicKey) publicKey).getParams().getQ();
+    final BigInteger y = ((DSAPublicKey) publicKey).getY();
+    final BigInteger w = s.modInverse(q);
+    final BigInteger u1 = w.multiply(new BigInteger(1, digestBytes)).mod(q);
+    final BigInteger u2 = r.multiply(w).mod(q);
+    final BigInteger v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q);
+    return v.equals(r);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/dss/DSSSignatureRawCodec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,164 @@
+/* DSSSignatureRawCodec.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig.dss;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.ISignatureCodec;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+
+/**
+ * An object that implements the {@link ISignatureCodec} operations for the
+ * <i>Raw</i> format to use with DSS signatures.
+ */
+public class DSSSignatureRawCodec
+    implements ISignatureCodec
+{
+  public int getFormatID()
+  {
+    return RAW_FORMAT;
+  }
+
+  /**
+   * Returns the encoded form of the designated DSS (Digital Signature Standard)
+   * signature object according to the <i>Raw</i> format supported by this
+   * library.
+   * <p>
+   * The <i>Raw</i> format for a DSA signature, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_DSS_SIGNATURE},</li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the DSS parameter
+   * <code>r</code> in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSS parameter <code>r</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DSS parameter
+   * <code>s</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DSS parameter <code>s</code>.
+   * </li>
+   * </ol>
+   * 
+   * @param signature the signature to encode, consisting of the two DSS
+   *          parameters <code>r</code> and <code>s</code> as a
+   *          {@link BigInteger} array.
+   * @return the <i>Raw</i> format encoding of the designated signature.
+   * @exception IllegalArgumentException if the designated signature is not a
+   *              DSS (Digital Signature Standard) one.
+   */
+  public byte[] encodeSignature(Object signature)
+  {
+    BigInteger r, s;
+    try
+      {
+        BigInteger[] sig = (BigInteger[]) signature;
+        r = sig[0];
+        s = sig[1];
+      }
+    catch (Exception x)
+      {
+        throw new IllegalArgumentException("signature");
+      }
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[0]);
+    baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[1]);
+    baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[2]);
+    baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[3]);
+    // version
+    baos.write(0x01);
+    // r
+    byte[] buffer = r.toByteArray();
+    int length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    // s
+    buffer = s.toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    return baos.toByteArray();
+  }
+
+  public Object decodeSignature(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_DSS_SIGNATURE[0]
+        || k[1] != Registry.MAGIC_RAW_DSS_SIGNATURE[1]
+        || k[2] != Registry.MAGIC_RAW_DSS_SIGNATURE[2]
+        || k[3] != Registry.MAGIC_RAW_DSS_SIGNATURE[3])
+      throw new IllegalArgumentException("magic");
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+
+    int i = 5;
+    int l;
+    byte[] buffer;
+    // r
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger r = new BigInteger(1, buffer);
+    // s
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger s = new BigInteger(1, buffer);
+    return new BigInteger[] { r, s };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/dss/DSSSignatureX509Codec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,193 @@
+/* DSSSignatureX509Codec.java -- X.509 encoder/decoder for DSS signatures
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.sig.dss;
+
+import gnu.java.security.Registry;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.sig.ISignatureCodec;
+import gnu.java.security.util.DerUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+
+/**
+ * An implementation of an {@link ISignatureCodec} that knows to encode and
+ * decode DSS signatures into the raw bytes which would constitute a DER-encoded
+ * form of the ASN.1 structure defined in RFC-2459, and RFC-2313 as described in
+ * the next paragraphs.
+ * <p>
+ * Digital signatures when transmitted in an X.509 certificates are encoded
+ * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e.
+ * 
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ *   tbsCertificate       TBSCertificate,
+ *   signatureAlgorithm   AlgorithmIdentifier,
+ *   signature            BIT STRING
+ * }
+ * </pre>
+ * <p>
+ * The output of the encoder, and the input of the decoder, of this codec are
+ * then the <i>raw</i> bytes of such a BIT STRING; i.e. not the DER-encoded
+ * form itself.
+ * <p>
+ * RFC-2459 states that, for the Digital Signature Standard (DSS), which
+ * generates two MPIs, commonly called <code>r</code> and <code>s</code>, as the
+ * result of digitally signing a message, these two numbers will be transferred
+ * as the following ASN.1 structure:
+ * 
+ * <pre>
+ *   Dss-Sig-Value ::= SEQUENCE {
+ *     r  INTEGER,
+ *     s  INTEGER
+ *   }
+ * </pre>
+ * <p>
+ * Client code that needs to build a DER BIT STRING <b>MUST</b> construct such
+ * an ASN.1 value. The following is an example of how to do this:
+ * <p>
+ * <pre>
+ * ...
+ * import gnu.java.security.der.BitString;
+ * import gnu.java.security.der.DER;
+ * import gnu.java.security.der.DERValue;
+ * ...
+ * DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
+ * ...
+ * </pre>
+ */
+public class DSSSignatureX509Codec
+    implements ISignatureCodec
+{
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return Registry.X509_ENCODING_ID;
+  }
+
+  /**
+   * Encodes a DSS Signature output as the <i>signature</i> raw bytes which can
+   * be used to construct an ASN.1 DER-encoded BIT STRING as defined in the
+   * documentation of this class.
+   * 
+   * @param signature the output of the DSS signature algorithm; i.e. the value
+   *          returned by the invocation of
+   *          {@link gnu.java.security.sig.ISignature#sign()} method. In the
+   *          case of a DSS signature this is an array of two MPIs called
+   *          <code>r</code> and <code>s</code>.
+   * @return the raw bytes of a DSS signature which could be then used as the
+   *         contents of a BIT STRING as per rfc-2459.
+   * @throws InvalidParameterException if an exception occurs during the
+   *           marshalling process.
+   */
+  public byte[] encodeSignature(Object signature)
+  {
+    BigInteger[] rs = (BigInteger[]) signature;
+
+    DERValue derR = new DERValue(DER.INTEGER, rs[0]);
+    DERValue derS = new DERValue(DER.INTEGER, rs[1]);
+
+    ArrayList dssSigValue = new ArrayList(2);
+    dssSigValue.add(derR);
+    dssSigValue.add(derS);
+    DERValue derDssSigValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                           dssSigValue);
+    byte[] result;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try
+      {
+        DERWriter.write(baos, derDssSigValue);
+        result = baos.toByteArray();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(x);
+        throw y;
+      }
+
+    return result;
+  }
+
+  /**
+   * Decodes a <i>signature</i> as defined in the documentation of this class.
+   * 
+   * @param input the byte array to unmarshall into a valid DSS signature
+   *          instance; i.e. an array of two MPIs. MUST NOT be null.
+   * @return an array of two MPIs, <code>r</code> and <code>s</code> in this
+   *         order, decoded from the designated <code>input</code>.
+   * @throw InvalidParameterException if an exception occurs during the
+   *        unmarshalling process.
+   */
+  public Object decodeSignature(byte[] input)
+  {
+    if (input == null)
+      throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+    BigInteger r, s;
+    DERReader der = new DERReader(input);
+    try
+      {
+        DERValue derDssSigValue = der.read();
+        DerUtil.checkIsConstructed(derDssSigValue, "Wrong Dss-Sig-Value field");
+
+        DERValue val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong R field");
+        r = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong S field");
+        s = (BigInteger) val.getValue();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(x);
+        throw y;
+      }
+
+    return new BigInteger[] { r, s };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,274 @@
+/* EME_PKCS1_V1_5.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig.rsa;
+
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.PRNG;
+
+import java.io.ByteArrayOutputStream;
+import java.security.interfaces.RSAKey;
+import java.util.Random;
+
+/**
+ * An implementation of the EME-PKCS1-V1.5 encoding and decoding methods.
+ * <p>
+ * EME-PKCS1-V1.5 is parameterised by the entity <code>k</code> which is the
+ * byte count of an RSA public shared modulus.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ * Standards (PKCS) #1:</a><br>
+ * RSA Cryptography Specifications Version 2.1.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+public class EME_PKCS1_V1_5
+{
+  private int k;
+
+  private ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+  /** Our default source of randomness. */
+  private PRNG prng = PRNG.getInstance();
+
+  private EME_PKCS1_V1_5(final int k)
+  {
+    super();
+
+    this.k = k;
+  }
+
+  public static final EME_PKCS1_V1_5 getInstance(final int k)
+  {
+    if (k < 0)
+      throw new IllegalArgumentException("k must be a positive integer");
+
+    return new EME_PKCS1_V1_5(k);
+  }
+
+  public static final EME_PKCS1_V1_5 getInstance(final RSAKey key)
+  {
+    final int modBits = key.getModulus().bitLength();
+    final int k = (modBits + 7) / 8;
+    return EME_PKCS1_V1_5.getInstance(k);
+  }
+
+  /**
+   * Generates an octet string <code>PS</code> of length <code>k - mLen -
+   * 3</code> consisting of pseudo-randomly generated nonzero octets. The length
+   * of <code>PS</code> will be at least eight octets.
+   * <p>
+   * The method then concatenates <code>PS</code>, the message <code>M</code>,
+   * and other padding to form an encoded message <code>EM</code> of length
+   * <code>k</code> octets as:
+   * <pre>
+   *     EM = 0x00 || 0x02 || PS || 0x00 || M.
+   * </pre>
+   * <p>
+   * This method uses a default PRNG to obtain the padding bytes.
+   * 
+   * @param M the message to encode.
+   * @return the encoded message <code>EM</code>.
+   */
+  public byte[] encode(final byte[] M)
+  {
+    // a. Generate an octet string PS of length k - mLen - 3 consisting
+    // of pseudo-randomly generated nonzero octets. The length of PS
+    // will be at least eight octets.
+    final byte[] PS = new byte[k - M.length - 3];
+    // FIXME. This should be configurable, somehow.
+    prng.nextBytes(PS);
+    int i = 0;
+    for (; i < PS.length; i++)
+      {
+        if (PS[i] == 0)
+          PS[i] = 1;
+      }
+    // b. Concatenate PS, the message M, and other padding to form an
+    // encoded message EM of length k octets as
+    //
+    // EM = 0x00 || 0x02 || PS || 0x00 || M.
+    return assembleEM(PS, M);
+  }
+
+  /**
+   * Similar to {@link #encode(byte[])} method, except that the source of
+   * randomness to use for obtaining the padding bytes (an instance of
+   * {@link IRandom}) is given as a parameter.
+   * 
+   * @param M the message to encode.
+   * @param irnd the {@link IRandom} instance to use as a source of randomness.
+   * @return the encoded message <code>EM</code>.
+   */
+  public byte[] encode(final byte[] M, final IRandom irnd)
+  {
+    final byte[] PS = new byte[k - M.length - 3];
+    try
+      {
+        irnd.nextBytes(PS, 0, PS.length);
+        int i = 0;
+        outer: while (true)
+          {
+            for (; i < PS.length; i++)
+              {
+                if (PS[i] == 0x00)
+                  {
+                    System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1);
+                    irnd.nextBytes(PS, PS.length - 1, 1);
+                    continue outer;
+                  }
+              }
+            break;
+          }
+      }
+    catch (IllegalStateException x)
+      {
+        throw new RuntimeException("encode(): " + String.valueOf(x));
+      }
+    catch (LimitReachedException x)
+      {
+        throw new RuntimeException("encode(): " + String.valueOf(x));
+      }
+    return assembleEM(PS, M);
+  }
+
+  /**
+   * Similar to the {@link #encode(byte[], IRandom)} method, except that the
+   * source of randmoness is an instance of {@link Random}.
+   * 
+   * @param M the message to encode.
+   * @param rnd the {@link Random} instance to use as a source of randomness.
+   * @return the encoded message <code>EM</code>.
+   */
+  public byte[] encode(final byte[] M, final Random rnd)
+  {
+    final byte[] PS = new byte[k - M.length - 3];
+    rnd.nextBytes(PS);
+    int i = 0;
+    outer: while (true)
+      {
+        for (; i < PS.length; i++)
+          {
+            if (PS[i] == 0x00)
+              {
+                System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1);
+                PS[PS.length - 1] = (byte) rnd.nextInt();
+                continue outer;
+              }
+          }
+        break;
+      }
+    return assembleEM(PS, M);
+  }
+
+  /**
+   * Separate the encoded message <code>EM</code> into an octet string
+   * <code>PS</code> consisting of nonzero octets and a message <code>M</code>
+   * as:
+   * <pre>
+   *     EM = 0x00 || 0x02 || PS || 0x00 || M.
+   * </pre>
+   * <p>
+   * If the first octet of <code>EM</code> does not have hexadecimal value
+   * <code>0x00</code>, if the second octet of <code>EM</code> does not
+   * have hexadecimal value <code>0x02</code>, if there is no octet with
+   * hexadecimal value <code>0x00</code> to separate <code>PS</code> from
+   * <code>M</code>, or if the length of <code>PS</code> is less than
+   * <code>8</code> octets, output "decryption error" and stop.
+   * 
+   * @param EM the designated encoded message.
+   * @return the decoded message <code>M</code> framed in the designated
+   *         <code>EM</code> value.
+   * @throws IllegalArgumentException if the length of the designated entity
+   *           <code>EM</code> is different than <code>k</code> (the length
+   *           in bytes of the public shared modulus), or if any of the
+   *           conditions described above is detected.
+   */
+  public byte[] decode(final byte[] EM)
+  {
+    // Separate the encoded message EM into an
+    // octet string PS consisting of nonzero octets and a message M as
+    //
+    // EM = 0x00 || 0x02 || PS || 0x00 || M.
+    //
+    // If the first octet of EM does not have hexadecimal value 0x00, if
+    // the second octet of EM does not have hexadecimal value 0x02, if
+    // there is no octet with hexadecimal value 0x00 to separate PS from
+    // M, or if the length of PS is less than 8 octets, output
+    // "decryption error" and stop. (See the note below.)
+    final int emLen = EM.length;
+    if (emLen != k)
+      throw new IllegalArgumentException("decryption error");
+    if (EM[0] != 0x00)
+      throw new IllegalArgumentException("decryption error");
+    if (EM[1] != 0x02)
+      throw new IllegalArgumentException("decryption error");
+    int i = 2;
+    for (; i < emLen; i++)
+      {
+        if (EM[i] == 0x00)
+          break;
+      }
+    if (i >= emLen || i < 11)
+      throw new IllegalArgumentException("decryption error");
+    i++;
+    final byte[] result = new byte[emLen - i];
+    System.arraycopy(EM, i, result, 0, result.length);
+    return result;
+  }
+
+  private byte[] assembleEM(final byte[] PS, final byte[] M)
+  {
+    // b. Concatenate PS, the message M, and other padding to form an
+    // encoded message EM of length k octets as
+    //
+    // EM = 0x00 || 0x02 || PS || 0x00 || M.
+    baos.reset();
+    baos.write(0x00);
+    baos.write(0x02);
+    baos.write(PS, 0, PS.length);
+    baos.write(0x00);
+    baos.write(M, 0, M.length);
+    final byte[] result = baos.toByteArray();
+    baos.reset();
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,243 @@
+/* EMSA_PKCS1_V1_5.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig.rsa;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * An implementation of the EMSA-PKCS1-V1.5 encoding scheme.
+ * <p>
+ * EMSA-PKCS1-V1.5 is parameterised by the choice of hash function Hash and
+ * hLen which denotes the length in octets of the hash function output.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ *    Standards (PKCS) #1:</a><br>
+ *    RSA Cryptography Specifications Version 2.1.<br>
+ *    Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+public class EMSA_PKCS1_V1_5
+    implements Cloneable
+{
+  /* Notes.
+   1. For the six hash functions mentioned in Appendix B.1, the DER encoding
+   T of the DigestInfo value is equal to the following:
+
+   MD2:     (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04 10 || H
+   MD5:     (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04 10 || H
+   SHA-1:   (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H
+   SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H
+   SHA-384: (0x)30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 || H
+   SHA-512: (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 || H
+   */
+  private static final byte[] MD2_PREFIX = {
+      (byte) 0x30, (byte) 0x20, (byte) 0x30, (byte) 0x0c, (byte) 0x06,
+      (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+      (byte) 0xf7, (byte) 0x0d, (byte) 0x02, (byte) 0x02, (byte) 0x05,
+      (byte) 0x00, (byte) 0x04, (byte) 0x10
+  };
+
+  private static final byte[] MD5_PREFIX = {
+      (byte) 0x30, (byte) 0x20, (byte) 0x30, (byte) 0x0c, (byte) 0x06,
+      (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+      (byte) 0xf7, (byte) 0x0d, (byte) 0x02, (byte) 0x05, (byte) 0x05,
+      (byte) 0x00, (byte) 0x04, (byte) 0x10
+  };
+
+  private static final byte[] SHA160_PREFIX = {
+      (byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06,
+      (byte) 0x05, (byte) 0x2b, (byte) 0x0e, (byte) 0x03, (byte) 0x02,
+      (byte) 0x1a, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x14
+  };
+
+  private static final byte[] SHA256_PREFIX = {
+      (byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
+      (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
+      (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x01,
+      (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x20
+  };
+
+  private static final byte[] SHA384_PREFIX = {
+      (byte) 0x30, (byte) 0x41, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
+      (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
+      (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x02,
+      (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x30
+  };
+
+  private static final byte[] SHA512_PREFIX = {
+      (byte) 0x30, (byte) 0x51, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
+      (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
+      (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x03,
+      (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x40
+  };
+
+  /** The underlying hash function to use with this instance. */
+  private IMessageDigest hash;
+
+  /** The output size of the hash function in octets. */
+  private int hLen; // TODO: field not used!!!  investigate
+
+  /** The DER part of DigestInfo not containing the hash value itself. */
+  private byte[] prefix;
+
+  /**
+   * Trivial private constructor to enforce use through Factory method.
+   *
+   * @param hash the message digest instance to use with this scheme instance.
+   */
+  private EMSA_PKCS1_V1_5(final IMessageDigest hash)
+  {
+    super();
+
+    this.hash = hash;
+    hLen = hash.hashSize();
+    final String name = hash.name();
+    if (name.equals(Registry.MD2_HASH))
+      prefix = MD2_PREFIX;
+    else if (name.equals(Registry.MD5_HASH))
+      prefix = MD5_PREFIX;
+    else if (name.equals(Registry.SHA160_HASH))
+      prefix = SHA160_PREFIX;
+    else if (name.equals(Registry.SHA256_HASH))
+      prefix = SHA256_PREFIX;
+    else if (name.equals(Registry.SHA384_HASH))
+      prefix = SHA384_PREFIX;
+    else if (name.equals(Registry.SHA512_HASH))
+      prefix = SHA512_PREFIX;
+    else
+      throw new UnsupportedOperationException(); // should not happen
+  }
+
+  /**
+   * Returns an instance of this object given a designated name of a hash
+   * function.
+   *
+   * @param mdName the canonical name of a hash function.
+   * @return an instance of this object configured for use with the designated
+   * options.
+   * @throws UnsupportedOperationException if the hash function is not
+   * implemented or does not have an ID listed in RFC-3447.
+   */
+  public static final EMSA_PKCS1_V1_5 getInstance(final String mdName)
+  {
+    final IMessageDigest hash = HashFactory.getInstance(mdName);
+    final String name = hash.name();
+    if (! (name.equals(Registry.MD2_HASH)
+          || name.equals(Registry.MD5_HASH)
+          || name.equals(Registry.SHA160_HASH)
+          || name.equals(Registry.SHA256_HASH)
+          || name.equals(Registry.SHA384_HASH)
+          || name.equals(Registry.SHA512_HASH)))
+      throw new UnsupportedOperationException("hash with no OID: " + name);
+
+    return new EMSA_PKCS1_V1_5(hash);
+  }
+
+  public Object clone()
+  {
+    return getInstance(hash.name());
+  }
+
+  /**
+   * Frames the hash of a message, along with an ID of the hash function in
+   * a DER sequence according to the specifications of EMSA-PKCS1-V1.5 as
+   * described in RFC-3447 (see class documentation).
+   *
+   * @param mHash the byte sequence resulting from applying the message digest
+   * algorithm Hash to the message <i>M</i>.
+   * @param emLen intended length in octets of the encoded message, at least
+   * <code>tLen + 11</code>, where <code>tLen</code> is the octet length of the
+   * DER encoding <code>T</code> of a certain value computed during the
+   * encoding operation.
+   * @return encoded message, an octet string of length <code>emLen</code>.
+   * @throws IllegalArgumentException if the message is too long, or if the
+   * intended encoded message length is too short.
+   */
+  public byte[] encode(final byte[] mHash, final int emLen)
+  {
+    // 1. Apply the hash function to the message M to produce a hash value
+    //    H: H = Hash(M).
+    //    If the hash function outputs "message too long," output "message
+    //    too long" and stop.
+    // 2. Encode the algorithm ID for the hash function and the hash value
+    //    into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with
+    //    the Distinguished Encoding Rules (DER), where the type DigestInfo
+    //    has the syntax
+    //       DigestInfo ::= SEQUENCE {
+    //          digestAlgorithm AlgorithmIdentifier,
+    //          digest OCTET STRING
+    //       }
+    //   The first field identifies the hash function and the second contains
+    //   the hash value.  Let T be the DER encoding of the DigestInfo value
+    //   (see the notes below) and let tLen be the length in octets of T.
+    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    baos.write(prefix, 0, prefix.length);
+    baos.write(mHash, 0, mHash.length);
+    final byte[] T = baos.toByteArray();
+    final int tLen = T.length;
+    // 3. If emLen < tLen + 11, output "intended encoded message length too
+    //    short" and stop.
+    if (emLen < tLen + 11)
+      throw new IllegalArgumentException("emLen too short");
+    // 4. Generate an octet string PS consisting of emLen - tLen - 3 octets
+    //    with hexadecimal value 0xff.  The length of PS will be at least 8
+    //    octets.
+    final byte[] PS = new byte[emLen - tLen - 3];
+    for (int i = 0; i < PS.length; i++)
+      PS[i] = (byte) 0xFF;
+    // 5. Concatenate PS, the DER encoding T, and other padding to form the
+    //    encoded message EM as: EM = 0x00 || 0x01 || PS || 0x00 || T.
+    baos.reset();
+    baos.write(0x00);
+    baos.write(0x01);
+    baos.write(PS, 0, PS.length);
+    baos.write(0x00);
+    baos.write(T, 0, tLen);
+    final byte[] result = baos.toByteArray();
+    baos.reset();
+    // 6. Output EM.
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/EMSA_PSS.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,371 @@
+/* EMSA_PSS.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig.rsa;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+/**
+ * An implementation of the EMSA-PSS encoding/decoding scheme.
+ * <p>
+ * EMSA-PSS coincides with EMSA4 in IEEE P1363a D5 except that EMSA-PSS acts on
+ * octet strings and not on bit strings. In particular, the bit lengths of the
+ * hash and the salt must be multiples of 8 in EMSA-PSS. Moreover, EMSA4 outputs
+ * an integer of a desired bit length rather than an octet string.
+ * <p>
+ * EMSA-PSS is parameterized by the choice of hash function Hash and mask
+ * generation function MGF. In this submission, MGF is based on a Hash
+ * definition that coincides with the corresponding definitions in IEEE Std
+ * 1363-2000, PKCS #1 v2.0, and the draft ANSI X9.44. In PKCS #1 v2.0 and the
+ * draft ANSI X9.44, the recommended hash function is SHA-1, while IEEE Std
+ * 1363-2000 recommends SHA-1 and RIPEMD-160.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+public class EMSA_PSS
+    implements Cloneable
+{
+  private static final Logger log = Logger.getLogger(EMSA_PSS.class.getName());
+
+  /** The underlying hash function to use with this instance. */
+  private IMessageDigest hash;
+
+  /** The output size of the hash function in octets. */
+  private int hLen;
+
+  /**
+   * Trivial private constructor to enforce use through Factory method.
+   * 
+   * @param hash the message digest instance to use with this scheme instance.
+   */
+  private EMSA_PSS(IMessageDigest hash)
+  {
+    super();
+
+    this.hash = hash;
+    hLen = hash.hashSize();
+  }
+
+  /**
+   * Returns an instance of this object given a designated name of a hash
+   * function.
+   * 
+   * @param mdName the canonical name of a hash function.
+   * @return an instance of this object configured for use with the designated
+   *         options.
+   */
+  public static EMSA_PSS getInstance(String mdName)
+  {
+    IMessageDigest hash = HashFactory.getInstance(mdName);
+    return new EMSA_PSS(hash);
+  }
+
+  public Object clone()
+  {
+    return getInstance(hash.name());
+  }
+
+  /**
+   * The encoding operation EMSA-PSS-Encode computes the hash of a message
+   * <code>M</code> using a hash function and maps the result to an encoded
+   * message <code>EM</code> of a specified length using a mask generation
+   * function.
+   * 
+   * @param mHash the byte sequence resulting from applying the message digest
+   *          algorithm Hash to the message <i>M</i>.
+   * @param emBits the maximal bit length of the integer OS2IP(EM), at least
+   *          <code>8.hLen + 8.sLen + 9</code>.
+   * @param salt the salt to use when encoding the output.
+   * @return the encoded message <code>EM</code>, an octet string of length
+   *         <code>emLen = CEILING(emBits / 8)</code>.
+   * @exception IllegalArgumentException if an exception occurs.
+   */
+  public byte[] encode(byte[] mHash, int emBits, byte[] salt)
+  {
+    int sLen = salt.length;
+    // 1. If the length of M is greater than the input limitation for the hash
+    // function (2**61 - 1 octets for SHA-1) then output "message too long"
+    // and stop.
+    // 2. Let mHash = Hash(M), an octet string of length hLen.
+    if (hLen != mHash.length)
+      throw new IllegalArgumentException("wrong hash");
+    // 3. If emBits < 8.hLen + 8.sLen + 9, output 'encoding error' and stop.
+    if (emBits < (8 * hLen + 8 * sLen + 9))
+      throw new IllegalArgumentException("encoding error");
+    int emLen = (emBits + 7) / 8;
+    // 4. Generate a random octet string salt of length sLen; if sLen = 0,
+    // then salt is the empty string.
+    // ...passed as argument to accomodate JCE
+    // 5. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt;
+    // M0 is an octet string of length 8 + hLen + sLen with eight initial zero
+    // octets.
+    // 6. Let H = Hash(M0), an octet string of length hLen.
+    byte[] H;
+    int i;
+    synchronized (hash)
+      {
+        for (i = 0; i < 8; i++)
+          hash.update((byte) 0x00);
+
+        hash.update(mHash, 0, hLen);
+        hash.update(salt, 0, sLen);
+        H = hash.digest();
+      }
+    // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
+    // zero octets. The length of PS may be 0.
+    // 8. Let DB = PS || 01 || salt.
+    byte[] DB = new byte[emLen - sLen - hLen - 2 + 1 + sLen];
+    DB[emLen - sLen - hLen - 2] = 0x01;
+    System.arraycopy(salt, 0, DB, emLen - sLen - hLen - 1, sLen);
+    // 9. Let dbMask = MGF(H, emLen - hLen - 1).
+    byte[] dbMask = MGF(H, emLen - hLen - 1);
+    if (Configuration.DEBUG)
+      {
+        log.fine("dbMask (encode): " + Util.toString(dbMask));
+        log.fine("DB (encode): " + Util.toString(DB));
+      }
+    // 10. Let maskedDB = DB XOR dbMask.
+    for (i = 0; i < DB.length; i++)
+      DB[i] = (byte)(DB[i] ^ dbMask[i]);
+    // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in
+    // maskedDB to zero.
+    DB[0] &= (0xFF >>> (8 * emLen - emBits));
+    // 12. Let EM = maskedDB || H || bc, where bc is the single octet with
+    // hexadecimal value 0xBC.
+    byte[] result = new byte[emLen];
+    System.arraycopy(DB, 0, result, 0, emLen - hLen - 1);
+    System.arraycopy(H, 0, result, emLen - hLen - 1, hLen);
+    result[emLen - 1] = (byte) 0xBC;
+    // 13. Output EM.
+    return result;
+  }
+
+  /**
+   * The decoding operation EMSA-PSS-Decode recovers the message hash from an
+   * encoded message <code>EM</code> and compares it to the hash of
+   * <code>M</code>.
+   * 
+   * @param mHash the byte sequence resulting from applying the message digest
+   *          algorithm Hash to the message <i>M</i>.
+   * @param EM the <i>encoded message</i>, an octet string of length
+   *          <code>emLen = CEILING(emBits/8).
+   * @param emBits the maximal bit length of the integer OS2IP(EM), at least
+   * <code>8.hLen + 8.sLen + 9</code>.
+   * @param sLen the length, in octets, of the expected salt.
+   * @return <code>true</code> if the result of the verification was
+   * <i>consistent</i> with the expected reseult; and <code>false</code> if the
+   * result was <i>inconsistent</i>.
+   * @exception IllegalArgumentException if an exception occurs.
+   */
+  public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen)
+  {
+    if (Configuration.DEBUG)
+      {
+        log.fine("mHash: " + Util.toString(mHash));
+        log.fine("EM: " + Util.toString(EM));
+        log.fine("emBits: " + String.valueOf(emBits));
+        log.fine("sLen: " + String.valueOf(sLen));
+      }
+    if (sLen < 0)
+      throw new IllegalArgumentException("sLen");
+    // 1. If the length of M is greater than the input limitation for the hash
+    // function (2**61 ? 1 octets for SHA-1) then output 'inconsistent' and
+    // stop.
+    // 2. Let mHash = Hash(M), an octet string of length hLen.
+    if (hLen != mHash.length)
+      {
+        if (Configuration.DEBUG)
+          log.fine("hLen != mHash.length; hLen: " + String.valueOf(hLen));
+        throw new IllegalArgumentException("wrong hash");
+      }
+    // 3. If emBits < 8.hLen + 8.sLen + 9, output 'decoding error' and stop.
+    if (emBits < (8 * hLen + 8 * sLen + 9))
+      {
+        if (Configuration.DEBUG)
+          log.fine("emBits < (8hLen + 8sLen + 9); sLen: "
+                   + String.valueOf(sLen));
+        throw new IllegalArgumentException("decoding error");
+      }
+    int emLen = (emBits + 7) / 8;
+    // 4. If the rightmost octet of EM does not have hexadecimal value bc,
+    // output 'inconsistent' and stop.
+    if ((EM[EM.length - 1] & 0xFF) != 0xBC)
+      {
+        if (Configuration.DEBUG)
+          log.fine("EM does not end with 0xBC");
+        return false;
+      }
+    // 5. Let maskedDB be the leftmost emLen ? hLen ? 1 octets of EM, and let
+    // H be the next hLen octets.
+    // 6. If the leftmost 8.emLen ? emBits bits of the leftmost octet in
+    // maskedDB are not all equal to zero, output 'inconsistent' and stop.
+    if ((EM[0] & (0xFF << (8 - (8 * emLen - emBits)))) != 0)
+      {
+        if (Configuration.DEBUG)
+          log.fine("Leftmost 8emLen - emBits bits of EM are not 0s");
+        return false;
+      }
+    byte[] DB = new byte[emLen - hLen - 1];
+    byte[] H = new byte[hLen];
+    System.arraycopy(EM, 0, DB, 0, emLen - hLen - 1);
+    System.arraycopy(EM, emLen - hLen - 1, H, 0, hLen);
+    // 7. Let dbMask = MGF(H, emLen ? hLen ? 1).
+    byte[] dbMask = MGF(H, emLen - hLen - 1);
+    // 8. Let DB = maskedDB XOR dbMask.
+    int i;
+    for (i = 0; i < DB.length; i++)
+      DB[i] = (byte)(DB[i] ^ dbMask[i]);
+    // 9. Set the leftmost 8.emLen ? emBits bits of DB to zero.
+    DB[0] &= (0xFF >>> (8 * emLen - emBits));
+    if (Configuration.DEBUG)
+      {
+        log.fine("dbMask (decode): " + Util.toString(dbMask));
+        log.fine("DB (decode): " + Util.toString(DB));
+      }
+    // 10. If the emLen -hLen -sLen -2 leftmost octets of DB are not zero or
+    // if the octet at position emLen -hLen -sLen -1 is not equal to 0x01,
+    // output 'inconsistent' and stop.
+    // IMPORTANT (rsn): this is an error in the specs, the index of the 0x01
+    // byte should be emLen -hLen -sLen -2 and not -1! authors have been advised
+    for (i = 0; i < (emLen - hLen - sLen - 2); i++)
+      {
+        if (DB[i] != 0)
+          {
+            if (Configuration.DEBUG)
+              log.fine("DB[" + String.valueOf(i) + "] != 0x00");
+            return false;
+          }
+      }
+    if (DB[i] != 0x01)
+      { // i == emLen -hLen -sLen -2
+        if (Configuration.DEBUG)
+          log.fine("DB's byte at position (emLen -hLen -sLen -2); i.e. "
+                   + String.valueOf(i) + " is not 0x01");
+        return false;
+      }
+    // 11. Let salt be the last sLen octets of DB.
+    byte[] salt = new byte[sLen];
+    System.arraycopy(DB, DB.length - sLen, salt, 0, sLen);
+    // 12. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt;
+    // M0 is an octet string of length 8 + hLen + sLen with eight initial
+    // zero octets.
+    // 13. Let H0 = Hash(M0), an octet string of length hLen.
+    byte[] H0;
+    synchronized (hash)
+      {
+        for (i = 0; i < 8; i++)
+          hash.update((byte) 0x00);
+
+        hash.update(mHash, 0, hLen);
+        hash.update(salt, 0, sLen);
+        H0 = hash.digest();
+      }
+    // 14. If H = H0, output 'consistent.' Otherwise, output 'inconsistent.'
+    return Arrays.equals(H, H0);
+  }
+
+  /**
+   * A mask generation function takes an octet string of variable length and a
+   * desired output length as input, and outputs an octet string of the desired
+   * length. There may be restrictions on the length of the input and output
+   * octet strings, but such bounds are generally very large. Mask generation
+   * functions are deterministic; the octet string output is completely
+   * determined by the input octet string. The output of a mask generation
+   * function should be pseudorandom, that is, it should be infeasible to
+   * predict, given one part of the output but not the input, another part of
+   * the output. The provable security of RSA-PSS relies on the random nature of
+   * the output of the mask generation function, which in turn relies on the
+   * random nature of the underlying hash function.
+   * 
+   * @param Z a seed.
+   * @param l the desired output length in octets.
+   * @return the mask.
+   * @exception IllegalArgumentException if the desired output length is too
+   *              long.
+   */
+  private byte[] MGF(byte[] Z, int l)
+  {
+    // 1. If l > (2**32).hLen, output 'mask too long' and stop.
+    if (l < 1 || (l & 0xFFFFFFFFL) > ((hLen & 0xFFFFFFFFL) << 32L))
+      throw new IllegalArgumentException("mask too long");
+    // 2. Let T be the empty octet string.
+    byte[] result = new byte[l];
+    // 3. For i = 0 to CEILING(l/hLen) ? 1, do
+    int limit = ((l + hLen - 1) / hLen) - 1;
+    IMessageDigest hashZ = null;
+    hashZ = (IMessageDigest) hash.clone();
+    hashZ.digest();
+    hashZ.update(Z, 0, Z.length);
+    IMessageDigest hashZC = null;
+    byte[] t;
+    int sofar = 0;
+    int length;
+    for (int i = 0; i < limit; i++)
+      {
+        // 3.1 Convert i to an octet string C of length 4 with the primitive
+        // I2OSP: C = I2OSP(i, 4).
+        // 3.2 Concatenate the hash of the seed Z and C to the octet string T:
+        // T = T || Hash(Z || C)
+        hashZC = (IMessageDigest) hashZ.clone();
+        hashZC.update((byte)(i >>> 24));
+        hashZC.update((byte)(i >>> 16));
+        hashZC.update((byte)(i >>> 8));
+        hashZC.update((byte) i);
+        t = hashZC.digest();
+        length = l - sofar;
+        length = (length > hLen ? hLen : length);
+        System.arraycopy(t, 0, result, sofar, length);
+        sofar += length;
+      }
+    // 4. Output the leading l octets of T as the octet string mask.
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/RSA.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,324 @@
+/* RSA.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig.rsa;
+
+import gnu.java.security.Properties;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+/**
+ * Utility methods related to the RSA algorithm.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ * Standards (PKCS) #1:</a><br>
+ * RSA Cryptography Specifications Version 2.1.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * <li><a href="http://crypto.stanford.edu/~dabo/abstracts/ssl-timing.html">
+ * Remote timing attacks are practical</a><br>
+ * D. Boneh and D. Brumley.</li>
+ * </ol>
+ */
+public class RSA
+{
+  private static final BigInteger ZERO = BigInteger.ZERO;
+
+  private static final BigInteger ONE = BigInteger.ONE;
+
+  /** Our default source of randomness. */
+  private static final PRNG prng = PRNG.getInstance();
+
+  /** Trivial private constructor to enforce Singleton pattern. */
+  private RSA()
+  {
+    super();
+  }
+
+  /**
+   * An implementation of the <b>RSASP</b> method: Assuming that the designated
+   * RSA private key is a valid one, this method computes a <i>signature
+   * representative</i> for a designated <i>message representative</i> signed
+   * by the holder of the designated RSA private key.
+   * 
+   * @param K the RSA private key.
+   * @param m the <i>message representative</i>: an integer between
+   *          <code>0</code> and <code>n - 1</code>, where <code>n</code>
+   *          is the RSA <i>modulus</i>.
+   * @return the <i>signature representative</i>, an integer between
+   *         <code>0</code> and <code>n - 1</code>, where <code>n</code>
+   *         is the RSA <i>modulus</i>.
+   * @throws ClassCastException if <code>K</code> is not an RSA one.
+   * @throws IllegalArgumentException if <code>m</code> (the <i>message
+   *           representative</i>) is out of range.
+   */
+  public static final BigInteger sign(final PrivateKey K, final BigInteger m)
+  {
+    try
+      {
+        return RSADP((RSAPrivateKey) K, m);
+      }
+    catch (IllegalArgumentException x)
+      {
+        throw new IllegalArgumentException("message representative out of range");
+      }
+  }
+
+  /**
+   * An implementation of the <b>RSAVP</b> method: Assuming that the designated
+   * RSA public key is a valid one, this method computes a <i>message
+   * representative</i> for the designated <i>signature representative</i>
+   * generated by an RSA private key, for a message intended for the holder of
+   * the designated RSA public key.
+   * 
+   * @param K the RSA public key.
+   * @param s the <i>signature representative</i>, an integer between
+   *          <code>0</code> and <code>n - 1</code>, where <code>n</code>
+   *          is the RSA <i>modulus</i>.
+   * @return a <i>message representative</i>: an integer between <code>0</code>
+   *         and <code>n - 1</code>, where <code>n</code> is the RSA
+   *         <i>modulus</i>.
+   * @throws ClassCastException if <code>K</code> is not an RSA one.
+   * @throws IllegalArgumentException if <code>s</code> (the <i>signature
+   *           representative</i>) is out of range.
+   */
+  public static final BigInteger verify(final PublicKey K, final BigInteger s)
+  {
+    try
+      {
+        return RSAEP((RSAPublicKey) K, s);
+      }
+    catch (IllegalArgumentException x)
+      {
+        throw new IllegalArgumentException("signature representative out of range");
+      }
+  }
+
+  /**
+   * An implementation of the <code>RSAEP</code> algorithm.
+   * 
+   * @param K the recipient's RSA public key.
+   * @param m the message representative as an MPI.
+   * @return the resulting MPI --an MPI between <code>0</code> and
+   *         <code>n - 1</code> (<code>n</code> being the public shared
+   *         modulus)-- that will eventually be padded with an appropriate
+   *         framing/padding scheme.
+   * @throws ClassCastException if <code>K</code> is not an RSA one.
+   * @throws IllegalArgumentException if <code>m</code>, the message
+   *           representative is not between <code>0</code> and
+   *           <code>n - 1</code> (<code>n</code> being the public shared
+   *           modulus).
+   */
+  public static final BigInteger encrypt(final PublicKey K, final BigInteger m)
+  {
+    try
+      {
+        return RSAEP((RSAPublicKey) K, m);
+      }
+    catch (IllegalArgumentException x)
+      {
+        throw new IllegalArgumentException("message representative out of range");
+      }
+  }
+
+  /**
+   * An implementation of the <code>RSADP</code> algorithm.
+   * 
+   * @param K the recipient's RSA private key.
+   * @param c the ciphertext representative as an MPI.
+   * @return the message representative, an MPI between <code>0</code> and
+   *         <code>n - 1</code> (<code>n</code> being the shared public
+   *         modulus).
+   * @throws ClassCastException if <code>K</code> is not an RSA one.
+   * @throws IllegalArgumentException if <code>c</code>, the ciphertext
+   *           representative is not between <code>0</code> and
+   *           <code>n - 1</code> (<code>n</code> being the shared public
+   *           modulus).
+   */
+  public static final BigInteger decrypt(final PrivateKey K, final BigInteger c)
+  {
+    try
+      {
+        return RSADP((RSAPrivateKey) K, c);
+      }
+    catch (IllegalArgumentException x)
+      {
+        throw new IllegalArgumentException("ciphertext representative out of range");
+      }
+  }
+
+  /**
+   * Converts a <i>multi-precision integer</i> (MPI) <code>s</code> into an
+   * octet sequence of length <code>k</code>.
+   * 
+   * @param s the multi-precision integer to convert.
+   * @param k the length of the output.
+   * @return the result of the transform.
+   * @exception IllegalArgumentException if the length in octets of meaningful
+   *              bytes of <code>s</code> is greater than <code>k</code>.
+   */
+  public static final byte[] I2OSP(final BigInteger s, final int k)
+  {
+    byte[] result = s.toByteArray();
+    if (result.length < k)
+      {
+        final byte[] newResult = new byte[k];
+        System.arraycopy(result, 0, newResult, k - result.length, result.length);
+        result = newResult;
+      }
+    else if (result.length > k)
+      { // leftmost extra bytes should all be 0
+        final int limit = result.length - k;
+        for (int i = 0; i < limit; i++)
+          {
+            if (result[i] != 0x00)
+              throw new IllegalArgumentException("integer too large");
+          }
+        final byte[] newResult = new byte[k];
+        System.arraycopy(result, limit, newResult, 0, k);
+        result = newResult;
+      }
+    return result;
+  }
+
+  private static final BigInteger RSAEP(final RSAPublicKey K, final BigInteger m)
+  {
+    // 1. If the representative m is not between 0 and n - 1, output
+    // "representative out of range" and stop.
+    final BigInteger n = K.getModulus();
+    if (m.compareTo(ZERO) < 0 || m.compareTo(n.subtract(ONE)) > 0)
+      throw new IllegalArgumentException();
+    // 2. Let c = m^e mod n.
+    final BigInteger e = K.getPublicExponent();
+    final BigInteger result = m.modPow(e, n);
+    // 3. Output c.
+    return result;
+  }
+
+  private static final BigInteger RSADP(final RSAPrivateKey K, BigInteger c)
+  {
+    // 1. If the representative c is not between 0 and n - 1, output
+    // "representative out of range" and stop.
+    final BigInteger n = K.getModulus();
+    if (c.compareTo(ZERO) < 0 || c.compareTo(n.subtract(ONE)) > 0)
+      throw new IllegalArgumentException();
+    // 2. The representative m is computed as follows.
+    BigInteger result;
+    if (! (K instanceof RSAPrivateCrtKey))
+      {
+        // a. If the first form (n, d) of K is used, let m = c^d mod n.
+        final BigInteger d = K.getPrivateExponent();
+        result = c.modPow(d, n);
+      }
+    else
+      {
+        // from [3] p.13 --see class docs:
+        // The RSA blinding operation calculates x = (r^e) * g mod n before
+        // decryption, where r is random, e is the RSA encryption exponent, and
+        // g is the ciphertext to be decrypted. x is then decrypted as normal,
+        // followed by division by r, i.e. (x^e) / r mod n. Since r is random,
+        // x is random and timing the decryption should not reveal information
+        // about the key. Note that r should be a new random number for every
+        // decryption.
+        final boolean rsaBlinding = Properties.doRSABlinding();
+        BigInteger r = null;
+        BigInteger e = null;
+        if (rsaBlinding)
+          { // pre-decryption
+            r = newR(n);
+            e = ((RSAPrivateCrtKey) K).getPublicExponent();
+            final BigInteger x = r.modPow(e, n).multiply(c).mod(n);
+            c = x;
+          }
+        // b. If the second form (p, q, dP, dQ, qInv) and (r_i, d_i, t_i)
+        // of K is used, proceed as follows:
+        final BigInteger p = ((RSAPrivateCrtKey) K).getPrimeP();
+        final BigInteger q = ((RSAPrivateCrtKey) K).getPrimeQ();
+        final BigInteger dP = ((RSAPrivateCrtKey) K).getPrimeExponentP();
+        final BigInteger dQ = ((RSAPrivateCrtKey) K).getPrimeExponentQ();
+        final BigInteger qInv = ((RSAPrivateCrtKey) K).getCrtCoefficient();
+        // i. Let m_1 = c^dP mod p and m_2 = c^dQ mod q.
+        final BigInteger m_1 = c.modPow(dP, p);
+        final BigInteger m_2 = c.modPow(dQ, q);
+        // ii. If u > 2, let m_i = c^(d_i) mod r_i, i = 3, ..., u.
+        // iii. Let h = (m_1 - m_2) * qInv mod p.
+        final BigInteger h = m_1.subtract(m_2).multiply(qInv).mod(p);
+        // iv. Let m = m_2 + q * h.
+        result = m_2.add(q.multiply(h));
+        if (rsaBlinding) // post-decryption
+          result = result.multiply(r.modInverse(n)).mod(n);
+      }
+    // 3. Output m
+    return result;
+  }
+
+  /**
+   * Returns a random MPI with a random bit-length of the form <code>8b</code>,
+   * where <code>b</code> is in the range <code>[32..64]</code>.
+   * 
+   * @return a random MPI whose length in bytes is between 32 and 64 inclusive.
+   */
+  private static final BigInteger newR(final BigInteger N)
+  {
+    final int upper = (N.bitLength() + 7) / 8;
+    final int lower = upper / 2;
+    final byte[] bl = new byte[1];
+    int b;
+    do
+      {
+        prng.nextBytes(bl);
+        b = bl[0] & 0xFF;
+      }
+    while (b < lower || b > upper);
+    final byte[] buffer = new byte[b]; // 256-bit MPI
+    prng.nextBytes(buffer);
+    return new BigInteger(1, buffer);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,224 @@
+/* RSAPKCS1V1_5Signature.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig.rsa;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.sig.BaseSignature;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+
+/**
+ * The RSA-PKCS1-V1.5 signature scheme is a digital signature scheme with
+ * appendix (SSA) combining the RSA algorithm with the EMSA-PKCS1-v1_5 encoding
+ * method.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ * Standards (PKCS) #1:</a><br>
+ * RSA Cryptography Specifications Version 2.1.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+public class RSAPKCS1V1_5Signature
+    extends BaseSignature
+{
+  /** The underlying EMSA-PKCS1-v1.5 instance for this object. */
+  private EMSA_PKCS1_V1_5 pkcs1;
+
+  /**
+   * Default 0-arguments constructor. Uses SHA-1 as the default hash.
+   */
+  public RSAPKCS1V1_5Signature()
+  {
+    this(Registry.SHA160_HASH);
+  }
+
+  /**
+   * Constructs an instance of this object using the designated message digest
+   * algorithm as its underlying hash function.
+   * 
+   * @param mdName the canonical name of the underlying hash function.
+   */
+  public RSAPKCS1V1_5Signature(final String mdName)
+  {
+    this(HashFactory.getInstance(mdName));
+  }
+
+  public RSAPKCS1V1_5Signature(IMessageDigest md)
+  {
+    super(Registry.RSA_PKCS1_V1_5_SIG, md);
+
+    pkcs1 = EMSA_PKCS1_V1_5.getInstance(md.name());
+  }
+
+  /** Private constructor for cloning purposes. */
+  private RSAPKCS1V1_5Signature(final RSAPKCS1V1_5Signature that)
+  {
+    this(that.md.name());
+
+    this.publicKey = that.publicKey;
+    this.privateKey = that.privateKey;
+    this.md = (IMessageDigest) that.md.clone();
+    this.pkcs1 = (EMSA_PKCS1_V1_5) that.pkcs1.clone();
+  }
+
+  public Object clone()
+  {
+    return new RSAPKCS1V1_5Signature(this);
+  }
+
+  protected void setupForVerification(final PublicKey k)
+      throws IllegalArgumentException
+  {
+    if (! (k instanceof RSAPublicKey))
+      throw new IllegalArgumentException();
+
+    publicKey = k;
+  }
+
+  protected void setupForSigning(final PrivateKey k)
+      throws IllegalArgumentException
+  {
+    if (! (k instanceof RSAPrivateKey))
+      throw new IllegalArgumentException();
+
+    privateKey = k;
+  }
+
+  protected Object generateSignature() throws IllegalStateException
+  {
+    // 1. EMSA-PKCS1-v1_5 encoding: Apply the EMSA-PKCS1-v1_5 encoding
+    // operation (Section 9.2) to the message M to produce an encoded
+    // message EM of length k octets:
+    //
+    // EM = EMSA-PKCS1-V1_5-ENCODE (M, k).
+    //
+    // If the encoding operation outputs "message too long," output
+    // "message too long" and stop. If the encoding operation outputs
+    // "intended encoded message length too short," output "RSA modulus
+    // too short" and stop.
+    final int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength();
+    final int k = (modBits + 7) / 8;
+    final byte[] EM = pkcs1.encode(md.digest(), k);
+    // 2. RSA signature:
+    // a. Convert the encoded message EM to an integer message epresentative
+    // m (see Section 4.2): m = OS2IP (EM).
+    final BigInteger m = new BigInteger(1, EM);
+    // b. Apply the RSASP1 signature primitive (Section 5.2.1) to the RSA
+    // private key K and the message representative m to produce an
+    // integer signature representative s: s = RSASP1 (K, m).
+    final BigInteger s = RSA.sign(privateKey, m);
+    // c. Convert the signature representative s to a signature S of length
+    // k octets (see Section 4.1): S = I2OSP (s, k).
+    // 3. Output the signature S.
+    return RSA.I2OSP(s, k);
+  }
+
+  protected boolean verifySignature(final Object sig)
+      throws IllegalStateException
+  {
+    if (publicKey == null)
+      throw new IllegalStateException();
+    final byte[] S = (byte[]) sig;
+    // 1. Length checking: If the length of the signature S is not k octets,
+    // output "invalid signature" and stop.
+    final int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength();
+    final int k = (modBits + 7) / 8;
+    if (S.length != k)
+      return false;
+    // 2. RSA verification:
+    // a. Convert the signature S to an integer signature representative
+    // s (see Section 4.2): s = OS2IP (S).
+    final BigInteger s = new BigInteger(1, S);
+    // b. Apply the RSAVP1 verification primitive (Section 5.2.2) to the
+    // RSA public key (n, e) and the signature representative s to
+    // produce an integer message representative m:
+    // m = RSAVP1 ((n, e), s).
+    // If RSAVP1 outputs "signature representative out of range,"
+    // output "invalid signature" and stop.
+    final BigInteger m;
+    try
+      {
+        m = RSA.verify(publicKey, s);
+      }
+    catch (IllegalArgumentException x)
+      {
+        return false;
+      }
+    // c. Convert the message representative m to an encoded message EM
+    // of length k octets (see Section 4.1): EM = I2OSP (m, k).
+    // If I2OSP outputs "integer too large," output "invalid signature"
+    // and stop.
+    final byte[] EM;
+    try
+      {
+        EM = RSA.I2OSP(m, k);
+      }
+    catch (IllegalArgumentException x)
+      {
+        return false;
+      }
+    // 3. EMSA-PKCS1-v1_5 encoding: Apply the EMSA-PKCS1-v1_5 encoding
+    // operation (Section 9.2) to the message M to produce a second
+    // encoded message EM' of length k octets:
+    // EM' = EMSA-PKCS1-V1_5-ENCODE (M, k).
+    // If the encoding operation outputs "message too long," output
+    // "message too long" and stop. If the encoding operation outputs
+    // "intended encoded message length too short," output "RSA modulus
+    // too short" and stop.
+    final byte[] EMp = pkcs1.encode(md.digest(), k);
+    // 4. Compare the encoded message EM and the second encoded message EM'.
+    // If they are the same, output "valid signature"; otherwise, output
+    // "invalid signature."
+    return Arrays.equals(EM, EMp);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,153 @@
+/* RSAPKCS1V1_5SignatureRawCodec.java -- Raw RSA PKCS1 v1.5 signature codeec
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.sig.rsa;
+
+import java.io.ByteArrayOutputStream;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.ISignatureCodec;
+
+/**
+ * An object that implements the {@link ISignatureCodec} operations for the
+ * <i>Raw</i> format to use with RSA-PKCS#1 v1.5 signatures.
+ */
+public class RSAPKCS1V1_5SignatureRawCodec
+    implements ISignatureCodec
+{
+  public int getFormatID()
+  {
+    return RAW_FORMAT;
+  }
+
+  /**
+   * Returns the encoded form of the designated RSA-PKCS#1 (v1.5) signature
+   * object according to the <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for such a signature, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <p>
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE},
+   * <li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the RSA-PKCS#1 (v1.5)
+   * signature bytes in internet order,</li>
+   * <li>the RSA-PKCS#1 (v1.5) signature bytes in internet order.</li>
+   * </ol>
+   * 
+   * @param signature the signature to encode, consisting of the output of the
+   *          <code>sign()</code> method of a {@link RSAPKCS1V1_5Signature}
+   *          instance --a byte array.
+   * @return the <i>Raw</i> format encoding of the designated signature.
+   * @exception IllegalArgumentException if the designated signature is not an
+   *              RSA-PKCS#1 (v1.5) one.
+   */
+  public byte[] encodeSignature(Object signature)
+  {
+    byte[] buffer;
+    try
+      {
+        buffer = (byte[]) signature;
+      }
+    catch (Exception x)
+      {
+        throw new IllegalArgumentException("Signature/codec mismatch");
+      }
+
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+    // magic
+    baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[0]);
+    baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[1]);
+    baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[2]);
+    baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[3]);
+
+    // version
+    baos.write(0x01);
+
+    // signature bytes
+    int length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+
+    return baos.toByteArray();
+  }
+
+  /**
+   * Returns the decoded object from a designated input assumed to have been
+   * generated by the {@link #encodeSignature(Object)} method.
+   * 
+   * @param input the input bytes of a previously Raw-encoded RSA PKCS1 (v1.5)
+   *          signature.
+   * @return the signature object.
+   * @throws IllegalArgumentException if the designated input does not start
+   *           with the right <i>magic</i> characters, or if the <i>version</i>
+   *           is not supported.
+   */
+  public Object decodeSignature(byte[] input)
+  {
+    // magic
+    if (input[0] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[0]
+        || input[1] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[1]
+        || input[2] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[2]
+        || input[3] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[3])
+      throw new IllegalArgumentException("Signature/codec mismatch");
+
+    // version
+    if (input[4] != 0x01)
+      throw new IllegalArgumentException("Wrong or unsupported format version");
+
+    int i = 5;
+    int l;
+
+    // signature bytes
+    l =    input[i++]         << 24
+        | (input[i++] & 0xFF) << 16
+        | (input[i++] & 0xFF) <<  8
+        | (input[i++] & 0xFF);
+    byte[] result = new byte[l];
+    System.arraycopy(input, i, result, 0, l);
+
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,128 @@
+/* RSAPSSSignatureX509Codec.java -- X.509 encoder/decoder for RSA signatures
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.sig.rsa;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.ISignatureCodec;
+
+import java.security.InvalidParameterException;
+
+/**
+ * An implementation of an {@link ISignatureCodec} that knows to encode and
+ * decode RSA PKCS1 (v1.5) signatures into the raw bytes which would constitute
+ * a DER-encoded form of the ASN.1 structure defined in RFC-2459, and RFC-2313
+ * as described in the next paragraphs.
+ * <p>
+ * Digital signatures when transmitted in an X.509 certificates are encoded
+ * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e.
+ * 
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ *   tbsCertificate       TBSCertificate,
+ *   signatureAlgorithm   AlgorithmIdentifier,
+ *   signature            BIT STRING
+ * }
+ * </pre>
+ * <p>
+ * The output of the encoder, and the input of the decoder, of this codec are
+ * then the <i>raw</i> bytes of such a BIT STRING; i.e. not the DER-encoded
+ * form itself.
+ * <p>
+ * Our implementation of the RSA PKCS1 signature algorithm outputs a byte array
+ * as the result of generating a digital signature, in accordance with RFC-2313.
+ * As a consequence, the encoder and decoder of this codec, simply pass through
+ * such a byte array.
+ * <p>
+ * Client code that needs to build a DER BIT STRING <b>MUST</b> construct such
+ * an ASN.1 value. The following is an example of how to do this:
+ * <p>
+ * <pre>
+ * ...
+ * import gnu.java.security.der.BitString;
+ * import gnu.java.security.der.DER;
+ * import gnu.java.security.der.DERValue;
+ * ...
+ * DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
+ * ...
+ * </pre>
+ */
+public class RSAPKCS1V1_5SignatureX509Codec
+    implements ISignatureCodec
+{
+  // default 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return Registry.X509_ENCODING_ID;
+  }
+
+  /**
+   * Encodes an RSA Signature output as a <i>signature</i> BIT STRING as
+   * defined in the documentation of this class.
+   * 
+   * @param signature the output of the RSA PKCS1 (v1.5) signature algorithm;
+   *          i.e. the value returned by the invocation of
+   *          {@link gnu.java.security.sig.ISignature#sign()} method. In the
+   *          case of the RSA PKCS1 (v1.5) signature this is an array of bytes.
+   * @return the raw bytes of an RSA signature which could be then used as the
+   *         contents of a BIT STRING as per rfc-2459.
+   */
+  public byte[] encodeSignature(Object signature)
+  {
+    byte[] result = (byte[]) signature;
+    return result;
+  }
+
+  /**
+   * Decodes a <i>signature</i> as defined in the documentation of this class.
+   * 
+   * @param input the byte array to unmarshall into a valid RSA PKCS1 (v1.5)
+   *          signature instance; i.e. a byte array. MUST NOT be null.
+   * @return an array of raw bytes decoded from the designated input. In the
+   *         case of RSA PKCS1 (v1.5) this is the same as the input.
+   * @throw InvalidParameterException if the <code>input</code> array is null.
+   */
+  public Object decodeSignature(byte[] input)
+  {
+    if (input == null)
+      throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+    return input;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/RSAPSSSignature.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,255 @@
+/* RSAPSSSignature.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig.rsa;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.sig.BaseSignature;
+import gnu.java.security.util.Util;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.logging.Logger;
+
+/**
+ * The RSA-PSS signature scheme is a public-key encryption scheme combining the
+ * RSA algorithm with the Probabilistic Signature Scheme (PSS) encoding method.
+ * <p>
+ * The inventors of RSA are Ronald L. Rivest, Adi Shamir, and Leonard Adleman,
+ * while the inventors of the PSS encoding method are Mihir Bellare and Phillip
+ * Rogaway. During efforts to adopt RSA-PSS into the P1363a standards effort,
+ * certain adaptations to the original version of RSA-PSS were made by Mihir
+ * Bellare and Phillip Rogaway and also by Burt Kaliski (the editor of IEEE
+ * P1363a) to facilitate implementation and integration into existing protocols.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+public class RSAPSSSignature
+    extends BaseSignature
+{
+  private static final Logger log = Logger.getLogger(RSAPSSSignature.class.getName());
+
+  /** The underlying EMSA-PSS instance for this object. */
+  private EMSA_PSS pss;
+
+  /** The desired length in octets of the EMSA-PSS salt. */
+  private int sLen;
+
+  /**
+   * Default 0-arguments constructor. Uses SHA-1 as the default hash and a
+   * 0-octet <i>salt</i>.
+   */
+  public RSAPSSSignature()
+  {
+    this(Registry.SHA160_HASH, 0);
+  }
+
+  /**
+   * Constructs an instance of this object using the designated message digest
+   * algorithm as its underlying hash function, and having 0-octet <i>salt</i>.
+   * 
+   * @param mdName the canonical name of the underlying hash function.
+   */
+  public RSAPSSSignature(String mdName)
+  {
+    this(mdName, 0);
+  }
+
+  /**
+   * Constructs an instance of this object using the designated message digest
+   * algorithm as its underlying hash function.
+   * 
+   * @param mdName the canonical name of the underlying hash function.
+   * @param sLen the desired length in octets of the salt to use for encoding /
+   *          decoding signatures.
+   */
+  public RSAPSSSignature(String mdName, int sLen)
+  {
+    this(HashFactory.getInstance(mdName), sLen);
+  }
+
+  public RSAPSSSignature(IMessageDigest md, int sLen)
+  {
+    super(Registry.RSA_PSS_SIG, md);
+
+    pss = EMSA_PSS.getInstance(md.name());
+    this.sLen = sLen;
+  }
+
+  /** Private constructor for cloning purposes. */
+  private RSAPSSSignature(RSAPSSSignature that)
+  {
+    this(that.md.name(), that.sLen);
+
+    this.publicKey = that.publicKey;
+    this.privateKey = that.privateKey;
+    this.md = (IMessageDigest) that.md.clone();
+    this.pss = (EMSA_PSS) that.pss.clone();
+  }
+
+  public Object clone()
+  {
+    return new RSAPSSSignature(this);
+  }
+
+  protected void setupForVerification(PublicKey k)
+      throws IllegalArgumentException
+  {
+    if (! (k instanceof RSAPublicKey))
+      throw new IllegalArgumentException();
+
+    publicKey = (RSAPublicKey) k;
+  }
+
+  protected void setupForSigning(PrivateKey k) throws IllegalArgumentException
+  {
+    if (! (k instanceof RSAPrivateKey))
+      throw new IllegalArgumentException();
+
+    privateKey = (RSAPrivateKey) k;
+  }
+
+  protected Object generateSignature() throws IllegalStateException
+  {
+    // 1. Apply the EMSA-PSS encoding operation to the message M to produce an
+    // encoded message EM of length CEILING((modBits ? 1)/8) octets such
+    // that the bit length of the integer OS2IP(EM) is at most modBits ? 1:
+    // EM = EMSA-PSS-Encode(M,modBits ? 1).
+    // Note that the octet length of EM will be one less than k if
+    // modBits ? 1 is divisible by 8. If the encoding operation outputs
+    // 'message too long' or 'encoding error,' then output 'message too
+    // long' or 'encoding error' and stop.
+    int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength();
+    byte[] salt = new byte[sLen];
+    this.nextRandomBytes(salt);
+    byte[] EM = pss.encode(md.digest(), modBits - 1, salt);
+    if (Configuration.DEBUG)
+      log.fine("EM (sign): " + Util.toString(EM));
+    // 2. Convert the encoded message EM to an integer message representative
+    // m (see Section 1.2.2): m = OS2IP(EM).
+    BigInteger m = new BigInteger(1, EM);
+    // 3. Apply the RSASP signature primitive to the public key K and the
+    // message representative m to produce an integer signature
+    // representative s: s = RSASP(K,m).
+    BigInteger s = RSA.sign(privateKey, m);
+    // 4. Convert the signature representative s to a signature S of length k
+    // octets (see Section 1.2.1): S = I2OSP(s, k).
+    // 5. Output the signature S.
+    int k = (modBits + 7) / 8;
+    // return encodeSignature(s, k);
+    return RSA.I2OSP(s, k);
+  }
+
+  protected boolean verifySignature(Object sig) throws IllegalStateException
+  {
+    if (publicKey == null)
+      throw new IllegalStateException();
+    // byte[] S = decodeSignature(sig);
+    byte[] S = (byte[]) sig;
+    // 1. If the length of the signature S is not k octets, output 'signature
+    // invalid' and stop.
+    int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength();
+    int k = (modBits + 7) / 8;
+    if (S.length != k)
+      return false;
+    // 2. Convert the signature S to an integer signature representative s:
+    // s = OS2IP(S).
+    BigInteger s = new BigInteger(1, S);
+    // 3. Apply the RSAVP verification primitive to the public key (n, e) and
+    // the signature representative s to produce an integer message
+    // representative m: m = RSAVP((n, e), s).
+    // If RSAVP outputs 'signature representative out of range,' then
+    // output 'signature invalid' and stop.
+    BigInteger m = null;
+    try
+      {
+        m = RSA.verify(publicKey, s);
+      }
+    catch (IllegalArgumentException x)
+      {
+        return false;
+      }
+    // 4. Convert the message representative m to an encoded message EM of
+    // length emLen = CEILING((modBits - 1)/8) octets, where modBits is
+    // equal to the bit length of the modulus: EM = I2OSP(m, emLen).
+    // Note that emLen will be one less than k if modBits - 1 is divisible
+    // by 8. If I2OSP outputs 'integer too large,' then output 'signature
+    // invalid' and stop.
+    int emBits = modBits - 1;
+    int emLen = (emBits + 7) / 8;
+    byte[] EM = m.toByteArray();
+    if (Configuration.DEBUG)
+      log.fine("EM (verify): " + Util.toString(EM));
+    if (EM.length > emLen)
+      return false;
+    else if (EM.length < emLen)
+      {
+        byte[] newEM = new byte[emLen];
+        System.arraycopy(EM, 0, newEM, emLen - EM.length, EM.length);
+        EM = newEM;
+      }
+    // 5. Apply the EMSA-PSS decoding operation to the message M and the
+    // encoded message EM: Result = EMSA-PSS-Decode(M, EM, emBits). If
+    // Result = 'consistent,' output 'signature verified.' Otherwise,
+    // output 'signature invalid.'
+    byte[] mHash = md.digest();
+    boolean result = false;
+    try
+      {
+        result = pss.decode(mHash, EM, emBits, sLen);
+      }
+    catch (IllegalArgumentException x)
+      {
+        result = false;
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,134 @@
+/* RSAPSSSignatureRawCodec.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.sig.rsa;
+
+import gnu.java.security.Registry;
+import gnu.java.security.sig.ISignatureCodec;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * An object that implements the {@link ISignatureCodec} operations for the
+ * <i>Raw</i> format to use with RSA-PSS signatures.
+ */
+public class RSAPSSSignatureRawCodec
+    implements ISignatureCodec
+{
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return RAW_FORMAT;
+  }
+
+  /**
+   * Returns the encoded form of the designated RSA-PSS signature object
+   * according to the <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for an RSA-PSS signature, in this implementation, is
+   * a byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_RSA_PSS_SIGNATURE},
+   * <li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the RSA-PSS signature
+   * bytes in internet order,</li>
+   * <li>the RSA-PSS signature bytes in internet order.</li>
+   * </ol>
+   * 
+   * @param signature the signature to encode, consisting of the output of the
+   *          <code>sign()</code> method of a {@link RSAPSSSignature} instance
+   *          --a byte array.
+   * @return the <i>Raw</i> format encoding of the designated signature.
+   * @exception IllegalArgumentException if the designated signature is not an
+   *              RSA-PSS one.
+   */
+  public byte[] encodeSignature(Object signature)
+  {
+    byte[] buffer;
+    try
+      {
+        buffer = (byte[]) signature;
+      }
+    catch (Exception x)
+      {
+        throw new IllegalArgumentException("signature");
+      }
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0]);
+    baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1]);
+    baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2]);
+    baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3]);
+    // version
+    baos.write(0x01);
+    // signature bytes
+    int length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>> 8) & 0xFF);
+    baos.write(length & 0xFF);
+    baos.write(buffer, 0, length);
+    return baos.toByteArray();
+  }
+
+  public Object decodeSignature(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0]
+        || k[1] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1]
+        || k[2] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2]
+        || k[3] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3])
+      throw new IllegalArgumentException("magic");
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+    int i = 5;
+    int l;
+    // signature bytes
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    byte[] result = new byte[l];
+    System.arraycopy(k, i, result, 0, l);
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/sig/rsa/RSASignatureFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,176 @@
+/* RSASignatureFactory.java -- A Factory class to instantiate RSA Signatures
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.sig.rsa;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.sig.ISignature;
+
+/**
+ * A Factory class to instantiate RSA Signature classes.
+ */
+public class RSASignatureFactory
+{
+  private static Set names;
+
+  /**
+   * Private constructor to enforce usage through Factory (class) methods.
+   */
+  private RSASignatureFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns a new instance of an RSA Signature given its name. The name of an
+   * RSA Signature always starts with <code>rsa-</code>, followed by either
+   * <code>pss</code> or <code>pkcs1_v1.5</code>. An optional message digest
+   * name, to be used with the RSA signature may be specified by appending the
+   * hyphen chanaracter <code>-</code> followed by the canonical message digest
+   * algorithm name. When no message digest algorithm name is given, SHA-160 is
+   * used.
+   *  
+   * @param name the composite RSA signature name.
+   * @return a new instance of an RSA Signature algorithm implementation.
+   * Returns <code>null</code> if the given name does not correspond to any
+   * supported RSA Signature encoding and message digest combination.
+   */
+  public static final ISignature getInstance(String name)
+  {
+    if (name == null)
+      return null;
+
+    name = name.trim();
+    if (name.length() == 0)
+      return null;
+
+    name = name.toLowerCase();
+    if (! name.startsWith(Registry.RSA_SIG_PREFIX))
+      return null;
+
+    name = name.substring(Registry.RSA_SIG_PREFIX.length()).trim();
+    if (name.startsWith(Registry.RSA_PSS_ENCODING))
+      return getPSSSignature(name);
+    else if (name.startsWith(Registry.RSA_PKCS1_V1_5_ENCODING))
+      return getPKCS1Signature(name);
+    else
+      return null;
+  }
+
+  /**
+   * Returns a {@link Set} of names of <i>RSA</i> signatures supported by this
+   * <i>Factory</i>.
+   * 
+   * @return a {@link Set} of RSA Signature algorithm names (Strings).
+   */
+  public static synchronized final Set getNames()
+  {
+    if (names == null)
+      {
+        Set hashNames = HashFactory.getNames();
+        HashSet hs = new HashSet();
+        for (Iterator it = hashNames.iterator(); it.hasNext();)
+          {
+            String mdName = (String) it.next();
+            hs.add(Registry.RSA_PSS_SIG + "-" + mdName);
+          }
+
+        hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD2_HASH);
+        hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD5_HASH);
+        hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA160_HASH);
+        hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA256_HASH);
+        hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA384_HASH);
+        hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA512_HASH);
+
+        names = Collections.unmodifiableSet(hs);
+      }
+
+    return names;
+  }
+
+  private static final ISignature getPSSSignature(String name)
+  {
+    name = name.substring(Registry.RSA_PSS_ENCODING.length()).trim();
+    // remove the hyphen if found at the beginning
+    if (name.startsWith("-"))
+      name = name.substring(1).trim();
+
+    IMessageDigest md;
+    if (name.length() == 0)
+      md = HashFactory.getInstance(Registry.SHA160_HASH);
+    else
+      {
+        // check if there is such a hash
+        md = HashFactory.getInstance(name);
+        if (md == null)
+          return null;
+      }
+
+    ISignature result = new RSAPSSSignature(md, 0);
+    return result;
+  }
+
+  private static final ISignature getPKCS1Signature(String name)
+  {
+    name = name.substring(Registry.RSA_PKCS1_V1_5_ENCODING.length()).trim();
+    // remove the hyphen if found at the beginning
+    if (name.startsWith("-"))
+      name = name.substring(1).trim();
+
+    IMessageDigest md;
+    if (name.length() == 0)
+      md = HashFactory.getInstance(Registry.SHA160_HASH);
+    else
+      {
+        // check if there is such a hash
+        md = HashFactory.getInstance(name);
+        if (md == null)
+          return null;
+      }
+
+    ISignature result = new RSAPKCS1V1_5Signature(md);
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/ByteArray.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,109 @@
+/* ByteArray.java -- wrapper around a byte array, with nice toString output.
+   Copyright (C) 2005  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+public final class ByteArray
+{
+  private final byte[] value;
+
+  public ByteArray (final byte[] value)
+  {
+    this.value = value;
+  }
+
+  public byte[] getValue ()
+  {
+    return value;
+  }
+
+  public String toString ()
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+    int i = 0;
+    int len = value.length;
+    while (i < len)
+      {
+	out.print (formatInt (i, 16, 8));
+	out.print ("  ");
+	int l = Math.min (16, len - i);
+	String s = toHexString (value, i, l, ' ');
+	out.print (s);
+	for (int j = 56 - (56 - s.length ()); j < 56; j++)
+	  out.print (" ");
+	for (int j = 0; j < l; j++)
+	  {
+	    byte b = value[i+j];
+	    if ((b & 0xFF) < 0x20 || (b & 0xFF) > 0x7E)
+	      out.print (".");
+	    else
+	      out.print ((char) (b & 0xFF));
+	  }
+	out.println ();
+	i += 16;
+      }
+    return str.toString ();
+  }
+
+  public static String toHexString (byte[] buf, int off, int len, char sep)
+  {
+    StringBuffer str = new StringBuffer();
+    for (int i = 0; i < len; i++)
+      {
+	str.append (Character.forDigit (buf[i+off] >>> 4 & 0x0F, 16));
+	str.append (Character.forDigit (buf[i+off] & 0x0F, 16));
+        if (i < len - 1)
+          str.append(sep);
+      }
+    return str.toString();
+  }
+
+  public static String formatInt (int value, int radix, int len)
+  {
+    String s = Integer.toString (value, radix);
+    StringBuffer buf = new StringBuffer ();
+    for (int j = 0; j < len - s.length(); j++)
+      buf.append ("0");
+    buf.append (s);
+    return buf.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/ByteBufferOutputStream.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,118 @@
+/* ByteBufferOutputStream.java -- output stream with a growable underlying
+                                  byte buffer.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An output stream that writes bytes to a ByteBuffer, which will be resized
+ * if more space is needed.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ByteBufferOutputStream extends OutputStream
+{
+  private ByteBuffer buffer;
+  
+  public ByteBufferOutputStream()
+  {
+    this(256);
+  }
+  
+  public ByteBufferOutputStream(int initialCapacity)
+  {
+    buffer = ByteBuffer.allocate(initialCapacity);
+  }
+
+  /* (non-Javadoc)
+   * @see java.io.OutputStream#write(int)
+   */
+  public @Override synchronized void write(int b) throws IOException
+  {
+    if (!buffer.hasRemaining())
+      growBuffer();
+    buffer.put((byte) b); 
+  }
+  
+  public @Override synchronized void write(byte[] b, int offset, int length)
+  {
+    if (buffer.remaining() < length)
+      growBuffer();
+    buffer.put(b, offset, length);
+  }
+  
+  public @Override void write(byte[] b)
+  {
+    write(b, 0, b.length);
+  }
+
+  /**
+   * Get the current state of the buffer. The returned buffer will have
+   * its position set to zero, its capacity set to the current limit,
+   * and its limit set to its capacity.
+   * 
+   * @return The buffer.
+   */
+  public ByteBuffer buffer()
+  {
+    return ((ByteBuffer) buffer.duplicate().flip()).slice();
+  }
+  
+  public String toString()
+  {
+    return super.toString() + " [ buffer: " + buffer + " ]";
+  }
+  
+  private void growBuffer()
+  {
+    int newCapacity = buffer.capacity();
+    if (newCapacity < 16384) // If the buffer isn't huge yet, double its size
+      newCapacity = newCapacity << 1;
+    else // Otherwize, increment by a bit.
+      newCapacity += 4096;
+    ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity);
+    buffer.flip();
+    newBuffer.put(buffer);
+    buffer = newBuffer;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/DerUtil.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,64 @@
+/* DerUtil.java -- Utility methods for DER read/write operations
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.util;
+
+import gnu.java.security.der.DEREncodingException;
+import gnu.java.security.der.DERValue;
+
+import java.math.BigInteger;
+
+/**
+ * Utility methods for DER encoding handling.
+ */
+public abstract class DerUtil
+{
+  public static final void checkIsConstructed(DERValue v, String msg)
+      throws DEREncodingException
+  {
+    if (! v.isConstructed())
+      throw new DEREncodingException(msg);
+  }
+
+  public static final void checkIsBigInteger(DERValue v, String msg)
+      throws DEREncodingException
+  {
+    if (! (v.getValue() instanceof BigInteger))
+      throw new DEREncodingException(msg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/ExpirableObject.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,150 @@
+/* ExpirableObject.java -- an object that is automatically destroyed.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.util;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.Destroyable;
+
+/**
+ * The base class for objects with sensitive data that are automatically
+ * destroyed after a timeout elapses. On creation, an object that extends this
+ * class will automatically be added to a {@link Timer} object that, once a
+ * timeout elapses, will automatically call the {@link Destroyable#destroy()}
+ * method.
+ * <p>
+ * Concrete subclasses must implement the {@link #doDestroy()} method instead of
+ * {@link Destroyable#destroy()}; the behavior of that method should match
+ * exactly the behavior desired of <code>destroy()</code>.
+ * <p>
+ * Note that if a {@link DestroyFailedException} occurs when the timeout
+ * expires, it will not be reported.
+ * 
+ * @see Destroyable
+ */
+public abstract class ExpirableObject
+    implements Destroyable
+{
+  /**
+   * The default timeout, used in the default constructor.
+   */
+  public static final long DEFAULT_TIMEOUT = 3600000L;
+
+  /**
+   * The timer that expires instances.
+   */
+  private static final Timer EXPIRER = new Timer(true);
+
+  /**
+   * A reference to the task that will destroy this object when the timeout
+   * expires.
+   */
+  private final Destroyer destroyer;
+
+  /**
+   * Create a new expirable object that will expire after one hour.
+   */
+  protected ExpirableObject()
+  {
+    this(DEFAULT_TIMEOUT);
+  }
+
+  /**
+   * Create a new expirable object that will expire after the specified timeout.
+   * 
+   * @param delay The delay before expiration.
+   * @throws IllegalArgumentException If <i>delay</i> is negative, or if
+   *           <code>delay + System.currentTimeMillis()</code> is negative.
+   */
+  protected ExpirableObject(final long delay)
+  {
+    destroyer = new Destroyer(this);
+    EXPIRER.schedule(destroyer, delay);
+  }
+
+  /**
+   * Destroys this object. This method calls {@link #doDestroy}, then, if no
+   * exception is thrown, cancels the task that would destroy this object when
+   * the timeout is reached.
+   * 
+   * @throws DestroyFailedException If this operation fails.
+   */
+  public final void destroy() throws DestroyFailedException
+  {
+    doDestroy();
+    destroyer.cancel();
+  }
+
+  /**
+   * Subclasses must implement this method instead of the {@link
+   * Destroyable#destroy()} method.
+   * 
+   * @throws DestroyFailedException If this operation fails.
+   */
+  protected abstract void doDestroy() throws DestroyFailedException;
+
+  /**
+   * The task that destroys the target when the timeout elapses.
+   */
+  private final class Destroyer
+      extends TimerTask
+  {
+    private final ExpirableObject target;
+
+    Destroyer(final ExpirableObject target)
+    {
+      super();
+      this.target = target;
+    }
+
+    public void run()
+    {
+      try
+        {
+          if (! target.isDestroyed())
+            target.doDestroy();
+        }
+      catch (DestroyFailedException dfe)
+        {
+        }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/FormatUtil.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,140 @@
+/* FormatUtil.java -- Encoding and decoding format utility methods
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.util;
+
+import gnu.java.security.Registry;
+
+/**
+ * Encoding and decoding format utility methods.
+ */
+public class FormatUtil
+{
+  /** Trivial constructor to enforce Singleton pattern. */
+  private FormatUtil()
+  {
+    super();
+  }
+
+  /**
+   * Returns the fully qualified name of the designated encoding ID.
+   * 
+   * @param formatID the unique identifier of the encoding format.
+   * @return the fully qualified name of the designated format. Returns
+   *         <code>null</code> if no such encoding format is known.
+   */
+  public static final String getEncodingName(int formatID)
+  {
+    String result = null;
+    switch (formatID)
+      {
+      case Registry.RAW_ENCODING_ID:
+        result = Registry.RAW_ENCODING;
+        break;
+      case Registry.X509_ENCODING_ID:
+        result = Registry.X509_ENCODING;
+        break;
+      case Registry.PKCS8_ENCODING_ID:
+        result = Registry.PKCS8_ENCODING;
+        break;
+      case Registry.ASN1_ENCODING_ID:
+        result = Registry.ASN1_ENCODING;
+        break;
+      }
+
+    return result;
+  }
+
+  /**
+   * Returns the short name of the designated encoding ID. This is used by the
+   * JCE Adapters.
+   * 
+   * @param formatID the unique identifier of the encoding format.
+   * @return the short name of the designated format. Returns <code>null</code>
+   *         if no such encoding format is known.
+   */
+  public static final String getEncodingShortName(int formatID)
+  {
+    String result = null;
+    switch (formatID)
+      {
+      case Registry.RAW_ENCODING_ID:
+        result = Registry.RAW_ENCODING_SHORT_NAME;
+        break;
+      case Registry.X509_ENCODING_ID:
+        result = Registry.X509_ENCODING_SORT_NAME;
+        break;
+      case Registry.PKCS8_ENCODING_ID:
+        result = Registry.PKCS8_ENCODING_SHORT_NAME;
+        break;
+      case Registry.ASN1_ENCODING_ID:
+        result = Registry.ASN1_ENCODING_SHORT_NAME;
+        break;
+      }
+
+    return result;
+  }
+
+  /**
+   * Returns the identifier of the encoding format given its short name.
+   * 
+   * @param name the case-insensitive canonical short name of an encoding
+   *          format.
+   * @return the identifier of the designated encoding format, or <code>0</code>
+   *         if the name does not correspond to any known format.
+   */
+  public static final int getFormatID(String name)
+  {
+    if (name == null)
+      return 0;
+
+    name = name.trim();
+    if (name.length() == 0)
+      return 0;
+
+    int result = 0;
+    if (name.equalsIgnoreCase(Registry.RAW_ENCODING_SHORT_NAME))
+      result = Registry.RAW_ENCODING_ID;
+    else if (name.equalsIgnoreCase(Registry.X509_ENCODING_SORT_NAME))
+      result = Registry.X509_ENCODING_ID;
+    else if (name.equalsIgnoreCase(Registry.PKCS8_ENCODING_SHORT_NAME))
+      result = Registry.PKCS8_ENCODING_ID;
+    
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/IntegerUtil.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,109 @@
+/* IntegerUtil.java -- JDK 5 Integer methods with 1.4 API
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.util;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Utility class which offers Integer related methods found in RI's version 5
+ * but written with RI's 1.4 API.
+ */
+public abstract class IntegerUtil
+{
+  /** Maximum size of our cache of constructed Integers. */
+  private static final int CACHE_SIZE = 100;
+  /** LRU (Least Recently Used) cache, of the last accessed 100 Integers. */
+  private static final Map cache = new LinkedHashMap(CACHE_SIZE + 1, 0.75F, true)
+  {
+    public boolean removeEldestEntry(Map.Entry entry)
+    {
+      return size() > CACHE_SIZE;
+    }
+  };
+
+  /** Trivial private constructor to enforce Singleton usage. */
+  private IntegerUtil()
+  {
+    super();
+  }
+
+  /**
+   * Similar to {@link Integer#valueOf(String)} except it caches the result in
+   * a local LRU cache of 100 elements, organized by access order.
+   * <p>
+   * This method MUST be used in the gnu.java.security and gnu.javax.crypto
+   * packages to ensure they would work with a version 1.4 only of the Java
+   * class library API.
+   * 
+   * @param aString a string representation of an integer.
+   * @return the {@link Integer} object representing the designated string.
+   */
+  public static final Integer valueOf(String aString)
+  {
+    Integer result;
+    synchronized (cache)
+    {
+      result = (Integer) cache.get(aString);
+      if (result == null)
+        {
+          result = Integer.valueOf(aString);
+          cache.put(aString, result);
+        }
+    }
+    return result;
+  }
+
+  /**
+   * Simulates the <code>valueOf(int)</code> method found in {@link Integer} of
+   * the RI's version 1.5 using a local LRU cache of 100 elements, organized by
+   * access order.
+   * <p>
+   * This method MUST be used in the gnu.java.security and gnu.javax.crypto
+   * packages to ensure they would work with a version 1.4 only of the Java
+   * class library API.
+   * 
+   * @param anInt a decimal integer.
+   * @return the {@link Integer} object representing the designated primitive.
+   */
+  public static final Integer valueOf(int anInt)
+  {
+    return valueOf(Integer.toString(anInt, 10));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/PRNG.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,141 @@
+/* PRNG.java -- A Utility methods for default source of randomness
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.util;
+
+import java.util.HashMap;
+
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.prng.MDGenerator;
+
+/**
+ * A useful hash-based (SHA) pseudo-random number generator used throughout this
+ * library.
+ * 
+ * @see MDGenerator
+ */
+public class PRNG
+{
+  /** The underlying {@link IRandom}. */
+  private IRandom delegate;
+
+  /**
+   * Private constructor to enforce using the Factory method.
+   * 
+   * @param delegate the undelying {@link IRandom} object used.
+   */
+  private PRNG(IRandom delegate)
+  {
+    super();
+
+    this.delegate = delegate;
+  }
+
+  public static final PRNG getInstance()
+  {
+    IRandom delegate = new MDGenerator();
+    try
+      {
+        HashMap map = new HashMap();
+        // initialise it with a seed
+        long t = System.currentTimeMillis();
+        byte[] seed = new byte[] {
+            (byte)(t >>> 56), (byte)(t >>> 48),
+            (byte)(t >>> 40), (byte)(t >>> 32),
+            (byte)(t >>> 24), (byte)(t >>> 16),
+            (byte)(t >>>  8), (byte) t };
+        map.put(MDGenerator.SEEED, seed);
+        delegate.init(map); // default is to use SHA-1 hash
+      }
+    catch (Exception x)
+      {
+        throw new ExceptionInInitializerError(x);
+      }
+    return new PRNG(delegate);
+  }
+
+  /**
+   * Completely fills the designated <code>buffer</code> with random data
+   * generated by the underlying delegate.
+   * 
+   * @param buffer the place holder of random bytes generated by the underlying
+   *          delegate. On output, the contents of <code>buffer</code> are
+   *          replaced with pseudo-random data, iff the <code>buffer</code>
+   *          size is not zero.
+   */
+  public void nextBytes(byte[] buffer)
+  {
+    nextBytes(buffer, 0, buffer.length);
+  }
+
+  /**
+   * Fills the designated <code>buffer</code>, starting from byte at position
+   * <code>offset</code> with, at most, <code>length</code> bytes of random
+   * data generated by the underlying delegate.
+   * 
+   * @see IRandom#nextBytes
+   */
+  public void nextBytes(byte[] buffer, int offset, int length)
+  {
+    try
+      {
+        delegate.nextBytes(buffer, offset, length);
+      }
+    catch (LimitReachedException x) // re-initialise with a seed
+      {
+        try
+          {
+            HashMap map = new HashMap();
+            long t = System.currentTimeMillis();
+            byte[] seed = new byte[] {
+                (byte)(t >>> 56), (byte)(t >>> 48),
+                (byte)(t >>> 40), (byte)(t >>> 32),
+                (byte)(t >>> 24), (byte)(t >>> 16),
+                (byte)(t >>>  8), (byte) t };
+            map.put(MDGenerator.SEEED, seed);
+            delegate.init(map); // default is to use SHA-1 hash
+            delegate.nextBytes(buffer, offset, length);
+          }
+        catch (Exception y)
+          {
+            throw new ExceptionInInitializerError(y);
+          }
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/Prime.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,164 @@
+/* Prime.java --- Prime number generation utilities
+   Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.util;
+import java.math.BigInteger;
+import java.util.Random;
+//import java.security.SecureRandom;
+
+public final class Prime
+{
+
+  /*
+    See IEEE P1363 A.15.4 (10/05/98 Draft)
+  */
+  public static BigInteger generateRandomPrime( int pmin, int pmax, BigInteger f )
+  {
+    BigInteger d;
+
+    //Step 1 - generate prime
+    BigInteger p = new BigInteger( (pmax + pmin)/2, new Random() );
+    if( p.compareTo( BigInteger.valueOf( 1 ).shiftLeft( pmin ) ) <= 0 )
+      {
+	p = p.add( BigInteger.valueOf( 1 ).shiftLeft( pmin ).subtract( p ) );
+      }
+	
+    //Step 2 - test for even
+    if( p.mod( BigInteger.valueOf(2) ).compareTo( BigInteger.valueOf( 0 )) == 0)
+      p = p.add( BigInteger.valueOf( 1 ) );
+
+    for(;;)
+      {
+	//Step 3
+	if( p.compareTo( BigInteger.valueOf( 1 ).shiftLeft( pmax)) > 0)
+	  {
+	    //Step 3.1
+	    p = p.subtract( BigInteger.valueOf( 1 ).shiftLeft( pmax) );
+	    p = p.add( BigInteger.valueOf( 1 ).shiftLeft( pmin) );
+	    p = p.subtract( BigInteger.valueOf( 1 ) );
+
+	    //Step 3.2
+	    // put step 2 code here so looping code is cleaner
+	    //Step 2 - test for even
+	    if( p.mod( BigInteger.valueOf(2) ).compareTo( BigInteger.valueOf( 0 )) == 0)
+	      p = p.add( BigInteger.valueOf( 1 ) );
+	    continue;
+	  }
+	
+	//Step 4 - compute GCD
+	d = p.subtract( BigInteger.valueOf(1) );
+	d = d.gcd( f );
+
+	//Step 5 - test d
+	if( d.compareTo( BigInteger.valueOf( 1 ) ) == 0)
+	  {
+	    //Step 5.1 - test primality
+	    if( p.isProbablePrime( 1 ) == true )
+	      {
+				//Step 5.2;
+		return p;
+	      }
+	  }
+	//Step 6
+	p = p.add( BigInteger.valueOf( 2 ) );
+
+	//Step 7
+      }
+  }
+
+
+  /*
+    See IEEE P1363 A.15.5 (10/05/98 Draft)
+  */
+  public static BigInteger generateRandomPrime( BigInteger r, BigInteger a, int pmin, int pmax, BigInteger f )
+  {
+    BigInteger d, w;
+
+    //Step 1 - generate prime
+    BigInteger p = new BigInteger( (pmax + pmin)/2, new Random() );
+
+  steptwo:{ //Step 2
+      w = p.mod( r.multiply( BigInteger.valueOf(2) ));
+
+      //Step 3
+      p = p.add( r.multiply( BigInteger.valueOf(2) ) );
+      p = p.subtract( w );
+      p = p.add(a);
+
+      //Step 4 - test for even
+      if( p.mod( BigInteger.valueOf(2) ).compareTo( BigInteger.valueOf( 0 )) == 0)
+	p = p.add( r );
+
+      for(;;)
+	{
+	  //Step 5
+	  if( p.compareTo( BigInteger.valueOf( 1 ).shiftLeft( pmax)) > 0)
+	    {
+	      //Step 5.1
+	      p = p.subtract( BigInteger.valueOf( 1 ).shiftLeft( pmax) );
+	      p = p.add( BigInteger.valueOf( 1 ).shiftLeft( pmin) );
+	      p = p.subtract( BigInteger.valueOf( 1 ) );
+
+	      //Step 5.2 - goto to Step 2
+	      break steptwo;
+	    }
+
+	  //Step 6
+	  d = p.subtract( BigInteger.valueOf(1) );
+	  d = d.gcd( f );
+
+	  //Step 7 - test d
+	  if( d.compareTo( BigInteger.valueOf( 1 ) ) == 0)
+	    {
+	      //Step 7.1 - test primality
+	      if( p.isProbablePrime( 1 ) == true )
+		{
+				//Step 7.2;
+		  return p;
+		}
+	    }
+	  //Step 8
+	  p = p.add( r.multiply( BigInteger.valueOf(2) ) );
+
+	  //Step 9
+	}
+    }
+    //Should never reach here but makes the compiler happy
+    return BigInteger.valueOf(0);	
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/Sequence.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,133 @@
+/* Sequence.java -- a sequence of integers.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.util;
+
+import java.util.AbstractList;
+import java.util.LinkedList;
+
+/**
+ * A monotonic sequence of integers in the finite field 2<sup>32</sup>.
+ */
+public final class Sequence
+    extends AbstractList
+{
+  private final Integer[] sequence;
+
+  /**
+   * Create a sequence of integers from 0 to <i>end</i>, with an increment of
+   * 1. If <i>end</i> is less than 0, then the sequence will wrap around
+   * through all positive integers then negative integers until the end value is
+   * reached. Naturally, this will result in an enormous object, so don't do
+   * this.
+   * 
+   * @param end The ending value.
+   */
+  public Sequence(int end)
+  {
+    this(0, end, 1);
+  }
+
+  /**
+   * Create a sequence of integers from <i>start</i> to <i>end</i>, with an
+   * increment of 1. If <i>end</i> is less than <i>start</i>, then the
+   * sequence will wrap around until the end value is reached. Naturally, this
+   * will result in an enormous object, so don't do this.
+   * 
+   * @param start The starting value.
+   * @param end The ending value.
+   */
+  public Sequence(int start, int end)
+  {
+    this(start, end, 1);
+  }
+
+  /**
+   * Create a sequence of integers from <i>start</i> to <i>end</i>, with an
+   * increment of <i>span</i>. If <i>end</i> is less than <i>start</i>, then
+   * the sequence will wrap around until the end value is reached. Naturally,
+   * this will result in an enormous object, so don't do this.
+   * <p>
+   * <i>span</i> can be negative, resulting in a decresing sequence.
+   * <p>
+   * If <i>span</i> is 0, then the sequence will contain {<i>start</i>,
+   * <i>end</i>} if <i>start</i> != <i>end</i>, or just the singleton
+   * <i>start</i> if <i>start</i> == <i>end</i>.
+   * 
+   * @param start The starting value.
+   * @param end The ending value.
+   * @param span The increment value.
+   */
+  public Sequence(int start, int end, int span)
+  {
+    if (span == 0)
+      {
+        if (start != end)
+          sequence = new Integer[] { Integer.valueOf(start),
+                                     Integer.valueOf(end) };
+        else
+          sequence = new Integer[] { Integer.valueOf(start) };
+      }
+    else
+      {
+        LinkedList l = new LinkedList();
+        for (int i = start; i != end; i += span)
+          l.add(Integer.valueOf(i));
+
+        l.add(Integer.valueOf(end));
+        sequence = (Integer[]) l.toArray(new Integer[l.size()]);
+      }
+  }
+
+  public Object get(int index)
+  {
+    if (index < 0 || index >= size())
+      throw new IndexOutOfBoundsException("index=" + index + ", size=" + size());
+    return sequence[index];
+  }
+
+  public int size()
+  {
+    return sequence.length;
+  }
+
+  public Object[] toArray()
+  {
+    return (Object[]) sequence.clone();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/SimpleList.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,155 @@
+/* SimpleList.java -- simple way to make tuples.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.util;
+
+import java.util.AbstractList;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * A simple way to create immutable n-tuples. This class can be created with up
+ * to four elements specified via one of the constructors, or with a collection
+ * of arbitrary size.
+ */
+public final class SimpleList
+    extends AbstractList
+{
+  private final Object[] elements;
+
+  /**
+   * Create a singleton list.
+   * 
+   * @param element The first element.
+   */
+  public SimpleList(final Object element)
+  {
+    elements = new Object[1];
+    elements[0] = element;
+  }
+
+  /**
+   * Create an ordered pair (2-tuple).
+   * 
+   * @param e1 The first element.
+   * @param e2 The second element.
+   */
+  public SimpleList(final Object e1, final Object e2)
+  {
+    elements = new Object[2];
+    elements[0] = e1;
+    elements[1] = e2;
+  }
+
+  /**
+   * Create a 3-tuple.
+   * 
+   * @param e1 The first element.
+   * @param e2 The second element.
+   * @param e3 The third element.
+   */
+  public SimpleList(final Object e1, final Object e2, final Object e3)
+  {
+    elements = new Object[3];
+    elements[0] = e1;
+    elements[1] = e2;
+    elements[2] = e3;
+  }
+
+  /**
+   * Create a 4-tuple.
+   * 
+   * @param e1 The first element.
+   * @param e2 The second element.
+   * @param e3 The third element.
+   * @param e4 The fourth element.
+   */
+  public SimpleList(final Object e1, final Object e2, final Object e3,
+                    final Object e4)
+  {
+    elements = new Object[4];
+    elements[0] = e1;
+    elements[1] = e2;
+    elements[2] = e3;
+    elements[3] = e4;
+  }
+
+  /**
+   * Create the empty list.
+   */
+  public SimpleList()
+  {
+    elements = null;
+  }
+
+  /**
+   * Create an n-tuple of arbitrary size. Even if the supplied collection has no
+   * natural order, the created n-tuple will have the order that the elements
+   * are returned by the collection's iterator.
+   * 
+   * @param c The collection.
+   */
+  public SimpleList(Collection c)
+  {
+    elements = new Object[c.size()];
+    int i = 0;
+    for (Iterator it = c.iterator(); it.hasNext() && i < elements.length;)
+      elements[i++] = it.next();
+  }
+
+  public int size()
+  {
+    if (elements == null)
+      return 0;
+    return elements.length;
+  }
+
+  public Object get(int index)
+  {
+    if (elements == null)
+      throw new IndexOutOfBoundsException("list is empty");
+    if (index < 0 || index >= elements.length)
+      throw new IndexOutOfBoundsException("index=" + index + ", size=" + size());
+    return elements[index];
+  }
+
+  public String toString()
+  {
+    return SimpleList.class.getName() + "(" + size() + ") " + super.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/Util.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,627 @@
+/* Util.java -- various utility routines.
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.java.security.util;
+
+import java.math.BigInteger;
+
+/**
+ * A collection of utility methods used throughout this project.
+ */
+public class Util
+{
+  // Hex charset
+  private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
+
+  // Base-64 charset
+  private static final String BASE64_CHARS =
+      "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
+
+  private static final char[] BASE64_CHARSET = BASE64_CHARS.toCharArray();
+
+  /** Trivial constructor to enforce Singleton pattern. */
+  private Util()
+  {
+    super();
+  }
+
+  /**
+   * Returns a string of hexadecimal digits from a byte array. Each byte is
+   * converted to 2 hex symbols; zero(es) included.
+   * <p>
+   * This method calls the method with same name and three arguments as:
+   * <pre>
+   * toString(ba, 0, ba.length);
+   * </pre>
+   * 
+   * @param ba the byte array to convert.
+   * @return a string of hexadecimal characters (two for each byte) representing
+   *         the designated input byte array.
+   */
+  public static String toString(byte[] ba)
+  {
+    return toString(ba, 0, ba.length);
+  }
+
+  /**
+   * Returns a string of hexadecimal digits from a byte array, starting at
+   * <code>offset</code> and consisting of <code>length</code> bytes. Each
+   * byte is converted to 2 hex symbols; zero(es) included.
+   * 
+   * @param ba the byte array to convert.
+   * @param offset the index from which to start considering the bytes to
+   *          convert.
+   * @param length the count of bytes, starting from the designated offset to
+   *          convert.
+   * @return a string of hexadecimal characters (two for each byte) representing
+   *         the designated input byte sub-array.
+   */
+  public static final String toString(byte[] ba, int offset, int length)
+  {
+    char[] buf = new char[length * 2];
+    for (int i = 0, j = 0, k; i < length;)
+      {
+        k = ba[offset + i++];
+        buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F];
+        buf[j++] = HEX_DIGITS[ k        & 0x0F];
+      }
+    return new String(buf);
+  }
+
+  /**
+   * Returns a string of hexadecimal digits from a byte array. Each byte is
+   * converted to 2 hex symbols; zero(es) included. The argument is treated as a
+   * large little-endian integer and is returned as a large big-endian integer.
+   * <p>
+   * This method calls the method with same name and three arguments as:
+   * <pre>
+   * toReversedString(ba, 0, ba.length);
+   * </pre>
+   * 
+   * @param ba the byte array to convert.
+   * @return a string of hexadecimal characters (two for each byte) representing
+   *         the designated input byte array.
+   */
+  public static String toReversedString(byte[] ba)
+  {
+    return toReversedString(ba, 0, ba.length);
+  }
+
+  /**
+   * Returns a string of hexadecimal digits from a byte array, starting at
+   * <code>offset</code> and consisting of <code>length</code> bytes. Each
+   * byte is converted to 2 hex symbols; zero(es) included.
+   * <p>
+   * The byte array is treated as a large little-endian integer, and is returned
+   * as a large big-endian integer.
+   * 
+   * @param ba the byte array to convert.
+   * @param offset the index from which to start considering the bytes to
+   *          convert.
+   * @param length the count of bytes, starting from the designated offset to
+   *          convert.
+   * @return a string of hexadecimal characters (two for each byte) representing
+   *         the designated input byte sub-array.
+   */
+  public static final String toReversedString(byte[] ba, int offset, int length)
+  {
+    char[] buf = new char[length * 2];
+    for (int i = offset + length - 1, j = 0, k; i >= offset;)
+      {
+        k = ba[offset + i--];
+        buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F];
+        buf[j++] = HEX_DIGITS[ k        & 0x0F];
+      }
+    return new String(buf);
+  }
+
+  /**
+   * <p>
+   * Returns a byte array from a string of hexadecimal digits.
+   * </p>
+   * 
+   * @param s a string of hexadecimal ASCII characters
+   * @return the decoded byte array from the input hexadecimal string.
+   */
+  public static byte[] toBytesFromString(String s)
+  {
+    int limit = s.length();
+    byte[] result = new byte[((limit + 1) / 2)];
+    int i = 0, j = 0;
+    if ((limit % 2) == 1)
+      result[j++] = (byte) fromDigit(s.charAt(i++));
+    while (i < limit)
+      {
+        result[j  ] = (byte) (fromDigit(s.charAt(i++)) << 4);
+        result[j++] |= (byte) fromDigit(s.charAt(i++));
+      }
+    return result;
+  }
+
+  /**
+   * Returns a byte array from a string of hexadecimal digits, interpreting them
+   * as a large big-endian integer and returning it as a large little-endian
+   * integer.
+   * 
+   * @param s a string of hexadecimal ASCII characters
+   * @return the decoded byte array from the input hexadecimal string.
+   */
+  public static byte[] toReversedBytesFromString(String s)
+  {
+    int limit = s.length();
+    byte[] result = new byte[((limit + 1) / 2)];
+    int i = 0;
+    if ((limit % 2) == 1)
+      result[i++] = (byte) fromDigit(s.charAt(--limit));
+    while (limit > 0)
+      {
+        result[i  ] = (byte) fromDigit(s.charAt(--limit));
+        result[i++] |= (byte) (fromDigit(s.charAt(--limit)) << 4);
+      }
+    return result;
+  }
+
+  /**
+   * Returns a number from <code>0</code> to <code>15</code> corresponding
+   * to the designated hexadecimal digit.
+   * 
+   * @param c a hexadecimal ASCII symbol.
+   */
+  public static int fromDigit(char c)
+  {
+    if (c >= '0' && c <= '9')
+      return c - '0';
+    else if (c >= 'A' && c <= 'F')
+      return c - 'A' + 10;
+    else if (c >= 'a' && c <= 'f')
+      return c - 'a' + 10;
+    else
+      throw new IllegalArgumentException("Invalid hexadecimal digit: " + c);
+  }
+
+  /**
+   * Returns a string of 8 hexadecimal digits (most significant digit first)
+   * corresponding to the unsigned integer <code>n</code>.
+   * 
+   * @param n the unsigned integer to convert.
+   * @return a hexadecimal string 8-character long.
+   */
+  public static String toString(int n)
+  {
+    char[] buf = new char[8];
+    for (int i = 7; i >= 0; i--)
+      {
+        buf[i] = HEX_DIGITS[n & 0x0F];
+        n >>>= 4;
+      }
+    return new String(buf);
+  }
+
+  /**
+   * Returns a string of hexadecimal digits from an integer array. Each int is
+   * converted to 4 hex symbols.
+   */
+  public static String toString(int[] ia)
+  {
+    int length = ia.length;
+    char[] buf = new char[length * 8];
+    for (int i = 0, j = 0, k; i < length; i++)
+      {
+        k = ia[i];
+        buf[j++] = HEX_DIGITS[(k >>> 28) & 0x0F];
+        buf[j++] = HEX_DIGITS[(k >>> 24) & 0x0F];
+        buf[j++] = HEX_DIGITS[(k >>> 20) & 0x0F];
+        buf[j++] = HEX_DIGITS[(k >>> 16) & 0x0F];
+        buf[j++] = HEX_DIGITS[(k >>> 12) & 0x0F];
+        buf[j++] = HEX_DIGITS[(k >>>  8) & 0x0F];
+        buf[j++] = HEX_DIGITS[(k >>>  4) & 0x0F];
+        buf[j++] = HEX_DIGITS[ k         & 0x0F];
+      }
+    return new String(buf);
+  }
+
+  /**
+   * Returns a string of 16 hexadecimal digits (most significant digit first)
+   * corresponding to the unsigned long <code>n</code>.
+   * 
+   * @param n the unsigned long to convert.
+   * @return a hexadecimal string 16-character long.
+   */
+  public static String toString(long n)
+  {
+    char[] b = new char[16];
+    for (int i = 15; i >= 0; i--)
+      {
+        b[i] = HEX_DIGITS[(int)(n & 0x0FL)];
+        n >>>= 4;
+      }
+    return new String(b);
+  }
+
+  /**
+   * Similar to the <code>toString()</code> method except that the Unicode
+   * escape character is inserted before every pair of bytes. Useful to
+   * externalise byte arrays that will be constructed later from such strings;
+   * eg. s-box values.
+   * 
+   * @throws ArrayIndexOutOfBoundsException if the length is odd.
+   */
+  public static String toUnicodeString(byte[] ba)
+  {
+    return toUnicodeString(ba, 0, ba.length);
+  }
+
+  /**
+   * Similar to the <code>toString()</code> method except that the Unicode
+   * escape character is inserted before every pair of bytes. Useful to
+   * externalise byte arrays that will be constructed later from such strings;
+   * eg. s-box values.
+   * 
+   * @throws ArrayIndexOutOfBoundsException if the length is odd.
+   */
+  public static final String toUnicodeString(byte[] ba, int offset, int length)
+  {
+    StringBuffer sb = new StringBuffer();
+    int i = 0;
+    int j = 0;
+    int k;
+    sb.append('\n').append("\"");
+    while (i < length)
+      {
+        sb.append("\\u");
+        k = ba[offset + i++];
+        sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]);
+        sb.append(HEX_DIGITS[ k        & 0x0F]);
+        k = ba[offset + i++];
+        sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]);
+        sb.append(HEX_DIGITS[ k        & 0x0F]);
+        if ((++j % 8) == 0)
+          sb.append("\"+").append('\n').append("\"");
+      }
+    sb.append("\"").append('\n');
+    return sb.toString();
+  }
+
+  /**
+   * Similar to the <code>toString()</code> method except that the Unicode
+   * escape character is inserted before every pair of bytes. Useful to
+   * externalise integer arrays that will be constructed later from such
+   * strings; eg. s-box values.
+   * 
+   * @throws ArrayIndexOutOfBoundsException if the length is not a multiple of
+   *           4.
+   */
+  public static String toUnicodeString(int[] ia)
+  {
+    StringBuffer sb = new StringBuffer();
+    int i = 0;
+    int j = 0;
+    int k;
+    sb.append('\n').append("\"");
+    while (i < ia.length)
+      {
+        k = ia[i++];
+        sb.append("\\u");
+        sb.append(HEX_DIGITS[(k >>> 28) & 0x0F]);
+        sb.append(HEX_DIGITS[(k >>> 24) & 0x0F]);
+        sb.append(HEX_DIGITS[(k >>> 20) & 0x0F]);
+        sb.append(HEX_DIGITS[(k >>> 16) & 0x0F]);
+        sb.append("\\u");
+        sb.append(HEX_DIGITS[(k >>> 12) & 0x0F]);
+        sb.append(HEX_DIGITS[(k >>>  8) & 0x0F]);
+        sb.append(HEX_DIGITS[(k >>>  4) & 0x0F]);
+        sb.append(HEX_DIGITS[ k         & 0x0F]);
+        if ((++j % 4) == 0)
+          sb.append("\"+").append('\n').append("\"");
+      }
+    sb.append("\"").append('\n');
+    return sb.toString();
+  }
+
+  public static byte[] toBytesFromUnicode(String s)
+  {
+    int limit = s.length() * 2;
+    byte[] result = new byte[limit];
+    char c;
+    for (int i = 0; i < limit; i++)
+      {
+        c = s.charAt(i >>> 1);
+        result[i] = (byte)(((i & 1) == 0) ? c >>> 8 : c);
+      }
+    return result;
+  }
+
+  /**
+   * Dumps a byte array as a string, in a format that is easy to read for
+   * debugging. The string <code>m</code> is prepended to the start of each
+   * line.
+   * <p>
+   * If <code>offset</code> and <code>length</code> are omitted, the whole
+   * array is used. If <code>m</code> is omitted, nothing is prepended to each
+   * line.
+   * 
+   * @param data the byte array to be dumped.
+   * @param offset the offset within <i>data</i> to start from.
+   * @param length the number of bytes to dump.
+   * @param m a string to be prepended to each line.
+   * @return a string containing the result.
+   */
+  public static String dumpString(byte[] data, int offset, int length, String m)
+  {
+    if (data == null)
+      return m + "null\n";
+    StringBuffer sb = new StringBuffer(length * 3);
+    if (length > 32)
+      sb.append(m).append("Hexadecimal dump of ")
+          .append(length).append(" bytes...\n");
+    // each line will list 32 bytes in 4 groups of 8 each
+    int end = offset + length;
+    String s;
+    int l = Integer.toString(length).length();
+    if (l < 4)
+      l = 4;
+    for (; offset < end; offset += 32)
+      {
+        if (length > 32)
+          {
+            s = "         " + offset;
+            sb.append(m).append(s.substring(s.length() - l)).append(": ");
+          }
+        int i = 0;
+        for (; i < 32 && offset + i + 7 < end; i += 8)
+          sb.append(toString(data, offset + i, 8)).append(' ');
+        if (i < 32)
+          for (; i < 32 && offset + i < end; i++)
+            sb.append(byteToString(data[offset + i]));
+        sb.append('\n');
+      }
+    return sb.toString();
+  }
+
+  public static String dumpString(byte[] data)
+  {
+    return (data == null) ? "null\n" : dumpString(data, 0, data.length, "");
+  }
+
+  public static String dumpString(byte[] data, String m)
+  {
+    return (data == null) ? "null\n" : dumpString(data, 0, data.length, m);
+  }
+
+  public static String dumpString(byte[] data, int offset, int length)
+  {
+    return dumpString(data, offset, length, "");
+  }
+
+  /**
+   * Returns a string of 2 hexadecimal digits (most significant digit first)
+   * corresponding to the lowest 8 bits of <code>n</code>.
+   * 
+   * @param n the byte value to convert.
+   * @return a string of 2 hex characters representing the input.
+   */
+  public static String byteToString(int n)
+  {
+    char[] buf = { HEX_DIGITS[(n >>> 4) & 0x0F], HEX_DIGITS[n & 0x0F] };
+    return new String(buf);
+  }
+
+  /**
+   * Converts a designated byte array to a Base-64 representation, with the
+   * exceptions that (a) leading 0-byte(s) are ignored, and (b) the character
+   * '.' (dot) shall be used instead of "+' (plus).
+   * <p>
+   * Used by SASL password file manipulation primitives.
+   * 
+   * @param buffer an arbitrary sequence of bytes to represent in Base-64.
+   * @return unpadded (without the '=' character(s)) Base-64 representation of
+   *         the input.
+   */
+  public static final String toBase64(byte[] buffer)
+  {
+    int len = buffer.length, pos = len % 3;
+    byte b0 = 0, b1 = 0, b2 = 0;
+    switch (pos)
+      {
+      case 1:
+        b2 = buffer[0];
+        break;
+      case 2:
+        b1 = buffer[0];
+        b2 = buffer[1];
+        break;
+      }
+    StringBuffer sb = new StringBuffer();
+    int c;
+    boolean notleading = false;
+    do
+      {
+        c = (b0 & 0xFC) >>> 2;
+        if (notleading || c != 0)
+          {
+            sb.append(BASE64_CHARSET[c]);
+            notleading = true;
+          }
+        c = ((b0 & 0x03) << 4) | ((b1 & 0xF0) >>> 4);
+        if (notleading || c != 0)
+          {
+            sb.append(BASE64_CHARSET[c]);
+            notleading = true;
+          }
+        c = ((b1 & 0x0F) << 2) | ((b2 & 0xC0) >>> 6);
+        if (notleading || c != 0)
+          {
+            sb.append(BASE64_CHARSET[c]);
+            notleading = true;
+          }
+        c = b2 & 0x3F;
+        if (notleading || c != 0)
+          {
+            sb.append(BASE64_CHARSET[c]);
+            notleading = true;
+          }
+        if (pos >= len)
+          break;
+        else
+          {
+            try
+              {
+                b0 = buffer[pos++];
+                b1 = buffer[pos++];
+                b2 = buffer[pos++];
+              }
+            catch (ArrayIndexOutOfBoundsException x)
+              {
+                break;
+              }
+          }
+      }
+    while (true);
+
+    if (notleading)
+      return sb.toString();
+    return "0";
+  }
+
+  /**
+   * The inverse function of the above.
+   * <p>
+   * Converts a string representing the encoding of some bytes in Base-64 to
+   * their original form.
+   * 
+   * @param str the Base-64 encoded representation of some byte(s).
+   * @return the bytes represented by the <code>str</code>.
+   * @throws NumberFormatException if <code>str</code> is <code>null</code>,
+   *           or <code>str</code> contains an illegal Base-64 character.
+   * @see #toBase64(byte[])
+   */
+  public static final byte[] fromBase64(String str)
+  {
+    int len = str.length();
+    if (len == 0)
+      throw new NumberFormatException("Empty string");
+    byte[] a = new byte[len + 1];
+    int i, j;
+    for (i = 0; i < len; i++)
+      try
+        {
+          a[i] = (byte) BASE64_CHARS.indexOf(str.charAt(i));
+        }
+      catch (ArrayIndexOutOfBoundsException x)
+        {
+          throw new NumberFormatException("Illegal character at #" + i);
+        }
+    i = len - 1;
+    j = len;
+    try
+      {
+        while (true)
+          {
+            a[j] = a[i];
+            if (--i < 0)
+              break;
+            a[j] |= (a[i] & 0x03) << 6;
+            j--;
+            a[j] = (byte)((a[i] & 0x3C) >>> 2);
+            if (--i < 0)
+              break;
+            a[j] |= (a[i] & 0x0F) << 4;
+            j--;
+            a[j] = (byte)((a[i] & 0x30) >>> 4);
+            if (--i < 0)
+              break;
+            a[j] |= (a[i] << 2);
+            j--;
+            a[j] = 0;
+            if (--i < 0)
+              break;
+          }
+      }
+    catch (Exception ignored)
+      {
+      }
+    try
+      { // ignore leading 0-bytes
+        while (a[j] == 0)
+          j++;
+      }
+    catch (Exception x)
+      {
+        return new byte[1]; // one 0-byte
+      }
+    byte[] result = new byte[len - j + 1];
+    System.arraycopy(a, j, result, 0, len - j + 1);
+    return result;
+  }
+
+  // BigInteger utilities ----------------------------------------------------
+
+  /**
+   * Treats the input as the MSB representation of a number, and discards
+   * leading zero elements. For efficiency, the input is simply returned if no
+   * leading zeroes are found.
+   * 
+   * @param n the {@link BigInteger} to trim.
+   * @return the byte array representation of the designated {@link BigInteger}
+   *         with no leading 0-bytes.
+   */
+  public static final byte[] trim(BigInteger n)
+  {
+    byte[] in = n.toByteArray();
+    if (in.length == 0 || in[0] != 0)
+      return in;
+    int len = in.length;
+    int i = 1;
+    while (in[i] == 0 && i < len)
+      ++i;
+    byte[] result = new byte[len - i];
+    System.arraycopy(in, i, result, 0, len - i);
+    return result;
+  }
+
+  /**
+   * Returns a hexadecimal dump of the trimmed bytes of a {@link BigInteger}.
+   * 
+   * @param x the {@link BigInteger} to display.
+   * @return the string representation of the designated {@link BigInteger}.
+   */
+  public static final String dump(BigInteger x)
+  {
+    return dumpString(trim(x));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/util/package.html	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.util package.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.security.util</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/GnuPKIExtension.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,59 @@
+/* GnuPKIExtension.java -- interface for GNU PKI extensions.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509;
+
+import gnu.java.security.OID;
+import gnu.java.security.x509.ext.Extension;
+
+import java.security.cert.X509Extension;
+import java.util.Collection;
+
+public interface GnuPKIExtension extends X509Extension
+{
+
+  /**
+   * Returns the extension object for the given object identifier.
+   *
+   * @param oid The OID of the extension to get.
+   * @return The extension, or null if there is no such extension.
+   */
+  Extension getExtension(OID oid);
+
+  Collection getExtensions();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/PolicyNodeImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,214 @@
+/* PolicyNodeImpl.java -- An implementation of a policy tree node.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509;
+
+import java.security.cert.PolicyNode;
+import java.security.cert.PolicyQualifierInfo;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public final class PolicyNodeImpl implements PolicyNode
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private String policy;
+  private final Set expectedPolicies;
+  private final Set qualifiers;
+  private final Set children;
+  private PolicyNodeImpl parent;
+  private int depth;
+  private boolean critical;
+  private boolean readOnly;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public PolicyNodeImpl()
+  {
+    expectedPolicies = new HashSet();
+    qualifiers = new HashSet();
+    children = new HashSet();
+    readOnly = false;
+    critical = false;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public void addChild(PolicyNodeImpl node)
+  {
+    if (readOnly)
+      throw new IllegalStateException("read only");
+    if (node.getParent() != null)
+      throw new IllegalStateException("already a child node");
+    node.parent = this;
+    node.setDepth(depth + 1);
+    children.add(node);
+  }
+
+  public Iterator getChildren()
+  {
+    return Collections.unmodifiableSet(children).iterator();
+  }
+
+  public int getDepth()
+  {
+    return depth;
+  }
+
+  public void setDepth(int depth)
+  {
+    if (readOnly)
+      throw new IllegalStateException("read only");
+    this.depth = depth;
+  }
+
+  public void addAllExpectedPolicies(Set policies)
+  {
+    if (readOnly)
+      throw new IllegalStateException("read only");
+    expectedPolicies.addAll(policies);
+  }
+
+  public void addExpectedPolicy(String policy)
+  {
+    if (readOnly)
+      throw new IllegalStateException("read only");
+    expectedPolicies.add(policy);
+  }
+
+  public Set getExpectedPolicies()
+  {
+    return Collections.unmodifiableSet(expectedPolicies);
+  }
+
+  public PolicyNode getParent()
+  {
+    return parent;
+  }
+
+  public void addAllPolicyQualifiers (Collection qualifiers)
+  {
+    for (Iterator it = qualifiers.iterator(); it.hasNext(); )
+      {
+        if (!(it.next() instanceof PolicyQualifierInfo))
+          throw new IllegalArgumentException ("can only add PolicyQualifierInfos");
+      }
+    qualifiers.addAll (qualifiers);
+  }
+
+  public void addPolicyQualifier (PolicyQualifierInfo qualifier)
+  {
+    if (readOnly)
+      throw new IllegalStateException("read only");
+    qualifiers.add(qualifier);
+  }
+
+  public Set getPolicyQualifiers()
+  {
+    return Collections.unmodifiableSet(qualifiers);
+  }
+
+  public String getValidPolicy()
+  {
+    return policy;
+  }
+
+  public void setValidPolicy(String policy)
+  {
+    if (readOnly)
+      throw new IllegalStateException("read only");
+    this.policy = policy;
+  }
+
+  public boolean isCritical()
+  {
+    return critical;
+  }
+
+  public void setCritical(boolean critical)
+  {
+    if (readOnly)
+      throw new IllegalStateException("read only");
+    this.critical = critical;
+  }
+
+  public void setReadOnly()
+  {
+    if (readOnly)
+      return;
+    readOnly = true;
+    for (Iterator it = getChildren(); it.hasNext(); )
+      ((PolicyNodeImpl) it.next()).setReadOnly();
+  }
+
+  public String toString()
+  {
+    StringBuffer buf = new StringBuffer();
+    for (int i = 0; i < depth; i++)
+      buf.append("  ");
+    buf.append("(");
+    buf.append(PolicyNodeImpl.class.getName());
+    buf.append(" (oid ");
+    buf.append(policy);
+    buf.append(") (depth ");
+    buf.append(depth);
+    buf.append(") (qualifiers ");
+    buf.append(qualifiers);
+    buf.append(") (critical ");
+    buf.append(critical);
+    buf.append(") (expectedPolicies ");
+    buf.append(expectedPolicies);
+    buf.append(") (children (");
+    final String nl = System.getProperty("line.separator");
+    for (Iterator it = getChildren(); it.hasNext(); )
+      {
+        buf.append(nl);
+        buf.append(it.next().toString());
+      }
+    buf.append(")))");
+    return buf.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/X500DistinguishedName.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,556 @@
+/* X500DistinguishedName.java -- X.500 distinguished name.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class X500DistinguishedName implements Principal
+{
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID CN         = new OID("2.5.4.3");
+  public static final OID C          = new OID("2.5.4.6");
+  public static final OID L          = new OID("2.5.4.7");
+  public static final OID ST         = new OID("2.5.4.8");
+  public static final OID STREET     = new OID("2.5.4.9");
+  public static final OID O          = new OID("2.5.4.10");
+  public static final OID OU         = new OID("2.5.4.11");
+  public static final OID T          = new OID("2.5.4.12");
+  public static final OID DNQ        = new OID("2.5.4.46");
+  public static final OID NAME       = new OID("2.5.4.41");
+  public static final OID GIVENNAME  = new OID("2.5.4.42");
+  public static final OID INITIALS   = new OID("2.5.4.43");
+  public static final OID GENERATION = new OID("2.5.4.44");
+  public static final OID EMAIL      = new OID("1.2.840.113549.1.9.1");
+  public static final OID DC         = new OID("0.9.2342.19200300.100.1.25");
+  public static final OID UID        = new OID("0.9.2342.19200300.100.1.1");
+
+  private List components;
+  private Map currentRdn;
+  private boolean fixed;
+  private String stringRep;
+  private byte[] encoded;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public X500DistinguishedName()
+  {
+    components = new LinkedList();
+    currentRdn = new LinkedHashMap();
+    components.add(currentRdn);
+  }
+
+  public X500DistinguishedName(String name)
+  {
+    this();
+    try
+      {
+        parseString(name);
+      }
+    catch (IOException ioe)
+      {
+        throw new IllegalArgumentException(ioe.toString());
+      }
+  }
+
+  public X500DistinguishedName(byte[] encoded) throws IOException
+  {
+    this();
+    parseDer(new DERReader(encoded));
+  }
+
+  public X500DistinguishedName(InputStream encoded) throws IOException
+  {
+    this();
+    parseDer(new DERReader(encoded));
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public String getName()
+  {
+    return toString();
+  }
+
+  public void newRelativeDistinguishedName()
+  {
+    if (fixed || currentRdn.isEmpty()) return;
+    currentRdn = new LinkedHashMap();
+    components.add(currentRdn);
+  }
+
+  public int size()
+  {
+    return components.size();
+  }
+
+  public int countComponents()
+  {
+    int count = 0;
+    for (Iterator it = components.iterator(); it.hasNext(); )
+      {
+        count += ((Map) it.next()).size();
+      }
+    return count;
+  }
+
+  public boolean containsComponent(OID oid, String value)
+  {
+    for (Iterator it = components.iterator(); it.hasNext(); )
+      {
+        Map rdn = (Map) it.next();
+        String s = (String) rdn.get(oid);
+        if (s == null)
+          continue;
+        if (compressWS(value).equalsIgnoreCase(compressWS(s)))
+          return true;
+      }
+    return false;
+  }
+
+  public String getComponent(OID oid)
+  {
+    for (Iterator it = components.iterator(); it.hasNext(); )
+      {
+        Map rdn = (Map) it.next();
+        if (rdn.containsKey(oid))
+          return (String) rdn.get(oid);
+      }
+    return null;
+  }
+
+  public String getComponent(OID oid, int rdn)
+  {
+    if (rdn >= size())
+      return null;
+    return (String) ((Map) components.get(rdn)).get(oid);
+  }
+
+  public void putComponent(OID oid, String value)
+  {
+    currentRdn.put(oid, value);
+  }
+
+  public void putComponent(String name, String value)
+  {
+    name = name.trim().toLowerCase();
+    if (name.equals("cn"))
+      putComponent(CN, value);
+    else if (name.equals("c"))
+      putComponent(C, value);
+    else if (name.equals("l"))
+      putComponent(L, value);
+    else if (name.equals("street"))
+      putComponent(STREET, value);
+    else if (name.equals("st"))
+      putComponent(ST, value);
+    else if (name.equals("t"))
+      putComponent(T, value);
+    else if (name.equals("dnq"))
+      putComponent(DNQ, value);
+    else if (name.equals("name"))
+      putComponent(NAME, value);
+    else if (name.equals("givenname"))
+      putComponent(GIVENNAME, value);
+    else if (name.equals("initials"))
+      putComponent(INITIALS, value);
+    else if (name.equals("generation"))
+      putComponent(GENERATION, value);
+    else if (name.equals("email"))
+      putComponent(EMAIL, value);
+    else if (name.equals("dc"))
+      putComponent(DC, value);
+    else if (name.equals("uid"))
+      putComponent(UID, value);
+    else if (name.equals("o"))
+      putComponent(O, value);
+    else if (name.equals("ou"))
+      putComponent(OU, value);
+    else
+      putComponent(new OID(name), value);
+  }
+
+  public void setUnmodifiable()
+  {
+    if (fixed) return;
+    fixed = true;
+    List newComps = new ArrayList(components.size());
+    for (Iterator it = components.iterator(); it.hasNext(); )
+      {
+        Map rdn = (Map) it.next();
+        rdn = Collections.unmodifiableMap(rdn);
+        newComps.add(rdn);
+      }
+    components = Collections.unmodifiableList(newComps);
+    currentRdn = Collections.EMPTY_MAP;
+  }
+
+  public int hashCode()
+  {
+    int sum = 0;
+    for (Iterator it = components.iterator(); it.hasNext(); )
+      {
+        Map m = (Map) it.next();
+        for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
+          {
+            Map.Entry e = (Map.Entry) it2.next();
+            sum += e.getKey().hashCode();
+            sum += e.getValue().hashCode();
+          }
+      }
+    return sum;
+  }
+
+  public boolean equals(Object o)
+  {
+    if (!(o instanceof X500DistinguishedName))
+      return false;
+    if (size() != ((X500DistinguishedName) o).size())
+      return false;
+    for (int i = 0; i < size(); i++)
+      {
+        Map m = (Map) components.get(i);
+        for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
+          {
+            Map.Entry e = (Map.Entry) it2.next();
+            OID oid = (OID) e.getKey();
+            String v1 = (String) e.getValue();
+            String v2 = ((X500DistinguishedName) o).getComponent(oid, i);
+            if (!compressWS(v1).equalsIgnoreCase(compressWS(v2)))
+              return false;
+          }
+      }
+    return true;
+  }
+
+  public String toString()
+  {
+    if (fixed && stringRep != null)
+      return stringRep;
+    StringBuffer str = new StringBuffer();
+    for (Iterator it = components.iterator(); it.hasNext(); )
+      {
+        Map m = (Map) it.next();
+        for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
+          {
+            Map.Entry entry = (Map.Entry) it2.next();
+            OID oid = (OID) entry.getKey();
+            String value = (String) entry.getValue();
+            if (oid.equals(CN))
+              str.append("CN");
+            else if (oid.equals(C))
+              str.append("C");
+            else if (oid.equals(L))
+              str.append("L");
+            else if (oid.equals(ST))
+              str.append("ST");
+            else if (oid.equals(STREET))
+              str.append("STREET");
+            else if (oid.equals(O))
+              str.append("O");
+            else if (oid.equals(OU))
+              str.append("OU");
+            else if (oid.equals(T))
+              str.append("T");
+            else if (oid.equals(DNQ))
+              str.append("DNQ");
+            else if (oid.equals(NAME))
+              str.append("NAME");
+            else
+              str.append(oid.toString());
+            str.append('=');
+            str.append(value);
+            if (it2.hasNext())
+              str.append("+");
+          }
+        if (it.hasNext())
+          str.append(',');
+      }
+    return (stringRep = str.toString());
+  }
+
+  public byte[] getDer()
+  {
+    if (fixed && encoded != null)
+      return (byte[]) encoded.clone();
+
+    ArrayList name = new ArrayList(components.size());
+    for (Iterator it = components.iterator(); it.hasNext(); )
+      {
+        Map m = (Map) it.next();
+        if (m.isEmpty())
+          continue;
+
+        Set rdn = new HashSet();
+        for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
+          {
+            Map.Entry e = (Map.Entry) it2.next();
+            ArrayList atav = new ArrayList(2);
+            atav.add(new DERValue(DER.OBJECT_IDENTIFIER, e.getKey()));
+            atav.add(new DERValue(DER.UTF8_STRING, e.getValue()));
+            rdn.add(new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, atav));
+          }
+        name.add(new DERValue(DER.SET|DER.CONSTRUCTED, rdn));
+      }
+    DERValue val = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, name);
+    return (byte[]) (encoded = val.getEncoded()).clone();
+  }
+
+  // Own methods.
+  // -------------------------------------------------------------------------
+
+  private int sep;
+
+  private void parseString(String str) throws IOException
+  {
+    Reader in = new StringReader(str);
+    while (true)
+      {
+        String key = readAttributeType(in);
+        if (key == null)
+          break;
+        String value = readAttributeValue(in);
+        putComponent(key, value);
+        if (sep == ',')
+          newRelativeDistinguishedName();
+      }
+    setUnmodifiable();
+  }
+
+  private String readAttributeType(Reader in) throws IOException
+  {
+    StringBuffer buf = new StringBuffer();
+    int ch;
+    while ((ch = in.read()) != '=')
+      {
+        if (ch == -1)
+          {
+            if (buf.length() > 0)
+              throw new EOFException();
+            return null;
+          }
+        if (ch > 127)
+          throw new IOException("Invalid char: " + (char) ch);
+        if (Character.isLetterOrDigit((char) ch) || ch == '-' || ch == '.')
+          buf.append((char) ch);
+        else
+          throw new IOException("Invalid char: " + (char) ch);
+      }
+    return buf.toString();
+  }
+
+  private String readAttributeValue(Reader in) throws IOException
+  {
+    StringBuffer buf = new StringBuffer();
+    int ch = in.read();
+    if (ch == '#')
+      {
+        while (true)
+          {
+            ch = in.read();
+            if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
+                || Character.isDigit((char) ch))
+              buf.append((char) ch);
+            else if (ch == '+' || ch == ',')
+              {
+                sep = ch;
+                String hex = buf.toString();
+                return new String(Util.toByteArray(hex));
+              }
+            else
+              throw new IOException("illegal character: " + (char) ch);
+          }
+      }
+    else if (ch == '"')
+      {
+        while (true)
+          {
+            ch = in.read();
+            if (ch == '"')
+              break;
+            else if (ch == '\\')
+              {
+                ch = in.read();
+                if (ch == -1)
+                  throw new EOFException();
+                if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
+                    || Character.isDigit((char) ch))
+                  {
+                    int i = Character.digit((char) ch, 16) << 4;
+                    ch = in.read();
+                    if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
+                          || Character.isDigit((char) ch)))
+                      throw new IOException("illegal hex char");
+                    i |= Character.digit((char) ch, 16);
+                    buf.append((char) i);
+                  }
+                else
+                  buf.append((char) ch);
+              }
+            else
+              buf.append((char) ch);
+          }
+        sep = in.read();
+        if (sep != '+' || sep != ',')
+          throw new IOException("illegal character: " + (char) ch);
+        return buf.toString();
+      }
+    else
+      {
+        while (true)
+          {
+            switch (ch)
+              {
+              case '+':
+              case ',':
+                sep = ch;
+                return buf.toString();
+              case '\\':
+                ch = in.read();
+                if (ch == -1)
+                  throw new EOFException();
+                if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
+                    || Character.isDigit((char) ch))
+                  {
+                    int i = Character.digit((char) ch, 16) << 4;
+                    ch = in.read();
+                    if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
+                          || Character.isDigit((char) ch)))
+                      throw new IOException("illegal hex char");
+                    i |= Character.digit((char) ch, 16);
+                    buf.append((char) i);
+                  }
+                else
+                  buf.append((char) ch);
+                break;
+              case '=':
+              case '<':
+              case '>':
+              case '#':
+              case ';':
+                throw new IOException("illegal character: " + (char) ch);
+              case -1:
+                throw new EOFException();
+              default:
+                buf.append((char) ch);
+                ch = in.read();
+                if (ch == -1)
+                  return buf.toString();
+              }
+          }
+      }
+  }
+
+  private void parseDer(DERReader der) throws IOException
+  {
+    DERValue name = der.read();
+    if (!name.isConstructed())
+      throw new IOException("malformed Name");
+    encoded = name.getEncoded();
+    int len = 0;
+    while (len < name.getLength())
+      {
+        DERValue rdn = der.read();
+        if (!rdn.isConstructed())
+          throw new IOException("badly formed RDNSequence");
+        int len2 = 0;
+        while (len2 < rdn.getLength())
+          {
+            DERValue atav = der.read();
+            if (!atav.isConstructed())
+              throw new IOException("badly formed AttributeTypeAndValue");
+            DERValue val = der.read();
+            if (val.getTag() != DER.OBJECT_IDENTIFIER)
+              throw new IOException("badly formed AttributeTypeAndValue");
+            OID oid = (OID) val.getValue();
+            val = der.read();
+            if (!(val.getValue() instanceof String))
+              throw new IOException("badly formed AttributeTypeAndValue");
+            String value = (String) val.getValue();
+            putComponent(oid, value);
+            len2 += atav.getEncodedLength();
+          }
+        len += rdn.getEncodedLength();
+        if (len < name.getLength())
+          newRelativeDistinguishedName();
+      }
+    setUnmodifiable();
+  }
+
+  private static String compressWS(String str)
+  {
+    StringBuffer buf = new StringBuffer();
+    char lastChar = 0;
+    for (int i = 0; i < str.length(); i++)
+      {
+        char c = str.charAt(i);
+        if (Character.isWhitespace(c))
+          {
+            if (!Character.isWhitespace(lastChar))
+              buf.append(' ');
+          }
+        else
+          buf.append(c);
+        lastChar = c;
+      }
+    return buf.toString().trim();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/X509CRL.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,485 @@
+/* X509CRL.java -- X.509 certificate revocation list.
+   Copyright (C) 2003, 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.x509.ext.Extension;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * X.509 certificate revocation lists.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class X509CRL extends java.security.cert.X509CRL
+  implements GnuPKIExtension
+{
+  private static final Logger log = Logger.getLogger(X509CRL.class.getName());
+  private static final OID ID_DSA = new OID("1.2.840.10040.4.1");
+  private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3");
+  private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1");
+  private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2");
+  private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4");
+  private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5");
+
+  private byte[] encoded;
+
+  private byte[] tbsCRLBytes;
+  private int version;
+  private OID algId;
+  private byte[] algParams;
+  private Date thisUpdate;
+  private Date nextUpdate;
+  private X500DistinguishedName issuerDN;
+  private HashMap revokedCerts;
+  private HashMap extensions;
+
+  private OID sigAlg;
+  private byte[] sigAlgParams;
+  private byte[] rawSig;
+  private byte[] signature;
+
+  // Constructors.
+  // ------------------------------------------------------------------------
+
+  /**
+   * Create a new X.509 CRL.
+   *
+   * @param encoded The DER encoded CRL.
+   * @throws CRLException If the input bytes are incorrect.
+   * @throws IOException  If the input bytes cannot be read.
+   */
+  public X509CRL(InputStream encoded) throws CRLException, IOException
+  {
+    super();
+    revokedCerts = new HashMap();
+    extensions = new HashMap();
+    try
+      {
+        parse(encoded);
+      }
+    catch (IOException ioe)
+      {
+        ioe.printStackTrace();
+        throw ioe;
+      }
+    catch (Exception x)
+      {
+        x.printStackTrace();
+        throw new CRLException(x.toString());
+      }
+  }
+
+  // X509CRL methods.
+  // ------------------------------------------------------------------------
+
+  public boolean equals(Object o)
+  {
+    if (!(o instanceof X509CRL))
+      return false;
+    return ((X509CRL) o).getRevokedCertificates().equals(revokedCerts.values());
+  }
+
+  public int hashCode()
+  {
+    return revokedCerts.hashCode();
+  }
+
+  public byte[] getEncoded() throws CRLException
+  {
+    return (byte[]) encoded.clone();
+  }
+
+  public void verify(PublicKey key)
+    throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
+           NoSuchProviderException, SignatureException
+  {
+    Signature sig = Signature.getInstance(sigAlg.toString());
+    doVerify(sig, key);
+  }
+
+  public void verify(PublicKey key, String provider)
+    throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
+           NoSuchProviderException, SignatureException
+  {
+    Signature sig = Signature.getInstance(sigAlg.toString(), provider);
+    doVerify(sig, key);
+  }
+
+  public int getVersion()
+  {
+    return version;
+  }
+
+  public Principal getIssuerDN()
+  {
+    return issuerDN;
+  }
+
+  public X500Principal getIssuerX500Principal()
+  {
+    return new X500Principal(issuerDN.getDer());
+  }
+
+  public Date getThisUpdate()
+  {
+    return (Date) thisUpdate.clone();
+  }
+
+  public Date getNextUpdate()
+  {
+    if (nextUpdate != null)
+      return (Date) nextUpdate.clone();
+    return null;
+  }
+
+  public java.security.cert.X509CRLEntry getRevokedCertificate(BigInteger serialNo)
+  {
+    return (java.security.cert.X509CRLEntry) revokedCerts.get(serialNo);
+  }
+
+  public Set getRevokedCertificates()
+  {
+    return Collections.unmodifiableSet(new HashSet(revokedCerts.values()));
+  }
+
+  public byte[] getTBSCertList() throws CRLException
+  {
+    return (byte[]) tbsCRLBytes.clone();
+  }
+
+  public byte[] getSignature()
+  {
+    return (byte[]) rawSig.clone();
+  }
+
+  public String getSigAlgName()
+  {
+    if (sigAlg.equals(ID_DSA_WITH_SHA1))
+      return "SHA1withDSA";
+    if (sigAlg.equals(ID_RSA_WITH_MD2))
+      return "MD2withRSA";
+    if (sigAlg.equals(ID_RSA_WITH_MD5))
+      return "MD5withRSA";
+    if (sigAlg.equals(ID_RSA_WITH_SHA1))
+      return "SHA1withRSA";
+    return "unknown";
+  }
+
+  public String getSigAlgOID()
+  {
+    return sigAlg.toString();
+  }
+
+  public byte[] getSigAlgParams()
+  {
+    if (sigAlgParams != null)
+      return (byte[]) sigAlgParams.clone();
+    return null;
+  }
+
+  // X509Extension methods.
+  // ------------------------------------------------------------------------
+
+  public boolean hasUnsupportedCriticalExtension()
+  {
+    for (Iterator it = extensions.values().iterator(); it.hasNext(); )
+      {
+        Extension e = (Extension) it.next();
+        if (e.isCritical() && !e.isSupported())
+          return true;
+      }
+    return false;
+  }
+
+  public Set getCriticalExtensionOIDs()
+  {
+    HashSet s = new HashSet();
+    for (Iterator it = extensions.values().iterator(); it.hasNext(); )
+      {
+        Extension e = (Extension) it.next();
+        if (e.isCritical())
+          s.add(e.getOid().toString());
+      }
+    return Collections.unmodifiableSet(s);
+  }
+
+  public Set getNonCriticalExtensionOIDs()
+  {
+    HashSet s = new HashSet();
+    for (Iterator it = extensions.values().iterator(); it.hasNext(); )
+      {
+        Extension e = (Extension) it.next();
+        if (!e.isCritical())
+          s.add(e.getOid().toString());
+      }
+    return Collections.unmodifiableSet(s);
+  }
+
+  public byte[] getExtensionValue(String oid)
+  {
+    Extension e = getExtension(new OID(oid));
+    if (e != null)
+      {
+        return e.getValue().getEncoded();
+      }
+    return null;
+  }
+
+  // GnuPKIExtension method.
+  // -------------------------------------------------------------------------
+
+  public Extension getExtension(OID oid)
+  {
+    return (Extension) extensions.get(oid);
+  }
+
+  public Collection getExtensions()
+  {
+    return extensions.values();
+  }
+
+  // CRL methods.
+  // -------------------------------------------------------------------------
+
+  public String toString()
+  {
+    return X509CRL.class.getName();
+  }
+
+  public boolean isRevoked(Certificate cert)
+  {
+    if (!(cert instanceof java.security.cert.X509Certificate))
+      throw new IllegalArgumentException("not a X.509 certificate");
+    BigInteger certSerial =
+      ((java.security.cert.X509Certificate) cert).getSerialNumber();
+    X509CRLEntry ent = (X509CRLEntry) revokedCerts.get(certSerial);
+    if (ent == null)
+      return false;
+    return ent.getRevocationDate().compareTo(new Date()) < 0;
+  }
+
+  // Own methods.
+  // ------------------------------------------------------------------------
+
+  private void doVerify(Signature sig, PublicKey key)
+    throws CRLException, InvalidKeyException, SignatureException
+  {
+    sig.initVerify(key);
+    sig.update(tbsCRLBytes);
+    if (!sig.verify(signature))
+      throw new CRLException("signature not verified");
+  }
+
+  private void parse(InputStream in) throws Exception
+  {
+    // CertificateList ::= SEQUENCE {
+    DERReader der = new DERReader(in);
+    DERValue val = der.read();
+    if (Configuration.DEBUG)
+      log.fine("start CertificateList len == " + val.getLength());
+    if (!val.isConstructed())
+      throw new IOException("malformed CertificateList");
+    encoded = val.getEncoded();
+
+    //   tbsCertList ::= SEQUENCE {  -- TBSCertList
+    val = der.read();
+    if (!val.isConstructed())
+      throw new IOException("malformed TBSCertList");
+    if (Configuration.DEBUG)
+      log.fine("start tbsCertList  len == " + val.getLength());
+    tbsCRLBytes = val.getEncoded();
+
+    //     version    Version OPTIONAL,
+    //                  -- If present must be v2
+    val = der.read();
+    if (val.getValue() instanceof BigInteger)
+      {
+        version = ((BigInteger) val.getValue()).intValue() + 1;
+        val = der.read();
+      }
+    else
+      version = 1;
+    if (Configuration.DEBUG)
+      log.fine("read version == " + version);
+
+    //     signature   AlgorithmIdentifier,
+    if (Configuration.DEBUG)
+      log.fine("start AlgorithmIdentifier len == " + val.getLength());
+    if (!val.isConstructed())
+      throw new IOException("malformed AlgorithmIdentifier");
+    DERValue algIdVal = der.read();
+    algId = (OID) algIdVal.getValue();
+    if (Configuration.DEBUG)
+      log.fine("read object identifier == " + algId);
+    if (val.getLength() > algIdVal.getEncodedLength())
+      {
+        val = der.read();
+        if (Configuration.DEBUG)
+          log.fine("read parameters  len == " + val.getEncodedLength());
+        algParams = val.getEncoded();
+        if (val.isConstructed())
+          in.skip(val.getLength());
+      }
+
+    //     issuer   Name,
+    val = der.read();
+    issuerDN = new X500DistinguishedName(val.getEncoded());
+    der.skip(val.getLength());
+    if (Configuration.DEBUG)
+      log.fine("read issuer == " + issuerDN);
+
+    //     thisUpdate   Time,
+    thisUpdate = (Date) der.read().getValue();
+    if (Configuration.DEBUG)
+      log.fine("read thisUpdate == " + thisUpdate);
+
+    //     nextUpdate   Time OPTIONAL,
+    val = der.read();
+    if (val.getValue() instanceof Date)
+      {
+        nextUpdate = (Date) val.getValue();
+        if (Configuration.DEBUG)
+          log.fine("read nextUpdate == " + nextUpdate);
+        val = der.read();
+      }
+
+    //     revokedCertificates SEQUENCE OF SEQUENCE {
+    //       -- X509CRLEntry objects...
+    //     } OPTIONAL,
+    if (val.getTag() != 0)
+      {
+        int len = 0;
+        while (len < val.getLength())
+          {
+            X509CRLEntry entry = new X509CRLEntry(version, der);
+            revokedCerts.put(entry.getSerialNumber(), entry);
+            len += entry.getEncoded().length;
+          }
+        val = der.read();
+      }
+
+    //    crlExtensions   [0] EXPLICIT Extensions OPTIONAL
+    //                        -- if present MUST be v2
+    if (val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0)
+      {
+        if (version < 2)
+          throw new IOException("extra data in CRL");
+        DERValue exts = der.read();
+        if (!exts.isConstructed())
+          throw new IOException("malformed Extensions");
+        if (Configuration.DEBUG)
+          log.fine("start Extensions  len == " + exts.getLength());
+        int len = 0;
+        while (len < exts.getLength())
+          {
+            DERValue ext = der.read();
+            if (!ext.isConstructed())
+              throw new IOException("malformed Extension");
+            Extension e = new Extension(ext.getEncoded());
+            extensions.put(e.getOid(), e);
+            der.skip(ext.getLength());
+            len += ext.getEncodedLength();
+            if (Configuration.DEBUG)
+              log.fine("current count == " + len);
+          }
+        val = der.read();
+      }
+
+    if (Configuration.DEBUG)
+      log.fine("read tag == " + val.getTag());
+    if (!val.isConstructed())
+      throw new IOException("malformed AlgorithmIdentifier");
+    if (Configuration.DEBUG)
+      log.fine("start AlgorithmIdentifier  len == " + val.getLength());
+    DERValue sigAlgVal = der.read();
+    if (Configuration.DEBUG)
+      log.fine("read tag == " + sigAlgVal.getTag());
+    if (sigAlgVal.getTag() != DER.OBJECT_IDENTIFIER)
+      throw new IOException("malformed AlgorithmIdentifier");
+    sigAlg = (OID) sigAlgVal.getValue();
+    if (Configuration.DEBUG)
+      {
+        log.fine("signature id == " + sigAlg);
+        log.fine("sigAlgVal length == " + sigAlgVal.getEncodedLength());
+      }
+    if (val.getLength() > sigAlgVal.getEncodedLength())
+      {
+        val = der.read();
+        if (Configuration.DEBUG)
+          log.fine("sig params tag = " + val.getTag() + " len == "
+                   + val.getEncodedLength());
+        sigAlgParams = (byte[]) val.getEncoded();
+        if (val.isConstructed())
+          in.skip(val.getLength());
+      }
+    val = der.read();
+    if (Configuration.DEBUG)
+      log.fine("read tag = " + val.getTag());
+    rawSig = val.getEncoded();
+    signature = ((BitString) val.getValue()).toByteArray();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/X509CRLEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,273 @@
+/* X509CRLEntry.java -- an entry in a X.509 CRL.
+   Copyright (C) 2003, 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.x509.ext.Extension;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * A single entry in a X.509 certificate revocation list.
+ *
+ * @see X509CRL
+ * @author Casey Marshall
+ */
+class X509CRLEntry extends java.security.cert.X509CRLEntry
+  implements GnuPKIExtension
+{
+  private static final Logger log = Logger.getLogger(X509CRLEntry.class.getName());
+  /** The DER encoded form of this CRL entry. */
+  private byte[] encoded;
+
+  /** The revoked certificate's serial number. */
+  private BigInteger serialNo;
+
+  /** The date the certificate was revoked. */
+  private Date revocationDate;
+
+  /** The CRL entry extensions. */
+  private HashMap extensions;
+
+  // Constructor.
+  // ------------------------------------------------------------------------
+
+  /**
+   * Create a new X.509 certificate revocation list entry from the given
+   * input stream and CRL version number.
+   *
+   * @param version The CRL version.
+   * @param encoded The stream of DER bytes.
+   * @throws CRLException If the ASN.1 structure is invalid.
+   * @throws IOException  If the bytes cannot be read.
+   */
+  X509CRLEntry(int version, DERReader encoded)
+    throws CRLException, IOException
+  {
+    super();
+    extensions = new HashMap();
+    try
+      {
+        parse(version, encoded);
+      }
+    catch (IOException ioe)
+      {
+        throw ioe;
+      }
+    catch (Exception x)
+      {
+        throw new CRLException(x.toString());
+      }
+  }
+
+  // X509CRLEntry methods.
+  // ------------------------------------------------------------------------
+
+  public boolean equals(Object o)
+  {
+    if (!(o instanceof X509CRLEntry))
+      return false;
+    return ((X509CRLEntry) o).getSerialNumber().equals(serialNo) &&
+           ((X509CRLEntry) o).getRevocationDate().equals(revocationDate);
+  }
+
+  public int hashCode()
+  {
+    return serialNo.hashCode();
+  }
+
+  public byte[] getEncoded() throws CRLException
+  {
+    return (byte[]) encoded.clone();
+  }
+
+  public BigInteger getSerialNumber()
+  {
+    return serialNo;
+  }
+
+  public Date getRevocationDate()
+  {
+    return (Date) revocationDate.clone();
+  }
+
+  public boolean hasExtensions()
+  {
+    return ! extensions.isEmpty();
+  }
+
+  public String toString()
+  {
+    return "X509CRLEntry serial=" + serialNo + " revocation date="
+      + revocationDate + " ext=" + extensions;
+  }
+
+  // X509Extension methods.
+  // -------------------------------------------------------------------------
+
+  public boolean hasUnsupportedCriticalExtension()
+  {
+    for (Iterator it = extensions.values().iterator(); it.hasNext(); )
+      {
+        Extension e = (Extension) it.next();
+        if (e.isCritical() && !e.isSupported())
+          return true;
+      }
+    return false;
+  }
+
+  public Set getCriticalExtensionOIDs()
+  {
+    HashSet s = new HashSet();
+    for (Iterator it = extensions.values().iterator(); it.hasNext(); )
+      {
+        Extension e = (Extension) it.next();
+        if (e.isCritical())
+          s.add(e.getOid().toString());
+      }
+    return Collections.unmodifiableSet(s);
+  }
+
+  public Set getNonCriticalExtensionOIDs()
+  {
+    HashSet s = new HashSet();
+    for (Iterator it = extensions.values().iterator(); it.hasNext(); )
+      {
+        Extension e = (Extension) it.next();
+        if (!e.isCritical())
+          s.add(e.getOid().toString());
+      }
+    return Collections.unmodifiableSet(s);
+  }
+
+  public byte[] getExtensionValue(String oid)
+  {
+    Extension e = getExtension(new OID(oid));
+    if (e != null)
+      {
+        return e.getValue().getEncoded();
+      }
+    return null;
+  }
+
+  // GnuPKIExtension method.
+  // -------------------------------------------------------------------------
+
+  public Extension getExtension(OID oid)
+  {
+    return (Extension) extensions.get(oid);
+  }
+
+  public Collection getExtensions()
+  {
+    return extensions.values();
+  }
+
+  // Own methods.
+  // -------------------------------------------------------------------------
+
+  private void parse(int version, DERReader der) throws Exception
+  {
+    // RevokedCertificate ::= SEQUENCE {
+    DERValue entry = der.read();
+    if (Configuration.DEBUG)
+      log.fine("start CRL entry   len == " + entry.getLength());
+    if (!entry.isConstructed())
+      throw new IOException("malformed revokedCertificate");
+    encoded = entry.getEncoded();
+    int len = 0;
+    if (Configuration.DEBUG)
+      log.fine("encoded entry:\n" + Util.hexDump(encoded, ">>>> "));
+
+    //   userCertificate   CertificateSerialNumber,
+    DERValue val = der.read();
+    serialNo = (BigInteger) val.getValue();
+    len += val.getEncodedLength();
+    if (Configuration.DEBUG)
+      log.fine("userCertificate == " + serialNo + "  current count == " + len);
+
+    //   revocationDate   Time,
+    val = der.read();
+    revocationDate = (Date) val.getValue();
+    len += val.getEncodedLength();
+    if (Configuration.DEBUG)
+      log.fine("revocationDate == " + revocationDate + "  current count == "
+               + len);
+    //   crlEntryExtensions   Extensions OPTIONAL
+    //                          -- if present MUST be v2
+    if (len < entry.getLength())
+      {
+        if (version < 2)
+          throw new IOException("extra data in CRL entry");
+        DERValue exts = der.read();
+        if (!exts.isConstructed())
+          throw new IOException("malformed Extensions");
+        if (Configuration.DEBUG)
+          log.fine("start Extensions  len == " + exts.getLength());
+        len = 0;
+        while (len < exts.getLength())
+          {
+            val = der.read();
+            if (!val.isConstructed())
+              throw new IOException("malformed Extension");
+            if (Configuration.DEBUG)
+              log.fine("start Extension  len == " + val.getLength());
+            Extension e = new Extension(val.getEncoded());
+            extensions.put(e.getOid(), e);
+            der.skip(val.getLength());
+            len += val.getEncodedLength();
+            if (Configuration.DEBUG)
+              log.fine("current count == " + len);
+          }
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/X509CRLSelectorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,138 @@
+/* X509CRLSelectorImpl.java -- implementation of an X509CRLSelector.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509;
+
+import java.io.IOException;
+
+import java.security.Principal;
+import java.security.cert.CRL;
+import java.security.cert.CRLSelector;
+import java.security.cert.X509CRL;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Sun's implementation of X509CRLSelector sucks. This one tries to work
+ * better.
+ */
+public class X509CRLSelectorImpl implements CRLSelector
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private Set issuerNames;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public X509CRLSelectorImpl()
+  {
+    issuerNames = new HashSet();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public void addIssuerName(byte[] issuerName) throws IOException
+  {
+    issuerNames.add(new X500DistinguishedName(issuerName));
+  }
+
+  public void addIssuerName(String issuerName)
+  {
+    issuerNames.add(new X500DistinguishedName(issuerName));
+  }
+
+  public void addIssuerName(Principal issuerName) throws IOException
+  {
+    if (issuerName instanceof X500DistinguishedName)
+      issuerNames.add(issuerName);
+    else if (issuerName instanceof X500Principal)
+      issuerNames.add(new X500DistinguishedName(((X500Principal) issuerName).getEncoded()));
+    else
+      issuerNames.add(new X500DistinguishedName(issuerName.getName()));
+  }
+
+  public Collection getIssuerNames()
+  {
+    return Collections.unmodifiableSet(issuerNames);
+  }
+
+  public Object clone()
+  {
+    X509CRLSelectorImpl copy = new X509CRLSelectorImpl();
+    copy.issuerNames.addAll(issuerNames);
+    return copy;
+  }
+
+  public boolean match(CRL crl)
+  {
+    if (!(crl instanceof X509CRL))
+      return false;
+    try
+      {
+        Principal p = ((X509CRL) crl).getIssuerDN();
+        X500DistinguishedName thisName = null;
+        if (p instanceof X500DistinguishedName)
+          thisName = (X500DistinguishedName) p;
+        else if (p instanceof X500Principal)
+          thisName = new X500DistinguishedName(((X500Principal) p).getEncoded());
+        else
+          thisName = new X500DistinguishedName(p.getName());
+        for (Iterator it = issuerNames.iterator(); it.hasNext(); )
+          {
+            X500DistinguishedName name = (X500DistinguishedName) it.next();
+            if (thisName.equals(name))
+              return true;
+          }
+      }
+    catch (Exception x)
+      {
+      }
+    return false;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/X509CertPath.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,303 @@
+/* X509CertPath.java -- an X.509 certificate path.
+   Copyright (C) 2004  Free Software Fonudation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DEREncodingException;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A certificate path (or certificate chain) of X509Certificates.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class X509CertPath extends CertPath
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  public static final List ENCODINGS = Collections.unmodifiableList(
+    Arrays.asList(new String[] { "PkiPath", "PKCS7" }));
+
+  private static final OID PKCS7_SIGNED_DATA = new OID("1.2.840.113549.1.7.2");
+  private static final OID PKCS7_DATA = new OID("1.2.840.113549.1.7.1");
+
+  /** The certificate path. */
+  private List path;
+
+  /** The cached PKCS #7 encoded bytes. */
+  private byte[] pkcs_encoded;
+
+  /** The cached PkiPath encoded bytes. */
+  private byte[] pki_encoded;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public X509CertPath(List path)
+  {
+    super("X.509");
+    this.path = Collections.unmodifiableList(path);
+  }
+
+  public X509CertPath(InputStream in) throws CertificateEncodingException
+  {
+    this(in, (String) ENCODINGS.get(0));
+  }
+
+  public X509CertPath(InputStream in, String encoding)
+    throws CertificateEncodingException
+  {
+    super("X.509");
+    try
+      {
+        parse(in, encoding);
+      }
+    catch (IOException ioe)
+      {
+        throw new CertificateEncodingException();
+      }
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public List getCertificates()
+  {
+    return path; // already unmodifiable
+  }
+
+  public byte[] getEncoded() throws CertificateEncodingException
+  {
+    return getEncoded((String) ENCODINGS.get(0));
+  }
+
+  public byte[] getEncoded(String encoding) throws CertificateEncodingException
+  {
+    if (encoding.equalsIgnoreCase("PkiPath"))
+      {
+        if (pki_encoded == null)
+          {
+            try
+              {
+                pki_encoded = encodePki();
+              }
+            catch (IOException ioe)
+              {
+                throw new CertificateEncodingException();
+              }
+          }
+        return (byte[]) pki_encoded.clone();
+      }
+    else if (encoding.equalsIgnoreCase("PKCS7"))
+      {
+        if (pkcs_encoded == null)
+          {
+            try
+              {
+                pkcs_encoded = encodePKCS();
+              }
+            catch (IOException ioe)
+              {
+                throw new CertificateEncodingException();
+              }
+          }
+        return (byte[]) pkcs_encoded.clone();
+      }
+    else
+      throw new CertificateEncodingException("unknown encoding: " + encoding);
+  }
+
+  public Iterator getEncodings()
+  {
+    return ENCODINGS.iterator(); // already unmodifiable
+  }
+
+  // Own methods.
+  // -------------------------------------------------------------------------
+
+  private void parse(InputStream in, String encoding)
+    throws CertificateEncodingException, IOException
+  {
+    DERReader der = new DERReader(in);
+    DERValue path = null;
+    if (encoding.equalsIgnoreCase("PkiPath"))
+      {
+        // PKI encoding is just a SEQUENCE of X.509 certificates.
+        path = der.read();
+        if (!path.isConstructed())
+          throw new DEREncodingException("malformed PkiPath");
+      }
+    else if (encoding.equalsIgnoreCase("PKCS7"))
+      {
+        // PKCS #7 encoding means that the certificates are contained in a
+        // SignedData PKCS #7 type.
+        //
+        // ContentInfo ::= SEQUENCE {
+        //   contentType ::= ContentType,
+        //   content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+        //
+        // ContentType ::= OBJECT IDENTIFIER
+        //
+        // SignedData ::= SEQUENCE {
+        //   version Version,
+        //   digestAlgorithms DigestAlgorithmIdentifiers,
+        //   contentInfo ContentInfo,
+        //   certificates [0] IMPLICIT ExtendedCertificatesAndCertificates
+        //                    OPTIONAL,
+        //   crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+        //   signerInfos SignerInfos }
+        //
+        // Version ::= INTEGER
+        //
+        DERValue value = der.read();
+        if (!value.isConstructed())
+          throw new DEREncodingException("malformed ContentInfo");
+        value = der.read();
+        if (!(value.getValue() instanceof OID) ||
+            ((OID) value.getValue()).equals(PKCS7_SIGNED_DATA))
+          throw new DEREncodingException("not a SignedData");
+        value = der.read();
+        if (!value.isConstructed() || value.getTag() != 0)
+          throw new DEREncodingException("malformed content");
+        value = der.read();
+        if (value.getTag() != DER.INTEGER)
+          throw new DEREncodingException("malformed Version");
+        value = der.read();
+        if (!value.isConstructed() || value.getTag() != DER.SET)
+          throw new DEREncodingException("malformed DigestAlgorithmIdentifiers");
+        der.skip(value.getLength());
+        value = der.read();
+        if (!value.isConstructed())
+          throw new DEREncodingException("malformed ContentInfo");
+        der.skip(value.getLength());
+        path = der.read();
+        if (!path.isConstructed() || path.getTag() != 0)
+          throw new DEREncodingException("no certificates");
+      }
+    else
+      throw new CertificateEncodingException("unknown encoding: " + encoding);
+
+    LinkedList certs = new LinkedList();
+    int len = 0;
+    while (len < path.getLength())
+      {
+        DERValue cert = der.read();
+        try
+          {
+            certs.add(new X509Certificate(new ByteArrayInputStream(cert.getEncoded())));
+          }
+        catch (CertificateException ce)
+          {
+            throw new CertificateEncodingException(ce.getMessage());
+          }
+        len += cert.getEncodedLength();
+        der.skip(cert.getLength());
+      }
+
+    this.path = Collections.unmodifiableList(certs);
+  }
+
+  private byte[] encodePki()
+    throws CertificateEncodingException, IOException
+  {
+    synchronized (path)
+      {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        for (Iterator i = path.iterator(); i.hasNext(); )
+          {
+            out.write(((Certificate) i.next()).getEncoded());
+          }
+        byte[] b = out.toByteArray();
+        DERValue val = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                    b.length, b, null);
+        return val.getEncoded();
+      }
+  }
+
+  private byte[] encodePKCS()
+    throws CertificateEncodingException, IOException
+  {
+    synchronized (path)
+      {
+        ArrayList signedData = new ArrayList(5);
+        signedData.add(new DERValue(DER.INTEGER, BigInteger.ONE));
+        signedData.add(new DERValue(DER.CONSTRUCTED | DER.SET,
+                                    Collections.EMPTY_SET));
+        signedData.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+          Collections.singletonList(
+            new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_DATA))));
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        for (Iterator i = path.iterator(); i.hasNext(); )
+          {
+            out.write(((Certificate) i.next()).getEncoded());
+          }
+        byte[] b = out.toByteArray();
+        signedData.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT,
+                                    b.length, b, null));
+        DERValue sdValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                        signedData);
+
+        ArrayList contentInfo = new ArrayList(2);
+        contentInfo.add(new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_SIGNED_DATA));
+        contentInfo.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT, sdValue));
+        return new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                            contentInfo).getEncoded();
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/X509CertSelectorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,197 @@
+/* X509CertSelectorImpl.java -- implementation of an X509CertSelector.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Sun's implementation of X509CertSelector sucks. This one tries to work
+ * better.
+ */
+public class X509CertSelectorImpl implements CertSelector
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private Set issuerNames;
+  private Set subjectNames;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public X509CertSelectorImpl()
+  {
+    issuerNames = new HashSet();
+    subjectNames = new HashSet();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public void addIssuerName(byte[] issuerName) throws IOException
+  {
+    issuerNames.add(new X500DistinguishedName(issuerName));
+  }
+
+  public void addIssuerName(String issuerName)
+  {
+    issuerNames.add(new X500DistinguishedName(issuerName));
+  }
+
+  public void addIssuerName(Principal issuerName) throws IOException
+  {
+    if (issuerName instanceof X500DistinguishedName)
+      issuerNames.add(issuerName);
+    else if (issuerName instanceof X500Principal)
+      issuerNames.add(new X500DistinguishedName(((X500Principal) issuerName).getEncoded()));
+    else
+      issuerNames.add(new X500DistinguishedName(issuerName.getName()));
+  }
+
+  public Collection getIssuerNames()
+  {
+    return Collections.unmodifiableSet(issuerNames);
+  }
+
+  public void addSubjectName(byte[] subjectName) throws IOException
+  {
+    subjectNames.add(new X500DistinguishedName(subjectName));
+  }
+
+  public void addSubjectName(String subjectName) throws IOException
+  {
+    subjectNames.add(new X500DistinguishedName(subjectName));
+  }
+
+  public void addSubjectName(Principal subjectName) throws IOException
+  {
+    if (subjectName instanceof X500DistinguishedName)
+      subjectNames.add(subjectName);
+    else if (subjectName instanceof X500Principal)
+      subjectNames.add(new X500DistinguishedName(((X500Principal) subjectName).getEncoded()));
+    else
+      subjectNames.add(new X500DistinguishedName(subjectName.getName()));
+  }
+
+  public Collection getSubjectNames()
+  {
+    return Collections.unmodifiableSet(subjectNames);
+  }
+
+  public Object clone()
+  {
+    X509CertSelectorImpl copy = new X509CertSelectorImpl();
+    copy.issuerNames.addAll(issuerNames);
+    copy.subjectNames.addAll(subjectNames);
+    return copy;
+  }
+
+  public boolean match(Certificate cert)
+  {
+    if (!(cert instanceof X509Certificate))
+      return false;
+    boolean matchIssuer = false;
+    boolean matchSubject = false;
+    try
+      {
+        Principal p = ((X509Certificate) cert).getIssuerDN();
+        X500DistinguishedName thisName = null;
+        if (p instanceof X500DistinguishedName)
+          thisName = (X500DistinguishedName) p;
+        else if (p instanceof X500Principal)
+          thisName = new X500DistinguishedName(((X500Principal) p).getEncoded());
+        else
+          thisName = new X500DistinguishedName(p.getName());
+        if (issuerNames.isEmpty())
+          matchIssuer = true;
+        else
+          {
+            for (Iterator it = issuerNames.iterator(); it.hasNext(); )
+              {
+                X500DistinguishedName name = (X500DistinguishedName) it.next();
+                if (thisName.equals(name))
+                  {
+                    matchIssuer = true;
+                    break;
+                  }
+              }
+          }
+
+        p = ((X509Certificate) cert).getSubjectDN();
+        thisName = null;
+        if (p instanceof X500DistinguishedName)
+          thisName = (X500DistinguishedName) p;
+        else if (p instanceof X500Principal)
+          thisName = new X500DistinguishedName(((X500Principal) p).getEncoded());
+        else
+          thisName = new X500DistinguishedName(p.getName());
+        if (subjectNames.isEmpty())
+          matchSubject = true;
+        else
+          {
+            for (Iterator it = subjectNames.iterator(); it.hasNext(); )
+              {
+                X500DistinguishedName name = (X500DistinguishedName) it.next();
+                if (thisName.equals(name))
+                  {
+                    matchSubject = true;
+                    break;
+                  }
+              }
+          }
+      }
+    catch (Exception x)
+      {
+      }
+    return matchIssuer && matchSubject;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/X509Certificate.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,757 @@
+/* X509Certificate.java -- X.509 certificate.
+   Copyright (C) 2003, 2004, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.OID;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.x509.ext.BasicConstraints;
+import gnu.java.security.x509.ext.ExtendedKeyUsage;
+import gnu.java.security.x509.ext.Extension;
+import gnu.java.security.x509.ext.GeneralName;
+import gnu.java.security.x509.ext.IssuerAlternativeNames;
+import gnu.java.security.x509.ext.KeyUsage;
+import gnu.java.security.x509.ext.SubjectAlternativeNames;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * An implementation of X.509 certificates.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class X509Certificate extends java.security.cert.X509Certificate
+  implements Serializable, GnuPKIExtension
+{
+
+  // Constants and fields.
+  // ------------------------------------------------------------------------
+
+  private static final long serialVersionUID = -2491127588187038216L;
+  private static final Logger logger = SystemLogger.SYSTEM;
+
+  protected static final OID ID_DSA = new OID ("1.2.840.10040.4.1");
+  protected static final OID ID_DSA_WITH_SHA1 = new OID ("1.2.840.10040.4.3");
+  protected static final OID ID_RSA = new OID ("1.2.840.113549.1.1.1");
+  protected static final OID ID_RSA_WITH_MD2 = new OID ("1.2.840.113549.1.1.2");
+  protected static final OID ID_RSA_WITH_MD5 = new OID ("1.2.840.113549.1.1.4");
+  protected static final OID ID_RSA_WITH_SHA1 = new OID ("1.2.840.113549.1.1.5");
+  protected static final OID ID_ECDSA_WITH_SHA1 = new OID ("1.2.840.10045.4.1");
+
+  // This object SHOULD be serialized with an instance of
+  // java.security.cert.Certificate.CertificateRep, thus all fields are
+  // transient.
+
+  // The encoded certificate.
+  protected transient byte[] encoded;
+
+  // TBSCertificate part.
+  protected transient byte[] tbsCertBytes;
+  protected transient int version;
+  protected transient BigInteger serialNo;
+  protected transient OID algId;
+  protected transient byte[] algVal;
+  protected transient X500DistinguishedName issuer;
+  protected transient Date notBefore;
+  protected transient Date notAfter;
+  protected transient X500DistinguishedName subject;
+  protected transient PublicKey subjectKey;
+  protected transient BitString issuerUniqueId;
+  protected transient BitString subjectUniqueId;
+  protected transient Map<OID, Extension> extensions;
+
+  // Signature.
+  protected transient OID sigAlgId;
+  protected transient byte[] sigAlgVal;
+  protected transient byte[] signature;
+
+  // Constructors.
+  // ------------------------------------------------------------------------
+
+  /**
+   * Create a new X.509 certificate from the encoded data. The input
+   * data are expected to be the ASN.1 DER encoding of the certificate.
+   *
+   * @param encoded The encoded certificate data.
+   * @throws IOException If the certificate cannot be read, possibly
+   * from a formatting error.
+   * @throws CertificateException If the data read is not an X.509
+   * certificate.
+   */
+  public X509Certificate(InputStream encoded)
+    throws CertificateException, IOException
+  {
+    super();
+    extensions = new HashMap<OID, Extension>();
+    try
+      {
+        parse(encoded);
+      }
+    catch (IOException ioe)
+      {
+        logger.log (Component.X509, "", ioe);
+        throw ioe;
+      }
+    catch (Exception e)
+      {
+        logger.log (Component.X509, "", e);
+        CertificateException ce = new CertificateException(e.getMessage());
+        ce.initCause (e);
+        throw ce;
+      }
+  }
+
+  protected X509Certificate()
+  {
+    extensions = new HashMap<OID, Extension>();
+  }
+
+  // X509Certificate methods.
+  // ------------------------------------------------------------------------
+
+  public void checkValidity()
+    throws CertificateExpiredException, CertificateNotYetValidException
+  {
+    checkValidity(new Date());
+  }
+
+  public void checkValidity(Date date)
+    throws CertificateExpiredException, CertificateNotYetValidException
+  {
+    if (date.compareTo(notBefore) < 0)
+      {
+        throw new CertificateNotYetValidException();
+      }
+    if (date.compareTo(notAfter) > 0)
+      {
+        throw new CertificateExpiredException();
+      }
+  }
+
+  public int getVersion()
+  {
+    return version;
+  }
+
+  public BigInteger getSerialNumber()
+  {
+    return serialNo;
+  }
+
+  public Principal getIssuerDN()
+  {
+    return issuer;
+  }
+
+  public X500Principal getIssuerX500Principal()
+  {
+    return new X500Principal(issuer.getDer());
+  }
+
+  public Principal getSubjectDN()
+  {
+    return subject;
+  }
+
+  public X500Principal getSubjectX500Principal()
+  {
+    return new X500Principal(subject.getDer());
+  }
+
+  public Date getNotBefore()
+  {
+    return (Date) notBefore.clone();
+  }
+
+  public Date getNotAfter()
+  {
+    return (Date) notAfter.clone();
+  }
+
+  public byte[] getTBSCertificate() throws CertificateEncodingException
+  {
+    return (byte[]) tbsCertBytes.clone();
+  }
+
+  public byte[] getSignature()
+  {
+    return (byte[]) signature.clone();
+  }
+
+  public String getSigAlgName()
+  {
+    if (sigAlgId.equals(ID_DSA_WITH_SHA1))
+      {
+        return "SHA1withDSA";
+      }
+    if (sigAlgId.equals(ID_RSA_WITH_MD2))
+      {
+        return "MD2withRSA";
+      }
+    if (sigAlgId.equals(ID_RSA_WITH_MD5))
+      {
+        return "MD5withRSA";
+      }
+    if (sigAlgId.equals(ID_RSA_WITH_SHA1))
+      {
+        return "SHA1withRSA";
+      }
+    return "unknown";
+  }
+
+  public String getSigAlgOID()
+  {
+    return sigAlgId.toString();
+  }
+
+  public byte[] getSigAlgParams()
+  {
+    return (byte[]) sigAlgVal.clone();
+  }
+
+  public boolean[] getIssuerUniqueID()
+  {
+    if (issuerUniqueId != null)
+      {
+        return issuerUniqueId.toBooleanArray();
+      }
+    return null;
+  }
+
+  public boolean[] getSubjectUniqueID()
+  {
+    if (subjectUniqueId != null)
+      {
+        return subjectUniqueId.toBooleanArray();
+      }
+    return null;
+  }
+
+  public boolean[] getKeyUsage()
+  {
+    Extension e = getExtension(KeyUsage.ID);
+    if (e != null)
+      {
+        KeyUsage ku = (KeyUsage) e.getValue();
+        boolean[] result = new boolean[9];
+        boolean[] b = ku.getKeyUsage().toBooleanArray();
+        System.arraycopy(b, 0, result, 0, b.length);
+        return result;
+      }
+    return null;
+  }
+
+  public List<String> getExtendedKeyUsage() throws CertificateParsingException
+  {
+    Extension e = getExtension(ExtendedKeyUsage.ID);
+    if (e != null)
+      {
+        List<OID> a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds();
+        List<String> b = new ArrayList<String>(a.size());
+        for (OID oid : a)
+          b.add(oid.toString());
+        return Collections.unmodifiableList(b);
+      }
+    return null;
+  }
+
+  public int getBasicConstraints()
+  {
+    Extension e = getExtension(BasicConstraints.ID);
+    if (e != null)
+      {
+        return ((BasicConstraints) e.getValue()).getPathLengthConstraint();
+      }
+    return -1;
+  }
+
+  public Collection<List<?>> getSubjectAlternativeNames()
+    throws CertificateParsingException
+  {
+    Extension e = getExtension(SubjectAlternativeNames.ID);
+    if (e != null)
+      {
+        List<GeneralName> names
+          = ((SubjectAlternativeNames) e.getValue()).getNames();
+        List<List<?>> list = new ArrayList<List<?>>(names.size());
+        for (GeneralName name : names)
+          {
+            List<Object> n = new ArrayList<Object>(2);
+            n.add(name.kind().tag());
+            n.add(name.name());
+            list.add(n);
+          }
+        return list;
+      }
+    return null;
+  }
+
+  public Collection<List<?>> getIssuerAlternativeNames()
+    throws CertificateParsingException
+  {
+    Extension e = getExtension(IssuerAlternativeNames.ID);
+    if (e != null)
+      {
+        List<GeneralName> names
+          = ((IssuerAlternativeNames) e.getValue()).getNames();
+        List<List<?>> list = new ArrayList<List<?>>(names.size());
+        for (GeneralName name : names)
+          {
+            List<Object> n = new ArrayList<Object>(2);
+            n.add(name.kind().tag());
+            n.add(name.name());
+            list.add(n);
+          }
+        return list;
+      }
+    return null;
+  }
+
+// X509Extension methods.
+  // ------------------------------------------------------------------------
+
+  public boolean hasUnsupportedCriticalExtension()
+  {
+    for (Iterator it = extensions.values().iterator(); it.hasNext(); )
+      {
+        Extension e = (Extension) it.next();
+        if (e.isCritical() && !e.isSupported())
+          return true;
+      }
+    return false;
+  }
+
+  public Set<String> getCriticalExtensionOIDs()
+  {
+    HashSet<String> s = new HashSet<String>();
+    for (Extension e : extensions.values())
+      {
+        if (e.isCritical())
+          s.add(e.getOid().toString());
+      }
+    return Collections.unmodifiableSet(s);
+  }
+
+  public Set<String> getNonCriticalExtensionOIDs()
+  {
+    HashSet<String> s = new HashSet<String>();
+    for (Extension e : extensions.values())
+      {
+        if (!e.isCritical())
+          s.add(e.getOid().toString());
+      }
+    return Collections.unmodifiableSet(s);
+  }
+
+  public byte[] getExtensionValue(String oid)
+  {
+    Extension e = getExtension(new OID(oid));
+    if (e != null)
+      {
+        return e.getValue().getEncoded();
+      }
+    return null;
+  }
+
+  // GnuPKIExtension method.
+  // -------------------------------------------------------------------------
+
+  public Extension getExtension(OID oid)
+  {
+    return (Extension) extensions.get(oid);
+  }
+
+  public Collection getExtensions()
+  {
+    return extensions.values();
+  }
+
+  // Certificate methods.
+  // -------------------------------------------------------------------------
+
+  public byte[] getEncoded() throws CertificateEncodingException
+  {
+    return (byte[]) encoded.clone();
+  }
+
+  public void verify(PublicKey key)
+    throws CertificateException, NoSuchAlgorithmException,
+           InvalidKeyException, NoSuchProviderException, SignatureException
+  {
+    Signature sig = Signature.getInstance(sigAlgId.toString());
+    doVerify(sig, key);
+  }
+
+  public void verify(PublicKey key, String provider)
+    throws CertificateException, NoSuchAlgorithmException,
+           InvalidKeyException, NoSuchProviderException, SignatureException
+  {
+    Signature sig = Signature.getInstance(sigAlgId.toString(), provider);
+    doVerify(sig, key);
+  }
+
+  public String toString()
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str);
+    out.println(X509Certificate.class.getName() + " {");
+    out.println("  TBSCertificate {");
+    out.println("    version = " + version + ";");
+    out.println("    serialNo = " + serialNo + ";");
+    out.println("    signature = {");
+    out.println("      algorithm = " + getSigAlgName() + ";");
+    out.print("      parameters =");
+    if (sigAlgVal != null)
+      {
+        out.println();
+        out.print(Util.hexDump(sigAlgVal, "        "));
+      }
+    else
+      {
+        out.println(" null;");
+      }
+    out.println("    }");
+    out.println("    issuer = " + issuer.getName() + ";");
+    out.println("    validity = {");
+    out.println("      notBefore = " + notBefore + ";");
+    out.println("      notAfter  = " + notAfter + ";");
+    out.println("    }");
+    out.println("    subject = " + subject.getName() + ";");
+    out.println("    subjectPublicKeyInfo = {");
+    out.println("      algorithm = " + subjectKey.getAlgorithm());
+    out.println("      key =");
+    out.print(Util.hexDump(subjectKey.getEncoded(), "        "));
+    out.println("    };");
+    out.println("    issuerUniqueId  = " + issuerUniqueId + ";");
+    out.println("    subjectUniqueId = " + subjectUniqueId + ";");
+    out.println("    extensions = {");
+    for (Iterator it = extensions.values().iterator(); it.hasNext(); )
+      {
+        out.println("      " + it.next());
+      }
+    out.println("    }");
+    out.println("  }");
+    out.println("  signatureAlgorithm = " + getSigAlgName() + ";");
+    out.println("  signatureValue =");
+    out.print(Util.hexDump(signature, "    "));
+    out.println("}");
+    return str.toString();
+  }
+
+  public PublicKey getPublicKey()
+  {
+    return subjectKey;
+  }
+
+  public boolean equals(Object other)
+  {
+    if (!(other instanceof X509Certificate))
+      return false;
+    try
+      {
+        if (other instanceof X509Certificate)
+          return Arrays.equals(encoded, ((X509Certificate) other).encoded);
+        byte[] enc = ((X509Certificate) other).getEncoded();
+        if (enc == null)
+          return false;
+        return Arrays.equals(encoded, enc);
+      }
+    catch (CertificateEncodingException cee)
+      {
+        return false;
+      }
+  }
+
+  // Own methods.
+  // ------------------------------------------------------------------------
+
+  /**
+   * Verify this certificate's signature.
+   */
+  private void doVerify(Signature sig, PublicKey key)
+    throws CertificateException, InvalidKeyException, SignatureException
+  {
+    logger.log (Component.X509, "verifying sig={0} key={1}",
+                new Object[] { sig, key });
+    sig.initVerify(key);
+    sig.update(tbsCertBytes);
+    if (!sig.verify(signature))
+      {
+        throw new CertificateException("signature not validated");
+      }
+  }
+
+  /**
+   * Parse a DER stream into an X.509 certificate.
+   *
+   * @param encoded The encoded bytes.
+   */
+  private void parse(InputStream encoded) throws Exception
+  {
+    DERReader der = new DERReader(encoded);
+
+    // Certificate ::= SEQUENCE {
+    DERValue cert = der.read();
+    logger.log (Component.X509, "start Certificate  len == {0}",
+                Integer.valueOf(cert.getLength()));
+
+    this.encoded = cert.getEncoded();
+    if (!cert.isConstructed())
+      {
+        throw new IOException("malformed Certificate");
+      }
+
+    // TBSCertificate ::= SEQUENCE {
+    DERValue tbsCert = der.read();
+    if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE)
+      {
+        throw new IOException("malformed TBSCertificate");
+      }
+    tbsCertBytes = tbsCert.getEncoded();
+    logger.log (Component.X509, "start TBSCertificate  len == {0}",
+                Integer.valueOf(tbsCert.getLength()));
+
+    // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) }
+    DERValue val = der.read();
+    if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0)
+      {
+        version = ((BigInteger) der.read().getValue()).intValue() + 1;
+        val = der.read();
+      }
+    else
+      {
+        version = 1;
+      }
+    logger.log (Component.X509, "read version == {0}",
+                Integer.valueOf(version));
+
+    // SerialNumber ::= INTEGER
+    serialNo = (BigInteger) val.getValue();
+    logger.log (Component.X509, "read serial number == {0}", serialNo);
+
+    // AlgorithmIdentifier ::= SEQUENCE {
+    val = der.read();
+    if (!val.isConstructed())
+      {
+        throw new IOException("malformed AlgorithmIdentifier");
+      }
+    int certAlgLen = val.getLength();
+    logger.log (Component.X509, "start AlgorithmIdentifier  len == {0}",
+                Integer.valueOf(certAlgLen));
+    val = der.read();
+
+    //   algorithm    OBJECT IDENTIFIER,
+    algId = (OID) val.getValue();
+    logger.log (Component.X509, "read algorithm ID == {0}", algId);
+
+    //   parameters   ANY DEFINED BY algorithm OPTIONAL }
+    if (certAlgLen > val.getEncodedLength())
+      {
+        val = der.read();
+        if (val == null)
+          {
+            algVal = null;
+          }
+        else
+          {
+            algVal = val.getEncoded();
+
+            if (val.isConstructed())
+              encoded.skip(val.getLength());
+          }
+        logger.log (Component.X509, "read algorithm parameters == {0}", algVal);
+      }
+
+    // issuer   Name,
+    val = der.read();
+    issuer = new X500DistinguishedName(val.getEncoded());
+    der.skip(val.getLength());
+    logger.log (Component.X509, "read issuer == {0}", issuer);
+
+    // Validity ::= SEQUENCE {
+    //   notBefore   Time,
+    //   notAfter    Time }
+    if (!der.read().isConstructed())
+      {
+        throw new IOException("malformed Validity");
+      }
+    notBefore = (Date) der.read().getValue();
+    logger.log (Component.X509, "read notBefore == {0}", notBefore);
+    notAfter  = (Date) der.read().getValue();
+    logger.log (Component.X509, "read notAfter == {0}", notAfter);
+
+    // subject   Name,
+    val = der.read();
+    subject = new X500DistinguishedName(val.getEncoded());
+    der.skip(val.getLength());
+    logger.log (Component.X509, "read subject == {0}", subject);
+
+    // SubjectPublicKeyInfo ::= SEQUENCE {
+    //   algorithm         AlgorithmIdentifier,
+    //   subjectPublicKey  BIT STRING }
+    DERValue spki = der.read();
+    if (!spki.isConstructed())
+      {
+        throw new IOException("malformed SubjectPublicKeyInfo");
+      }
+    KeyFactory spkFac = KeyFactory.getInstance("X.509");
+    subjectKey = spkFac.generatePublic(new X509EncodedKeySpec(spki.getEncoded()));
+    der.skip(spki.getLength());
+    logger.log (Component.X509, "read subjectPublicKey == {0}", subjectKey);
+
+    val = der.read();
+    if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1)
+      {
+        byte[] b = (byte[]) val.getValue();
+        issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
+        logger.log (Component.X509, "read issuerUniqueId == {0}", issuerUniqueId);
+        val = der.read();
+      }
+    if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2)
+      {
+        byte[] b = (byte[]) val.getValue();
+        subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
+        logger.log (Component.X509, "read subjectUniqueId == {0}", subjectUniqueId);
+        val = der.read();
+      }
+    if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3)
+      {
+        val = der.read();
+        logger.log (Component.X509, "start Extensions  len == {0}",
+                    Integer.valueOf(val.getLength()));
+        int len = 0;
+        while (len < val.getLength())
+          {
+            DERValue ext = der.read();
+            logger.log (Component.X509, "start extension  len == {0}",
+                        Integer.valueOf(ext.getLength()));
+            Extension e = new Extension(ext.getEncoded());
+            extensions.put(e.getOid(), e);
+            der.skip(ext.getLength());
+            len += ext.getEncodedLength();
+            logger.log (Component.X509, "read extension {0} == {1}",
+                        new Object[] { e.getOid (), e });
+            logger.log (Component.X509, "count == {0}", Integer.valueOf(len));
+          }
+
+        val = der.read ();
+      }
+
+    logger.log (Component.X509, "read value {0}", val);
+    if (!val.isConstructed())
+      {
+        throw new CertificateException ("malformed AlgorithmIdentifier");
+      }
+    int sigAlgLen = val.getLength();
+    logger.log (Component.X509, "start AlgorithmIdentifier  len == {0}",
+                Integer.valueOf(sigAlgLen));
+    val = der.read();
+    sigAlgId = (OID) val.getValue();
+    logger.log (Component.X509, "read algorithm id == {0}", sigAlgId);
+    if (sigAlgLen > val.getEncodedLength())
+      {
+        val = der.read();
+        if (val.getValue() == null)
+          {
+            if (subjectKey instanceof DSAPublicKey)
+              {
+                AlgorithmParameters params =
+                  AlgorithmParameters.getInstance("DSA");
+                DSAParams dsap = ((DSAPublicKey) subjectKey).getParams();
+                DSAParameterSpec spec =
+                  new DSAParameterSpec(dsap.getP(), dsap.getQ(), dsap.getG());
+                params.init(spec);
+                sigAlgVal = params.getEncoded();
+              }
+          }
+        else
+          {
+            sigAlgVal = (byte[]) val.getEncoded();
+          }
+        if (val.isConstructed())
+          {
+            encoded.skip(val.getLength());
+          }
+        logger.log (Component.X509, "read parameters == {0}", sigAlgVal);
+      }
+    signature = ((BitString) der.read().getValue()).toByteArray();
+    logger.log (Component.X509, "read signature ==\n{0}", Util.hexDump(signature, ">>>> "));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,133 @@
+/* AuthorityKeyIdentifier.java -- Authority key identifier extension.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.x509.Util;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public class AuthorityKeyIdentifier extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.35");
+
+  private final byte[] keyIdentifier;
+  private final GeneralNames authorityCertIssuer;
+  private final BigInteger authorityCertSerialNumber;
+
+  // Contstructor.
+  // -------------------------------------------------------------------------
+
+  public AuthorityKeyIdentifier(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERReader der = new DERReader(encoded);
+
+    // AuthorityKeyIdentifier ::= SEQUENCE {
+    DERValue val = der.read();
+    if (!val.isConstructed())
+      throw new IOException("malformed AuthorityKeyIdentifier");
+    if (val.getLength() > 0)
+      val = der.read();
+
+    //   keyIdentifier  [0] KeyIdentifier OPTIONAL,
+    //   KeyIdentifier ::= OCTET STRING
+    if (val.getTagClass() == DER.APPLICATION && val.getTag() == 0)
+      {
+        keyIdentifier = (byte[]) val.getValue();
+        val = der.read();
+      }
+    else
+      keyIdentifier = null;
+
+    //   authorityCertIssuer  [1] GeneralNames OPTIONAL,
+    if (val.getTagClass() == DER.APPLICATION && val.getTag() == 1)
+      {
+        byte[] b = val.getEncoded();
+        b[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE);
+        authorityCertIssuer = new GeneralNames(b);
+        der.skip(val.getLength());
+        val = der.read();
+      }
+    else
+      authorityCertIssuer = null;
+
+    //   authorityCertSerialNumber  [2] CertificateSerialNumber OPTIONAL }
+    if (val.getTagClass() == DER.APPLICATION && val.getTag() == 2)
+      {
+        authorityCertSerialNumber = new BigInteger((byte[]) val.getValue());
+      }
+    else
+      authorityCertSerialNumber = null;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public byte[] getKeyIdentifier()
+  {
+    return keyIdentifier != null ? (byte[]) keyIdentifier.clone() : null;
+  }
+
+  public GeneralNames getAuthorityCertIssuer()
+  {
+    return authorityCertIssuer;
+  }
+
+  public BigInteger getAuthorityCertSerialNumber()
+  {
+    return authorityCertSerialNumber;
+  }
+
+  public String toString()
+  {
+    return AuthorityKeyIdentifier.class.getName() + " [ keyId=" +
+      (keyIdentifier != null ? Util.toHexString (keyIdentifier, ':') : "nil") +
+      " authorityCertIssuer=" + authorityCertIssuer +
+      " authorityCertSerialNumbe=" + authorityCertSerialNumber + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/BasicConstraints.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,129 @@
+/* BasicConstraints.java -- the basic constraints extension.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BasicConstraints extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.19");
+
+  private final boolean ca;
+  private final int pathLenConstraint;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public BasicConstraints(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERReader der = new DERReader(encoded);
+    DERValue bc = der.read();
+    if (!bc.isConstructed())
+      throw new IOException("malformed BasicConstraints");
+    DERValue val = bc;
+    if (bc.getLength() > 0)
+      val = der.read();
+    if (val.getTag() == DER.BOOLEAN)
+      {
+        ca = ((Boolean) val.getValue()).booleanValue();
+        if (val.getEncodedLength() < bc.getLength())
+          val = der.read();
+      }
+    else
+      ca = false;
+    if (val.getTag() == DER.INTEGER)
+      {
+        pathLenConstraint = ((BigInteger) val.getValue()).intValue();
+      }
+    else
+      pathLenConstraint = -1;
+  }
+
+  public BasicConstraints (final boolean ca, final int pathLenConstraint)
+  {
+    this.ca = ca;
+    this.pathLenConstraint = pathLenConstraint;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public boolean isCA()
+  {
+    return ca;
+  }
+
+  public int getPathLengthConstraint()
+  {
+    return pathLenConstraint;
+  }
+
+  public byte[] getEncoded()
+  {
+    if (encoded == null)
+      {
+        List bc = new ArrayList (2);
+        bc.add (new DERValue (DER.BOOLEAN, Boolean.valueOf (ca)));
+        if (pathLenConstraint >= 0)
+          bc.add (new DERValue (DER.INTEGER,
+                                BigInteger.valueOf ((long) pathLenConstraint)));
+        encoded = new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, bc).getEncoded();
+      }
+    return (byte[]) encoded.clone();
+  }
+
+  public String toString()
+  {
+    return BasicConstraints.class.getName() + " [ isCA=" + ca +
+      " pathLen=" + pathLenConstraint + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/CRLNumber.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,97 @@
+/* CRLNumber.java -- CRL number extension.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public class CRLNumber extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.20");
+
+  private final BigInteger number;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public CRLNumber(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERValue val = DERReader.read(encoded);
+    if (val.getTag() != DER.INTEGER)
+      throw new IOException("malformed CRLNumber");
+    number = (BigInteger) val.getValue();
+  }
+
+  public CRLNumber (final BigInteger number)
+  {
+    this.number = number;
+  }
+
+  // Instance method.
+  // -------------------------------------------------------------------------
+
+  public BigInteger getNumber()
+  {
+    return number;
+  }
+
+  public byte[] getEncoded()
+  {
+    if (encoded == null)
+      {
+        encoded = new DERValue (DER.INTEGER, number).getEncoded();
+      }
+    return (byte[]) encoded.clone();
+  }
+
+  public String toString()
+  {
+    return CRLNumber.class.getName() + " [ " + number + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/CertificatePolicies.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,205 @@
+/* CertificatePolicies.java -- certificate policy extension.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.security.cert.PolicyQualifierInfo;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class CertificatePolicies extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.32");
+
+  private final List<OID> policies;
+  private final Map<OID, List<PolicyQualifierInfo>> policyQualifierInfos;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public CertificatePolicies(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERReader der = new DERReader(encoded);
+    DERValue pol = der.read();
+    if (!pol.isConstructed())
+      throw new IOException("malformed CertificatePolicies");
+
+    int len = 0;
+    LinkedList<OID> policyList = new LinkedList<OID>();
+    HashMap<OID, List<PolicyQualifierInfo>> qualifierMap
+      = new HashMap<OID, List<PolicyQualifierInfo>>();
+    while (len < pol.getLength())
+      {
+        DERValue policyInfo = der.read();
+        if (!policyInfo.isConstructed())
+          throw new IOException("malformed PolicyInformation");
+        DERValue val = der.read();
+        if (val.getTag() != DER.OBJECT_IDENTIFIER)
+          throw new IOException("malformed CertPolicyId");
+        OID policyId = (OID) val.getValue();
+        policyList.add(policyId);
+        if (val.getEncodedLength() < policyInfo.getLength())
+          {
+            DERValue qual = der.read();
+            int len2 = 0;
+            LinkedList<PolicyQualifierInfo> quals = new LinkedList<PolicyQualifierInfo>();
+            while (len2 < qual.getLength())
+              {
+                val = der.read();
+                quals.add(new PolicyQualifierInfo(val.getEncoded()));
+                der.skip(val.getLength());
+                len2 += val.getEncodedLength();
+              }
+            qualifierMap.put(policyId, quals);
+          }
+        len += policyInfo.getEncodedLength();
+      }
+
+    policies = Collections.unmodifiableList(policyList);
+    policyQualifierInfos = Collections.unmodifiableMap(qualifierMap);
+  }
+
+  public CertificatePolicies (final List<OID> policies,
+                              final Map<OID, List<PolicyQualifierInfo>> policyQualifierInfos)
+  {
+    for (Iterator it = policies.iterator(); it.hasNext(); )
+      if (!(it.next() instanceof OID))
+        throw new IllegalArgumentException ("policies must be OIDs");
+    for (Iterator it = policyQualifierInfos.entrySet().iterator(); it.hasNext();)
+      {
+        Map.Entry e = (Map.Entry) it.next();
+        if (!(e.getKey() instanceof OID) || !policies.contains (e.getKey()))
+          throw new IllegalArgumentException
+            ("policyQualifierInfos keys must be OIDs");
+        if (!(e.getValue() instanceof List))
+          throw new IllegalArgumentException
+            ("policyQualifierInfos values must be Lists of PolicyQualifierInfos");
+        for (Iterator it2 = ((List) e.getValue()).iterator(); it.hasNext(); )
+          if (!(it2.next() instanceof PolicyQualifierInfo))
+            throw new IllegalArgumentException
+              ("policyQualifierInfos values must be Lists of PolicyQualifierInfos");
+      }
+    this.policies = Collections.unmodifiableList (new ArrayList<OID>(policies));
+    this.policyQualifierInfos = Collections.unmodifiableMap
+      (new HashMap<OID, List<PolicyQualifierInfo>>(policyQualifierInfos));
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public List<OID> getPolicies()
+  {
+    return policies;
+  }
+  
+  /**
+   * Returns the list of policy OIDs, formatted as dotted-decimal strings.
+   *
+   * @return
+   */
+  public List<String> getPolicyStrings()
+  {
+    List<String> l = new ArrayList<String>(policies.size());
+    for (OID oid : policies)
+      {
+        l.add(oid.toString());
+      }
+    return l;
+  }
+
+  public List<PolicyQualifierInfo> getPolicyQualifierInfos(OID oid)
+  {
+    return policyQualifierInfos.get(oid);
+  }
+
+  public byte[] getEncoded()
+  {
+    if (encoded == null)
+      {
+        List<DERValue> pol = new ArrayList<DERValue>(policies.size());
+        for (Iterator<OID> it = policies.iterator(); it.hasNext(); )
+          {
+            OID policy = it.next();
+            List<PolicyQualifierInfo> qualifiers = getPolicyQualifierInfos(policy);
+            List<DERValue> l = new ArrayList<DERValue>(qualifiers == null ? 1 : 2);
+            l.add(new DERValue(DER.OBJECT_IDENTIFIER, policy));
+            if (qualifiers != null)
+              {
+                List<DERValue> ll = new ArrayList<DERValue>(qualifiers.size());
+                for (Iterator<PolicyQualifierInfo> it2 = qualifiers.iterator(); it.hasNext(); )
+                  {
+                    PolicyQualifierInfo info = it2.next();
+                    try
+                      {
+                        ll.add(DERReader.read(info.getEncoded()));
+                      }
+                    catch (IOException ioe)
+                      {
+                      }
+                  }
+                l.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, ll));
+              }
+            pol.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, l));
+          }
+        encoded = new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, pol).getEncoded();
+      }
+    return (byte[]) encoded.clone();
+  }
+
+  public String toString()
+  {
+    return CertificatePolicies.class.getName() + " [ policies=" + policies +
+      " policyQualifierInfos=" + policyQualifierInfos + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/ExtendedKeyUsage.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,95 @@
+/* ExtendedKeyUsage.java -- the extended key usage extension.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ExtendedKeyUsage extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.37");
+
+  private final List<OID> purposeIds;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public ExtendedKeyUsage(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERReader der = new DERReader(encoded);
+    DERValue usageList = der.read();
+    if (!usageList.isConstructed())
+      throw new IOException("malformed ExtKeyUsageSyntax");
+    int len = 0;
+    purposeIds = new LinkedList<OID>();
+    while (len < usageList.getLength())
+      {
+        DERValue val = der.read();
+        if (val.getTag() != DER.OBJECT_IDENTIFIER)
+          throw new IOException("malformed KeyPurposeId");
+        purposeIds.add((OID) val.getValue());
+        len += val.getEncodedLength();
+      }
+  }
+
+  // Instance method.
+  // -------------------------------------------------------------------------
+
+  public List<OID> getPurposeIds()
+  {
+    return Collections.unmodifiableList(purposeIds);
+  }
+
+  public String toString()
+  {
+    return ExtendedKeyUsage.class.getName() + " [ " + purposeIds + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/Extension.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,297 @@
+/* Extension.java -- an X.509 certificate or CRL extension.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.x509.Util;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+
+public class Extension
+{
+  private static final Logger log = Logger.getLogger(Extension.class.getName());
+  /**
+   * This extension's object identifier.
+   */
+  protected final OID oid;
+
+  /**
+   * The criticality flag.
+   */
+  protected final boolean critical;
+
+  /**
+   * Whether or not this extension is locally supported.
+   */
+  protected boolean isSupported;
+
+  /**
+   * The extension value.
+   */
+  protected final Value value;
+
+  /**
+   * The DER encoded form.
+   */
+  protected byte[] encoded;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public Extension(byte[] encoded) throws IOException
+  {
+    this.encoded = (byte[]) encoded.clone();
+    DERReader der = new DERReader(encoded);
+
+    // Extension ::= SEQUENCE {
+    DERValue val = der.read();
+    if (Configuration.DEBUG)
+      log.fine("read val  tag == " + val.getTag() + " len == " + val.getLength());
+    if (!val.isConstructed())
+      throw new IOException("malformed Extension");
+
+    //   extnID    OBJECT IDENTIFIER,
+    val = der.read();
+    if (val.getTag() != DER.OBJECT_IDENTIFIER)
+      throw new IOException("expecting OBJECT IDENTIFIER");
+    oid = (OID) val.getValue();
+    if (Configuration.DEBUG)
+      log.fine("read oid == " + oid);
+
+    //   critical  BOOLEAN DEFAULT FALSE,
+    val = der.read();
+    if (val.getTag() == DER.BOOLEAN)
+      {
+        critical = ((Boolean) val.getValue()).booleanValue();
+        val = der.read();
+      }
+    else
+      critical = false;
+    if (Configuration.DEBUG)
+      log.fine("is critical == " + critical);
+
+    //   extnValue OCTET STRING }
+    if (val.getTag() != DER.OCTET_STRING)
+      throw new IOException("expecting OCTET STRING");
+    byte[] encval = (byte[]) val.getValue();
+    isSupported = true;
+    if (oid.equals(AuthorityKeyIdentifier.ID))
+      {
+        value = new AuthorityKeyIdentifier(encval);
+      }
+    else if (oid.equals(SubjectKeyIdentifier.ID))
+      {
+        value = new SubjectKeyIdentifier(encval);
+      }
+    else if (oid.equals(KeyUsage.ID))
+      {
+        value = new KeyUsage(encval);
+      }
+    else if (oid.equals(PrivateKeyUsagePeriod.ID))
+      {
+        value = new PrivateKeyUsagePeriod(encval);
+      }
+    else if (oid.equals(CertificatePolicies.ID))
+      {
+        value = new CertificatePolicies(encval);
+      }
+    else if (oid.equals (PolicyConstraint.ID))
+      {
+        value = new PolicyConstraint (encval);
+      }
+    else if (oid.equals(PolicyMappings.ID))
+      {
+        value = new PolicyMappings(encval);
+      }
+    else if (oid.equals(SubjectAlternativeNames.ID))
+      {
+        value = new SubjectAlternativeNames(encval);
+      }
+    else if (oid.equals(IssuerAlternativeNames.ID))
+      {
+        value = new IssuerAlternativeNames(encval);
+      }
+    else if (oid.equals(BasicConstraints.ID))
+      {
+        value = new BasicConstraints(encval);
+      }
+    else if (oid.equals(ExtendedKeyUsage.ID))
+      {
+        value = new ExtendedKeyUsage(encval);
+      }
+    else if (oid.equals(CRLNumber.ID))
+      {
+        value = new CRLNumber(encval);
+      }
+    else if (oid.equals(ReasonCode.ID))
+      {
+        value = new ReasonCode(encval);
+      }
+    else if (oid.equals(NameConstraints.ID))
+      {
+        value = new NameConstraints(encval);
+      }
+    else
+      {
+        value = new Value(encval);
+        isSupported = false;
+      }
+    if (Configuration.DEBUG)
+      log.fine("read value == " + value);
+  }
+
+  public Extension (final OID oid, final Value value, final boolean critical)
+  {
+    this.oid = oid;
+    this.value = value;
+    this.critical = critical;
+    isSupported = true;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public OID getOid()
+  {
+    return oid;
+  }
+
+  public boolean isCritical()
+  {
+    return critical;
+  }
+
+  public boolean isSupported()
+  {
+    return isSupported;
+  }
+
+  public Value getValue()
+  {
+    return value;
+  }
+
+  public byte[] getEncoded()
+  {
+    if (encoded == null)
+      encode();
+    return (byte[]) encoded.clone();
+  }
+
+  public String toString()
+  {
+    return Extension.class.getName() + " [ id=" + oid + " critical=" +
+      critical + " value=" + value + " ]";
+  }
+
+  public DERValue getDerValue()
+  {
+    List<DERValue> ext = new ArrayList<DERValue>(3);
+    ext.add(new DERValue(DER.OBJECT_IDENTIFIER, oid));
+    ext.add(new DERValue(DER.BOOLEAN, Boolean.valueOf(critical)));
+    ext.add(new DERValue(DER.OCTET_STRING, value.getEncoded()));
+    return new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, ext);
+  }
+
+  // Own methods.
+  // -------------------------------------------------------------------------
+
+  private void encode()
+  {
+    encoded = getDerValue().getEncoded();
+  }
+
+  // Inner class.
+  // -------------------------------------------------------------------------
+
+  public static class Value
+  {
+
+    // Fields.
+    // -----------------------------------------------------------------------
+
+    protected byte[] encoded;
+
+    // Constructor.
+    // -----------------------------------------------------------------------
+
+    public Value(byte[] encoded)
+    {
+      this.encoded = (byte[]) encoded.clone();
+    }
+
+    protected Value() { }
+
+    // Instance methods.
+    // -----------------------------------------------------------------------
+
+    public byte[] getEncoded()
+    {
+      return (byte[]) encoded;
+    }
+
+    public int hashCode()
+    {
+      int result = 0;
+      for (int i = 0; i < encoded.length; ++i)
+        result = result * 31 + encoded[i];
+      return result;
+    }
+
+    public boolean equals(Object o)
+    {
+      if (!(o instanceof Value))
+        return false;
+      return Arrays.equals(encoded, ((Value) o).encoded);
+    }
+
+    public String toString()
+    {
+      return Util.toHexString(encoded, ':');
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/GeneralName.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,232 @@
+/* GeneralName.java -- a GeneralName.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.x509.Util;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * The GeneralName structure from X.509.
+ * 
+ * <pre>
+  GeneralName ::= CHOICE {
+    otherName                       [0]     OtherName,
+    rfc822Name                      [1]     IA5String,
+    dNSName                         [2]     IA5String,
+    x400Address                     [3]     ORAddress,
+    directoryName                   [4]     Name,
+    ediPartyName                    [5]     EDIPartyName,
+    uniformResourceIdentifier       [6]     IA5String,
+    iPAddress                       [7]     OCTET STRING,
+    registeredID                    [8]     OBJECT IDENTIFIER }
+
+  OtherName ::= SEQUENCE {
+    type-id    OBJECT IDENTIFIER,
+    value      [0] EXPLICIT ANY DEFINED BY type-id }
+
+  EDIPartyName ::= SEQUENCE {
+    nameAssigner            [0]     DirectoryString OPTIONAL,
+    partyName               [1]     DirectoryString }
+</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class GeneralName
+{
+  public static enum Kind
+  {
+    otherName (0),
+    rfc822Name (1),
+    dNSName (2),
+    x400Address (3),
+    directoryName (4),
+    ediPartyName (5),
+    uniformResourceIdentifier (6),
+    iPAddress (7),
+    registeredId (8);
+
+    private int tag;
+    
+    private Kind(int tag)
+    {
+      this.tag = tag;
+    }
+    
+    public static Kind forTag(final int tag)
+    {
+      switch (tag)
+      {
+        case 0: return otherName;
+        case 1: return rfc822Name;
+        case 2: return dNSName;
+        case 3: return x400Address;
+        case 4: return directoryName;
+        case 5: return ediPartyName;
+        case 6: return uniformResourceIdentifier;
+        case 7: return iPAddress;
+        case 8: return registeredId;
+      }
+      
+      throw new IllegalArgumentException("invalid tag: " + tag);
+    }
+    
+    public int tag()
+    {
+      return tag;
+    }
+  };
+
+  private final Kind kind;
+  private final byte[] name;
+  private final byte[] encoded;
+  
+  public GeneralName(byte[] encoded) throws IOException
+  {
+    DERReader reader = new DERReader(encoded);
+    DERValue value = reader.read();
+    
+    if (value.getTagClass() != DER.CONTEXT)
+      throw new IOException("malformed GeneralName");
+    
+    this.encoded = value.getEncoded();
+    
+    kind = Kind.forTag(value.getTag());
+    switch (kind)
+    {
+      case otherName:
+        name = value.getEncoded();
+        name[0] = (byte) (DER.CONSTRUCTED | DER.SEQUENCE);
+        // Skip the two fields of the name.
+        reader.read();  // OID
+        reader.read();  // Octet string
+        break;
+
+      case rfc822Name:
+        name = (byte[]) value.getValue();
+        break;
+
+      case dNSName:
+        name = (byte[]) value.getValue();
+        break;
+
+      case x400Address:
+        name = (byte[]) value.getValue();
+        break;
+
+      case directoryName:
+        name = value.getEncoded();
+        name[0] = (byte) (DER.CONSTRUCTED | DER.SEQUENCE);
+        break;
+
+      case ediPartyName:
+        name = value.getEncoded();
+        name[0] = (byte) (DER.CONSTRUCTED | DER.SEQUENCE);
+        break;
+
+      case uniformResourceIdentifier:
+        name = (byte[]) value.getValue();
+        break;
+
+      case iPAddress:
+        name = (byte[]) value.getValue();
+        break;
+
+      case registeredId:
+        name = value.getEncoded();
+        name[0] = DER.OBJECT_IDENTIFIER;
+        break;
+        
+      default:
+        name = null; // Not reached.
+    }
+  }
+  
+  public GeneralName(Kind kind, byte[] name)
+  {
+    this.kind = kind;
+    this.name = (byte[]) name.clone();
+    this.encoded = null;
+  }
+  
+  public Kind kind()
+  {
+    return kind;
+  }
+  
+  public byte[] name()
+  {
+    return (byte[]) name.clone();
+  }
+  
+  public byte[] encoded()
+  {
+    try
+      {
+        return (byte[]) encoded.clone();
+      }
+    catch (NullPointerException npe)
+      {
+        return null;
+      }
+  }
+  
+  public boolean equals(Object o)
+  {
+    try
+      {
+        GeneralName that = (GeneralName) o;
+        return (that.kind() == kind() && Arrays.equals(name, that.name));
+      }
+    catch (ClassCastException cce)
+      {
+        return false;
+      }
+  }
+  
+  public String toString()
+  {
+    return (super.toString() + " [ kind=" + kind + "; name=" +
+            Util.hexDump(name, "") + " ]");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/GeneralNames.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,89 @@
+/* GeneralNames.java -- the GeneralNames object
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+public class GeneralNames
+{
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  private List<GeneralName> names;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public GeneralNames(final byte[] encoded) throws IOException
+  {
+    names = new LinkedList<GeneralName>();
+    DERReader der = new DERReader(encoded);
+    DERValue nameList = der.read();
+    if (!nameList.isConstructed())
+      throw new IOException("malformed GeneralNames");
+    int len = 0;
+    while (len < nameList.getLength())
+      {
+        DERValue name = der.read();
+        GeneralName generalName = new GeneralName(name.getEncoded());
+        names.add(generalName);
+        len += name.getEncodedLength();
+      }
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public List<GeneralName> getNames()
+  {
+    return Collections.unmodifiableList(names);
+  }
+
+  public String toString()
+  {
+    return GeneralNames.class.getName() + " [ " + names + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/GeneralSubtree.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,156 @@
+/* GeneralSubtree.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+/**
+ * The GeneralSubtree structure, a part of the {@link NameConstraints}
+ * extension.
+ *
+ * <pre>
+  GeneralSubtree ::= SEQUENCE {
+    base                    GeneralName,
+    minimum         [0]     BaseDistance DEFAULT 0,
+    maximum         [1]     BaseDistance OPTIONAL }
+
+  BaseDistance ::= INTEGER (0..MAX)</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class GeneralSubtree
+{
+  private final GeneralName base;
+  private final int minimum;
+  private final int maximum;
+  
+  public GeneralSubtree(byte[] encoded) throws IOException
+  {
+    DERReader reader = new DERReader(encoded);
+    DERValue generalSubtree = reader.read();
+    
+    if (!generalSubtree.isConstructed())
+      throw new IOException("malformed GeneralSubtree");
+    
+    DERValue generalName = reader.read();
+    base = new GeneralName(generalName.getEncoded());
+    if (generalName.isConstructed())
+      reader.skip(generalName.getLength());
+    
+    int len = generalName.getEncodedLength();
+    if (len < generalSubtree.getLength())
+      {
+        DERValue distance = reader.read();
+        if (distance.getTag() == 0)
+          {
+            minimum = ((BigInteger) distance.getValue()).intValue();
+            len += distance.getEncodedLength();
+            if (len < generalSubtree.getLength())
+              {
+                distance = reader.read();
+                if (distance.getTag() != 1)
+                  throw new IOException("unexpected tag "
+                                        + distance.getTag() +
+                                        " (expected 1 for GeneralSubtree maximum distance)");
+                maximum = ((BigInteger) distance.getValue()).intValue();
+              }
+            else
+              {
+                maximum = -1;
+              }
+          }
+        else if (distance.getTag() == 1)
+          {
+            minimum = 1;
+            maximum = ((BigInteger) distance.getValue()).intValue();
+          }
+        else
+          {
+            throw new IOException("unexpected tag " + distance.getTag()
+                                  + " (expected 0 or 1 for GeneralSubtree distance)");
+          }
+      }
+    else
+      {
+        minimum = 0;
+        maximum = -1;
+      }
+  }
+  
+  /**
+   * Returns the base name.
+   *
+   * @return The base name.
+   */
+  public GeneralName base()
+  {
+    return base;
+  }
+  
+  /**
+   * Returns the minimum base distance, possibly zero.
+   *
+   * @return The minimum base distance.
+   */
+  public int minimum()
+  {
+    return minimum;
+  }
+  
+  /**
+   * Returns the maximum base distance, or -1 if this value was not specified.
+   *
+   * @return The maximum base distance.
+   */
+  public int maximum()
+  {
+    return maximum;
+  }
+  
+  public String toString()
+  {
+    return (GeneralSubtree.class.getName() + " [ base=" + base
+            + "; minimum=" + minimum + "; maximim=" + maximum
+            + " ]");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/IssuerAlternativeNames.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,77 @@
+/* IssuerAlternatuveNames.java -- issuer alternative names extension.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+
+import java.io.IOException;
+import java.util.List;
+
+public class IssuerAlternativeNames extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.18");
+
+  private final GeneralNames names;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public IssuerAlternativeNames(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    names = new GeneralNames(encoded);
+  }
+
+  // Instance method.
+  // -------------------------------------------------------------------------
+
+  public List<GeneralName> getNames()
+  {
+    return names.getNames();
+  }
+
+  public String toString()
+  {
+    return IssuerAlternativeNames.class.getName() + " [ " + names + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/KeyUsage.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,92 @@
+/* KeyUsage.java -- the key usage extension.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+
+public class KeyUsage extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.15");
+  public static final int DIGITAL_SIGNATURE = 0;
+  public static final int NON_REPUDIATION   = 1;
+  public static final int KEY_ENCIPHERMENT  = 2;
+  public static final int DATA_ENCIPHERMENT = 3;
+  public static final int KEY_AGREEMENT     = 4;
+  public static final int KEY_CERT_SIGN     = 5;
+  public static final int CRL_SIGN          = 6;
+  public static final int ENCIPHER_ONLY     = 7;
+  public static final int DECIPHER_ONLY     = 8;
+
+  private final BitString keyUsage;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public KeyUsage(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERValue val = DERReader.read(encoded);
+    if (val.getTag() != DER.BIT_STRING)
+      throw new IOException("malformed KeyUsage");
+    keyUsage = (BitString) val.getValue();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public BitString getKeyUsage()
+  {
+    return keyUsage;
+  }
+
+  public String toString()
+  {
+    return KeyUsage.class.getName() + " [ " + keyUsage + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/NameConstraints.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,161 @@
+/* NameConstraints.java -- the NameConstraints X.509 extension.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.x509.ext.Extension.Value;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * The NameConstraints extension. From RFC 3280, section 4.2.1.11, this
+ * extension is defined as:
+ * 
+ * <pre>
+  id-ce-nameConstraints OBJECT IDENTIFIER ::=  { id-ce 30 }
+
+  NameConstraints ::= SEQUENCE {
+    permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
+    excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
+
+  GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+
+  GeneralSubtree ::= SEQUENCE {
+    base                    GeneralName,
+    minimum         [0]     BaseDistance DEFAULT 0,
+    maximum         [1]     BaseDistance OPTIONAL }
+
+  BaseDistance ::= INTEGER (0..MAX)
+  </pre>
+ * 
+ * See also the classes {@link GeneralNames} and {@link GeneralSubtree}.
+ * 
+ * @author csm
+ */
+public class NameConstraints extends Value
+{
+  public static final OID ID = new OID("2.5.29.30");
+  
+  private List<GeneralSubtree> permittedSubtrees;
+  private List<GeneralSubtree> excludedSubtrees;
+  
+  public NameConstraints(byte[] encoded) throws IOException
+  {
+    super(encoded);
+    
+    DERReader der = new DERReader(encoded);
+    DERValue value = der.read();
+    if (!value.isConstructed())
+      {
+        throw new IOException("malformed NameConstraints");
+      }
+    
+    permittedSubtrees = new LinkedList<GeneralSubtree>();
+    excludedSubtrees = new LinkedList<GeneralSubtree>();
+    int len = 0;
+    if (len < value.getLength())
+      {
+        DERValue subtrees = der.read();
+        if (subtrees.getTag() == 0)
+          {
+            int len2 = 0;
+            while (len2 < subtrees.getLength())
+              {
+                DERValue subtree = der.read();
+                permittedSubtrees.add(new GeneralSubtree(subtree.getEncoded()));
+                der.skip(subtree.getLength());
+                len2 += subtree.getEncodedLength();
+              }
+            len += subtrees.getEncodedLength();
+            
+            if (len < value.getLength())
+              {
+                subtrees = der.read();
+                if (subtrees.getTag() != 1)
+                  throw new IOException("unexpected tag " + subtrees.getTag()
+                                        + " (expecting 1 for excludedSubtrees)");
+                len2 = 0;
+                while (len2 < subtrees.getLength())
+                  {
+                    DERValue subtree = der.read();
+                    excludedSubtrees.add(new GeneralSubtree(subtree.getEncoded()));
+                    der.skip(subtree.getLength());
+                    len2 += subtree.getEncodedLength();
+                  }
+              }
+          }
+        else if (subtrees.getTag() == 1)
+          {
+            int len2 = 0;
+            while (len2 < subtrees.getLength())
+              {
+                DERValue subtree = der.read();
+                excludedSubtrees.add(new GeneralSubtree(subtree.getEncoded()));
+                der.skip(subtree.getLength());
+                len2 += subtree.getEncodedLength();
+              }            
+          }
+        else
+          throw new IOException("unexpected tag " + subtrees.getTag()
+                                + " (expecting 0 or 1)");
+      }
+  }
+  
+  public List<GeneralSubtree> permittedSubtrees()
+  {
+    return Collections.unmodifiableList(permittedSubtrees);
+  }
+  
+  public List<GeneralSubtree> excludedSubtrees()
+  {
+    return Collections.unmodifiableList(excludedSubtrees);
+  }
+  
+  public String toString()
+  {
+    return NameConstraints.class.getName() + " [ permittedSubtrees="
+      + permittedSubtrees + "; excludedSubtrees=" + excludedSubtrees
+      + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/PolicyConstraint.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,107 @@
+/* PolicyConstraint.java -- policyConstraint extension
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public class PolicyConstraint extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID ("2.5.29.36");
+
+  private final int requireExplicitPolicy;
+  private final int inhibitPolicyMapping;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public PolicyConstraint (final byte[] encoded) throws IOException
+  {
+    super (encoded);
+    int rpc = -1, ipm = -1;
+    DERReader der = new DERReader(encoded);
+    DERValue pc = der.read();
+    if (!pc.isConstructed())
+      throw new IOException("malformed PolicyConstraints");
+    DERValue val;
+    int len = pc.getLength();
+    while (len > 0)
+      {
+        val = der.read();
+        if (val.getTag() == 0)
+          rpc = new BigInteger ((byte[]) val.getValue()).intValue();
+        else if (val.getTag() == 1)
+          ipm = new BigInteger ((byte[]) val.getValue()).intValue();
+        else
+          throw new IOException ("invalid policy constraint");
+        len -= val.getEncodedLength();
+      }
+
+    requireExplicitPolicy = rpc;
+    inhibitPolicyMapping = ipm;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public int getRequireExplicitPolicy()
+  {
+    return requireExplicitPolicy;
+  }
+
+  public int getInhibitPolicyMapping()
+  {
+    return inhibitPolicyMapping;
+  }
+
+  public String toString()
+  {
+    return PolicyConstraint.class.getName() + " [ requireExplicitPolicy=" +
+      requireExplicitPolicy + " inhibitPolicyMapping=" + inhibitPolicyMapping
+      + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/PolicyMappings.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,104 @@
+/* PolicyMappings.java -- policy mappings extension.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class PolicyMappings extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.33");
+
+  private final Map mappings;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public PolicyMappings(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERReader der = new DERReader(encoded);
+    DERValue maps = der.read();
+    if (!maps.isConstructed())
+      throw new IOException("malformed PolicyMappings");
+    int len = 0;
+    HashMap _mappings = new HashMap();
+    while (len < maps.getLength())
+      {
+        DERValue map = der.read();
+        if (!map.isConstructed())
+          throw new IOException("malformed PolicyMapping");
+        DERValue val = der.read();
+        if (val.getTag() != DER.OBJECT_IDENTIFIER)
+          throw new IOException("malformed PolicyMapping");
+        OID issuerPolicy = (OID) val.getValue();
+        val = der.read();
+        if (val.getTag() != DER.OBJECT_IDENTIFIER)
+          throw new IOException("malformed PolicyMapping");
+        OID subjectPolicy = (OID) val.getValue();
+        _mappings.put(issuerPolicy, subjectPolicy);
+        len += map.getEncodedLength();
+      }
+    mappings = Collections.unmodifiableMap(_mappings);
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public OID getSubjectDomainPolicy(OID issuerDomainPolicy)
+  {
+    return (OID) mappings.get(issuerDomainPolicy);
+  }
+
+  public String toString()
+  {
+    return PolicyMappings.class.getName() + " [ " + mappings + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,105 @@
+/* PrivateKeyUsagePeriod.java -- private key usage period extension.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.util.Date;
+
+public class PrivateKeyUsagePeriod extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.16");
+
+  private final Date notBefore;
+  private final Date notAfter;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public PrivateKeyUsagePeriod(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERReader der = new DERReader(encoded);
+    DERValue val = der.read();
+    if (!val.isConstructed())
+      throw new IOException("malformed PrivateKeyUsagePeriod");
+    if (val.getLength() > 0)
+      val = der.read();
+    if (val.getTagClass() == DER.APPLICATION || val.getTag() == 0)
+      {
+        notBefore = (Date) val.getValueAs (DER.GENERALIZED_TIME);
+        val = der.read();
+      }
+    else
+      notBefore = null;
+    if (val.getTagClass() == DER.APPLICATION || val.getTag() == 1)
+      {
+        notAfter = (Date) val.getValueAs (DER.GENERALIZED_TIME);
+      }
+    else
+      notAfter = null;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public Date getNotBefore()
+  {
+    return notBefore != null ? (Date) notBefore.clone() : null;
+  }
+
+  public Date getNotAfter()
+  {
+    return notAfter != null ? (Date) notAfter.clone() : null;
+  }
+
+  public String toString()
+  {
+    return PrivateKeyUsagePeriod.class.getName() + " [ notBefore=" + notBefore
+      + " notAfter=" + notAfter + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/ReasonCode.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,85 @@
+/* ReasonCode.java -- a reason code for a certificate revocation.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public class ReasonCode extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.21");
+
+  public final int reason;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public ReasonCode(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERValue val = DERReader.read(encoded);
+    if (val.getTag() != DER.ENUMERATED)
+      throw new IOException("malformed CRLReason");
+    reason = ((BigInteger) val.getValue()).intValue();
+    if (reason < 0 || reason == 7 || reason > 10)
+      throw new IOException("illegal reason: " + reason);
+  }
+
+  // Instance method.
+  // -------------------------------------------------------------------------
+
+  public int getReasonCode()
+  {
+    return reason;
+  }
+
+  public String toString()
+  {
+    return ReasonCode.class.getName() + " [ " + reason + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/SubjectAlternativeNames.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,77 @@
+/* SubjectAlternatuveNames.java -- subject alternative names extension.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+
+import java.io.IOException;
+import java.util.List;
+
+public class SubjectAlternativeNames extends Extension.Value
+{
+
+  // Constants and fields.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.17");
+
+  private final GeneralNames names;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public SubjectAlternativeNames(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    names = new GeneralNames(encoded);
+  }
+
+  // Instance method.
+  // -------------------------------------------------------------------------
+
+  public List<GeneralName> getNames()
+  {
+    return names.getNames();
+  }
+
+  public String toString()
+  {
+    return SubjectAlternativeNames.class.getName() + " [ " + names + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/SubjectKeyIdentifier.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,84 @@
+/* SubjectKeyIdentifier.java -- subject key identifier extension.
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.x509.ext;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.x509.Util;
+
+import java.io.IOException;
+
+public class SubjectKeyIdentifier extends Extension.Value
+{
+
+  // Constant.
+  // -------------------------------------------------------------------------
+
+  public static final OID ID = new OID("2.5.29.14");
+
+  private final byte[] keyIdentifier;
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public SubjectKeyIdentifier(final byte[] encoded) throws IOException
+  {
+    super(encoded);
+    DERValue val = DERReader.read(encoded);
+    if (val.getTag() != DER.OCTET_STRING)
+      throw new IOException("malformed SubjectKeyIdentifier");
+    keyIdentifier = (byte[]) val.getValue();
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  public byte[] getKeyIdentifier()
+  {
+    return (byte[]) keyIdentifier.clone();
+  }
+
+  public String toString()
+  {
+    return SubjectKeyIdentifier.class.getName() + " [ " +
+      Util.toHexString (keyIdentifier, ':') + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/ext/package.html	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.x509.ext package.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.security.x509.ext</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/java/security/x509/package.html	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.x509 package.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.security.x509</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/RSACipherImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,299 @@
+/* RSACipherImpl.java --
+   Copyright (C) 2005, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.sig.rsa.EME_PKCS1_V1_5;
+import gnu.java.security.util.ByteArray;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+
+public class RSACipherImpl
+    extends CipherSpi
+{
+  private static final SystemLogger logger = SystemLogger.SYSTEM;
+
+  private static final byte[] EMPTY = new byte[0];
+  private int opmode = -1;
+  private RSAPrivateKey decipherKey = null;
+  private RSAPublicKey blindingKey = null;
+  private RSAPublicKey encipherKey = null;
+  private SecureRandom random = null;
+  private byte[] dataBuffer = null;
+  private int pos = 0;
+
+  protected void engineSetMode(String mode) throws NoSuchAlgorithmException
+  {
+    throw new NoSuchAlgorithmException("only one mode available");
+  }
+
+  protected void engineSetPadding(String pad) throws NoSuchPaddingException
+  {
+    throw new NoSuchPaddingException("only one padding available");
+  }
+
+  protected int engineGetBlockSize()
+  {
+    return 1;
+  }
+
+  protected int engineGetOutputSize(int inputLen)
+  {
+    int outputLen = 0;
+    if (decipherKey != null)
+      outputLen = (decipherKey.getModulus().bitLength() + 7) / 8;
+    else if (encipherKey != null)
+      outputLen = (encipherKey.getModulus().bitLength() + 7) / 8;
+    else
+      throw new IllegalStateException("not initialized");
+    if (inputLen > outputLen)
+      throw new IllegalArgumentException("not configured to encode " + inputLen
+                                         + "bytes; at most " + outputLen);
+    return outputLen;
+  }
+
+  protected int engineGetKeySize(final Key key) throws InvalidKeyException
+  {
+    if (! (key instanceof RSAKey))
+      throw new InvalidKeyException("not an RSA key");
+    return ((RSAKey) key).getModulus().bitLength();
+  }
+
+  protected byte[] engineGetIV()
+  {
+    return null;
+  }
+
+  protected AlgorithmParameters engineGetParameters()
+  {
+    return null;
+  }
+
+  protected void engineInit(int opmode, Key key, SecureRandom random)
+      throws InvalidKeyException
+  {
+    int outputLen = 0;
+    if (opmode == Cipher.ENCRYPT_MODE)
+      {
+        if (! (key instanceof RSAPublicKey))
+          throw new InvalidKeyException("expecting a RSAPublicKey");
+        encipherKey = (RSAPublicKey) key;
+        decipherKey = null;
+        blindingKey = null;
+        outputLen = (encipherKey.getModulus().bitLength() + 7) / 8;
+      }
+    else if (opmode == Cipher.DECRYPT_MODE)
+      {
+        if (key instanceof RSAPrivateKey)
+          {
+            decipherKey = (RSAPrivateKey) key;
+            encipherKey = null;
+            blindingKey = null;
+            outputLen = (decipherKey.getModulus().bitLength() + 7) / 8;
+          }
+        else if (key instanceof RSAPublicKey)
+          {
+            if (decipherKey == null)
+              throw new IllegalStateException("must configure decryption key first");
+            if (! decipherKey.getModulus().equals(((RSAPublicKey) key).getModulus()))
+              throw new InvalidKeyException("blinding key is not compatible");
+            blindingKey = (RSAPublicKey) key;
+            return;
+          }
+        else
+          throw new InvalidKeyException(
+              "expecting either an RSAPrivateKey or an RSAPublicKey (for blinding)");
+      }
+    else
+      throw new IllegalArgumentException("only encryption and decryption supported");
+    this.random = random;
+    this.opmode = opmode;
+    pos = 0;
+    dataBuffer = new byte[outputLen];
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameterSpec spec,
+                            SecureRandom random) throws InvalidKeyException
+  {
+    engineInit(opmode, key, random);
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+                            SecureRandom random) throws InvalidKeyException
+  {
+    engineInit(opmode, key, random);
+  }
+
+  protected byte[] engineUpdate(byte[] in, int offset, int length)
+  {
+    if (opmode != Cipher.ENCRYPT_MODE && opmode != Cipher.DECRYPT_MODE)
+      throw new IllegalStateException("not initialized");
+    System.arraycopy(in, offset, dataBuffer, pos, length);
+    pos += length;
+    return EMPTY;
+  }
+
+  protected int engineUpdate(byte[] in, int offset, int length, byte[] out,
+                             int outOffset)
+  {
+    engineUpdate(in, offset, length);
+    return 0;
+  }
+
+  protected byte[] engineDoFinal(byte[] in, int offset, int length)
+      throws IllegalBlockSizeException, BadPaddingException
+  {
+    engineUpdate(in, offset, length);
+    if (opmode == Cipher.DECRYPT_MODE)
+      {
+        BigInteger enc = new BigInteger (1, dataBuffer);
+        byte[] dec = rsaDecrypt (enc);
+        logger.log (Component.CRYPTO, "RSA: decryption produced\n{0}",
+                    new ByteArray (dec));
+        EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(decipherKey);
+        byte[] result = pkcs.decode(dec);
+        return result;
+      }
+    else
+      {
+        offset = dataBuffer.length - pos;
+        if (offset < 3)
+          throw new IllegalBlockSizeException("input is too large to encrypt");
+        EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(encipherKey);
+        if (random == null)
+          random = new SecureRandom();
+        byte[] em = new byte[pos];
+        System.arraycopy(dataBuffer, 0, em, 0, pos);
+        byte[] dec = pkcs.encode(em, random);
+        logger.log (Component.CRYPTO, "RSA: produced padded plaintext\n{0}",
+                    new ByteArray (dec));
+        BigInteger x = new BigInteger (1, dec);
+        BigInteger y = x.modPow (encipherKey.getPublicExponent (),
+                                 encipherKey.getModulus ());
+        byte[] enc = y.toByteArray ();
+        if (enc[0] == 0x00)
+          {
+            byte[] tmp = new byte[enc.length - 1];
+            System.arraycopy(enc, 1, tmp, 0, tmp.length);
+            enc = tmp;
+          }
+        pos = 0;
+        return enc;
+      }
+  }
+
+  protected int engineDoFinal(byte[] out, int offset)
+      throws ShortBufferException, IllegalBlockSizeException,
+      BadPaddingException
+  {
+    byte[] result = engineDoFinal(EMPTY, 0, 0);
+    if (out.length - offset < result.length)
+      throw new ShortBufferException("need " + result.length + ", have "
+                                     + (out.length - offset));
+    System.arraycopy(result, 0, out, offset, result.length);
+    return result.length;
+  }
+
+  protected int engineDoFinal(final byte[] input, final int offset,
+                              final int length, final byte[] output,
+                              final int outputOffset)
+      throws ShortBufferException, IllegalBlockSizeException,
+      BadPaddingException
+  {
+    byte[] result = engineDoFinal(input, offset, length);
+    if (output.length - outputOffset < result.length)
+      throw new ShortBufferException("need " + result.length + ", have "
+                                     + (output.length - outputOffset));
+    System.arraycopy(result, 0, output, outputOffset, result.length);
+    return result.length;
+  }
+
+  /**
+   * Decrypts the ciphertext, employing RSA blinding if possible.
+   */
+  private byte[] rsaDecrypt(BigInteger enc)
+  {
+    if (random == null)
+      random = new SecureRandom();
+    BigInteger n = decipherKey.getModulus();
+    BigInteger r = null;
+    BigInteger pubExp = null;
+    if (blindingKey != null)
+      pubExp = blindingKey.getPublicExponent();
+    if (pubExp != null && (decipherKey instanceof RSAPrivateCrtKey))
+      pubExp = ((RSAPrivateCrtKey) decipherKey).getPublicExponent();
+    if (pubExp != null)
+      {
+        r = new BigInteger(n.bitLength() - 1, random);
+        enc = r.modPow(pubExp, n).multiply(enc).mod(n);
+      }
+    BigInteger dec = enc.modPow(decipherKey.getPrivateExponent(), n);
+    if (pubExp != null)
+      {
+        dec = dec.multiply (r.modInverse (n)).mod (n);
+      }
+
+    byte[] decb = dec.toByteArray();
+    if (decb[0] != 0x00)
+      {
+        byte[] b = new byte[decb.length + 1];
+        System.arraycopy(decb, 0, b, 1, decb.length);
+        decb = b;
+      }
+    return decb;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/Assembly.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,272 @@
+/* Assembly.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import java.util.Map;
+
+/**
+ * An <code>Assembly</code> is a construction consisting of a chain of
+ * {@link Transformer} elements; each wired in pre- or post- transformation
+ * mode. This chain is terminated by one <code>LoopbackTransformer</code>
+ * element.
+ * <p>
+ * Once constructed, and correctly initialised, the bulk of the methods
+ * available on the <code>Assembly</code> are delegated to the <i>head</i> of
+ * the {@link Transformer} chain of the <code>Assembly</code>.
+ * 
+ * @see Transformer
+ */
+public class Assembly
+{
+  public static final String DIRECTION = "gnu.crypto.assembly.assembly.direction";
+
+  /** Flag that tells if the instance is initialised or not; and if yes how. */
+  private Direction wired;
+
+  /** The first Transformer in the chain. */
+  private Transformer head;
+
+  /**
+   * Trivial constructor that sets the <i>chain</i> to a
+   * <code>LoopbackTransformer</code>.
+   */
+  public Assembly()
+  {
+    super();
+
+    wired = null;
+    head = new LoopbackTransformer();
+  }
+
+  /**
+   * Adds the designated {@link Transformer} and signals that it should operate
+   * in pre-processing mode; i.e. it should apply its internal transformation
+   * algorithm on the input data stream, <b>before</b> it passes that stream to
+   * the next element in the <i>chain</i>.
+   * 
+   * @param t the {@link Transformer} to add at the head of the current chain.
+   * @throws IllegalArgumentException if the designated {@link Transformer} has
+   *           a non-null tail; i.e. it is already an element of a chain.
+   */
+  public void addPreTransformer(Transformer t)
+  {
+    wireTransformer(t, Operation.PRE_PROCESSING);
+  }
+
+  /**
+   * Adds the designated {@link Transformer} and signals that it should operate
+   * in post-processing mode; i.e. it should apply its internal transformation
+   * algorithm on the input data stream, <b>after</b> it passes that stream to
+   * the next element in the <i>chain</i>.
+   * 
+   * @param t the {@link Transformer} to add at the head of the current chain.
+   * @throws IllegalArgumentException if the designated {@link Transformer} has
+   *           a non-null tail; i.e. it is already an element of a chain.
+   */
+  public void addPostTransformer(Transformer t)
+  {
+    wireTransformer(t, Operation.POST_PROCESSING);
+  }
+
+  /**
+   * Initialises the <code>Assembly</code> for operation with specific
+   * characteristics.
+   * 
+   * @param attributes a set of name-value pairs that describes the desired
+   *          future behaviour of this instance.
+   * @throws IllegalStateException if the instance is already initialised.
+   */
+  public void init(Map attributes) throws TransformerException
+  {
+    if (wired != null)
+      throw new IllegalStateException();
+    Direction flow = (Direction) attributes.get(DIRECTION);
+    if (flow == null)
+      flow = Direction.FORWARD;
+    attributes.put(Transformer.DIRECTION, flow);
+    head.init(attributes);
+    wired = flow;
+  }
+
+  /**
+   * Resets the <code>Assembly</code> for re-initialisation and use with other
+   * characteristics. This method always succeeds.
+   */
+  public void reset()
+  {
+    head.reset();
+    wired = null;
+  }
+
+  /**
+   * Convenience method that calls the method with same name and three
+   * arguments, using a byte array of length <code>1</code> whose contents are
+   * the designated byte.
+   * 
+   * @param b the byte to process.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #update(byte[], int, int)
+   */
+  public byte[] update(byte b) throws TransformerException
+  {
+    return update(new byte[] { b }, 0, 1);
+  }
+
+  /**
+   * Convenience method that calls the method with same name and three
+   * arguments. All bytes in <code>in</code>, starting from index position
+   * <code>0</code> are considered.
+   * 
+   * @param in the input data bytes.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #update(byte[], int, int)
+   */
+  public byte[] update(byte[] in) throws TransformerException
+  {
+    return update(in, 0, in.length);
+  }
+
+  /**
+   * Processes a designated number of bytes from a given byte array.
+   * 
+   * @param in the input data bytes.
+   * @param offset index of <code>in</code> from which to start considering
+   *          data.
+   * @param length the count of bytes to process.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   */
+  public byte[] update(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    if (wired == null)
+      throw new IllegalStateException();
+    return head.update(in, offset, length);
+  }
+
+  /**
+   * Convenience method that calls the method with same name and three arguments
+   * using a 0-long byte array.
+   * 
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #lastUpdate(byte[], int, int)
+   */
+  public byte[] lastUpdate() throws TransformerException
+  {
+    return lastUpdate(new byte[0], 0, 0);
+  }
+
+  /**
+   * Convenience method that calls the method with same name and three
+   * arguments, using a byte array of length <code>1</code> whose contents are
+   * the designated byte.
+   * 
+   * @param b the byte to process.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #lastUpdate(byte[], int, int)
+   */
+  public byte[] lastUpdate(byte b) throws TransformerException
+  {
+    return lastUpdate(new byte[] { b }, 0, 1);
+  }
+
+  /**
+   * Convenience method that calls the method with same name and three
+   * arguments. All bytes in <code>in</code>, starting from index position
+   * <code>0</code> are considered.
+   * 
+   * @param in the input data bytes.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #lastUpdate(byte[], int, int)
+   */
+  public byte[] lastUpdate(byte[] in) throws TransformerException
+  {
+    return lastUpdate(in, 0, in.length);
+  }
+
+  /**
+   * Processes a designated number of bytes from a given byte array and signals,
+   * at the same time, that this is the last <i>push</i> operation for this
+   * <code>Assembly</code>.
+   * 
+   * @param in the input data bytes.
+   * @param offset index of <code>in</code> from which to start considering
+   *          data.
+   * @param length the count of bytes to process.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   */
+  public byte[] lastUpdate(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    if (wired == null)
+      throw new IllegalStateException();
+    byte[] result = head.lastUpdate(in, offset, length);
+    reset();
+    return result;
+  }
+
+  private void wireTransformer(Transformer t, Operation mode)
+  {
+    if (t.tail != null)
+      throw new IllegalArgumentException();
+    t.setMode(mode);
+    t.tail = head;
+    head = t;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/Cascade.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,348 @@
+/* Cascade.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A <i>Cascade</i> Cipher is the concatenation of two or more block ciphers
+ * each with independent keys. Plaintext is input to the first stage; the output
+ * of stage <code>i</code> is input to stage <code>i + 1</code>; and the
+ * output of the last stage is the <i>Cascade</i>'s ciphertext output.
+ * <p>
+ * In the simplest case, all stages in a <code>Cascade</code> have <i>k</i>-bit
+ * keys, and the stage inputs and outputs are all n-bit quantities. The stage
+ * ciphers may differ (general cascade of ciphers), or all be identical (cascade
+ * of identical ciphers).
+ * <p>
+ * The term "block ciphers" used above refers to implementations of
+ * {@link gnu.javax.crypto.mode.IMode}, including the
+ * {@link gnu.javax.crypto.mode.ECB} mode which basically exposes a
+ * symmetric-key block cipher algorithm as a <i>Mode</i> of Operations.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+public class Cascade
+{
+  public static final String DIRECTION = "gnu.crypto.assembly.cascade.direction";
+
+  /** The map of Stages chained in this cascade. */
+  protected HashMap stages;
+
+  /** The ordered list of Stage UIDs to their attribute maps. */
+  protected LinkedList stageKeys;
+
+  /** The current operational direction of this instance. */
+  protected Direction wired;
+
+  /** The curently set block-size for this instance. */
+  protected int blockSize;
+
+  public Cascade()
+  {
+    super();
+
+    stages = new HashMap(3);
+    stageKeys = new LinkedList();
+    wired = null;
+    blockSize = 0;
+  }
+
+  /**
+   * Returns the Least Common Multiple of two integers.
+   * 
+   * @param a the first integer.
+   * @param b the second integer.
+   * @return the LCM of <code>abs(a)</code> and <code>abs(b)</code>.
+   */
+  private static final int lcm(int a, int b)
+  {
+    BigInteger A = BigInteger.valueOf(a * 1L);
+    BigInteger B = BigInteger.valueOf(b * 1L);
+    return A.multiply(B).divide(A.gcd(B)).abs().intValue();
+  }
+
+  /**
+   * Adds to the end of the current chain, a designated {@link Stage}.
+   * 
+   * @param stage the {@link Stage} to append to the chain.
+   * @return a unique identifier for this stage, within this cascade.
+   * @throws IllegalStateException if the instance is already initialised.
+   * @throws IllegalArgumentException if the designated stage is already in the
+   *           chain, or it has incompatible characteristics with the current
+   *           elements already in the chain.
+   */
+  public Object append(Stage stage) throws IllegalArgumentException
+  {
+    return insert(size(), stage);
+  }
+
+  /**
+   * Adds to the begining of the current chain, a designated {@link Stage}.
+   * 
+   * @param stage the {@link Stage} to prepend to the chain.
+   * @return a unique identifier for this stage, within this cascade.
+   * @throws IllegalStateException if the instance is already initialised.
+   * @throws IllegalArgumentException if the designated stage is already in the
+   *           chain, or it has incompatible characteristics with the current
+   *           elements already in the chain.
+   */
+  public Object prepend(Stage stage) throws IllegalArgumentException
+  {
+    return insert(0, stage);
+  }
+
+  /**
+   * Inserts a {@link Stage} into the current chain, at the specified index
+   * (zero-based) position.
+   * 
+   * @param stage the {@link Stage} to insert into the chain.
+   * @return a unique identifier for this stage, within this cascade.
+   * @throws IllegalArgumentException if the designated stage is already in the
+   *           chain, or it has incompatible characteristics with the current
+   *           elements already in the chain.
+   * @throws IllegalStateException if the instance is already initialised.
+   * @throws IndexOutOfBoundsException if <code>index</code> is less than
+   *           <code>0</code> or greater than the current size of this
+   *           cascade.
+   */
+  public Object insert(int index, Stage stage) throws IllegalArgumentException,
+      IndexOutOfBoundsException
+  {
+    if (stages.containsValue(stage))
+      throw new IllegalArgumentException();
+    if (wired != null || stage == null)
+      throw new IllegalStateException();
+    if (index < 0 || index > size())
+      throw new IndexOutOfBoundsException();
+    // check that there is a non-empty set of common block-sizes
+    Set set = stage.blockSizes();
+    if (stages.isEmpty())
+      {
+        if (set.isEmpty())
+          throw new IllegalArgumentException("1st stage with no block sizes");
+      }
+    else
+      {
+        Set common = this.blockSizes();
+        common.retainAll(set);
+        if (common.isEmpty())
+          throw new IllegalArgumentException("no common block sizes found");
+      }
+    Object result = new Object();
+    stageKeys.add(index, result);
+    stages.put(result, stage);
+    return result;
+  }
+
+  /**
+   * Returns the current number of stages in this chain.
+   * 
+   * @return the current count of stages in this chain.
+   */
+  public int size()
+  {
+    return stages.size();
+  }
+
+  /**
+   * Returns an {@link Iterator} over the stages contained in this instance.
+   * Each element of this iterator is a concrete implementation of a {@link
+   * Stage}.
+   * 
+   * @return an {@link Iterator} over the stages contained in this instance.
+   *         Each element of the returned iterator is a concrete instance of a
+   *         {@link Stage}.
+   */
+  public Iterator stages()
+  {
+    LinkedList result = new LinkedList();
+    for (Iterator it = stageKeys.listIterator(); it.hasNext();)
+      result.addLast(stages.get(it.next()));
+    return result.listIterator();
+  }
+
+  /**
+   * Returns the {@link Set} of supported block sizes for this
+   * <code>Cascade</code> that are common to all of its chained stages. Each
+   * element in the returned {@link Set} is an instance of {@link Integer}.
+   * 
+   * @return a {@link Set} of supported block sizes common to all the stages of
+   *         the chain.
+   */
+  public Set blockSizes()
+  {
+    HashSet result = null;
+    for (Iterator it = stages.values().iterator(); it.hasNext();)
+      {
+        Stage aStage = (Stage) it.next();
+        if (result == null) // first time
+          result = new HashSet(aStage.blockSizes());
+        else
+          result.retainAll(aStage.blockSizes());
+      }
+    return result == null ? Collections.EMPTY_SET : result;
+  }
+
+  /**
+   * Initialises the chain for operation with specific characteristics.
+   * 
+   * @param attributes a set of name-value pairs that describes the desired
+   *          future behaviour of this instance.
+   * @throws IllegalStateException if the chain, or any of its stages, is
+   *           already initialised.
+   * @throws InvalidKeyException if the intialisation data provided with the
+   *           stage is incorrect or causes an invalid key to be generated.
+   * @see Direction#FORWARD
+   * @see Direction#REVERSED
+   */
+  public void init(Map attributes) throws InvalidKeyException
+  {
+    if (wired != null)
+      throw new IllegalStateException();
+    Direction flow = (Direction) attributes.get(DIRECTION);
+    if (flow == null)
+      flow = Direction.FORWARD;
+    int optimalSize = 0;
+    for (Iterator it = stageKeys.listIterator(); it.hasNext();)
+      {
+        Object id = it.next();
+        Map attr = (Map) attributes.get(id);
+        attr.put(Stage.DIRECTION, flow);
+        Stage stage = (Stage) stages.get(id);
+        stage.init(attr);
+        optimalSize = optimalSize == 0 ? stage.currentBlockSize()
+                                       : lcm(optimalSize,
+                                             stage.currentBlockSize());
+      }
+    if (flow == Direction.REVERSED) // reverse order
+      Collections.reverse(stageKeys);
+    wired = flow;
+    blockSize = optimalSize;
+  }
+
+  /**
+   * Returns the currently set block size for the chain.
+   * 
+   * @return the current block size for the chain.
+   * @throws IllegalStateException if the instance is not initialised.
+   */
+  public int currentBlockSize()
+  {
+    if (wired == null)
+      throw new IllegalStateException();
+    return blockSize;
+  }
+
+  /**
+   * Resets the chain for re-initialisation and use with other characteristics.
+   * This method always succeeds.
+   */
+  public void reset()
+  {
+    for (Iterator it = stageKeys.listIterator(); it.hasNext();)
+      ((Stage) stages.get(it.next())).reset();
+    if (wired == Direction.REVERSED) // reverse it back
+      Collections.reverse(stageKeys);
+    wired = null;
+    blockSize = 0;
+  }
+
+  /**
+   * Processes exactly one block of <i>plaintext</i> (if initialised in the
+   * {@link Direction#FORWARD} state) or <i>ciphertext</i> (if initialised in
+   * the {@link Direction#REVERSED} state).
+   * 
+   * @param in the plaintext.
+   * @param inOffset index of <code>in</code> from which to start considering
+   *          data.
+   * @param out the ciphertext.
+   * @param outOffset index of <code>out</code> from which to store result.
+   * @throws IllegalStateException if the instance is not initialised.
+   */
+  public void update(byte[] in, int inOffset, byte[] out, int outOffset)
+  {
+    if (wired == null)
+      throw new IllegalStateException();
+    int stageBlockSize, j, i = stages.size();
+    for (Iterator it = stageKeys.listIterator(); it.hasNext();)
+      {
+        Stage stage = (Stage) stages.get(it.next());
+        stageBlockSize = stage.currentBlockSize();
+        for (j = 0; j < blockSize; j += stageBlockSize)
+          stage.update(in, inOffset + j, out, outOffset + j);
+        i--;
+        if (i > 0)
+          System.arraycopy(out, outOffset, in, inOffset, blockSize);
+      }
+  }
+
+  /**
+   * Conducts a simple <i>correctness</i> test that consists of basic symmetric
+   * encryption / decryption test(s) for all supported block and key sizes of
+   * underlying block cipher(s) wrapped by Mode leafs. The test also includes
+   * one (1) variable key Known Answer Test (KAT) for each block cipher.
+   * 
+   * @return <code>true</code> if the implementation passes simple
+   *         <i>correctness</i> tests. Returns <code>false</code> otherwise.
+   */
+  public boolean selfTest()
+  {
+    for (Iterator it = stageKeys.listIterator(); it.hasNext();)
+      {
+        if (! ((Stage) stages.get(it.next())).selfTest())
+          return false;
+      }
+    return true;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/CascadeStage.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,93 @@
+/* CascadeStage.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import java.security.InvalidKeyException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A Cascade <i>Stage</i> in a Cascade Cipher.
+ */
+class CascadeStage
+    extends Stage
+{
+  private Cascade delegate;
+
+  CascadeStage(Cascade cascade, Direction forwardDirection)
+  {
+    super(forwardDirection);
+
+    this.delegate = cascade;
+  }
+
+  public Set blockSizes()
+  {
+    return Collections.unmodifiableSet(delegate.blockSizes());
+  }
+
+  void initDelegate(Map attributes) throws InvalidKeyException
+  {
+    Direction flow = (Direction) attributes.get(DIRECTION);
+    attributes.put(DIRECTION, flow.equals(forward) ? forward
+                                                   : Direction.reverse(forward));
+    delegate.init(attributes);
+  }
+
+  public int currentBlockSize() throws IllegalStateException
+  {
+    return delegate.currentBlockSize();
+  }
+
+  void resetDelegate()
+  {
+    delegate.reset();
+  }
+
+  void updateDelegate(byte[] in, int inOffset, byte[] out, int outOffset)
+  {
+    delegate.update(in, inOffset, out, outOffset);
+  }
+
+  public boolean selfTest()
+  {
+    return delegate.selfTest();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/CascadeTransformer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,123 @@
+/* CascadeTransformer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import java.security.InvalidKeyException;
+import java.util.Map;
+
+/**
+ * An Adapter to use any {@link Cascade} as a {@link Transformer} in an
+ * {@link Assembly}.
+ */
+class CascadeTransformer
+    extends Transformer
+{
+  private Cascade delegate;
+
+  private int blockSize;
+
+  CascadeTransformer(Cascade delegate)
+  {
+    super();
+
+    this.delegate = delegate;
+  }
+
+  void initDelegate(Map attributes) throws TransformerException
+  {
+    attributes.put(Cascade.DIRECTION, wired);
+    try
+      {
+        delegate.init(attributes);
+      }
+    catch (InvalidKeyException x)
+      {
+        throw new TransformerException("initDelegate()", x);
+      }
+    blockSize = delegate.currentBlockSize();
+  }
+
+  int delegateBlockSize()
+  {
+    return blockSize;
+  }
+
+  void resetDelegate()
+  {
+    delegate.reset();
+    blockSize = 0;
+  }
+
+  byte[] updateDelegate(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    byte[] result = updateInternal(in, offset, length);
+    return result;
+  }
+
+  byte[] lastUpdateDelegate() throws TransformerException
+  {
+    if (inBuffer.size() != 0)
+      {
+        IllegalStateException cause = new IllegalStateException(
+            "Cascade transformer, after last update, must be empty but isn't");
+        throw new TransformerException("lastUpdateDelegate()", cause);
+      }
+    return new byte[0];
+  }
+
+  private byte[] updateInternal(byte[] in, int offset, int length)
+  {
+    byte[] result;
+    for (int i = 0; i < length; i++)
+      {
+        inBuffer.write(in[offset++] & 0xFF);
+        if (inBuffer.size() >= blockSize)
+          {
+            result = inBuffer.toByteArray();
+            inBuffer.reset();
+            delegate.update(result, 0, result, 0);
+            outBuffer.write(result, 0, blockSize);
+          }
+      }
+    result = outBuffer.toByteArray();
+    outBuffer.reset();
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/DeflateTransformer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,177 @@
+/* DeflateTransformer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import java.util.Map;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+/**
+ * A {@link Transformer} Adapter allowing inclusion of a DEFLATE compression
+ * algorithm in an {@link Assembly} chain. The {@link Direction#FORWARD}
+ * transformation is a compression (deflate) of input data, while the
+ * {@link Direction#REVERSED} one is a decompression (inflate) that restores the
+ * original data.
+ * <p>
+ * This {@link Transformer} uses a {@link Deflater} instance to carry on the
+ * compression, and an {@link Inflater} to do the decompression.
+ * <p>
+ * When using such a {@link Transformer}, in an {@link Assembly}, there must
+ * be at least one element behind this instance in the constructed chain;
+ * otherwise, a {@link TransformerException} is thrown at initialisation time.
+ */
+class DeflateTransformer
+    extends Transformer
+{
+  private Deflater compressor;
+
+  private Inflater decompressor;
+
+  private int outputBlockSize = 512; // default zlib buffer size
+
+  private byte[] zlibBuffer;
+
+  DeflateTransformer()
+  {
+    super();
+
+  }
+
+  void initDelegate(Map attributes) throws TransformerException
+  {
+    if (tail == null)
+      {
+        IllegalStateException cause = new IllegalStateException(
+            "Compression transformer missing its tail!");
+        throw new TransformerException("initDelegate()", cause);
+      }
+    outputBlockSize = tail.currentBlockSize();
+    zlibBuffer = new byte[outputBlockSize];
+    Direction flow = (Direction) attributes.get(DIRECTION);
+    if (flow == Direction.FORWARD)
+      compressor = new Deflater();
+    else
+      decompressor = new Inflater();
+  }
+
+  int delegateBlockSize()
+  {
+    return 1;
+  }
+
+  void resetDelegate()
+  {
+    compressor = null;
+    decompressor = null;
+    outputBlockSize = 1;
+    zlibBuffer = null;
+  }
+
+  byte[] updateDelegate(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    byte[] result;
+    if (wired == Direction.FORWARD)
+      {
+        compressor.setInput(in, offset, length);
+        while (! compressor.needsInput())
+          compress();
+      }
+    else // decompression: inflate first and then update tail
+      decompress(in, offset, length);
+    result = inBuffer.toByteArray();
+    inBuffer.reset();
+    return result;
+  }
+
+  byte[] lastUpdateDelegate() throws TransformerException
+  {
+    // process multiples of blocksize as much as possible
+    if (wired == Direction.FORWARD) // compressing
+      {
+        if (! compressor.finished())
+          {
+            compressor.finish();
+            while (! compressor.finished())
+              compress();
+          }
+      }
+    else // decompressing
+      {
+        if (! decompressor.finished())
+          {
+            IllegalStateException cause = new IllegalStateException(
+                "Compression transformer, after last update, must be finished "
+                + "but isn't");
+            throw new TransformerException("lastUpdateDelegate()", cause);
+          }
+      }
+    byte[] result = inBuffer.toByteArray();
+    inBuffer.reset();
+    return result;
+  }
+
+  private void compress()
+  {
+    int len = compressor.deflate(zlibBuffer);
+    if (len > 0)
+      inBuffer.write(zlibBuffer, 0, len);
+  }
+
+  private void decompress(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    decompressor.setInput(in, offset, length);
+    int len = 1;
+    while (len > 0)
+      {
+        try
+          {
+            len = decompressor.inflate(zlibBuffer);
+          }
+        catch (DataFormatException x)
+          {
+            throw new TransformerException("decompress()", x);
+          }
+        if (len > 0)
+          inBuffer.write(zlibBuffer, 0, len);
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/Direction.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,78 @@
+/* Direction.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+/**
+ * An enumeration type for wiring {@link Stage} instances into {@link Cascade}
+ * Cipher chains, as well as for operating a {@link Cascade} in a given
+ * direction.
+ * <p>
+ * The possible values for this type are two:
+ * <ol>
+ * <li>FORWARD: equivalent to {@link gnu.javax.crypto.mode.IMode#ENCRYPTION},
+ * and its inverse value</li>
+ * <li>REVERSED: equivalent to {@link gnu.javax.crypto.mode.IMode#DECRYPTION}.
+ * </li>
+ * </ol>
+ */
+public final class Direction
+{
+  public static final Direction FORWARD = new Direction(1);
+
+  public static final Direction REVERSED = new Direction(2);
+
+  private int value;
+
+  private Direction(int value)
+  {
+    super();
+
+    this.value = value;
+  }
+
+  public static final Direction reverse(Direction d)
+  {
+    return (d.equals(FORWARD) ? REVERSED : FORWARD);
+  }
+
+  public String toString()
+  {
+    return (this == FORWARD ? "forward" : "reversed");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/LoopbackTransformer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,100 @@
+/* LoopbackTransformer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import java.util.Map;
+
+/**
+ * A trivial {@link Transformer} to allow closing a chain in an {@link Assembly}.
+ * This class is not visible outside this package.
+ */
+final class LoopbackTransformer
+    extends Transformer
+{
+  /** Trivial package-private constructor. */
+  LoopbackTransformer()
+  {
+    super();
+  }
+
+  public void init(Map attributes) throws TransformerException
+  {
+  }
+
+  public void reset()
+  {
+  }
+
+  public byte[] update(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    return updateDelegate(in, offset, length);
+  }
+
+  public byte[] lastUpdate() throws TransformerException
+  {
+    return lastUpdateDelegate();
+  }
+
+  void initDelegate(Map attributes) throws TransformerException
+  {
+  }
+
+  int delegateBlockSize()
+  {
+    return 1;
+  }
+
+  void resetDelegate()
+  {
+  }
+
+  byte[] updateDelegate(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    byte[] result = new byte[length];
+    System.arraycopy(in, offset, result, 0, length);
+    return result;
+  }
+
+  byte[] lastUpdateDelegate() throws TransformerException
+  {
+    return new byte[0];
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/ModeStage.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,112 @@
+/* ModeStage.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import gnu.javax.crypto.mode.IMode;
+
+import java.security.InvalidKeyException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An {@link IMode} {@link Stage} in a {@link Cascade} Cipher chain.
+ * <p>
+ * Such a stage wraps an implementation of a Block Cipher Mode of Operation
+ * ({@link IMode}) to allow inclusion of such an instance in a cascade of block
+ * ciphers.
+ */
+class ModeStage
+    extends Stage
+{
+  private IMode delegate;
+
+  private transient Set cachedBlockSizes;
+
+  ModeStage(IMode mode, Direction forwardDirection)
+  {
+    super(forwardDirection);
+
+    delegate = mode;
+    cachedBlockSizes = null;
+  }
+
+  public Set blockSizes()
+  {
+    if (cachedBlockSizes == null)
+      {
+        HashSet result = new HashSet();
+        for (Iterator it = delegate.blockSizes(); it.hasNext();)
+          result.add(it.next());
+        cachedBlockSizes = Collections.unmodifiableSet(result);
+      }
+    return cachedBlockSizes;
+  }
+
+  void initDelegate(Map attributes) throws InvalidKeyException
+  {
+    Direction flow = (Direction) attributes.get(DIRECTION);
+    attributes.put(IMode.STATE,
+                   Integer.valueOf(flow.equals(forward) ? IMode.ENCRYPTION
+                                                        : IMode.DECRYPTION));
+    delegate.init(attributes);
+  }
+
+  public int currentBlockSize() throws IllegalStateException
+  {
+    return delegate.currentBlockSize();
+  }
+
+  void resetDelegate()
+  {
+    delegate.reset();
+  }
+
+  void updateDelegate(byte[] in, int inOffset, byte[] out, int outOffset)
+  {
+    delegate.update(in, inOffset, out, outOffset);
+  }
+
+  public boolean selfTest()
+  {
+    return delegate.selfTest();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/Operation.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,73 @@
+/* Operation.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+/**
+ * An enumeration type for specifying the operation type of a
+ * {@link Transformer}.
+ * <p>
+ * The possible values for this type are two:
+ * <ol>
+ * <li>PRE_PROCESSING: where the input data is first processed by the current
+ * {@link Transformer} before being passed to the rest of the chain; and</li>
+ * <li>POST_PROCESSING: where the input data is first passed to the rest of the
+ * chain, and the resulting bytes are then processed by the current
+ * {@link Transformer}.</li>
+ * </ol>
+ */
+public final class Operation
+{
+  public static final Operation PRE_PROCESSING = new Operation(1);
+
+  public static final Operation POST_PROCESSING = new Operation(2);
+
+  private int value;
+
+  private Operation(int value)
+  {
+    super();
+
+    this.value = value;
+  }
+
+  public String toString()
+  {
+    return (this == PRE_PROCESSING ? "pre-processing" : "post-processing");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/PaddingTransformer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,164 @@
+/* PaddingTransformer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import gnu.javax.crypto.pad.IPad;
+import gnu.javax.crypto.pad.WrongPaddingException;
+
+import java.util.Map;
+
+/**
+ * An Adapter to use any {@link IPad} as a {@link Transformer} in an
+ * {@link Assembly}.
+ * <p>
+ * When using such a {@link Transformer}, in an {@link Assembly}, there must
+ * be at least one element behind this instance in the constructed chain;
+ * otherwise, a {@link TransformerException} is thrown at initialisation time.
+ */
+class PaddingTransformer
+    extends Transformer
+{
+  private IPad delegate;
+
+  private int outputBlockSize = 1;
+
+  PaddingTransformer(IPad padding)
+  {
+    super();
+
+    this.delegate = padding;
+  }
+
+  void initDelegate(Map attributes) throws TransformerException
+  {
+    if (tail == null)
+      {
+        IllegalStateException cause = new IllegalStateException(
+            "Padding transformer missing its tail!");
+        throw new TransformerException("initDelegate()", cause);
+      }
+    outputBlockSize = tail.currentBlockSize();
+    delegate.init(outputBlockSize);
+  }
+
+  int delegateBlockSize()
+  {
+    return outputBlockSize;
+  }
+
+  void resetDelegate()
+  {
+    delegate.reset();
+    outputBlockSize = 1;
+  }
+
+  byte[] updateDelegate(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    inBuffer.write(in, offset, length);
+    byte[] tmp = inBuffer.toByteArray();
+    inBuffer.reset();
+    byte[] result;
+    if (wired == Direction.FORWARD) // padding
+      {
+        // buffers remaining bytes from (inBuffer + in) that are less than 1
+        // block
+        if (tmp.length < outputBlockSize)
+          {
+            inBuffer.write(tmp, 0, tmp.length);
+            result = new byte[0];
+          }
+        else
+          {
+            int newlen = outputBlockSize * (tmp.length / outputBlockSize);
+            inBuffer.write(tmp, newlen, tmp.length - newlen);
+            result = new byte[newlen];
+            System.arraycopy(tmp, 0, result, 0, newlen);
+          }
+      }
+    else // unpadding
+      {
+        // always keep in own buffer a max of 1 block to cater for lastUpdate
+        if (tmp.length < outputBlockSize)
+          {
+            inBuffer.write(tmp, 0, tmp.length);
+            result = new byte[0];
+          }
+        else
+          {
+            result = new byte[tmp.length - outputBlockSize];
+            System.arraycopy(tmp, 0, result, 0, result.length);
+            inBuffer.write(tmp, result.length, outputBlockSize);
+          }
+      }
+    return result;
+  }
+
+  byte[] lastUpdateDelegate() throws TransformerException
+  {
+    byte[] result;
+    // process multiples of blocksize as much as possible
+    // catenate result from processing inBuffer with last-update( tail )
+    if (wired == Direction.FORWARD) // padding
+      {
+        result = inBuffer.toByteArray();
+        byte[] padding = delegate.pad(result, 0, result.length);
+        inBuffer.write(padding, 0, padding.length);
+      }
+    else // unpadding
+      {
+        byte[] tmp = inBuffer.toByteArray();
+        inBuffer.reset();
+        int realLength;
+        try
+          {
+            realLength = tmp.length; // should be outputBlockSize
+            realLength -= delegate.unpad(tmp, 0, tmp.length);
+          }
+        catch (WrongPaddingException x)
+          {
+            throw new TransformerException("lastUpdateDelegate()", x);
+          }
+        inBuffer.write(tmp, 0, realLength);
+      }
+    result = inBuffer.toByteArray();
+    inBuffer.reset();
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/Stage.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,202 @@
+/* Stage.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import gnu.javax.crypto.mode.IMode;
+
+import java.security.InvalidKeyException;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A <i>Stage</i> in a Cascade Cipher.
+ * <p>
+ * Each stage may be either an implementation of a Block Cipher Mode of
+ * Operation ({@link IMode}) or another Cascade Cipher ({@link Cascade}).
+ * Each stage has also a <i>natural</i> operational direction when constructed
+ * for inclusion within a {@link Cascade}. This <i>natural</i> direction
+ * dictates how data flows from one stage into another when stages are chained
+ * together in a cascade. One can think of a stage and its natural direction as
+ * the specification of how to wire the stage into the chain. The following
+ * diagrams may help understand the paradigme. The first shows two stages
+ * chained each with a {@link Direction#FORWARD} direction.
+ * 
+ * <pre>
+ *            FORWARD         FORWARD
+ *        +------+       +-------+
+ *        |      |       |       |
+ *        |  +--in --+   |   +--in --+
+ *     ---+  | Stage |   |   | Stage |  +---
+ *           +--out--+   |   +--out--+  |
+ *               |       |       |      |
+ *               +-------+       +------+
+ * </pre>
+ * 
+ * <p>
+ * The second diagram shows two stages, one in a {@link Direction#FORWARD}
+ * direction, while the other is wired in a {@link Direction#REVERSED}
+ * direction.
+ * 
+ * <pre>
+ *            FORWARD         REVERSED
+ *        +------+               +------+
+ *        |      |               |      |
+ *        |  +--in --+       +--in --+  |
+ *     ---+  | Stage |       | Stage |  +---
+ *           +--out--+       +--out--+
+ *               |               |
+ *               +---------------+
+ * </pre>
+ * 
+ * @see ModeStage
+ * @see CascadeStage
+ */
+public abstract class Stage
+{
+  public static final String DIRECTION = "gnu.crypto.assembly.stage.direction";
+
+  protected Direction forward;
+
+  protected Direction wired;
+
+  protected Stage(Direction forwardDirection)
+  {
+    super();
+
+    this.forward = forwardDirection;
+    this.wired = null;
+  }
+
+  public static final Stage getInstance(IMode mode, Direction forwardDirection)
+  {
+    return new ModeStage(mode, forwardDirection);
+  }
+
+  public static final Stage getInstance(Cascade cascade,
+                                        Direction forwardDirection)
+  {
+    return new CascadeStage(cascade, forwardDirection);
+  }
+
+  /**
+   * Returns the {@link Set} of supported block sizes for this
+   * <code>Stage</code>. Each element in the returned {@link Set} is an
+   * instance of {@link Integer}.
+   * 
+   * @return a {@link Set} of supported block sizes.
+   */
+  public abstract Set blockSizes();
+
+  /**
+   * Initialises the stage for operation with specific characteristics.
+   * 
+   * @param attributes a set of name-value pairs that describes the desired
+   *          future behaviour of this instance.
+   * @throws IllegalStateException if the instance is already initialised.
+   * @throws InvalidKeyException if the key data is invalid.
+   */
+  public void init(Map attributes) throws InvalidKeyException
+  {
+    if (wired != null)
+      throw new IllegalStateException();
+    Direction flow = (Direction) attributes.get(DIRECTION);
+    if (flow == null)
+      {
+        flow = Direction.FORWARD;
+        attributes.put(DIRECTION, flow);
+      }
+    initDelegate(attributes);
+    wired = flow;
+  }
+
+  /**
+   * Returns the currently set block size for the stage.
+   * 
+   * @return the current block size for this stage.
+   * @throws IllegalStateException if the instance is not initialised.
+   */
+  public abstract int currentBlockSize() throws IllegalStateException;
+
+  /**
+   * Resets the stage for re-initialisation and use with other characteristics.
+   * This method always succeeds.
+   */
+  public void reset()
+  {
+    resetDelegate();
+    wired = null;
+  }
+
+  /**
+   * Processes exactly one block of <i>plaintext</i> (if initialised in the
+   * {@link Direction#FORWARD} state) or <i>ciphertext</i> (if initialised in
+   * the {@link Direction#REVERSED} state).
+   * 
+   * @param in the plaintext.
+   * @param inOffset index of <code>in</code> from which to start considering
+   *          data.
+   * @param out the ciphertext.
+   * @param outOffset index of <code>out</code> from which to store result.
+   * @throws IllegalStateException if the instance is not initialised.
+   */
+  public void update(byte[] in, int inOffset, byte[] out, int outOffset)
+  {
+    if (wired == null)
+      throw new IllegalStateException();
+    updateDelegate(in, inOffset, out, outOffset);
+  }
+
+  /**
+   * Conducts a simple <i>correctness</i> test that consists of basic symmetric
+   * encryption / decryption test(s) for all supported block and key sizes of
+   * underlying block cipher(s) wrapped by Mode leafs. The test also includes
+   * one (1) variable key Known Answer Test (KAT) for each block cipher.
+   * 
+   * @return <code>true</code> if the implementation passes simple
+   *         <i>correctness</i> tests. Returns <code>false</code> otherwise.
+   */
+  public abstract boolean selfTest();
+
+  abstract void initDelegate(Map attributes) throws InvalidKeyException;
+
+  abstract void resetDelegate();
+
+  abstract void updateDelegate(byte[] in, int inOffset, byte[] out,
+                               int outOffset);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/Transformer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,421 @@
+/* Transformer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import gnu.javax.crypto.pad.IPad;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Map;
+
+/**
+ * A <code>Transformer</code> is an abstract representation of a two-way
+ * <i>transformation</i> that can be chained together with other instances of
+ * this type. Examples of such transformations in this library are:
+ * {@link Cascade} cipher, {@link gnu.javax.crypto.pad.IPad} algorithm, and a
+ * ZLib-based deflater/inflater algorithm. A special implementation of a
+ * <code>Transformer</code> to close a chain is also provided.
+ * <p>
+ * A <code>Transformer</code> is characterised by the followings:
+ * <ul>
+ * <li>It can be chained to other instances, to form an {@link Assembly}.</li>
+ * <li>When configured in an {@link Assembly}, it can be set to apply its
+ * internal transformation on the input data stream before (pre-processing) or
+ * after (post-processing) passing the input data to the next element in the
+ * chain. Note that the same type <code>Transformer</code> can be used as
+ * either in pre-processing or a post-processing modes.</li>
+ * <li>A special transformer --<code>LoopbackTransformer</code>-- is used
+ * to close the chain.</li>
+ * <li>A useful type of <code>Transformer</code> --one we're interested in--
+ * has internal buffers. The distinction between a casual push (update)
+ * operation and the last one allows to correctly flush any intermediate bytes
+ * that may exist in those buffers.</li>
+ * </ul>
+ * <p>
+ * To allow wiring <code>Transformer</code> instances together, a
+ * <i>minimal-output-size</i> in bytes is necessary. The trivial case of a
+ * value of <code>1</code> for such attribute practically means that no output
+ * buffering, from the previous element, is needed --which is independant of
+ * buffering the input if the <code>Transformer</code> implementation itself
+ * is block-based.
+ * 
+ * @see CascadeTransformer
+ * @see PaddingTransformer
+ * @see DeflateTransformer
+ */
+public abstract class Transformer
+{
+  public static final String DIRECTION = "gnu.crypto.assembly.transformer.direction";
+
+  protected Direction wired;
+
+  protected Operation mode;
+
+  protected Transformer tail = null;
+
+  protected ByteArrayOutputStream inBuffer = new ByteArrayOutputStream(2048);
+
+  protected ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(2048);
+
+  /** Trivial protected constructor. */
+  protected Transformer()
+  {
+    super();
+
+    this.wired = null;
+  }
+
+  public static final Transformer getCascadeTransformer(Cascade cascade)
+  {
+    return new CascadeTransformer(cascade);
+  }
+
+  public static final Transformer getPaddingTransformer(IPad padding)
+  {
+    return new PaddingTransformer(padding);
+  }
+
+  public static final Transformer getDeflateTransformer()
+  {
+    return new DeflateTransformer();
+  }
+
+  /**
+   * Sets the operational mode of this <code>Transformer</code>.
+   * 
+   * @param mode the processing mode this <code>Transformer</code> is required
+   *          to operate in.
+   * @throws IllegalStateException if this instance has already been assigned an
+   *           operational mode.
+   */
+  public void setMode(final Operation mode)
+  {
+    if (this.mode != null)
+      throw new IllegalStateException();
+    this.mode = mode;
+  }
+
+  /**
+   * Returns <code>true</code> if this <code>Transformer</code> was wired in
+   * pre-processing mode; <code>false</code> otherwise.
+   * 
+   * @return <code>true</code> if this <code>Transformer</code> has been
+   *         wired in pre-processing mode; <code>false</code> otherwise.
+   * @throws IllegalStateException if this instance has not yet been assigned an
+   *           operational <i>type</i>.
+   */
+  public boolean isPreProcessing()
+  {
+    if (mode == null)
+      throw new IllegalStateException();
+    return (mode == Operation.PRE_PROCESSING);
+  }
+
+  /**
+   * Returns <code>true</code> if this <code>Transformer</code> was wired in
+   * post-processing mode; <code>false</code> otherwise.
+   * 
+   * @return <code>true</code> if this <code>Transformer</code> has been
+   *         wired in post-processing mode; <code>false</code> otherwise.
+   * @throws IllegalStateException if this instance has not yet been assigned an
+   *           operational <i>type</i>.
+   */
+  public boolean isPostProcessing()
+  {
+    return ! isPreProcessing();
+  }
+
+  /**
+   * Initialises the <code>Transformer</code> for operation with specific
+   * characteristics.
+   * 
+   * @param attributes a set of name-value pairs that describes the desired
+   *          future behaviour of this instance.
+   * @throws IllegalStateException if the instance is already initialised.
+   */
+  public void init(Map attributes) throws TransformerException
+  {
+    if (wired != null)
+      throw new IllegalStateException();
+    Direction flow = (Direction) attributes.get(DIRECTION);
+    if (flow == null)
+      flow = Direction.FORWARD;
+    wired = flow;
+    inBuffer.reset();
+    outBuffer.reset();
+    tail.init(attributes); // initialise tail first
+    initDelegate(attributes); // initialise this instance
+  }
+
+  /**
+   * Returns the block-size of this <code>Transformer</code>. A value of
+   * <code>1</code> indicates that this instance is block-agnostic.
+   * 
+   * @return the current minimal required block size.
+   */
+  public int currentBlockSize()
+  {
+    if (wired == null)
+      throw new IllegalStateException();
+    return delegateBlockSize();
+  }
+
+  /**
+   * Resets the <code>Transformer</code> for re-initialisation and use with
+   * other characteristics. This method always succeeds.
+   */
+  public void reset()
+  {
+    resetDelegate();
+    wired = null;
+    inBuffer.reset();
+    outBuffer.reset();
+    tail.reset(); // reset tail last
+  }
+
+  /**
+   * Convenience method that calls the method with same name and three
+   * arguments, using a byte array of length <code>1</code> whose contents are
+   * the designated byte.
+   * 
+   * @param b the byte to process.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #update(byte[], int, int)
+   */
+  public byte[] update(byte b) throws TransformerException
+  {
+    return update(new byte[] { b }, 0, 1);
+  }
+
+  /**
+   * Convenience method that calls the same method with three arguments. All
+   * bytes in <code>in</code>, starting from index position <code>0</code>
+   * are considered.
+   * 
+   * @param in the input data bytes.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #update(byte[], int, int)
+   */
+  public byte[] update(byte[] in) throws TransformerException
+  {
+    return update(in, 0, in.length);
+  }
+
+  /**
+   * Processes a designated number of bytes from a given byte array.
+   * 
+   * @param in the input data bytes.
+   * @param offset index of <code>in</code> from which to start considering
+   *          data.
+   * @param length the count of bytes to process.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   */
+  public byte[] update(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    if (wired == null)
+      throw new IllegalStateException();
+    byte[] result = (wired == Direction.FORWARD ? forwardUpdate(in, offset, length)
+                                                : inverseUpdate(in, offset, length));
+    return result;
+  }
+
+  /**
+   * Convenience method that calls the same method with three arguments. A
+   * zero-long byte array is used.
+   * 
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #lastUpdate(byte[], int, int)
+   */
+  public byte[] lastUpdate() throws TransformerException
+  {
+    byte[] result = (wired == Direction.FORWARD ? lastForwardUpdate()
+                                                : lastInverseUpdate());
+    if (inBuffer.size() != 0) // we still have some buffered bytes
+      throw new TransformerException("lastUpdate(): input buffer not empty");
+    return result;
+  }
+
+  /**
+   * Convenience method that calls the method with same name and three
+   * arguments, using a byte array of length <code>1</code> whose contents are
+   * the designated byte.
+   * 
+   * @param b the byte to process.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #lastUpdate(byte[], int, int)
+   */
+  public byte[] lastUpdate(byte b) throws TransformerException
+  {
+    return lastUpdate(new byte[] { b }, 0, 1);
+  }
+
+  /**
+   * Convenience method that calls the same method with three arguments. All
+   * bytes in <code>in</code>, starting from index position <code>0</code>
+   * are considered.
+   * 
+   * @param in the input data bytes.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   * @see #lastUpdate(byte[], int, int)
+   */
+  public byte[] lastUpdate(byte[] in) throws TransformerException
+  {
+    return lastUpdate(in, 0, in.length);
+  }
+
+  /**
+   * Processes a designated number of bytes from a given byte array and signals,
+   * at the same time, that this is the last <i>push</i> operation on this
+   * <code>Transformer</code>.
+   * 
+   * @param in the input data bytes.
+   * @param offset index of <code>in</code> from which to start considering
+   *          data.
+   * @param length the count of bytes to process.
+   * @return the result of transformation.
+   * @throws IllegalStateException if the instance is not initialised.
+   * @throws TransformerException if a transformation-related exception occurs
+   *           during the operation.
+   */
+  public byte[] lastUpdate(byte[] in, int offset, int length)
+      throws TransformerException
+  {
+    byte[] result = update(in, offset, length);
+    byte[] rest = lastUpdate();
+    if (rest.length > 0)
+      {
+        byte[] newResult = new byte[result.length + rest.length];
+        System.arraycopy(result, 0, newResult, 0, result.length);
+        System.arraycopy(rest, 0, newResult, result.length, rest.length);
+        result = newResult;
+      }
+    return result;
+  }
+
+  private byte[] forwardUpdate(byte[] in, int off, int len)
+      throws TransformerException
+  {
+    return (isPreProcessing() ? preTransform(in, off, len)
+                              : postTransform(in, off, len));
+  }
+
+  private byte[] inverseUpdate(byte[] in, int off, int len)
+      throws TransformerException
+  {
+    return (isPreProcessing() ? postTransform(in, off, len)
+                              : preTransform(in, off, len));
+  }
+
+  private byte[] preTransform(byte[] in, int off, int len)
+      throws TransformerException
+  {
+    byte[] result = updateDelegate(in, off, len);
+    result = tail.update(result);
+    return result;
+  }
+
+  private byte[] postTransform(byte[] in, int off, int len)
+      throws TransformerException
+  {
+    byte[] result = tail.update(in, off, len);
+    result = updateDelegate(result, 0, result.length);
+    return result;
+  }
+
+  private byte[] lastForwardUpdate() throws TransformerException
+  {
+    return (isPreProcessing() ? preLastTransform() : postLastTransform());
+  }
+
+  private byte[] lastInverseUpdate() throws TransformerException
+  {
+    return (isPreProcessing() ? postLastTransform() : preLastTransform());
+  }
+
+  private byte[] preLastTransform() throws TransformerException
+  {
+    byte[] result = lastUpdateDelegate();
+    result = tail.lastUpdate(result);
+    return result;
+  }
+
+  private byte[] postLastTransform() throws TransformerException
+  {
+    byte[] result = tail.lastUpdate();
+    result = updateDelegate(result, 0, result.length);
+    byte[] rest = lastUpdateDelegate();
+    if (rest.length > 0)
+      {
+        byte[] newResult = new byte[result.length + rest.length];
+        System.arraycopy(result, 0, newResult, 0, result.length);
+        System.arraycopy(rest, 0, newResult, result.length, rest.length);
+        result = newResult;
+      }
+    return result;
+  }
+
+  abstract void initDelegate(Map attributes) throws TransformerException;
+
+  abstract int delegateBlockSize();
+
+  abstract void resetDelegate();
+
+  abstract byte[] updateDelegate(byte[] in, int off, int len)
+      throws TransformerException;
+
+  abstract byte[] lastUpdateDelegate() throws TransformerException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/assembly/TransformerException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,138 @@
+/* TransformerException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.assembly;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ */
+public class TransformerException
+    extends Exception
+{
+  private Throwable _exception = null;
+
+  public TransformerException()
+  {
+    super();
+  }
+
+  public TransformerException(String details)
+  {
+    super(details);
+  }
+
+  public TransformerException(Throwable cause)
+  {
+    super();
+
+    this._exception = cause;
+  }
+
+  public TransformerException(String details, Throwable cause)
+  {
+    super(details);
+
+    this._exception = cause;
+  }
+
+  public Throwable getCause()
+  {
+    return _exception;
+  }
+
+  /**
+   * Prints this exception's stack trace to <code>System.err</code>. If this
+   * exception has a root exception; the stack trace of the root exception is
+   * also printed to <code>System.err</code>.
+   */
+  public void printStackTrace()
+  {
+    super.printStackTrace();
+    if (_exception != null)
+      _exception.printStackTrace();
+  }
+
+  /**
+   * Prints this exception's stack trace to a print stream. If this exception
+   * has a root exception; the stack trace of the root exception is also printed
+   * to the print stream.
+   * 
+   * @param ps the non-null print stream to which to print.
+   */
+  public void printStackTrace(PrintStream ps)
+  {
+    super.printStackTrace(ps);
+    if (_exception != null)
+      _exception.printStackTrace(ps);
+  }
+
+  /**
+   * Prints this exception's stack trace to a print writer. If this exception
+   * has a root exception; the stack trace of the root exception is also printed
+   * to the print writer.
+   * 
+   * @param pw the non-null print writer to use for output.
+   */
+  public void printStackTrace(PrintWriter pw)
+  {
+    super.printStackTrace(pw);
+    if (_exception != null)
+      _exception.printStackTrace(pw);
+  }
+
+  /**
+   * Returns the string representation of this exception. The string
+   * representation contains this exception's class name, its detailed messsage,
+   * and if it has a root exception, the string representation of the root
+   * exception. This string representation is meant for debugging and not meant
+   * to be interpreted programmatically.
+   * 
+   * @return the non-null string representation of this exception.
+   * @see Throwable#getMessage()
+   */
+  public String toString()
+  {
+    StringBuffer sb = new StringBuffer(this.getClass().getName())
+        .append(": ").append(super.toString());
+    if (_exception != null)
+      sb.append("; caused by: ").append(_exception.toString());
+    return sb.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/Anubis.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,491 @@
+/* Anubis.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+/**
+ * Anubis is a 128-bit block cipher that accepts a variable-length key. The
+ * cipher is a uniform substitution-permutation network whose inverse only
+ * differs from the forward operation in the key schedule. The design of both
+ * the round transformation and the key schedule is based upon the Wide Trail
+ * strategy and permits a wide variety of implementation trade-offs.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://planeta.terra.com.br/informatica/paulobarreto/AnubisPage.html">The
+ * ANUBIS Block Cipher</a>.<br>
+ * <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and <a
+ * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li>
+ * </ol>
+ */
+public final class Anubis
+    extends BaseCipher
+{
+  private static final Logger log = Logger.getLogger(Anubis.class.getName());
+  private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes
+  private static final int DEFAULT_KEY_SIZE = 16; // in bytes
+  private static final String Sd = // p. 25 [ANUBIS]
+      "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C"
+    + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC"
+    + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102"
+    + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C"
+    + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB"
+    + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38"
+    + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746"
+    + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C"
+    + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2"
+    + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE"
+    + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E"
+    + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B"
+    + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8"
+    + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856"
+    + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2"
+    + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42";
+  private static final byte[] S = new byte[256];
+  private static final int[] T0 = new int[256];
+  private static final int[] T1 = new int[256];
+  private static final int[] T2 = new int[256];
+  private static final int[] T3 = new int[256];
+  private static final int[] T4 = new int[256];
+  private static final int[] T5 = new int[256];
+  /**
+   * Anubis round constants. This is the largest possible considering that we
+   * always use R values, R = 8 + N, and 4 &lt;= N &lt;= 10.
+   */
+  private static final int[] rc = new int[18];
+  /**
+   * KAT vector (from ecb_vk): I=83
+   * KEY=000000000000000000002000000000000000000000000000
+   * CT=2E66AB15773F3D32FB6C697509460DF4
+   */
+  private static final byte[] KAT_KEY =
+      Util.toBytesFromString("000000000000000000002000000000000000000000000000");
+  private static final byte[] KAT_CT =
+      Util.toBytesFromString("2E66AB15773F3D32FB6C697509460DF4");
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  static
+    {
+      long time = System.currentTimeMillis();
+      int ROOT = 0x11d; // para. 2.1 [ANUBIS]
+      int i, s, s2, s4, s6, s8, t;
+      char c;
+      for (i = 0; i < 256; i++)
+        {
+          c = Sd.charAt(i >>> 1);
+          s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF;
+          S[i] = (byte) s;
+          s2 = s << 1;
+          if (s2 > 0xFF)
+            s2 ^= ROOT;
+          s4 = s2 << 1;
+          if (s4 > 0xFF)
+            s4 ^= ROOT;
+          s6 = s4 ^ s2;
+          s8 = s4 << 1;
+          if (s8 > 0xFF)
+            s8 ^= ROOT;
+          T0[i] = s  << 24 | s2 << 16 | s4 << 8 | s6;
+          T1[i] = s2 << 24 | s  << 16 | s6 << 8 | s4;
+          T2[i] = s4 << 24 | s6 << 16 | s  << 8 | s2;
+          T3[i] = s6 << 24 | s4 << 16 | s2 << 8 | s;
+          T4[i] = s  << 24 | s  << 16 | s  << 8 | s;
+          T5[s] = s  << 24 | s2 << 16 | s6 << 8 | s8;
+        }
+      // compute round constant
+      for (i = 0, s = 0; i < 18;)
+        rc[i++] =  S[(s++) & 0xFF]         << 24
+                | (S[(s++) & 0xFF] & 0xFF) << 16
+                | (S[(s++) & 0xFF] & 0xFF) << 8
+                | (S[(s++) & 0xFF] & 0xFF);
+      time = System.currentTimeMillis() - time;
+      if (Configuration.DEBUG)
+        {
+          log.fine("Static data");
+          log.fine("T0[]:");
+          StringBuilder sb;
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (t = 0; t < 4; t++)
+                sb.append("0x").append(Util.toString(T0[i * 4 + t])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T1[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (t = 0; t < 4; t++)
+                sb.append("0x").append(Util.toString(T1[i * 4 + t])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T2[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (t = 0; t < 4; t++)
+                sb.append("0x").append(Util.toString(T2[i * 4 + t])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T3[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (t = 0; t < 4; t++)
+                sb.append("0x").append(Util.toString(T3[i * 4 + t])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T4[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (t = 0; t < 4; t++)
+                sb.append("0x").append(Util.toString(T4[i * 4 + t])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T5[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (t = 0; t < 4; t++)
+                sb.append("0x").append(Util.toString(T5[i * 4 + t])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("rc[]:");
+          for (i = 0; i < 18; i++)
+            log.fine("0x" + Util.toString(rc[i]));
+          log.fine("Total initialization time: " + time + " ms.");
+        }
+    }
+
+  /** Trivial 0-arguments constructor. */
+  public Anubis()
+  {
+    super(Registry.ANUBIS_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
+  }
+
+  private static void anubis(byte[] in, int i, byte[] out, int j, int[][] K)
+  {
+    // extract encryption round keys
+    int R = K.length - 1;
+    int[] Ker = K[0];
+    // mu function + affine key addition
+    int a0 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Ker[0];
+    int a1 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Ker[1];
+    int a2 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Ker[2];
+    int a3 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i] & 0xFF)        ) ^ Ker[3];
+    int b0, b1, b2, b3;
+    // round function
+    for (int r = 1; r < R; r++)
+      {
+        Ker = K[r];
+        b0 = T0[ a0 >>> 24        ]
+           ^ T1[ a1 >>> 24        ]
+           ^ T2[ a2 >>> 24        ]
+           ^ T3[ a3 >>> 24        ] ^ Ker[0];
+        b1 = T0[(a0 >>> 16) & 0xFF]
+           ^ T1[(a1 >>> 16) & 0xFF]
+           ^ T2[(a2 >>> 16) & 0xFF]
+           ^ T3[(a3 >>> 16) & 0xFF] ^ Ker[1];
+        b2 = T0[(a0 >>>  8) & 0xFF]
+           ^ T1[(a1 >>>  8) & 0xFF]
+           ^ T2[(a2 >>>  8) & 0xFF]
+           ^ T3[(a3 >>>  8) & 0xFF] ^ Ker[2];
+        b3 = T0[ a0         & 0xFF]
+           ^ T1[ a1         & 0xFF]
+           ^ T2[ a2         & 0xFF]
+           ^ T3[ a3         & 0xFF] ^ Ker[3];
+        a0 = b0;
+        a1 = b1;
+        a2 = b2;
+        a3 = b3;
+        if (Configuration.DEBUG)
+          log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1)
+                   + Util.toString(a2) + Util.toString(a3));
+      }
+    // last round function
+    Ker = K[R];
+    int tt = Ker[0];
+    out[j++] = (byte)(S[ a0 >>> 24        ] ^ (tt >>> 24));
+    out[j++] = (byte)(S[ a1 >>> 24        ] ^ (tt >>> 16));
+    out[j++] = (byte)(S[ a2 >>> 24        ] ^ (tt >>> 8));
+    out[j++] = (byte)(S[ a3 >>> 24        ] ^  tt);
+    tt = Ker[1];
+    out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (tt >>> 24));
+    out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(S[(a2 >>> 16) & 0xFF] ^ (tt >>> 8));
+    out[j++] = (byte)(S[(a3 >>> 16) & 0xFF] ^  tt);
+    tt = Ker[2];
+    out[j++] = (byte)(S[(a0 >>>  8) & 0xFF] ^ (tt >>> 24));
+    out[j++] = (byte)(S[(a1 >>>  8) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(S[(a2 >>>  8) & 0xFF] ^ (tt >>> 8));
+    out[j++] = (byte)(S[(a3 >>>  8) & 0xFF] ^  tt);
+    tt = Ker[3];
+    out[j++] = (byte)(S[ a0         & 0xFF] ^ (tt >>> 24));
+    out[j++] = (byte)(S[ a1         & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(S[ a2         & 0xFF] ^ (tt >>> 8));
+    out[j  ] = (byte)(S[ a3         & 0xFF] ^  tt);
+    if (Configuration.DEBUG)
+      log.fine("T=" + Util.toString(out, j - 15, 16) + "\n");
+  }
+
+  public Object clone()
+  {
+    Anubis result = new Anubis();
+    result.currentBlockSize = this.currentBlockSize;
+
+    return result;
+  }
+
+  public Iterator blockSizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
+
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    ArrayList al = new ArrayList();
+    for (int n = 4; n < 10; n++)
+      al.add(Integer.valueOf(n * 32 / 8));
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  /**
+   * Expands a user-supplied key material into a session key for a designated
+   * <i>block size</i>.
+   * 
+   * @param uk the 32N-bit user-supplied key material; 4 &lt;= N &lt;= 10.
+   * @param bs the desired block size in bytes.
+   * @return an Object encapsulating the session key.
+   * @exception IllegalArgumentException if the block size is not 16 (128-bit).
+   * @exception InvalidKeyException if the key data is invalid.
+   */
+  public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    if (uk == null)
+      throw new InvalidKeyException("Empty key");
+    if ((uk.length % 4) != 0)
+      throw new InvalidKeyException("Key is not multiple of 32-bit.");
+    int N = uk.length / 4;
+    if (N < 4 || N > 10)
+      throw new InvalidKeyException("Key is not 32N; 4 <= N <= 10");
+    int R = 8 + N;
+    int[][] Ke = new int[R + 1][4]; // encryption round keys
+    int[][] Kd = new int[R + 1][4]; // decryption round keys
+    int[] tk = new int[N];
+    int[] kk = new int[N];
+    int r, i, j, k, k0, k1, k2, k3, tt;
+    // apply mu to k0
+    for (r = 0, i = 0; r < N;)
+      tk[r++] =  uk[i++]         << 24
+              | (uk[i++] & 0xFF) << 16
+              | (uk[i++] & 0xFF) << 8
+              | (uk[i++] & 0xFF);
+    for (r = 0; r <= R; r++)
+      {
+        if (r > 0)
+          {
+            // psi = key evolution function
+            kk[0] = T0[(tk[0    ] >>> 24)       ]
+                  ^ T1[(tk[N - 1] >>> 16) & 0xFF]
+                  ^ T2[(tk[N - 2] >>>  8) & 0xFF]
+                  ^ T3[ tk[N - 3]         & 0xFF];
+            kk[1] = T0[(tk[1    ] >>> 24)       ]
+                  ^ T1[(tk[0    ] >>> 16) & 0xFF]
+                  ^ T2[(tk[N - 1] >>>  8) & 0xFF]
+                  ^ T3[ tk[N - 2]         & 0xFF];
+            kk[2] = T0[(tk[2    ] >>> 24)       ]
+                  ^ T1[(tk[1    ] >>> 16) & 0xFF]
+                  ^ T2[(tk[0    ] >>>  8) & 0xFF]
+                  ^ T3[ tk[N - 1]         & 0xFF];
+            kk[3] = T0[(tk[3    ] >>> 24)       ]
+                  ^ T1[(tk[2    ] >>> 16) & 0xFF]
+                  ^ T2[(tk[1    ] >>>  8) & 0xFF]
+                  ^ T3[ tk[0    ]         & 0xFF];
+            for (i = 4; i < N; i++)
+              kk[i] = T0[ tk[i    ] >>> 24        ]
+                    ^ T1[(tk[i - 1] >>> 16) & 0xFF]
+                    ^ T2[(tk[i - 2] >>>  8) & 0xFF]
+                    ^ T3[ tk[i - 3]         & 0xFF];
+            // apply sigma (affine addition) to round constant
+            tk[0] = rc[r - 1] ^ kk[0];
+            for (i = 1; i < N; i++)
+              tk[i] = kk[i];
+          }
+        // phi = key selection function
+        tt = tk[N - 1];
+        k0 = T4[ tt >>> 24        ];
+        k1 = T4[(tt >>> 16) & 0xFF];
+        k2 = T4[(tt >>>  8) & 0xFF];
+        k3 = T4[ tt         & 0xFF];
+        for (k = N - 2; k >= 0; k--)
+          {
+            tt = tk[k];
+            k0 =  T4[ tt >>> 24        ]
+               ^ (T5[(k0 >>> 24) & 0xFF] & 0xFF000000)
+               ^ (T5[(k0 >>> 16) & 0xFF] & 0x00FF0000)
+               ^ (T5[(k0 >>>  8) & 0xFF] & 0x0000FF00)
+               ^ (T5 [k0         & 0xFF] & 0x000000FF);
+            k1 =  T4[(tt >>> 16) & 0xFF]
+               ^ (T5[(k1 >>> 24) & 0xFF] & 0xFF000000)
+               ^ (T5[(k1 >>> 16) & 0xFF] & 0x00FF0000)
+               ^ (T5[(k1 >>>  8) & 0xFF] & 0x0000FF00)
+               ^ (T5[ k1         & 0xFF] & 0x000000FF);
+            k2 =  T4[(tt >>>  8) & 0xFF]
+               ^ (T5[(k2 >>> 24) & 0xFF] & 0xFF000000)
+               ^ (T5[(k2 >>> 16) & 0xFF] & 0x00FF0000)
+               ^ (T5[(k2 >>>  8) & 0xFF] & 0x0000FF00)
+               ^ (T5[ k2         & 0xFF] & 0x000000FF);
+            k3 =  T4[ tt         & 0xFF]
+               ^ (T5[(k3 >>> 24) & 0xFF] & 0xFF000000)
+               ^ (T5[(k3 >>> 16) & 0xFF] & 0x00FF0000)
+               ^ (T5[(k3 >>>  8) & 0xFF] & 0x0000FF00)
+               ^ (T5[ k3         & 0xFF] & 0x000000FF);
+          }
+        Ke[r][0] = k0;
+        Ke[r][1] = k1;
+        Ke[r][2] = k2;
+        Ke[r][3] = k3;
+        if (r == 0 || r == R)
+          {
+            Kd[R - r][0] = k0;
+            Kd[R - r][1] = k1;
+            Kd[R - r][2] = k2;
+            Kd[R - r][3] = k3;
+          }
+        else
+          {
+            Kd[R - r][0] = T0[S[ k0 >>> 24        ] & 0xFF]
+                         ^ T1[S[(k0 >>> 16) & 0xFF] & 0xFF]
+                         ^ T2[S[(k0 >>>  8) & 0xFF] & 0xFF]
+                         ^ T3[S[ k0         & 0xFF] & 0xFF];
+            Kd[R - r][1] = T0[S[ k1 >>> 24        ] & 0xFF]
+                         ^ T1[S[(k1 >>> 16) & 0xFF] & 0xFF]
+                         ^ T2[S[(k1 >>>  8) & 0xFF] & 0xFF]
+                         ^ T3[S[ k1         & 0xFF] & 0xFF];
+            Kd[R - r][2] = T0[S[ k2 >>> 24        ] & 0xFF]
+                         ^ T1[S[(k2 >>> 16) & 0xFF] & 0xFF]
+                         ^ T2[S[(k2 >>>  8) & 0xFF] & 0xFF]
+                         ^ T3[S[ k2         & 0xFF] & 0xFF];
+            Kd[R - r][3] = T0[S[ k3 >>> 24        ] & 0xFF]
+                         ^ T1[S[(k3 >>> 16) & 0xFF] & 0xFF]
+                         ^ T2[S[(k3 >>>  8) & 0xFF] & 0xFF]
+                         ^ T3[S[ k3         & 0xFF] & 0xFF];
+          }
+      }
+    if (Configuration.DEBUG)
+      {
+        log.fine("Key schedule");
+        log.fine("Ke[]:");
+        StringBuilder sb;
+        for (r = 0; r < R + 1; r++)
+          {
+            sb = new StringBuilder("#").append(r).append(": ");
+            for (j = 0; j < 4; j++)
+              sb.append("0x").append(Util.toString(Ke[r][j])).append(", ");
+            log.fine(sb.toString());
+          }
+        log.fine("Kd[]:");
+        for (r = 0; r < R + 1; r++)
+          {
+            sb = new StringBuilder("#").append(r).append(": ");
+            for (j = 0; j < 4; j++)
+              sb.append("0x").append(Util.toString(Kd[r][j])).append(", ");
+            log.fine(sb.toString());
+          }
+      }
+    return new Object[] { Ke, Kd };
+  }
+
+  public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    int[][] K = (int[][])((Object[]) k)[0];
+    anubis(in, i, out, j, K);
+  }
+
+  public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    int[][] K = (int[][])((Object[]) k)[1];
+    anubis(in, i, out, j, K);
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        boolean result = super.selfTest(); // do symmetry tests
+        if (result)
+          result = testKat(KAT_KEY, KAT_CT);
+        valid = Boolean.valueOf(result);
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/BaseCipher.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,247 @@
+/* BaseCipher.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Configuration;
+
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A basic abstract class to facilitate implementing symmetric key block
+ * ciphers.
+ */
+public abstract class BaseCipher
+    implements IBlockCipher, IBlockCipherSpi
+{
+  private static final Logger log = Logger.getLogger(BaseCipher.class.getName());
+  /** The canonical name prefix of the cipher. */
+  protected String name;
+  /** The default block size, in bytes. */
+  protected int defaultBlockSize;
+  /** The default key size, in bytes. */
+  protected int defaultKeySize;
+  /** The current block size, in bytes. */
+  protected int currentBlockSize;
+  /** The session key for this instance. */
+  protected transient Object currentKey;
+  /** The instance lock. */
+  protected Object lock = new Object();
+
+  /**
+   * Trivial constructor for use by concrete subclasses.
+   * 
+   * @param name the canonical name prefix of this instance.
+   * @param defaultBlockSize the default block size in bytes.
+   * @param defaultKeySize the default key size in bytes.
+   */
+  protected BaseCipher(String name, int defaultBlockSize, int defaultKeySize)
+  {
+    super();
+
+    this.name = name;
+    this.defaultBlockSize = defaultBlockSize;
+    this.defaultKeySize = defaultKeySize;
+  }
+
+  public abstract Object clone();
+
+  public String name()
+  {
+    StringBuffer sb = new StringBuffer(name).append('-');
+    if (currentKey == null)
+      sb.append(String.valueOf(8 * defaultBlockSize));
+    else
+      sb.append(String.valueOf(8 * currentBlockSize));
+    return sb.toString();
+  }
+
+  public int defaultBlockSize()
+  {
+    return defaultBlockSize;
+  }
+
+  public int defaultKeySize()
+  {
+    return defaultKeySize;
+  }
+
+  public void init(Map attributes) throws InvalidKeyException
+  {
+    synchronized (lock)
+      {
+        if (currentKey != null)
+          throw new IllegalStateException();
+        Integer bs = (Integer) attributes.get(CIPHER_BLOCK_SIZE);
+        if (bs == null) // no block size was specified
+          {
+            if (currentBlockSize == 0) // happy birthday
+              currentBlockSize = defaultBlockSize;
+            // else it's a clone. use as is
+          }
+        else
+          {
+            currentBlockSize = bs.intValue();
+            // ensure that value is valid
+            Iterator it;
+            boolean ok = false;
+            for (it = blockSizes(); it.hasNext();)
+              {
+                ok = (currentBlockSize == ((Integer) it.next()).intValue());
+                if (ok)
+                  break;
+              }
+            if (! ok)
+              throw new IllegalArgumentException(IBlockCipher.CIPHER_BLOCK_SIZE);
+          }
+        byte[] k = (byte[]) attributes.get(KEY_MATERIAL);
+        currentKey = makeKey(k, currentBlockSize);
+      }
+  }
+
+  public int currentBlockSize()
+  {
+    if (currentKey == null)
+      throw new IllegalStateException();
+    return currentBlockSize;
+  }
+
+  public void reset()
+  {
+    synchronized (lock)
+      {
+        currentKey = null;
+      }
+  }
+
+  public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset)
+      throws IllegalStateException
+  {
+    synchronized (lock)
+      {
+        if (currentKey == null)
+          throw new IllegalStateException();
+        encrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize);
+      }
+  }
+
+  public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset)
+      throws IllegalStateException
+  {
+    synchronized (lock)
+      {
+        if (currentKey == null)
+          throw new IllegalStateException();
+        decrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize);
+      }
+  }
+
+  public boolean selfTest()
+  {
+    int ks;
+    Iterator bit;
+    // do symmetry tests for all block-size/key-size combos
+    for (Iterator kit = keySizes(); kit.hasNext();)
+      {
+        ks = ((Integer) kit.next()).intValue();
+        for (bit = blockSizes(); bit.hasNext();)
+          if (! testSymmetry(ks, ((Integer) bit.next()).intValue()))
+            return false;
+      }
+    return true;
+  }
+
+  private boolean testSymmetry(int ks, int bs)
+  {
+    try
+      {
+        byte[] kb = new byte[ks];
+        byte[] pt = new byte[bs];
+        byte[] ct = new byte[bs];
+        byte[] cpt = new byte[bs];
+        int i;
+        for (i = 0; i < ks; i++)
+          kb[i] = (byte) i;
+        for (i = 0; i < bs; i++)
+          pt[i] = (byte) i;
+        Object k = makeKey(kb, bs);
+        encrypt(pt, 0, ct, 0, k, bs);
+        decrypt(ct, 0, cpt, 0, k, bs);
+        return Arrays.equals(pt, cpt);
+      }
+    catch (Exception x)
+      {
+        if (Configuration.DEBUG)
+          log.log(Level.FINE, "Exception in testSymmetry() for " + name(), x);
+        return false;
+      }
+  }
+
+  protected boolean testKat(byte[] kb, byte[] ct)
+  {
+    return testKat(kb, ct, new byte[ct.length]); // all-zero plaintext
+  }
+
+  protected boolean testKat(byte[] kb, byte[] ct, byte[] pt)
+  {
+    try
+      {
+        int bs = pt.length;
+        byte[] t = new byte[bs];
+        Object k = makeKey(kb, bs);
+        // test encryption
+        encrypt(pt, 0, t, 0, k, bs);
+        if (! Arrays.equals(t, ct))
+          return false;
+        // test decryption
+        decrypt(t, 0, t, 0, k, bs);
+        return Arrays.equals(t, pt);
+      }
+    catch (Exception x)
+      {
+        if (Configuration.DEBUG)
+          log.log(Level.FINE, "Exception in testKat() for " + name(), x);
+        return false;
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/Blowfish.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,611 @@
+/* Blowfish.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+// --------------------------------------------------------------------------
+//
+// Based on the C implementation from the GNU Privacy Guard.
+//
+// --------------------------------------------------------------------------
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Sequence;
+import gnu.java.security.util.Util;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * Blowfish is a 16-round, 64-bit Feistel cipher designed by Bruce Schneier. It
+ * accepts a variable-length key of up to 448 bits.
+ * <p>
+ * References:
+ * <ol>
+ * <li>Schneier, Bruce: <i>Applied Cryptography</i>, Second Edition, 336--339,
+ * 647--654 (1996 Bruce Schneier).</li>
+ * <li><a href="http://www.counterpane.com/blowfish.html">The Blowfish
+ * Encryption Algorithm.</a></li>
+ * </ol>
+ */
+public class Blowfish
+    extends BaseCipher
+{
+  private static final int DEFAULT_BLOCK_SIZE = 8;
+  private static final int DEFAULT_KEY_SIZE = 8;
+  private static final int MAX_KEY_LENGTH = 56;
+  /** Initial value of the p-array. */
+  private static final int[] P = {
+      0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+      0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+      0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b };
+  /** Initial value of S-box 1. */
+  static final int[] KS0 = {
+      0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+      0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+      0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+      0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+      0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+      0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+      0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+      0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+      0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+      0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+      0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+      0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+      0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+      0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+      0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+      0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+      0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+      0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+      0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+      0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+      0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+      0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+      0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+      0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+      0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+      0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+      0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+      0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+      0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+      0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+      0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+      0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+      0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+      0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+      0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+      0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+      0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+      0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+      0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+      0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+      0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+      0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+      0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a };
+  /** Initial value of S-box 2. */
+  private static final int[] KS1 = {
+      0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+      0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+      0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+      0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+      0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+      0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+      0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+      0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+      0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+      0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+      0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+      0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+      0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+      0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+      0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+      0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+      0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+      0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+      0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+      0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+      0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+      0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+      0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+      0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+      0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+      0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+      0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+      0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+      0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+      0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+      0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+      0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+      0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+      0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+      0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+      0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+      0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+      0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+      0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+      0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+      0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+      0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+      0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 };
+  /** Initial value of S-box 3. */
+  private static final int[] KS2 = {
+      0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+      0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+      0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+      0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+      0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+      0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+      0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+      0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+      0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+      0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+      0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+      0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+      0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+      0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+      0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+      0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+      0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+      0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+      0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+      0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+      0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+      0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+      0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+      0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+      0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+      0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+      0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+      0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+      0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+      0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+      0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+      0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+      0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+      0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+      0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+      0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+      0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+      0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+      0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+      0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+      0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+      0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+      0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 };
+  /** Initial value of S-box 4. */
+  private static final int[] KS3 = {
+      0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+      0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+      0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+      0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+      0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+      0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+      0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+      0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+      0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+      0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+      0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+      0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+      0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+      0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+      0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+      0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+      0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+      0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+      0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+      0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+      0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+      0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+      0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+      0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+      0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+      0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+      0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+      0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+      0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+      0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+      0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+      0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+      0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+      0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+      0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+      0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+      0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+      0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+      0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+      0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+      0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+      0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+      0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 };
+  /** Cache of the self test. */
+  private static Boolean valid;
+  /**
+   * Test vector, as published in
+   * href="http://www.counterpane.com/vectors.txt">http://www.counterpane.com/vectors.txt</a>.
+   *
+   * KEY=0000000000000000
+   * PT=0000000000000000
+   * CT=4EF997456198DD78
+   */
+  private static final byte[] TV_KEY = Util.toBytesFromString("0000000000000000");
+  private static final byte[] TV_CT = Util.toBytesFromString("4EF997456198DD78");
+
+  public Blowfish()
+  {
+    super(Registry.BLOWFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
+  }
+
+  public Object clone()
+  {
+    Blowfish result = new Blowfish();
+    result.currentBlockSize = currentBlockSize;
+    return result;
+  }
+
+  public Iterator keySizes()
+  {
+    return new Sequence(8, MAX_KEY_LENGTH, 8).iterator();
+  }
+
+  public Iterator blockSizes()
+  {
+    return Collections.singleton(Integer.valueOf(DEFAULT_BLOCK_SIZE)).iterator();
+  }
+
+  public Object makeKey(byte[] k, int bs)
+  {
+    Context ctx = new Context();
+    System.arraycopy(P, 0, ctx.p, 0, P.length);
+    System.arraycopy(KS0, 0, ctx.s0, 0, KS0.length);
+    System.arraycopy(KS1, 0, ctx.s1, 0, KS1.length);
+    System.arraycopy(KS2, 0, ctx.s2, 0, KS2.length);
+    System.arraycopy(KS3, 0, ctx.s3, 0, KS3.length);
+    // XOR the key with the P-box
+    int l = 0;
+    for (int i = 0; i < ctx.p.length; i++)
+      {
+        int data = 0;
+        for (int j = 0; j < 4; j++)
+          {
+            data = (data << 8) | (k[l++] & 0xff);
+            if (l >= k.length)
+              l = 0;
+          }
+        ctx.p[i] ^= data;
+      }
+    // We swap the left and right words here only, so we can avoid
+    // swapping altogether during encryption/decryption.
+    int t;
+    Block x = new Block();
+    x.left = x.right = 0;
+    for (int i = 0; i < ctx.p.length; i += 2)
+      {
+        blowfishEncrypt(x, ctx);
+        ctx.p[i] = x.right;
+        ctx.p[i + 1] = x.left;
+        t = x.right;
+        x.right = x.left;
+        x.left = t;
+      }
+    for (int i = 0; i < ctx.s0.length; i += 2)
+      {
+        blowfishEncrypt(x, ctx);
+        ctx.s0[i] = x.right;
+        ctx.s0[i + 1] = x.left;
+        t = x.right;
+        x.right = x.left;
+        x.left = t;
+      }
+    for (int i = 0; i < ctx.s1.length; i += 2)
+      {
+        blowfishEncrypt(x, ctx);
+        ctx.s1[i] = x.right;
+        ctx.s1[i + 1] = x.left;
+        t = x.right;
+        x.right = x.left;
+        x.left = t;
+      }
+    for (int i = 0; i < ctx.s2.length; i += 2)
+      {
+        blowfishEncrypt(x, ctx);
+        ctx.s2[i] = x.right;
+        ctx.s2[i + 1] = x.left;
+        t = x.right;
+        x.right = x.left;
+        x.left = t;
+      }
+    for (int i = 0; i < ctx.s3.length; i += 2)
+      {
+        blowfishEncrypt(x, ctx);
+        ctx.s3[i] = x.right;
+        ctx.s3[i + 1] = x.left;
+        t = x.right;
+        x.right = x.left;
+        x.left = t;
+      }
+    x.left = x.right = 0;
+    return ctx;
+  }
+
+  public void encrypt(byte[] in, int i, byte[] out, int o, Object k, int bs)
+  {
+    Block x = new Block();
+    x.left =  (in[i    ] & 0xff) << 24
+            | (in[i + 1] & 0xff) << 16
+            | (in[i + 2] & 0xff) <<  8
+            | (in[i + 3] & 0xff);
+    x.right = (in[i + 4] & 0xff) << 24
+            | (in[i + 5] & 0xff) << 16
+            | (in[i + 6] & 0xff) <<  8
+            | (in[i + 7] & 0xff);
+    blowfishEncrypt(x, (Context) k);
+    out[o    ] = (byte)(x.right >>> 24);
+    out[o + 1] = (byte)(x.right >>> 16);
+    out[o + 2] = (byte)(x.right >>>  8);
+    out[o + 3] = (byte) x.right;
+    out[o + 4] = (byte)(x.left >>> 24);
+    out[o + 5] = (byte)(x.left >>> 16);
+    out[o + 6] = (byte)(x.left >>>  8);
+    out[o + 7] = (byte) x.left;
+    x.left = x.right = 0;
+  }
+
+  public void decrypt(byte[] in, int i, byte[] out, int o, Object k, int bs)
+  {
+    Block x = new Block();
+    x.left =  (in[i    ] & 0xff) << 24
+            | (in[i + 1] & 0xff) << 16
+            | (in[i + 2] & 0xff) <<  8
+            | (in[i + 3] & 0xff);
+    x.right = (in[i + 4] & 0xff) << 24
+            | (in[i + 5] & 0xff) << 16
+            | (in[i + 6] & 0xff) <<  8
+            | (in[i + 7] & 0xff);
+    blowfishDecrypt(x, (Context) k);
+    out[o    ] = (byte)(x.right >>> 24);
+    out[o + 1] = (byte)(x.right >>> 16);
+    out[o + 2] = (byte)(x.right >>>  8);
+    out[o + 3] = (byte) x.right;
+    out[o + 4] = (byte)(x.left >>> 24);
+    out[o + 5] = (byte)(x.left >>> 16);
+    out[o + 6] = (byte)(x.left >>>  8);
+    out[o + 7] = (byte) x.left;
+    x.left = x.right = 0;
+  }
+
+  /** Encrypt a single pair of 32-bit integers. */
+  private void blowfishEncrypt(Block x, Context ctx)
+  {
+    int[] p = ctx.p;
+    int[] s0 = ctx.s0, s1 = ctx.s1, s2 = ctx.s2, s3 = ctx.s3;
+    x.left ^= p[0];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[1];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[2];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[3];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[4];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[5];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[6];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[7];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[8];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[9];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[10];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[11];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[12];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[13];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[14];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[15];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[16];
+    x.right ^= p[17];
+  }
+
+  /** Decrypt a single pair of 32-bit integers. */
+  private void blowfishDecrypt(Block x, Context ctx)
+  {
+    int[] p = ctx.p;
+    int[] s0 = ctx.s0, s1 = ctx.s1, s2 = ctx.s2, s3 = ctx.s3;
+    x.left ^= p[17];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[16];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[15];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[14];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[13];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[12];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[11];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[10];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[9];
+    x.right ^= ((s0[x.left  >>> 24]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[8];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[7];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[6];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[5];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[4];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[3];
+    x.right ^= ((s0[x.left  >>> 24       ]
+               + s1[x.left  >>> 16 & 0xff])
+               ^ s2[x.left  >>>  8 & 0xff])
+               + s3[x.left         & 0xff] ^ p[2];
+    x.left ^=  ((s0[x.right >>> 24       ]
+               + s1[x.right >>> 16 & 0xff])
+               ^ s2[x.right >>>  8 & 0xff])
+               + s3[x.right        & 0xff] ^ p[1];
+    x.right ^= p[0];
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        boolean result = super.selfTest(); // symmetry
+        if (result)
+          result = testKat(TV_KEY, TV_CT);
+        valid = Boolean.valueOf(result);
+      }
+    return valid.booleanValue();
+  }
+
+  /** A simple wrapper for the P- and S-boxes. */
+  private class Context
+      implements Cloneable
+  {
+    /** The P-array. */
+    int[] p, s0, s1, s2, s3;
+
+    /** Default 0-arguments constructor. */
+    Context()
+    {
+      p = new int[18];
+      s0 = new int[256];
+      s1 = new int[256];
+      s2 = new int[256];
+      s3 = new int[256];
+    }
+
+    /**
+     * Private constructor for cloneing.
+     *
+     * @param that The instance being cloned.
+     */
+    private Context(Context that)
+    {
+      this.p = (int[]) that.p.clone();
+      this.s0 = (int[]) that.s0.clone();
+      this.s1 = (int[]) that.s1.clone();
+      this.s2 = (int[]) that.s2.clone();
+      this.s3 = (int[]) that.s3.clone();
+    }
+
+    public Object clone()
+    {
+      return new Context(this);
+    }
+  }
+
+  private class Block
+  {
+    int left, right;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/Cast5.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,987 @@
+/* Cast5.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * An implmenetation of the <code>CAST5</code> (a.k.a. CAST-128) algorithm,
+ * as per <i>RFC-2144</i>, dated May 1997.
+ * <p>
+ * In this RFC, <i>Carlisle Adams</i> (the CA in CAST, ST stands for
+ * <i>Stafford Tavares</i>) describes CAST5 as:
+ * <blockquote>
+ *    "...a DES-like Substitution-Permutation Network (SPN) cryptosystem which
+ *    appears to have good resistance to differential cryptanalysis, linear
+ *    cryptanalysis, and related-key cryptanalysis. This cipher also possesses
+ *    a number of other desirable cryptographic properties, including avalanche,
+ *    Strict Avalanche Criterion (SAC), Bit Independence Criterion (BIC), no
+ *    complementation property, and an absence of weak and semi-weak keys."
+ * </blockquote>
+ * <p>
+ * <code>CAST5</code> is a symmetric block cipher with a block-size of 8
+ * bytes and a variable key-size of up to 128 bits. Its authors, and their
+ * employer (Entrust Technologies, a Nortel majority-owned company), made it
+ * available worldwide on a royalty-free basis for commercial and non-commercial
+ * uses.
+ * <p>
+ * The <code>CAST5</code> encryption algorithm has been designed to allow a
+ * key size that can vary from <code>40</code> bits to <code>128</code> bits,
+ * in 8-bit increments (that is, the allowable key sizes are <code>40, 48, 56,
+ * 64, ..., 112, 120,</code> and <code>128</code> bits. For variable keysize
+ * operation, the specification is as follows:
+ * <ol>
+ *   <li>For key sizes up to and including <code>80</code> bits (i.e.,
+ *    <code>40, 48, 56, 64, 72,</code> and <code>80</code> bits), the algorithm
+ *    is exactly as specified but uses <code>12</code> rounds instead of
+ *    <code>16</code>;</li>
+ *   <li>For key sizes greater than <code>80</code> bits, the algorithm uses
+ *    the full <code>16</code> rounds;</li>
+ *   <li>For key sizes less than <code>128</code> bits, the key is padded with
+ *    zero bytes (in the rightmost, or least significant, positions) out to
+ *    <code>128</code> bits (since the <code>CAST5</code> key schedule assumes
+ *    an input key of <code>128</code> bits).</li>
+ * </ol>
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://www.ietf.org/rfc/rfc2144.txt">The CAST-128 Encryption
+ *    Algorithm</a>.<br>
+ *    <a href="mailto:cadams@entrust.com">Carlisle Adams</a>.</li>
+ * </ol>
+ */
+public class Cast5
+    extends BaseCipher
+{
+  private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes
+  private static final int DEFAULT_KEY_SIZE = 5; // in bytes
+  /**
+   * KAT vector (from rfc-2144):
+   * 40-bit  key         = 01 23 45 67 12
+   *                     = 01 23 45 67 12 00 00 00 00 00 00 00 00 00 00 00
+   *         plaintext   = 01 23 45 67 89 AB CD EF
+   *         ciphertext  = 7A C8 16 D1 6E 9B 30 2E
+   */
+  private static final byte[] KAT_KEY = Util.toBytesFromString("0123456712");
+  private static final byte[] KAT_PT = Util.toBytesFromString("0123456789ABCDEF");
+  private static final byte[] KAT_CT = Util.toBytesFromString("7AC816D16E9B302E");
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+  // CAST5 S-boxes
+  private static final int[] S1 = {
+      0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3,
+      0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675,
+      0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059,
+      0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D,
+      0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B,
+      0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE,
+      0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159,
+      0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935,
+      0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F,
+      0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165,
+      0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38,
+      0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE,
+      0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493,
+      0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A,
+      0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB,
+      0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291,
+      0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14,
+      0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6,
+      0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8,
+      0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511,
+      0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495,
+      0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E,
+      0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426,
+      0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324,
+      0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98,
+      0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F,
+      0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD,
+      0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D,
+      0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464,
+      0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A,
+      0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153,
+      0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D,
+      0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274,
+      0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755,
+      0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1,
+      0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9,
+      0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1,
+      0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79,
+      0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C,
+      0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E,
+      0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF,
+      0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D,
+      0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF };
+  private static final int[] S2 = {
+      0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A,
+      0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA,
+      0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605,
+      0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB,
+      0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B,
+      0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4,
+      0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083,
+      0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359,
+      0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F,
+      0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D,
+      0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E,
+      0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34,
+      0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366,
+      0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4,
+      0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064,
+      0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860,
+      0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6,
+      0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709,
+      0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364,
+      0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B,
+      0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B,
+      0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9,
+      0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C,
+      0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13,
+      0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741,
+      0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB,
+      0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B,
+      0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6,
+      0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA,
+      0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8,
+      0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028,
+      0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D,
+      0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6,
+      0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B,
+      0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1,
+      0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6,
+      0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB,
+      0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA,
+      0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D,
+      0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA,
+      0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E,
+      0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF,
+      0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 };
+  private static final int[] S3 = {
+      0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B,
+      0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE,
+      0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9,
+      0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E,
+      0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD,
+      0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E,
+      0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264,
+      0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B,
+      0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E,
+      0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F,
+      0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E,
+      0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82,
+      0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790,
+      0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504,
+      0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E,
+      0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176,
+      0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8,
+      0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D,
+      0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240,
+      0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341,
+      0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C,
+      0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15,
+      0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788,
+      0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F,
+      0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA,
+      0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392,
+      0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F,
+      0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B,
+      0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE,
+      0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67,
+      0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9,
+      0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536,
+      0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888,
+      0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D,
+      0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2,
+      0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69,
+      0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2,
+      0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE,
+      0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D,
+      0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D,
+      0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00,
+      0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5,
+      0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 };
+  private static final int[] S4 = {
+      0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57,
+      0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120,
+      0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD,
+      0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15,
+      0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE,
+      0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701,
+      0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801,
+      0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5,
+      0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1,
+      0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746,
+      0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3,
+      0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D,
+      0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C,
+      0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C,
+      0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16,
+      0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003,
+      0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7,
+      0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327,
+      0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002,
+      0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24,
+      0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7,
+      0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031,
+      0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF,
+      0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF,
+      0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035,
+      0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69,
+      0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC,
+      0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7,
+      0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E,
+      0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3,
+      0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6,
+      0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2,
+      0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F,
+      0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091,
+      0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6,
+      0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF,
+      0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2,
+      0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367,
+      0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA,
+      0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04,
+      0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6,
+      0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E,
+      0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 };
+  private static final int[] S5 = {
+      0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5,
+      0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00,
+      0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD,
+      0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF,
+      0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB,
+      0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725,
+      0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040,
+      0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7,
+      0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2,
+      0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC,
+      0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399,
+      0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774,
+      0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966,
+      0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468,
+      0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9,
+      0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910,
+      0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616,
+      0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4,
+      0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419,
+      0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049,
+      0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9,
+      0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6,
+      0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C,
+      0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE,
+      0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715,
+      0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6,
+      0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D,
+      0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4,
+      0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA,
+      0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487,
+      0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4,
+      0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5,
+      0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C,
+      0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78,
+      0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87,
+      0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801,
+      0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110,
+      0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58,
+      0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3,
+      0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20,
+      0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D,
+      0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55,
+      0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 };
+  private static final int[] S6 = {
+      0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4,
+      0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9,
+      0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD,
+      0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367,
+      0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F,
+      0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C,
+      0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0,
+      0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3,
+      0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941,
+      0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D,
+      0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223,
+      0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9,
+      0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6,
+      0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A,
+      0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7,
+      0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC,
+      0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89,
+      0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE,
+      0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0,
+      0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F,
+      0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4,
+      0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853,
+      0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87,
+      0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F,
+      0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585,
+      0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751,
+      0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75,
+      0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13,
+      0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283,
+      0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459,
+      0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF,
+      0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891,
+      0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0,
+      0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB,
+      0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200,
+      0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084,
+      0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF,
+      0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B,
+      0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869,
+      0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5,
+      0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB,
+      0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454,
+      0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F };
+  private static final int[] S7 = {
+      0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912,
+      0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82,
+      0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9,
+      0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43,
+      0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4,
+      0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9,
+      0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE,
+      0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516,
+      0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7,
+      0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E,
+      0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E,
+      0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756,
+      0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9,
+      0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B,
+      0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3,
+      0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688,
+      0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C,
+      0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802,
+      0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778,
+      0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7,
+      0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE,
+      0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858,
+      0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310,
+      0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A,
+      0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476,
+      0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF,
+      0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70,
+      0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962,
+      0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A,
+      0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07,
+      0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C,
+      0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C,
+      0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E,
+      0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378,
+      0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E,
+      0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE,
+      0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301,
+      0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2,
+      0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4,
+      0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914,
+      0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021,
+      0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA,
+      0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 };
+  private static final int[] S8 = {
+      0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B,
+      0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174,
+      0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C,
+      0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD,
+      0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7,
+      0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164,
+      0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D,
+      0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862,
+      0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8,
+      0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6,
+      0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04,
+      0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E,
+      0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38,
+      0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8,
+      0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354,
+      0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42,
+      0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160,
+      0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB,
+      0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2,
+      0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225,
+      0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98,
+      0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441,
+      0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4,
+      0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054,
+      0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5,
+      0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C,
+      0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5,
+      0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C,
+      0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B,
+      0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4,
+      0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084,
+      0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101,
+      0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A,
+      0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF,
+      0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77,
+      0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A,
+      0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F,
+      0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819,
+      0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3,
+      0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C,
+      0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1,
+      0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D,
+      0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E };
+  private static final int _12_ROUNDS = 12;
+  private static final int _16_ROUNDS = 16;
+
+  /** Trivial 0-arguments constructor. */
+  public Cast5()
+  {
+    super(Registry.CAST5_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
+  }
+
+  /**
+   * Assuming the input is a 32-bit block organised as: b31b30b29...b0, this
+   * method returns an array of 4 Java ints, containing from position 0 onward
+   * the values: {b31b30b29b28, b27b26b25b24, ... , b3b2b1b0}.
+   *
+   * @param x a 32-bit block.
+   * @return an array of 4 ints, each being the contents of an 8-bit block from
+   * the input.
+   */
+  private static final int[] unscramble(int x)
+  {
+    return new int[] { x >>> 24, (x >>> 16) & 0xFF, (x >>> 8) & 0xFF, x & 0xFF };
+  }
+
+  public Object clone()
+  {
+    Cast5 result = new Cast5();
+    result.currentBlockSize = this.currentBlockSize;
+    return result;
+  }
+
+  public Iterator blockSizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    ArrayList al = new ArrayList();
+    for (int n = 5; n < 17; n++)
+      al.add(Integer.valueOf(n));
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    if (uk == null)
+      throw new InvalidKeyException("Empty key");
+    int len = uk.length;
+    if (len < 5 || len > 16)
+      throw new InvalidKeyException("Key size (in bytes) is not in the range [5..16]");
+    Cast5Key result = new Cast5Key();
+    result.rounds = (len < 11) ? _12_ROUNDS : _16_ROUNDS;
+    byte[] kk = new byte[16];
+    System.arraycopy(uk, 0, kk, 0, len);
+    int z0z1z2z3, z4z5z6z7, z8z9zAzB, zCzDzEzF;
+    int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, zA, zB, zC, zD, zE, zF;
+    int x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xA, xB, xC, xD, xE, xF;
+    int[] b;
+    int x0x1x2x3 =  kk[0 ]         << 24
+                 | (kk[1 ] & 0xFF) << 16
+                 | (kk[2 ] & 0xFF) << 8
+                 | (kk[3 ] & 0xFF);
+    int x4x5x6x7 =  kk[4 ]         << 24
+                 | (kk[5 ] & 0xFF) << 16
+                 | (kk[6 ] & 0xFF) << 8
+                 | (kk[7 ] & 0xFF);
+    int x8x9xAxB =  kk[8 ]         << 24
+                 | (kk[9 ] & 0xFF) << 16
+                 | (kk[10] & 0xFF) << 8
+                 | (kk[11] & 0xFF);
+    int xCxDxExF =  kk[12]         << 24
+                 | (kk[13] & 0xFF) << 16
+                 | (kk[14] & 0xFF) << 8
+                 | (kk[15] & 0xFF);
+    b = unscramble(x0x1x2x3);
+    x0 = b[0];
+    x1 = b[1];
+    x2 = b[2];
+    x3 = b[3];
+    b = unscramble(x4x5x6x7);
+    x4 = b[0];
+    x5 = b[1];
+    x6 = b[2];
+    x7 = b[3];
+    b = unscramble(x8x9xAxB);
+    x8 = b[0];
+    x9 = b[1];
+    xA = b[2];
+    xB = b[3];
+    b = unscramble(xCxDxExF);
+    xC = b[0];
+    xD = b[1];
+    xE = b[2];
+    xF = b[3];
+    z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8];
+    b = unscramble(z0z1z2z3);
+    z0 = b[0];
+    z1 = b[1];
+    z2 = b[2];
+    z3 = b[3];
+    z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA];
+    b = unscramble(z4z5z6z7);
+    z4 = b[0];
+    z5 = b[1];
+    z6 = b[2];
+    z7 = b[3];
+    z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9];
+    b = unscramble(z8z9zAzB);
+    z8 = b[0];
+    z9 = b[1];
+    zA = b[2];
+    zB = b[3];
+    zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB];
+    b = unscramble(zCzDzEzF);
+    zC = b[0];
+    zD = b[1];
+    zE = b[2];
+    zF = b[3];
+    result.Km0 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2];
+    result.Km1 = S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6];
+    result.Km2 = S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9];
+    result.Km3 = S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC];
+    x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0];
+    b = unscramble(x0x1x2x3);
+    x0 = b[0];
+    x1 = b[1];
+    x2 = b[2];
+    x3 = b[3];
+    x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2];
+    b = unscramble(x4x5x6x7);
+    x4 = b[0];
+    x5 = b[1];
+    x6 = b[2];
+    x7 = b[3];
+    x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1];
+    b = unscramble(x8x9xAxB);
+    x8 = b[0];
+    x9 = b[1];
+    xA = b[2];
+    xB = b[3];
+    xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3];
+    b = unscramble(xCxDxExF);
+    xC = b[0];
+    xD = b[1];
+    xE = b[2];
+    xF = b[3];
+    result.Km4 = S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8];
+    result.Km5 = S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD];
+    result.Km6 = S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3];
+    result.Km7 = S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7];
+    z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8];
+    b = unscramble(z0z1z2z3);
+    z0 = b[0];
+    z1 = b[1];
+    z2 = b[2];
+    z3 = b[3];
+    z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA];
+    b = unscramble(z4z5z6z7);
+    z4 = b[0];
+    z5 = b[1];
+    z6 = b[2];
+    z7 = b[3];
+    z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9];
+    b = unscramble(z8z9zAzB);
+    z8 = b[0];
+    z9 = b[1];
+    zA = b[2];
+    zB = b[3];
+    zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB];
+    b = unscramble(zCzDzEzF);
+    zC = b[0];
+    zD = b[1];
+    zE = b[2];
+    zF = b[3];
+    result.Km8 = S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9];
+    result.Km9 = S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC];
+    result.Km10 = S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2];
+    result.Km11 = S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6];
+    x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0];
+    b = unscramble(x0x1x2x3);
+    x0 = b[0];
+    x1 = b[1];
+    x2 = b[2];
+    x3 = b[3];
+    x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2];
+    b = unscramble(x4x5x6x7);
+    x4 = b[0];
+    x5 = b[1];
+    x6 = b[2];
+    x7 = b[3];
+    x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1];
+    b = unscramble(x8x9xAxB);
+    x8 = b[0];
+    x9 = b[1];
+    xA = b[2];
+    xB = b[3];
+    xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3];
+    b = unscramble(xCxDxExF);
+    xC = b[0];
+    xD = b[1];
+    xE = b[2];
+    xF = b[3];
+    result.Km12 = S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3];
+    result.Km13 = S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7];
+    result.Km14 = S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8];
+    result.Km15 = S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD];
+    // The remaining half is identical to what is given above, carrying on
+    // from the last created x0..xF to generate keys K17 - K32. These keys
+    // will be used as the 'rotation' keys and as such only the five least
+    // significant bits are to be considered.
+    z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8];
+    b = unscramble(z0z1z2z3);
+    z0 = b[0];
+    z1 = b[1];
+    z2 = b[2];
+    z3 = b[3];
+    z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA];
+    b = unscramble(z4z5z6z7);
+    z4 = b[0];
+    z5 = b[1];
+    z6 = b[2];
+    z7 = b[3];
+    z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9];
+    b = unscramble(z8z9zAzB);
+    z8 = b[0];
+    z9 = b[1];
+    zA = b[2];
+    zB = b[3];
+    zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB];
+    b = unscramble(zCzDzEzF);
+    zC = b[0];
+    zD = b[1];
+    zE = b[2];
+    zF = b[3];
+    result.Kr0 = (S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]) & 0x1F;
+    result.Kr1 = (S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6]) & 0x1F;
+    result.Kr2 = (S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9]) & 0x1F;
+    result.Kr3 = (S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC]) & 0x1F;
+    x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0];
+    b = unscramble(x0x1x2x3);
+    x0 = b[0];
+    x1 = b[1];
+    x2 = b[2];
+    x3 = b[3];
+    x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2];
+    b = unscramble(x4x5x6x7);
+    x4 = b[0];
+    x5 = b[1];
+    x6 = b[2];
+    x7 = b[3];
+    x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1];
+    b = unscramble(x8x9xAxB);
+    x8 = b[0];
+    x9 = b[1];
+    xA = b[2];
+    xB = b[3];
+    xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3];
+    b = unscramble(xCxDxExF);
+    xC = b[0];
+    xD = b[1];
+    xE = b[2];
+    xF = b[3];
+    result.Kr4 = (S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8]) & 0x1F;
+    result.Kr5 = (S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD]) & 0x1F;
+    result.Kr6 = (S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3]) & 0x1F;
+    result.Kr7 = (S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7]) & 0x1F;
+    z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8];
+    b = unscramble(z0z1z2z3);
+    z0 = b[0];
+    z1 = b[1];
+    z2 = b[2];
+    z3 = b[3];
+    z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA];
+    b = unscramble(z4z5z6z7);
+    z4 = b[0];
+    z5 = b[1];
+    z6 = b[2];
+    z7 = b[3];
+    z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9];
+    b = unscramble(z8z9zAzB);
+    z8 = b[0];
+    z9 = b[1];
+    zA = b[2];
+    zB = b[3];
+    zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB];
+    b = unscramble(zCzDzEzF);
+    zC = b[0];
+    zD = b[1];
+    zE = b[2];
+    zF = b[3];
+    result.Kr8 = (S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9]) & 0x1F;
+    result.Kr9 = (S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC]) & 0x1F;
+    result.Kr10 = (S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2]) & 0x1F;
+    result.Kr11 = (S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6]) & 0x1F;
+    x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0];
+    b = unscramble(x0x1x2x3);
+    x0 = b[0];
+    x1 = b[1];
+    x2 = b[2];
+    x3 = b[3];
+    x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2];
+    b = unscramble(x4x5x6x7);
+    x4 = b[0];
+    x5 = b[1];
+    x6 = b[2];
+    x7 = b[3];
+    x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1];
+    b = unscramble(x8x9xAxB);
+    x8 = b[0];
+    x9 = b[1];
+    xA = b[2];
+    xB = b[3];
+    xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3];
+    b = unscramble(xCxDxExF);
+    xC = b[0];
+    xD = b[1];
+    xE = b[2];
+    xF = b[3];
+    result.Kr12 = (S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3]) & 0x1F;
+    result.Kr13 = (S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7]) & 0x1F;
+    result.Kr14 = (S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8]) & 0x1F;
+    result.Kr15 = (S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD]) & 0x1F;
+    return result;
+  }
+
+  /**
+   * The full encryption algorithm is given in the following four steps.
+   * <pre>
+   *    INPUT:  plaintext m1...m64; key K = k1...k128.
+   *    OUTPUT: ciphertext c1...c64.
+   * </pre>
+   * <ol>
+   *   <li>(key schedule) Compute 16 pairs of subkeys {Kmi, Kri} from a user
+   *    key (see makeKey() method).</li>
+   *   <li>(L0,R0) <-- (m1...m64).  (Split the plaintext into left and right
+   *    32-bit halves L0 = m1...m32 and R0 = m33...m64.).</li>
+   *   <li>(16 rounds) for i from 1 to 16, compute Li and Ri as follows:
+   *     <ul>
+   *       <li>Li = Ri-1;</li>
+   *       <li>Ri = Li-1 ^ F(Ri-1,Kmi,Kri), where F is defined in method F() --
+   *       f is of Type 1, Type 2, or Type 3, depending on i, and ^ being the
+   *       bitwise XOR function.</li>
+   *     </ul>
+   *   <li>c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and
+   *    concatenate to form the ciphertext.)</li>
+   * </ol>
+   * <p>
+   * Decryption is identical to the encryption algorithm given above, except
+   * that the rounds (and therefore the subkey pairs) are used in reverse order
+   * to compute (L0,R0) from (R16,L16).
+   * <p>
+   * Looking at the iterations/rounds in pairs we have:
+   * <pre>
+   *    (1a)    Li = Ri-1;
+   *    (1b)    Ri = Li-1 ^ Fi(Ri-1);
+   *    (2a)    Li+1 = Ri;
+   *    (2b)    Ri+1 = Li ^ Fi+1(Ri);
+   * </pre>
+   * which by substituting (2a) in (2b) becomes
+   * <pre>
+   *    (2c)    Ri+1 = Li ^ Fi+1(Li+1);
+   * </pre>
+   * by substituting (1b) in (2a) and (1a) in (2c), we get:
+   * <pre>
+   *    (3a)    Li+1 = Li-1 ^ Fi(Ri-1);
+   *    (3b)    Ri+1 = Ri-1 ^ Fi+1(Li+1);
+   * </pre>
+   * Using only one couple of variables L and R, initialised to L0 and R0
+   * respectively, the assignments for each pair of rounds become:
+   * <pre>
+   *    (4a)    L ^= Fi(R);
+   *    (4b)    R ^= Fi+1(L);
+   * </pre>
+   *
+   * @param in contains the plain-text 64-bit block.
+   * @param i start index within input where data is considered.
+   * @param out will contain the cipher-text block.
+   * @param j index in out where cipher-text starts.
+   * @param k the session key object.
+   * @param bs the desired block size.
+   */
+  public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    Cast5Key K = (Cast5Key) k;
+    int L = (in[i++] & 0xFF) << 24
+          | (in[i++] & 0xFF) << 16
+          | (in[i++] & 0xFF) << 8
+          |  in[i++] & 0xFF;
+    int R = (in[i++] & 0xFF) << 24
+          | (in[i++] & 0xFF) << 16
+          | (in[i++] & 0xFF) << 8
+          |  in[i  ] & 0xFF;
+    L ^= f1(R, K.Km0, K.Kr0);
+    R ^= f2(L, K.Km1, K.Kr1); // round 2
+    L ^= f3(R, K.Km2, K.Kr2);
+    R ^= f1(L, K.Km3, K.Kr3); // round 4
+    L ^= f2(R, K.Km4, K.Kr4);
+    R ^= f3(L, K.Km5, K.Kr5); // round 6
+    L ^= f1(R, K.Km6, K.Kr6);
+    R ^= f2(L, K.Km7, K.Kr7); // round 8
+    L ^= f3(R, K.Km8, K.Kr8);
+    R ^= f1(L, K.Km9, K.Kr9); // round 10
+    L ^= f2(R, K.Km10, K.Kr10);
+    R ^= f3(L, K.Km11, K.Kr11); // round 12
+    if (K.rounds == _16_ROUNDS)
+      {
+        L ^= f1(R, K.Km12, K.Kr12);
+        R ^= f2(L, K.Km13, K.Kr13); // round 14
+        L ^= f3(R, K.Km14, K.Kr14);
+        R ^= f1(L, K.Km15, K.Kr15); // round 16
+      }
+    out[j++] = (byte)(R >>> 24);
+    out[j++] = (byte)(R >>> 16);
+    out[j++] = (byte)(R >>> 8);
+    out[j++] = (byte) R;
+    out[j++] = (byte)(L >>> 24);
+    out[j++] = (byte)(L >>> 16);
+    out[j++] = (byte)(L >>> 8);
+    out[j  ] = (byte) L;
+  }
+
+  public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    Cast5Key K = (Cast5Key) k;
+    int L = (in[i++] & 0xFF) << 24
+          | (in[i++] & 0xFF) << 16
+          | (in[i++] & 0xFF) << 8
+          |  in[i++] & 0xFF;
+    int R = (in[i++] & 0xFF) << 24
+          | (in[i++] & 0xFF) << 16
+          | (in[i++] & 0xFF) << 8
+          |  in[i  ] & 0xFF;
+    if (K.rounds == _16_ROUNDS)
+      {
+        L ^= f1(R, K.Km15, K.Kr15);
+        R ^= f3(L, K.Km14, K.Kr14);
+        L ^= f2(R, K.Km13, K.Kr13);
+        R ^= f1(L, K.Km12, K.Kr12);
+      }
+    L ^= f3(R, K.Km11, K.Kr11);
+    R ^= f2(L, K.Km10, K.Kr10);
+    L ^= f1(R, K.Km9, K.Kr9);
+    R ^= f3(L, K.Km8, K.Kr8);
+    L ^= f2(R, K.Km7, K.Kr7);
+    R ^= f1(L, K.Km6, K.Kr6);
+    L ^= f3(R, K.Km5, K.Kr5);
+    R ^= f2(L, K.Km4, K.Kr4);
+    L ^= f1(R, K.Km3, K.Kr3);
+    R ^= f3(L, K.Km2, K.Kr2);
+    L ^= f2(R, K.Km1, K.Kr1);
+    R ^= f1(L, K.Km0, K.Kr0);
+    out[j++] = (byte)(R >>> 24);
+    out[j++] = (byte)(R >>> 16);
+    out[j++] = (byte)(R >>> 8);
+    out[j++] = (byte) R;
+    out[j++] = (byte)(L >>> 24);
+    out[j++] = (byte)(L >>> 16);
+    out[j++] = (byte)(L >>> 8);
+    out[j  ] = (byte) L;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        boolean result = super.selfTest(); // do symmetry tests
+        if (result)
+          result = testKat(KAT_KEY, KAT_CT, KAT_PT);
+        valid = Boolean.valueOf(result);
+      }
+    return valid.booleanValue();
+  }
+
+  private final int f1(int I, int m, int r)
+  {
+    I = m + I;
+    I = I << r | I >>> (32 - r);
+    return (((S1[(I >>> 24) & 0xFF])
+            ^ S2[(I >>> 16) & 0xFF])
+            - S3[(I >>>  8) & 0xFF])
+            + S4[ I         & 0xFF];
+  }
+
+  private final int f2(int I, int m, int r)
+  {
+    I = m ^ I;
+    I = I << r | I >>> (32 - r);
+    return (((S1[(I >>> 24) & 0xFF])
+            - S2[(I >>> 16) & 0xFF])
+            + S3[(I >>>  8) & 0xFF])
+            ^ S4[ I         & 0xFF];
+  }
+
+  private final int f3(int I, int m, int r)
+  {
+    I = m - I;
+    I = I << r | I >>> (32 - r);
+    return (((S1[(I >>> 24) & 0xFF])
+            + S2[(I >>> 16) & 0xFF])
+            ^ S3[(I >>>  8) & 0xFF])
+            - S4[ I         & 0xFF];
+  }
+
+  /** An opaque CAST5 key object. */
+  private class Cast5Key
+  {
+    int rounds;
+    /** Masking session keys. */
+    int Km0, Km1, Km2,  Km3,  Km4,  Km5,  Km6,  Km7,
+        Km8, Km9, Km10, Km11, Km12, Km13, Km14, Km15;
+    /** Rotation session keys. */
+    int Kr0, Kr1, Kr2,  Kr3,  Kr4,  Kr5,  Kr6,  Kr7,
+        Kr8, Kr9, Kr10, Kr11, Kr12, Kr13, Kr14, Kr15;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/CipherFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,129 @@
+/* CipherFactory.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Registry;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A <i>Factory</i> to instantiate symmetric block cipher instances.
+ */
+public class CipherFactory
+    implements Registry
+{
+  /** Trivial constructor to enforce Singleton pattern. */
+  private CipherFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a block cipher given its name.
+   * 
+   * @param name the case-insensitive name of the symmetric-key block cipher
+   *          algorithm.
+   * @return an instance of the designated cipher algorithm, or
+   *         <code>null</code> if none is found.
+   * @exception InternalError if the implementation does not pass its self-test.
+   */
+  public static final IBlockCipher getInstance(String name)
+  {
+    if (name == null)
+      return null;
+    name = name.trim();
+    IBlockCipher result = null;
+    if (name.equalsIgnoreCase(ANUBIS_CIPHER))
+      result = new Anubis();
+    else if (name.equalsIgnoreCase(BLOWFISH_CIPHER))
+      result = new Blowfish();
+    else if (name.equalsIgnoreCase(DES_CIPHER))
+      result = new DES();
+    else if (name.equalsIgnoreCase(KHAZAD_CIPHER))
+      result = new Khazad();
+    else if (name.equalsIgnoreCase(RIJNDAEL_CIPHER)
+             || name.equalsIgnoreCase(AES_CIPHER))
+      result = new Rijndael();
+    else if (name.equalsIgnoreCase(SERPENT_CIPHER))
+      result = new Serpent();
+    else if (name.equalsIgnoreCase(SQUARE_CIPHER))
+      result = new Square();
+    else if (name.equalsIgnoreCase(TRIPLEDES_CIPHER)
+             || name.equalsIgnoreCase(DESEDE_CIPHER))
+      result = new TripleDES();
+    else if (name.equalsIgnoreCase(TWOFISH_CIPHER))
+      result = new Twofish();
+    else if (name.equalsIgnoreCase(CAST5_CIPHER)
+             || (name.equalsIgnoreCase(CAST128_CIPHER)
+                 || (name.equalsIgnoreCase(CAST_128_CIPHER))))
+      result = new Cast5();
+    else if (name.equalsIgnoreCase(NULL_CIPHER))
+      result = new NullCipher();
+
+    if (result != null && ! result.selfTest())
+      throw new InternalError(result.name());
+
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of symmetric key block cipher implementation names
+   * supported by this <i>Factory</i>.
+   * 
+   * @return a {@link Set} of block cipher names (Strings).
+   */
+  public static final Set getNames()
+  {
+    HashSet hs = new HashSet();
+    hs.add(ANUBIS_CIPHER);
+    hs.add(BLOWFISH_CIPHER);
+    hs.add(DES_CIPHER);
+    hs.add(KHAZAD_CIPHER);
+    hs.add(RIJNDAEL_CIPHER);
+    hs.add(SERPENT_CIPHER);
+    hs.add(SQUARE_CIPHER);
+    hs.add(TRIPLEDES_CIPHER);
+    hs.add(TWOFISH_CIPHER);
+    hs.add(CAST5_CIPHER);
+    hs.add(NULL_CIPHER);
+    return Collections.unmodifiableSet(hs);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/DES.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,652 @@
+/* DES.java -- 
+   Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Registry;
+import gnu.java.security.Properties;
+import gnu.java.security.util.Util;
+
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * The Data Encryption Standard. DES is a 64-bit block cipher with a 56-bit
+ * key, developed by IBM in the 1970's for the standardization process begun by
+ * the National Bureau of Standards (now NIST).
+ * <p>
+ * New applications should not use DES except for compatibility.
+ * <p>
+ * This version is based upon the description and sample implementation in
+ * [1].
+ * <p>
+ * References:
+ * <ol>
+ *    <li>Bruce Schneier, <i>Applied Cryptography: Protocols, Algorithms, and
+ *    Source Code in C, Second Edition</i>. (1996 John Wiley and Sons) ISBN
+ *    0-471-11709-9. Pages 265--301, 623--632.</li>
+ * </ol>
+ */
+public class DES
+    extends BaseCipher
+{
+  /** DES operates on 64 bit blocks. */
+  public static final int BLOCK_SIZE = 8;
+  /** DES uses 56 bits of a 64 bit parity-adjusted key. */
+  public static final int KEY_SIZE = 8;
+  // S-Boxes 1 through 8.
+  private static final int[] SP1 = new int[] {
+      0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404,
+      0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400,
+      0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400,
+      0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404,
+      0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404,
+      0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000,
+      0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000,
+      0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404,
+      0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404,
+      0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000,
+      0x00010004, 0x00010400, 0x00000000, 0x01010004 };
+  private static final int[] SP2 = new int[] {
+      0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020,
+      0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000,
+      0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020,
+      0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000,
+      0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000,
+      0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000,
+      0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000,
+      0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000,
+      0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020,
+      0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020,
+      0x80000000, 0x80100020, 0x80108020, 0x00108000 };
+  private static final int[] SP3 = new int[] {
+      0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000,
+      0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000,
+      0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008,
+      0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208,
+      0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208,
+      0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208,
+      0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008,
+      0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008,
+      0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208,
+      0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000,
+      0x00020208, 0x00000008, 0x08020008, 0x00020200 };
+  private static final int[] SP4 = new int[] {
+      0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081,
+      0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081,
+      0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000,
+      0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080,
+      0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080,
+      0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081,
+      0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080,
+      0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+      0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001,
+      0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001,
+      0x00000080, 0x00800000, 0x00002000, 0x00802080 };
+  private static final int[] SP5 = new int[] {
+      0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100,
+      0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100,
+      0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000,
+      0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100,
+      0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000,
+      0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000,
+      0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000,
+      0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000,
+      0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000,
+      0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000,
+      0x00000000, 0x40080000, 0x02080100, 0x40000100 };
+  private static final int[] SP6 = new int[] {
+      0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010,
+      0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010,
+      0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010,
+      0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010,
+      0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000,
+      0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000,
+      0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000,
+      0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000,
+      0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000,
+      0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000,
+      0x20404000, 0x20000000, 0x00400010, 0x20004010 };
+  private static final int[] SP7 = new int[] {
+      0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802,
+      0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002,
+      0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802,
+      0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002,
+      0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002,
+      0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802,
+      0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000,
+      0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800,
+      0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000,
+      0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800,
+      0x04000002, 0x04000800, 0x00000800, 0x00200002 };
+  private static final int[] SP8 = new int[] {
+      0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040,
+      0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000,
+      0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040,
+      0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000,
+      0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000,
+      0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000,
+      0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040,
+      0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040,
+      0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000,
+      0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040,
+      0x00001040, 0x00040040, 0x10000000, 0x10041000 };
+  /**
+   * Constants that help in determining whether or not a byte array is parity
+   * adjusted.
+   */
+  private static final byte[] PARITY = {
+      8, 1, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 2, 8,
+      0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 3,
+      0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+      8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
+      0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+      8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
+      8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
+      0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+      0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+      8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
+      8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
+      0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+      8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
+      0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+      4, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
+      8, 5, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 6, 8 };
+  // Key schedule constants.
+  private static final byte[] ROTARS = {
+      1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 };
+  private static final byte[] PC1 = {
+      56, 48, 40, 32, 24, 16,  8,  0, 57, 49, 41, 33, 25, 17,  9,  1,
+      58, 50, 42, 34, 26, 18, 10,  2, 59, 51, 43, 35, 62, 54, 46, 38,
+      30, 22, 14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 60, 52, 44, 36,
+      28, 20, 12,  4, 27, 19, 11,  3 };
+  private static final byte[] PC2 = {
+      13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9, 22, 18, 11,  3,
+      25,  7, 15,  6, 26, 19, 12,  1, 40, 51, 30, 36, 46, 54, 29, 39,
+      50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+  /**
+   * Weak keys (parity adjusted): If all the bits in each half are either 0
+   * or 1, then the key used for any cycle of the algorithm is the same as
+   * all other cycles. 
+   */
+  public static final byte[][] WEAK_KEYS = {
+      Util.toBytesFromString("0101010101010101"),
+      Util.toBytesFromString("01010101FEFEFEFE"),
+      Util.toBytesFromString("FEFEFEFE01010101"),
+      Util.toBytesFromString("FEFEFEFEFEFEFEFE") };
+  /**
+   * Semi-weak keys (parity adjusted):  Some pairs of keys encrypt plain text
+   * to identical cipher text. In other words, one key in the pair can decrypt
+   * messages that were encrypted with the other key. These keys are called
+   * semi-weak keys. This occurs because instead of 16 different sub-keys being
+   * generated, these semi-weak keys produce only two different sub-keys.
+   */
+  public static final byte[][] SEMIWEAK_KEYS = {
+      Util.toBytesFromString("01FE01FE01FE01FE"),
+      Util.toBytesFromString("FE01FE01FE01FE01"),
+      Util.toBytesFromString("1FE01FE00EF10EF1"),
+      Util.toBytesFromString("E01FE01FF10EF10E"),
+      Util.toBytesFromString("01E001E001F101F1"),
+      Util.toBytesFromString("E001E001F101F101"),
+      Util.toBytesFromString("1FFE1FFE0EFE0EFE"),
+      Util.toBytesFromString("FE1FFE1FFE0EFE0E"),
+      Util.toBytesFromString("011F011F010E010E"),
+      Util.toBytesFromString("1F011F010E010E01"),
+      Util.toBytesFromString("E0FEE0FEF1FEF1FE"),
+      Util.toBytesFromString("FEE0FEE0FEF1FEF1") };
+  /** Possible weak keys (parity adjusted) --produce 4 instead of 16 subkeys. */
+  public static final byte[][] POSSIBLE_WEAK_KEYS = {
+      Util.toBytesFromString("1F1F01010E0E0101"),
+      Util.toBytesFromString("011F1F01010E0E01"),
+      Util.toBytesFromString("1F01011F0E01010E"),
+      Util.toBytesFromString("01011F1F01010E0E"),
+      Util.toBytesFromString("E0E00101F1F10101"),
+      Util.toBytesFromString("FEFE0101FEFE0101"),
+      Util.toBytesFromString("FEE01F01FEF10E01"),
+      Util.toBytesFromString("E0FE1F01F1FE0E01"),
+      Util.toBytesFromString("FEE0011FFEF1010E"),
+      Util.toBytesFromString("E0FE011FF1FE010E"),
+      Util.toBytesFromString("E0E01F1FF1F10E0E"),
+      Util.toBytesFromString("FEFE1F1FFEFE0E0E"),
+      Util.toBytesFromString("1F1F01010E0E0101"),
+      Util.toBytesFromString("011F1F01010E0E01"),
+      Util.toBytesFromString("1F01011F0E01010E"),
+      Util.toBytesFromString("01011F1F01010E0E"),
+      Util.toBytesFromString("01E0E00101F1F101"),
+      Util.toBytesFromString("1FFEE0010EFEF001"),
+      Util.toBytesFromString("1FE0FE010EF1FE01"),
+      Util.toBytesFromString("01FEFE0101FEFE01"),
+      Util.toBytesFromString("1FE0E01F0EF1F10E"),
+      Util.toBytesFromString("01FEE01F01FEF10E"),
+      Util.toBytesFromString("01E0FE1F01F1FE0E"),
+      Util.toBytesFromString("1FFEFE1F0EFEFE0E"),
+
+      Util.toBytesFromString("E00101E0F10101F1"),
+      Util.toBytesFromString("FE1F01E0FE0E0EF1"),
+      Util.toBytesFromString("FE011FE0FE010EF1"),
+      Util.toBytesFromString("E01F1FE0F10E0EF1"),
+      Util.toBytesFromString("FE0101FEFE0101FE"),
+      Util.toBytesFromString("E01F01FEF10E01FE"),
+      Util.toBytesFromString("E0011FFEF1010EFE"),
+      Util.toBytesFromString("FE1F1FFEFE0E0EFE"),
+      Util.toBytesFromString("1FFE01E00EFE01F1"),
+      Util.toBytesFromString("01FE1FE001FE0EF1"),
+      Util.toBytesFromString("1FE001FE0EF101FE"),
+      Util.toBytesFromString("01E01FFE01F10EFE"),
+      Util.toBytesFromString("0101E0E00101F1F1"),
+      Util.toBytesFromString("1F1FE0E00E0EF1F1"),
+      Util.toBytesFromString("1F01FEE00E01FEF1"),
+      Util.toBytesFromString("011FFEE0010EFEF1"),
+      Util.toBytesFromString("1F01E0FE0E01F1FE"),
+      Util.toBytesFromString("011FE0FE010EF1FE"),
+      Util.toBytesFromString("0101FEFE0001FEFE"),
+      Util.toBytesFromString("1F1FFEFE0E0EFEFE"),
+      Util.toBytesFromString("FEFEE0E0FEFEF1F1"),
+      Util.toBytesFromString("E0FEFEE0F1FEFEF1"),
+      Util.toBytesFromString("FEE0E0FEFEF1F1FE"),
+      Util.toBytesFromString("E0E0FEFEF1F1FEFE") };
+
+  /** Default 0-argument constructor. */
+  public DES()
+  {
+    super(Registry.DES_CIPHER, BLOCK_SIZE, KEY_SIZE);
+  }
+
+  /**
+   * Adjust the parity for a raw key array. This essentially means that each
+   * byte in the array will have an odd number of '1' bits (the last bit in
+   * each byte is unused.
+   *
+   * @param kb The key array, to be parity-adjusted.
+   * @param offset The starting index into the key bytes.
+   */
+  public static void adjustParity(byte[] kb, int offset)
+  {
+    for (int i = offset; i < offset + KEY_SIZE; i++)
+      kb[i] ^= (PARITY[kb[i] & 0xff] == 8) ? 1 : 0;
+  }
+
+  /**
+   * Test if a byte array, which must be at least 8 bytes long, is parity
+   * adjusted.
+   *
+   * @param kb The key bytes.
+   * @param offset The starting index into the key bytes.
+   * @return <code>true</code> if the first 8 bytes of <i>kb</i> have been
+   * parity adjusted. <code>false</code> otherwise.
+   */
+  public static boolean isParityAdjusted(byte[] kb, int offset)
+  {
+    int w = 0x88888888;
+    int n = PARITY[kb[offset + 0] & 0xff];
+    n <<= 4;
+    n |= PARITY[kb[offset + 1] & 0xff];
+    n <<= 4;
+    n |= PARITY[kb[offset + 2] & 0xff];
+    n <<= 4;
+    n |= PARITY[kb[offset + 3] & 0xff];
+    n <<= 4;
+    n |= PARITY[kb[offset + 4] & 0xff];
+    n <<= 4;
+    n |= PARITY[kb[offset + 5] & 0xff];
+    n <<= 4;
+    n |= PARITY[kb[offset + 6] & 0xff];
+    n <<= 4;
+    n |= PARITY[kb[offset + 7] & 0xff];
+    return (n & w) == 0;
+  }
+
+  /**
+   * Test if a key is a weak key.
+   *
+   * @param kb The key to test.
+   * @return <code>true</code> if the key is weak.
+   */
+  public static boolean isWeak(byte[] kb)
+  {
+    for (int i = 0; i < WEAK_KEYS.length; i++)
+      if (Arrays.equals(WEAK_KEYS[i], kb))
+        return true;
+    return false;
+  }
+
+  /**
+   * Test if a key is a semi-weak key.
+   *
+   * @param kb The key to test.
+   * @return <code>true</code> if this key is semi-weak.
+   */
+  public static boolean isSemiWeak(byte[] kb)
+  {
+    for (int i = 0; i < SEMIWEAK_KEYS.length; i++)
+      if (Arrays.equals(SEMIWEAK_KEYS[i], kb))
+        return true;
+    return false;
+  }
+
+  /**
+   * Test if the designated byte array represents a possibly weak key.
+   *
+   * @param kb the byte array to test.
+   * @return <code>true</code> if <code>kb</code>represents a possibly weak key.
+   * Returns <code>false</code> otherwise.
+   */
+  public static boolean isPossibleWeak(byte[] kb)
+  {
+    for (int i = 0; i < POSSIBLE_WEAK_KEYS.length; i++)
+      if (Arrays.equals(POSSIBLE_WEAK_KEYS[i], kb))
+        return true;
+    return false;
+  }
+
+  /**
+   * The core DES function. This is used for both encryption and decryption,
+   * the only difference being the key.
+   *
+   * @param in The input bytes.
+   * @param i The starting offset into the input bytes.
+   * @param out The output bytes.
+   * @param o The starting offset into the output bytes.
+   * @param key The working key.
+   */
+  private static void desFunc(byte[] in, int i, byte[] out, int o, int[] key)
+  {
+    int right, left, work;
+    // Load.
+    left =  (in[i++] & 0xff) << 24
+          | (in[i++] & 0xff) << 16
+          | (in[i++] & 0xff) << 8
+          |  in[i++] & 0xff;
+    right = (in[i++] & 0xff) << 24
+          | (in[i++] & 0xff) << 16
+          | (in[i++] & 0xff) << 8
+          |  in[i  ] & 0xff;
+    // Initial permutation.
+    work = ((left >>> 4) ^ right) & 0x0F0F0F0F;
+    left ^= work << 4;
+    right ^= work;
+
+    work = ((left >>> 16) ^ right) & 0x0000FFFF;
+    left ^= work << 16;
+    right ^= work;
+
+    work = ((right >>> 2) ^ left) & 0x33333333;
+    right ^= work << 2;
+    left ^= work;
+
+    work = ((right >>> 8) ^ left) & 0x00FF00FF;
+    right ^= work << 8;
+    left ^= work;
+
+    right = ((right << 1) | ((right >>> 31) & 1)) & 0xFFFFFFFF;
+    work = (left ^ right) & 0xAAAAAAAA;
+    left ^= work;
+    right ^= work;
+    left = ((left << 1) | ((left >>> 31) & 1)) & 0xFFFFFFFF;
+
+    int k = 0, t;
+    for (int round = 0; round < 8; round++)
+      {
+        work = right >>> 4 | right << 28;
+        work ^= key[k++];
+        t = SP7[work & 0x3F];
+        work >>>= 8;
+        t |= SP5[work & 0x3F];
+        work >>>= 8;
+        t |= SP3[work & 0x3F];
+        work >>>= 8;
+        t |= SP1[work & 0x3F];
+        work = right ^ key[k++];
+        t |= SP8[work & 0x3F];
+        work >>>= 8;
+        t |= SP6[work & 0x3F];
+        work >>>= 8;
+        t |= SP4[work & 0x3F];
+        work >>>= 8;
+        t |= SP2[work & 0x3F];
+        left ^= t;
+
+        work = left >>> 4 | left << 28;
+        work ^= key[k++];
+        t = SP7[work & 0x3F];
+        work >>>= 8;
+        t |= SP5[work & 0x3F];
+        work >>>= 8;
+        t |= SP3[work & 0x3F];
+        work >>>= 8;
+        t |= SP1[work & 0x3F];
+        work = left ^ key[k++];
+        t |= SP8[work & 0x3F];
+        work >>>= 8;
+        t |= SP6[work & 0x3F];
+        work >>>= 8;
+        t |= SP4[work & 0x3F];
+        work >>>= 8;
+        t |= SP2[work & 0x3F];
+        right ^= t;
+      }
+    // The final permutation.
+    right = (right << 31) | (right >>> 1);
+    work = (left ^ right) & 0xAAAAAAAA;
+    left ^= work;
+    right ^= work;
+    left = (left << 31) | (left >>> 1);
+
+    work = ((left >>> 8) ^ right) & 0x00FF00FF;
+    left ^= work << 8;
+    right ^= work;
+
+    work = ((left >>> 2) ^ right) & 0x33333333;
+    left ^= work << 2;
+    right ^= work;
+
+    work = ((right >>> 16) ^ left) & 0x0000FFFF;
+    right ^= work << 16;
+    left ^= work;
+
+    work = ((right >>> 4) ^ left) & 0x0F0F0F0F;
+    right ^= work << 4;
+    left ^= work;
+
+    out[o++] = (byte)(right >>> 24);
+    out[o++] = (byte)(right >>> 16);
+    out[o++] = (byte)(right >>> 8);
+    out[o++] = (byte) right;
+    out[o++] = (byte)(left >>> 24);
+    out[o++] = (byte)(left >>> 16);
+    out[o++] = (byte)(left >>> 8);
+    out[o  ] = (byte) left;
+  }
+
+  public Object clone()
+  {
+    return new DES();
+  }
+
+  public Iterator blockSizes()
+  {
+    return Collections.singleton(Integer.valueOf(BLOCK_SIZE)).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    return Collections.singleton(Integer.valueOf(KEY_SIZE)).iterator();
+  }
+
+  public Object makeKey(byte[] kb, int bs) throws InvalidKeyException
+  {
+    if (kb == null || kb.length != KEY_SIZE)
+      throw new InvalidKeyException("DES keys must be 8 bytes long");
+
+    if (Properties.checkForWeakKeys()
+        && (isWeak(kb) || isSemiWeak(kb) || isPossibleWeak(kb)))
+      throw new WeakKeyException();
+
+    int i, j, l, m, n;
+    long pc1m = 0, pcr = 0;
+
+    for (i = 0; i < 56; i++)
+      {
+        l = PC1[i];
+        pc1m |= ((kb[l >>> 3] & (0x80 >>> (l & 7))) != 0) ? (1L << (55 - i))
+                                                          : 0;
+      }
+    Context ctx = new Context();
+    // Encryption key first.
+    for (i = 0; i < 16; i++)
+      {
+        pcr = 0;
+        m = i << 1;
+        n = m + 1;
+        for (j = 0; j < 28; j++)
+          {
+            l = j + ROTARS[i];
+            if (l < 28)
+              pcr |= ((pc1m & 1L << (55 - l)) != 0) ? (1L << (55 - j)) : 0;
+            else
+              pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) ? (1L << (55 - j))
+                                                           : 0;
+          }
+        for (j = 28; j < 56; j++)
+          {
+            l = j + ROTARS[i];
+            if (l < 56)
+              pcr |= ((pc1m & 1L << (55 - l)) != 0) ? (1L << (55 - j)) : 0;
+            else
+              pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) ? (1L << (55 - j))
+                                                           : 0;
+          }
+        for (j = 0; j < 24; j++)
+          {
+            if ((pcr & 1L << (55 - PC2[j])) != 0)
+              ctx.ek[m] |= 1 << (23 - j);
+            if ((pcr & 1L << (55 - PC2[j + 24])) != 0)
+              ctx.ek[n] |= 1 << (23 - j);
+          }
+      }
+    // The decryption key is the same, but in reversed order.
+    for (i = 0; i < Context.EXPANDED_KEY_SIZE; i += 2)
+      {
+        ctx.dk[30 - i] = ctx.ek[i];
+        ctx.dk[31 - i] = ctx.ek[i + 1];
+      }
+    // "Cook" the keys.
+    for (i = 0; i < 32; i += 2)
+      {
+        int x, y;
+        x = ctx.ek[i];
+        y = ctx.ek[i + 1];
+        ctx.ek[i    ] = ((x & 0x00FC0000)  <<  6)
+                      | ((x & 0x00000FC0)  << 10)
+                      | ((y & 0x00FC0000) >>> 10)
+                      | ((y & 0x00000FC0) >>>  6);
+        ctx.ek[i + 1] = ((x & 0x0003F000)  << 12)
+                      | ((x & 0x0000003F)  << 16)
+                      | ((y & 0x0003F000) >>>  4)
+                      |  (y & 0x0000003F);
+        x = ctx.dk[i];
+        y = ctx.dk[i + 1];
+        ctx.dk[i    ] = ((x & 0x00FC0000)  <<  6)
+                      | ((x & 0x00000FC0)  << 10)
+                      | ((y & 0x00FC0000) >>> 10)
+                      | ((y & 0x00000FC0) >>>  6);
+        ctx.dk[i + 1] = ((x & 0x0003F000)  << 12)
+                      | ((x & 0x0000003F)  << 16)
+                      | ((y & 0x0003F000) >>>  4)
+                      |  (y & 0x0000003F);
+      }
+    return ctx;
+  }
+
+  public void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs)
+  {
+    desFunc(in, i, out, o, ((Context) K).ek);
+  }
+
+  public void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs)
+  {
+    desFunc(in, i, out, o, ((Context) K).dk);
+  }
+
+  /**
+   * Simple wrapper class around the session keys. Package-private so TripleDES
+   * can see it.
+   */
+  final class Context
+  {
+    private static final int EXPANDED_KEY_SIZE = 32;
+
+    /** The encryption key. */
+    int[] ek;
+
+    /** The decryption key. */
+    int[] dk;
+
+    /** Default 0-arguments constructor. */
+    Context()
+    {
+      ek = new int[EXPANDED_KEY_SIZE];
+      dk = new int[EXPANDED_KEY_SIZE];
+    }
+
+    byte[] getEncryptionKeyBytes()
+    {
+      return toByteArray(ek);
+    }
+
+    byte[] getDecryptionKeyBytes()
+    {
+      return toByteArray(dk);
+    }
+
+    byte[] toByteArray(int[] k)
+    {
+      byte[] result = new byte[4 * k.length];
+      for (int i = 0, j = 0; i < k.length; i++)
+        {
+          result[j++] = (byte)(k[i] >>> 24);
+          result[j++] = (byte)(k[i] >>> 16);
+          result[j++] = (byte)(k[i] >>> 8);
+          result[j++] = (byte) k[i];
+        }
+      return result;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/IBlockCipher.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,195 @@
+/* IBlockCipher.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import java.security.InvalidKeyException;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * The basic visible methods of any symmetric key block cipher.
+ * <p>
+ * A symmetric key block cipher is a function that maps n-bit plaintext blocks
+ * to n-bit ciphertext blocks; n being the cipher's <i>block size</i>. This
+ * encryption function is parameterised by a k-bit key, and is invertible. Its
+ * inverse is the decryption function.
+ * <p>
+ * Possible initialisation values for an instance of this type are:
+ * <ul>
+ * <li>The block size in which to operate this block cipher instance. This
+ * value is <b>optional</b>, if unspecified, the block cipher's default block
+ * size shall be used.</li>
+ * <li>The byte array containing the user supplied key material to use for
+ * generating the cipher's session key(s). This value is <b>mandatory</b> and
+ * should be included in the initialisation parameters. If it isn't, an
+ * {@link IllegalStateException} will be thrown if any method, other than
+ * <code>reset()</code> is invoked on the instance. Furthermore, the size of
+ * this key material shall be taken as an indication on the key size in which to
+ * operate this instance.</li>
+ * </ul>
+ * <p>
+ * <b>IMPLEMENTATION NOTE</b>: Although all the concrete classes in this
+ * package implement the {@link Cloneable} interface, it is important to note
+ * here that such an operation <b>DOES NOT</b> clone any session key material
+ * that may have been used in initialising the source cipher (the instance to be
+ * cloned). Instead a clone of an already initialised cipher is another instance
+ * that operates with the <b>same block size</b> but without any knowledge of
+ * neither key material nor key size.
+ */
+public interface IBlockCipher
+    extends Cloneable
+{
+  /**
+   * Property name of the block size in which to operate a block cipher. The
+   * value associated with this property name is taken to be an {@link Integer}.
+   */
+  String CIPHER_BLOCK_SIZE = "gnu.crypto.cipher.block.size";
+  /**
+   * Property name of the user-supplied key material. The value associated to
+   * this property name is taken to be a byte array.
+   */
+  String KEY_MATERIAL = "gnu.crypto.cipher.key.material";
+
+  /**
+   * Returns the canonical name of this instance.
+   * 
+   * @return the canonical name of this instance.
+   */
+  String name();
+
+  /**
+   * Returns the default value, in bytes, of the algorithm's block size.
+   * 
+   * @return the default value, in bytes, of the algorithm's block size.
+   */
+  int defaultBlockSize();
+
+  /**
+   * Returns the default value, in bytes, of the algorithm's key size.
+   * 
+   * @return the default value, in bytes, of the algorithm's key size.
+   */
+  int defaultKeySize();
+
+  /**
+   * Returns an {@link Iterator} over the supported block sizes. Each element
+   * returned by this object is an {@link Integer}.
+   * 
+   * @return an {@link Iterator} over the supported block sizes.
+   */
+  Iterator blockSizes();
+
+  /**
+   * Returns an {@link Iterator} over the supported key sizes. Each element
+   * returned by this object is an {@link Integer}.
+   * 
+   * @return an {@link Iterator} over the supported key sizes.
+   */
+  Iterator keySizes();
+
+  /**
+   * Returns a clone of this instance.
+   * 
+   * @return a clone copy of this instance.
+   */
+  Object clone();
+
+  /**
+   * Initialises the algorithm with designated attributes. Permissible names and
+   * values are described in the class documentation above.
+   * 
+   * @param attributes a set of name-value pairs that describes the desired
+   *          future behaviour of this instance.
+   * @exception InvalidKeyException if the key data is invalid.
+   * @exception IllegalStateException if the instance is already initialised.
+   * @see #KEY_MATERIAL
+   * @see #CIPHER_BLOCK_SIZE
+   */
+  void init(Map attributes) throws InvalidKeyException, IllegalStateException;
+
+  /**
+   * Returns the currently set block size for this instance.
+   * 
+   * @return the current block size for this instance.
+   * @exception IllegalStateException if the instance is not initialised.
+   */
+  int currentBlockSize() throws IllegalStateException;
+
+  /**
+   * Resets the algorithm instance for re-initialisation and use with other
+   * characteristics. This method always succeeds.
+   */
+  void reset();
+
+  /**
+   * Encrypts exactly one block of plaintext.
+   * 
+   * @param in the plaintext.
+   * @param inOffset index of <code>in</code> from which to start considering
+   *          data.
+   * @param out the ciphertext.
+   * @param outOffset index of <code>out</code> from which to store result.
+   * @exception IllegalStateException if the instance is not initialised.
+   */
+  void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset)
+      throws IllegalStateException;
+
+  /**
+   * Decrypts exactly one block of ciphertext.
+   * 
+   * @param in the plaintext.
+   * @param inOffset index of <code>in</code> from which to start considering
+   *          data.
+   * @param out the ciphertext.
+   * @param outOffset index of <code>out</code> from which to store result.
+   * @exception IllegalStateException if the instance is not initialised.
+   */
+  void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset)
+      throws IllegalStateException;
+
+  /**
+   * A <i>correctness</i> test that consists of basic symmetric encryption /
+   * decryption test(s) for all supported block and key sizes, as well as one
+   * (1) variable key Known Answer Test (KAT).
+   * 
+   * @return <code>true</code> if the implementation passes simple
+   *         <i>correctness</i> tests. Returns <code>false</code> otherwise.
+   */
+  boolean selfTest();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/IBlockCipherSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,124 @@
+/* IBlockCipherSpi.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import java.security.InvalidKeyException;
+import java.util.Iterator;
+
+/**
+ * Package-private interface exposing mandatory methods to be implemented by
+ * concrete {@link BaseCipher} sub-classes.
+ */
+interface IBlockCipherSpi
+    extends Cloneable
+{
+  /**
+   * Returns an {@link Iterator} over the supported block sizes. Each element
+   * returned by this object is a {@link java.lang.Integer}.
+   * 
+   * @return an <code>Iterator</code> over the supported block sizes.
+   */
+  Iterator blockSizes();
+
+  /**
+   * Returns an {@link Iterator} over the supported key sizes. Each element
+   * returned by this object is a {@link java.lang.Integer}.
+   * 
+   * @return an <code>Iterator</code> over the supported key sizes.
+   */
+  Iterator keySizes();
+
+  /**
+   * Expands a user-supplied key material into a session key for a designated
+   * <i>block size</i>.
+   * 
+   * @param k the user-supplied key material.
+   * @param bs the desired block size in bytes.
+   * @return an Object encapsulating the session key.
+   * @exception IllegalArgumentException if the block size is invalid.
+   * @exception InvalidKeyException if the key data is invalid.
+   */
+  Object makeKey(byte[] k, int bs) throws InvalidKeyException;
+
+  /**
+   * Encrypts exactly one block of plaintext.
+   * 
+   * @param in the plaintext.
+   * @param inOffset index of <code>in</code> from which to start considering
+   *          data.
+   * @param out the ciphertext.
+   * @param outOffset index of <code>out</code> from which to store the
+   *          result.
+   * @param k the session key to use.
+   * @param bs the block size to use.
+   * @exception IllegalArgumentException if the block size is invalid.
+   * @exception ArrayIndexOutOfBoundsException if there is not enough room in
+   *              either the plaintext or ciphertext buffers.
+   */
+  void encrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k,
+               int bs);
+
+  /**
+   * Decrypts exactly one block of ciphertext.
+   * 
+   * @param in the ciphertext.
+   * @param inOffset index of <code>in</code> from which to start considering
+   *          data.
+   * @param out the plaintext.
+   * @param outOffset index of <code>out</code> from which to store the
+   *          result.
+   * @param k the session key to use.
+   * @param bs the block size to use.
+   * @exception IllegalArgumentException if the block size is invalid.
+   * @exception ArrayIndexOutOfBoundsException if there is not enough room in
+   *              either the plaintext or ciphertext buffers.
+   */
+  void decrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k,
+               int bs);
+
+  /**
+   * A <i>correctness</i> test that consists of basic symmetric encryption /
+   * decryption test(s) for all supported block and key sizes, as well as one
+   * (1) variable key Known Answer Test (KAT).
+   * 
+   * @return <code>true</code> if the implementation passes simple
+   *         <i>correctness</i> tests. Returns <code>false</code> otherwise.
+   */
+  boolean selfTest();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/Khazad.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,449 @@
+/* Khazad.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+/**
+ * Khazad is a 64-bit (legacy-level) block cipher that accepts a 128-bit key.
+ * The cipher is a uniform substitution-permutation network whose inverse only
+ * differs from the forward operation in the key schedule. The overall cipher
+ * design follows the Wide Trail strategy, favours component reuse, and permits
+ * a wide variety of implementation trade-offs.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://planeta.terra.com.br/informatica/paulobarreto/KhazadPage.html">The
+ * Khazad Block Cipher</a>.<br>
+ * <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and <a
+ * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li>
+ * </ol>
+ */
+public final class Khazad
+    extends BaseCipher
+{
+  private static final Logger log = Logger.getLogger(Khazad.class.getName());
+  private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes
+  private static final int DEFAULT_KEY_SIZE = 16; // in bytes
+  private static final int R = 8; // standard number of rounds; para. 3.7
+  private static final String Sd = // p. 20 [KHAZAD]
+      "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C"
+    + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC"
+    + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102"
+    + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C"
+    + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB"
+    + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38"
+    + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746"
+    + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C"
+    + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2"
+    + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE"
+    + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E"
+    + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B"
+    + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8"
+    + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856"
+    + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2"
+    + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42";
+  private static final byte[] S = new byte[256];
+  private static final int[] T0 = new int[256];
+  private static final int[] T1 = new int[256];
+  private static final int[] T2 = new int[256];
+  private static final int[] T3 = new int[256];
+  private static final int[] T4 = new int[256];
+  private static final int[] T5 = new int[256];
+  private static final int[] T6 = new int[256];
+  private static final int[] T7 = new int[256];
+  private static final int[][] rc = new int[R + 1][2]; // round constants
+  /**
+   * KAT vector (from ecb_vk): I=120 KEY=00000000000000000000000000000100
+   * CT=A0C86A1BBE2CBF4C
+   */
+  private static final byte[] KAT_KEY =
+      Util.toBytesFromString("00000000000000000000000000000100");
+  private static final byte[] KAT_CT = Util.toBytesFromString("A0C86A1BBE2CBF4C");
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  static
+    {
+      long time = System.currentTimeMillis();
+      long ROOT = 0x11d; // para. 2.1 [KHAZAD]
+      int i, j;
+      int s, s2, s3, s4, s5, s6, s7, s8, sb;
+      char c;
+      for (i = 0; i < 256; i++)
+        {
+          c = Sd.charAt(i >>> 1);
+          s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF;
+          S[i] = (byte) s;
+          s2 = s << 1;
+          if (s2 > 0xFF)
+            s2 ^= ROOT;
+          s3 = s2 ^ s;
+          s4 = s2 << 1;
+          if (s4 > 0xFF)
+            s4 ^= ROOT;
+          s5 = s4 ^ s;
+          s6 = s4 ^ s2;
+          s7 = s6 ^ s;
+          s8 = s4 << 1;
+          if (s8 > 0xFF)
+            s8 ^= ROOT;
+          sb = s8 ^ s2 ^ s;
+          T0[i] = s  << 24 | s3 << 16 | s4 << 8 | s5;
+          T1[i] = s3 << 24 | s  << 16 | s5 << 8 | s4;
+          T2[i] = s4 << 24 | s5 << 16 | s  << 8 | s3;
+          T3[i] = s5 << 24 | s4 << 16 | s3 << 8 | s;
+          T4[i] = s6 << 24 | s8 << 16 | sb << 8 | s7;
+          T5[i] = s8 << 24 | s6 << 16 | s7 << 8 | sb;
+          T6[i] = sb << 24 | s7 << 16 | s6 << 8 | s8;
+          T7[i] = s7 << 24 | sb << 16 | s8 << 8 | s6;
+        }
+      for (i = 0, j = 0; i < R + 1; i++) // compute round constant
+        {
+          rc[i][0] =  S[j++]         << 24
+                   | (S[j++] & 0xFF) << 16
+                   | (S[j++] & 0xFF) << 8
+                   | (S[j++] & 0xFF);
+          rc[i][1] =  S[j++]         << 24
+                   | (S[j++] & 0xFF) << 16
+                   | (S[j++] & 0xFF) << 8
+                   | (S[j++] & 0xFF);
+        }
+      time = System.currentTimeMillis() - time;
+      if (Configuration.DEBUG)
+        {
+          log.fine("Static data");
+          log.fine("T0[]:");
+          StringBuilder b;
+          for (i = 0; i < 64; i++)
+            {
+              b = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                b.append("0x").append(Util.toString(T0[i * 4 + j])).append(", ");
+              log.fine(b.toString());
+            }
+          log.fine("T1[]:");
+          for (i = 0; i < 64; i++)
+            {
+              b = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                b.append("0x").append(Util.toString(T1[i * 4 + j])).append(", ");
+              log.fine(b.toString());
+            }
+          log.fine("T2[]:");
+          for (i = 0; i < 64; i++)
+            {
+              b = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                b.append("0x").append(Util.toString(T2[i * 4 + j])).append(", ");
+              log.fine(b.toString());
+            }
+          log.fine("T3[]:");
+          for (i = 0; i < 64; i++)
+            {
+              b = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                b.append("0x").append(Util.toString(T3[i * 4 + j])).append(", ");
+              log.fine(b.toString());
+            }
+          log.fine("T4[]:");
+          for (i = 0; i < 64; i++)
+            {
+              b = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                b.append("0x").append(Util.toString(T4[i * 4 + j])).append(", ");
+              log.fine(b.toString());
+            }
+          log.fine("T5[]:");
+          for (i = 0; i < 64; i++)
+            {
+              b = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                b.append("0x").append(Util.toString(T5[i * 4 + j])).append(", ");
+              log.fine(b.toString());
+            }
+          log.fine("T6[]:");
+          for (i = 0; i < 64; i++)
+            {
+              b = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                b.append("0x").append(Util.toString(T6[i * 4 + j])).append(", ");
+              log.fine(b.toString());
+            }
+          log.fine("T7[]:");
+          for (i = 0; i < 64; i++)
+            {
+              b = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                b.append("0x").append(Util.toString(T7[i * 4 + j])).append(", ");
+              log.fine(b.toString());
+            }
+          log.fine("rc[]:");
+          for (i = 0; i < R + 1; i++)
+            log.fine("0x" + Util.toString(rc[i][0]) + Util.toString(rc[i][1]));
+          log.fine("Total initialization time: " + time + " ms.");
+        }
+    }
+
+  /** Trivial 0-arguments constructor. */
+  public Khazad()
+  {
+    super(Registry.KHAZAD_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
+  }
+
+  private static void khazad(byte[] in, int i, byte[] out, int j, int[][] K)
+  {
+    // sigma(K[0])
+    int k0 = K[0][0];
+    int k1 = K[0][1];
+    int a0 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ k0;
+    int a1 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i  ] & 0xFF)      ) ^ k1;
+    int b0, b1;
+    // round function
+    for (int r = 1; r < R; r++)
+      {
+        k0 = K[r][0];
+        k1 = K[r][1];
+        b0 = T0[ a0 >>> 24        ]
+           ^ T1[(a0 >>> 16) & 0xFF]
+           ^ T2[(a0 >>>  8) & 0xFF]
+           ^ T3[ a0         & 0xFF]
+           ^ T4[ a1 >>> 24        ]
+           ^ T5[(a1 >>> 16) & 0xFF]
+           ^ T6[(a1 >>>  8) & 0xFF]
+           ^ T7[ a1         & 0xFF] ^ k0;
+        b1 = T0[ a1 >>> 24        ]
+           ^ T1[(a1 >>> 16) & 0xFF]
+           ^ T2[(a1 >>>  8) & 0xFF]
+           ^ T3[ a1         & 0xFF]
+           ^ T4[ a0 >>> 24        ]
+           ^ T5[(a0 >>> 16) & 0xFF]
+           ^ T6[(a0 >>>  8) & 0xFF]
+           ^ T7[ a0         & 0xFF] ^ k1;
+        a0 = b0;
+        a1 = b1;
+        if (Configuration.DEBUG)
+          log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1));
+      }
+    // sigma(K[R]) o gamma applied to previous output
+    k0 = K[R][0];
+    k1 = K[R][1];
+    out[j++] = (byte)(S[ a0 >>> 24        ] ^ (k0 >>> 24));
+    out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (k0 >>> 16));
+    out[j++] = (byte)(S[(a0 >>>  8) & 0xFF] ^ (k0 >>>  8));
+    out[j++] = (byte)(S[ a0         & 0xFF] ^  k0        );
+    out[j++] = (byte)(S[ a1 >>> 24        ] ^ (k1 >>> 24));
+    out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (k1 >>> 16));
+    out[j++] = (byte)(S[(a1 >>>  8) & 0xFF] ^ (k1 >>>  8));
+    out[j  ] = (byte)(S[ a1         & 0xFF] ^  k1        );
+    if (Configuration.DEBUG)
+      log.fine("T=" + Util.toString(out, j - 7, 8) + "\n");
+  }
+
+  public Object clone()
+  {
+    Khazad result = new Khazad();
+    result.currentBlockSize = this.currentBlockSize;
+
+    return result;
+  }
+
+  public Iterator blockSizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
+
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(DEFAULT_KEY_SIZE));
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  /**
+   * Expands a user-supplied key material into a session key for a designated
+   * <i>block size</i>.
+   * 
+   * @param uk the 128-bit user-supplied key material.
+   * @param bs the desired block size in bytes.
+   * @return an Object encapsulating the session key.
+   * @exception IllegalArgumentException if the block size is not 16 (128-bit).
+   * @exception InvalidKeyException if the key data is invalid.
+   */
+  public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    if (uk == null)
+      throw new InvalidKeyException("Empty key");
+    if (uk.length != 16)
+      throw new InvalidKeyException("Key is not 128-bit.");
+    int[][] Ke = new int[R + 1][2]; // encryption round keys
+    int[][] Kd = new int[R + 1][2]; // decryption round keys
+    int r, i;
+    int k20, k21, k10, k11, rc0, rc1, kr0, kr1;
+    i = 0;
+    k20 =  uk[i++]         << 24
+        | (uk[i++] & 0xFF) << 16
+        | (uk[i++] & 0xFF) << 8
+        | (uk[i++] & 0xFF);
+    k21 =  uk[i++]         << 24
+        | (uk[i++] & 0xFF) << 16
+        | (uk[i++] & 0xFF) << 8
+        | (uk[i++] & 0xFF);
+    k10 =  uk[i++]         << 24
+        | (uk[i++] & 0xFF) << 16
+        | (uk[i++] & 0xFF) << 8
+        | (uk[i++] & 0xFF);
+    k11 =  uk[i++]         << 24
+        | (uk[i++] & 0xFF) << 16
+        | (uk[i++] & 0xFF) << 8
+        | (uk[i++] & 0xFF);
+    for (r = 0, i = 0; r <= R; r++)
+      {
+        rc0 = rc[r][0];
+        rc1 = rc[r][1];
+        kr0 = T0[ k10 >>> 24        ]
+            ^ T1[(k10 >>> 16) & 0xFF]
+            ^ T2[(k10 >>>  8) & 0xFF]
+            ^ T3[ k10         & 0xFF]
+            ^ T4[(k11 >>> 24) & 0xFF]
+            ^ T5[(k11 >>> 16) & 0xFF]
+            ^ T6[(k11 >>>  8) & 0xFF]
+            ^ T7[ k11         & 0xFF] ^ rc0 ^ k20;
+        kr1 = T0[ k11 >>> 24        ]
+            ^ T1[(k11 >>> 16) & 0xFF]
+            ^ T2[(k11 >>>  8) & 0xFF]
+            ^ T3[ k11         & 0xFF]
+            ^ T4[(k10 >>> 24) & 0xFF]
+            ^ T5[(k10 >>> 16) & 0xFF]
+            ^ T6[(k10 >>>  8) & 0xFF]
+            ^ T7[ k10         & 0xFF] ^ rc1 ^ k21;
+        Ke[r][0] = kr0;
+        Ke[r][1] = kr1;
+        k20 = k10;
+        k21 = k11;
+        k10 = kr0;
+        k11 = kr1;
+        if (r == 0 || r == R)
+          {
+            Kd[R - r][0] = kr0;
+            Kd[R - r][1] = kr1;
+          }
+        else
+          {
+            Kd[R - r][0] = T0[S[ kr0 >>> 24        ] & 0xFF]
+                         ^ T1[S[(kr0 >>> 16) & 0xFF] & 0xFF]
+                         ^ T2[S[(kr0 >>>  8) & 0xFF] & 0xFF]
+                         ^ T3[S[ kr0         & 0xFF] & 0xFF]
+                         ^ T4[S[ kr1 >>> 24        ] & 0xFF]
+                         ^ T5[S[(kr1 >>> 16) & 0xFF] & 0xFF]
+                         ^ T6[S[(kr1 >>>  8) & 0xFF] & 0xFF]
+                         ^ T7[S[ kr1         & 0xFF] & 0xFF];
+            Kd[R - r][1] = T0[S[ kr1 >>> 24        ] & 0xFF]
+                         ^ T1[S[(kr1 >>> 16) & 0xFF] & 0xFF]
+                         ^ T2[S[(kr1 >>>  8) & 0xFF] & 0xFF]
+                         ^ T3[S[ kr1         & 0xFF] & 0xFF]
+                         ^ T4[S[ kr0 >>> 24        ] & 0xFF]
+                         ^ T5[S[(kr0 >>> 16) & 0xFF] & 0xFF]
+                         ^ T6[S[(kr0 >>>  8) & 0xFF] & 0xFF]
+                         ^ T7[S[ kr0         & 0xFF] & 0xFF];
+          }
+      }
+    if (Configuration.DEBUG)
+      {
+        log.fine("Key schedule");
+        log.fine("Ke[]:");
+        for (r = 0; r < R + 1; r++)
+          log.fine("#" + r + ": 0x" + Util.toString(Ke[r][0])
+                   + Util.toString(Ke[r][1]));
+        log.fine("Kd[]:");
+        for (r = 0; r < R + 1; r++)
+          log.fine("#" + r + ": 0x" + Util.toString(Kd[r][0])
+                   + Util.toString(Kd[r][1]));
+      }
+    return new Object[] { Ke, Kd };
+  }
+
+  public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    int[][] K = (int[][])((Object[]) k)[0];
+    khazad(in, i, out, j, K);
+  }
+
+  public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    int[][] K = (int[][])((Object[]) k)[1];
+    khazad(in, i, out, j, K);
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        boolean result = super.selfTest(); // do symmetry tests
+        if (result)
+          result = testKat(KAT_KEY, KAT_CT);
+        valid = Boolean.valueOf(result);
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/NullCipher.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,108 @@
+/* NullCipher.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Registry;
+
+import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * The implementation of a Null block cipher.
+ * <p>
+ * This cipher does not alter its input at all, claims to process block sizes
+ * 128-, 192- and 256-bit long, and key sizes from 64- to 512-bit in 8-bit
+ * increments.
+ */
+public final class NullCipher
+    extends BaseCipher
+{
+  /** Trivial 0-arguments constructor. */
+  public NullCipher()
+  {
+    super(Registry.NULL_CIPHER, 16, 16);
+  }
+
+  public Object clone()
+  {
+    NullCipher result = new NullCipher();
+    result.currentBlockSize = this.currentBlockSize;
+    return result;
+  }
+
+  public Iterator blockSizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(64 / 8));
+    al.add(Integer.valueOf(128 / 8));
+    al.add(Integer.valueOf(192 / 8));
+    al.add(Integer.valueOf(256 / 8));
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    ArrayList al = new ArrayList();
+    for (int n = 8; n < 64; n++)
+      al.add(Integer.valueOf(n));
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
+  {
+    return new Object();
+  }
+
+  public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    System.arraycopy(in, i, out, j, bs);
+  }
+
+  public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    System.arraycopy(in, i, out, j, bs);
+  }
+
+  public boolean selfTest()
+  {
+    return true;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/Rijndael.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,704 @@
+/* Rijndael.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+/**
+ * Rijndael --pronounced Reindaal-- is the AES. It is a variable block-size
+ * (128-, 192- and 256-bit), variable key-size (128-, 192- and 256-bit)
+ * symmetric key block cipher.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">The Rijndael
+ * Block Cipher - AES Proposal</a>.<br>
+ * <a href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a> and
+ * <a href="mailto:daemen.j@protonworld.com">Joan Daemen</a>.</li>
+ * </ol>
+ */
+public final class Rijndael
+    extends BaseCipher
+{
+  private static final Logger log = Logger.getLogger(Rijndael.class.getName());
+  private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes
+  private static final int DEFAULT_KEY_SIZE = 16; // in bytes
+  private static final String SS =
+      "\u637C\u777B\uF26B\u6FC5\u3001\u672B\uFED7\uAB76"
+    + "\uCA82\uC97D\uFA59\u47F0\uADD4\uA2AF\u9CA4\u72C0"
+    + "\uB7FD\u9326\u363F\uF7CC\u34A5\uE5F1\u71D8\u3115"
+    + "\u04C7\u23C3\u1896\u059A\u0712\u80E2\uEB27\uB275"
+    + "\u0983\u2C1A\u1B6E\u5AA0\u523B\uD6B3\u29E3\u2F84"
+    + "\u53D1\u00ED\u20FC\uB15B\u6ACB\uBE39\u4A4C\u58CF"
+    + "\uD0EF\uAAFB\u434D\u3385\u45F9\u027F\u503C\u9FA8"
+    + "\u51A3\u408F\u929D\u38F5\uBCB6\uDA21\u10FF\uF3D2"
+    + "\uCD0C\u13EC\u5F97\u4417\uC4A7\u7E3D\u645D\u1973"
+    + "\u6081\u4FDC\u222A\u9088\u46EE\uB814\uDE5E\u0BDB"
+    + "\uE032\u3A0A\u4906\u245C\uC2D3\uAC62\u9195\uE479"
+    + "\uE7C8\u376D\u8DD5\u4EA9\u6C56\uF4EA\u657A\uAE08"
+    + "\uBA78\u252E\u1CA6\uB4C6\uE8DD\u741F\u4BBD\u8B8A"
+    + "\u703E\uB566\u4803\uF60E\u6135\u57B9\u86C1\u1D9E"
+    + "\uE1F8\u9811\u69D9\u8E94\u9B1E\u87E9\uCE55\u28DF"
+    + "\u8CA1\u890D\uBFE6\u4268\u4199\u2D0F\uB054\uBB16";
+  private static final byte[] S = new byte[256];
+  private static final byte[] Si = new byte[256];
+  private static final int[] T1 = new int[256];
+  private static final int[] T2 = new int[256];
+  private static final int[] T3 = new int[256];
+  private static final int[] T4 = new int[256];
+  private static final int[] T5 = new int[256];
+  private static final int[] T6 = new int[256];
+  private static final int[] T7 = new int[256];
+  private static final int[] T8 = new int[256];
+  private static final int[] U1 = new int[256];
+  private static final int[] U2 = new int[256];
+  private static final int[] U3 = new int[256];
+  private static final int[] U4 = new int[256];
+  private static final byte[] rcon = new byte[30];
+  private static final int[][][] shifts = new int[][][] {
+      { { 0, 0 }, { 1, 3 }, { 2, 2 }, { 3, 1 } },
+      { { 0, 0 }, { 1, 5 }, { 2, 4 }, { 3, 3 } },
+      { { 0, 0 }, { 1, 7 }, { 3, 5 }, { 4, 4 } } };
+  /**
+   * KAT vector (from ecb_vk): I=96
+   * KEY=0000000000000000000000010000000000000000000000000000000000000000
+   * CT=E44429474D6FC3084EB2A6B8B46AF754
+   */
+  private static final byte[] KAT_KEY = Util.toBytesFromString(
+      "0000000000000000000000010000000000000000000000000000000000000000");
+  private static final byte[] KAT_CT = Util.toBytesFromString(
+      "E44429474D6FC3084EB2A6B8B46AF754");
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+
+  static
+    {
+      long time = System.currentTimeMillis();
+      int ROOT = 0x11B;
+      int i, j = 0;
+      // S-box, inverse S-box, T-boxes, U-boxes
+      int s, s2, s3, i2, i4, i8, i9, ib, id, ie, t;
+      char c;
+      for (i = 0; i < 256; i++)
+        {
+          c = SS.charAt(i >>> 1);
+          S[i] = (byte)(((i & 1) == 0) ? c >>> 8 : c & 0xFF);
+          s = S[i] & 0xFF;
+          Si[s] = (byte) i;
+          s2 = s << 1;
+          if (s2 >= 0x100)
+            s2 ^= ROOT;
+          s3 = s2 ^ s;
+          i2 = i << 1;
+          if (i2 >= 0x100)
+            i2 ^= ROOT;
+          i4 = i2 << 1;
+          if (i4 >= 0x100)
+            i4 ^= ROOT;
+          i8 = i4 << 1;
+          if (i8 >= 0x100)
+            i8 ^= ROOT;
+          i9 = i8 ^ i;
+          ib = i9 ^ i2;
+          id = i9 ^ i4;
+          ie = i8 ^ i4 ^ i2;
+          T1[i] = t = (s2 << 24) | (s << 16) | (s << 8) | s3;
+          T2[i] = (t >>>  8) | (t << 24);
+          T3[i] = (t >>> 16) | (t << 16);
+          T4[i] = (t >>> 24) | (t <<  8);
+          T5[s] = U1[i] = t = (ie << 24) | (i9 << 16) | (id << 8) | ib;
+          T6[s] = U2[i] = (t >>>  8) | (t << 24);
+          T7[s] = U3[i] = (t >>> 16) | (t << 16);
+          T8[s] = U4[i] = (t >>> 24) | (t <<  8);
+        }
+      // round constants
+      int r = 1;
+      rcon[0] = 1;
+      for (i = 1; i < 30; i++)
+        {
+          r <<= 1;
+          if (r >= 0x100)
+            r ^= ROOT;
+          rcon[i] = (byte) r;
+        }
+      time = System.currentTimeMillis() - time;
+      if (Configuration.DEBUG)
+        {
+          log.fine("Static Data");
+          log.fine("S[]:");
+          StringBuilder sb;
+          for (i = 0; i < 16; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 16; j++)
+                sb.append("0x").append(Util.toString(S[i * 16 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("Si[]:");
+          for (i = 0; i < 16; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 16; j++)
+                sb.append("0x").append(Util.toString(Si[i * 16 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+
+          log.fine("T1[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T1[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T2[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T2[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T3[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T3[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T4[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T4[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T5[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T6[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T6[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T7[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T7[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("T8[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(T8[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+
+          log.fine("U1[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(U1[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("U2[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(U2[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("U3[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(U3[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("U4[]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(U4[i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+
+          log.fine("rcon[]:");
+          for (i = 0; i < 5; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 6; j++)
+                sb.append("0x").append(Util.toString(rcon[i * 6 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("Total initialization time: " + time + " ms.");
+        }
+    }
+
+  /** Trivial 0-arguments constructor. */
+  public Rijndael()
+  {
+    super(Registry.RIJNDAEL_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
+  }
+
+  /**
+   * Returns the number of rounds for a given Rijndael's key and block sizes.
+   * 
+   * @param ks the size of the user key material in bytes.
+   * @param bs the desired block size in bytes.
+   * @return the number of rounds for a given Rijndael's key and block sizes.
+   */
+  public static int getRounds(int ks, int bs)
+  {
+    switch (ks)
+      {
+      case 16:
+        return bs == 16 ? 10 : (bs == 24 ? 12 : 14);
+      case 24:
+        return bs != 32 ? 12 : 14;
+      default: // 32 bytes = 256 bits
+        return 14;
+      }
+  }
+
+  private static void rijndaelEncrypt(byte[] in, int inOffset, byte[] out,
+                                      int outOffset, Object sessionKey, int bs)
+  {
+    Object[] sKey = (Object[]) sessionKey; // extract encryption round keys
+    int[][] Ke = (int[][]) sKey[0];
+    int BC = bs / 4;
+    int ROUNDS = Ke.length - 1;
+    int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2);
+    int s1 = shifts[SC][1][0];
+    int s2 = shifts[SC][2][0];
+    int s3 = shifts[SC][3][0];
+    int[] a = new int[BC];
+    int[] t = new int[BC]; // temporary work array
+    int i, tt;
+    for (i = 0; i < BC; i++) // plaintext to ints + key
+      t[i] = (in[inOffset++]         << 24
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) <<  8
+           | (in[inOffset++] & 0xFF)      ) ^ Ke[0][i];
+    for (int r = 1; r < ROUNDS; r++) // apply round transforms
+      {
+        for (i = 0; i < BC; i++)
+          a[i] = (T1[(t[ i           ] >>> 24)       ]
+                ^ T2[(t[(i + s1) % BC] >>> 16) & 0xFF]
+                ^ T3[(t[(i + s2) % BC] >>>  8) & 0xFF]
+                ^ T4[ t[(i + s3) % BC]         & 0xFF]) ^ Ke[r][i];
+        System.arraycopy(a, 0, t, 0, BC);
+        if (Configuration.DEBUG)
+          log.fine("CT" + r + "=" + Util.toString(t));
+      }
+    for (i = 0; i < BC; i++) // last round is special
+      {
+        tt = Ke[ROUNDS][i];
+        out[outOffset++] = (byte)(S[(t[ i           ] >>> 24)       ] ^ (tt >>> 24));
+        out[outOffset++] = (byte)(S[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16));
+        out[outOffset++] = (byte)(S[(t[(i + s2) % BC] >>>  8) & 0xFF] ^ (tt >>>  8));
+        out[outOffset++] = (byte)(S[ t[(i + s3) % BC]         & 0xFF] ^  tt        );
+      }
+    if (Configuration.DEBUG)
+      log.fine("CT=" + Util.toString(out, outOffset - bs, bs));
+  }
+
+  private static void rijndaelDecrypt(byte[] in, int inOffset, byte[] out,
+                                      int outOffset, Object sessionKey, int bs)
+  {
+    Object[] sKey = (Object[]) sessionKey; // extract decryption round keys
+    int[][] Kd = (int[][]) sKey[1];
+    int BC = bs / 4;
+    int ROUNDS = Kd.length - 1;
+    int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2);
+    int s1 = shifts[SC][1][1];
+    int s2 = shifts[SC][2][1];
+    int s3 = shifts[SC][3][1];
+    int[] a = new int[BC];
+    int[] t = new int[BC]; // temporary work array
+    int i, tt;
+    for (i = 0; i < BC; i++) // ciphertext to ints + key
+      t[i] = (in[inOffset++]         << 24
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) <<  8
+           | (in[inOffset++] & 0xFF)      ) ^ Kd[0][i];
+    for (int r = 1; r < ROUNDS; r++) // apply round transforms
+      {
+        for (i = 0; i < BC; i++)
+          a[i] = (T5[(t[ i           ] >>> 24)       ]
+                ^ T6[(t[(i + s1) % BC] >>> 16) & 0xFF]
+                ^ T7[(t[(i + s2) % BC] >>>  8) & 0xFF]
+                ^ T8[ t[(i + s3) % BC]         & 0xFF]) ^ Kd[r][i];
+        System.arraycopy(a, 0, t, 0, BC);
+        if (Configuration.DEBUG)
+          log.fine("PT" + r + "=" + Util.toString(t));
+      }
+    for (i = 0; i < BC; i++) // last round is special
+      {
+        tt = Kd[ROUNDS][i];
+        out[outOffset++] = (byte)(Si[(t[ i           ] >>> 24)       ] ^ (tt >>> 24));
+        out[outOffset++] = (byte)(Si[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16));
+        out[outOffset++] = (byte)(Si[(t[(i + s2) % BC] >>>  8) & 0xFF] ^ (tt >>>  8));
+        out[outOffset++] = (byte)(Si[ t[(i + s3) % BC]         & 0xFF] ^  tt        );
+      }
+    if (Configuration.DEBUG)
+      log.fine("PT=" + Util.toString(out, outOffset - bs, bs));
+  }
+
+  private static void aesEncrypt(byte[] in, int i, byte[] out, int j, Object key)
+  {
+    int[][] Ke = (int[][])((Object[]) key)[0]; // extract encryption round keys
+    int ROUNDS = Ke.length - 1;
+    int[] Ker = Ke[0];
+    // plaintext to ints + key
+    int t0 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Ker[0];
+    int t1 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Ker[1];
+    int t2 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Ker[2];
+    int t3 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Ker[3];
+    int a0, a1, a2, a3;
+    for (int r = 1; r < ROUNDS; r++) // apply round transforms
+      {
+        Ker = Ke[r];
+        a0 = (T1[(t0 >>> 24)       ]
+            ^ T2[(t1 >>> 16) & 0xFF]
+            ^ T3[(t2 >>>  8) & 0xFF]
+            ^ T4[ t3         & 0xFF]) ^ Ker[0];
+        a1 = (T1[(t1 >>> 24)       ]
+            ^ T2[(t2 >>> 16) & 0xFF]
+            ^ T3[(t3 >>>  8) & 0xFF]
+            ^ T4[ t0         & 0xFF]) ^ Ker[1];
+        a2 = (T1[(t2 >>> 24)       ]
+            ^ T2[(t3 >>> 16) & 0xFF]
+            ^ T3[(t0 >>>  8) & 0xFF]
+            ^ T4[ t1         & 0xFF]) ^ Ker[2];
+        a3 = (T1[(t3 >>> 24)       ]
+            ^ T2[(t0 >>> 16) & 0xFF]
+            ^ T3[(t1 >>>  8) & 0xFF]
+            ^ T4[ t2         & 0xFF]) ^ Ker[3];
+        t0 = a0;
+        t1 = a1;
+        t2 = a2;
+        t3 = a3;
+        if (Configuration.DEBUG)
+          log.fine("CT" + r + "=" + Util.toString(t0) + Util.toString(t1)
+                   + Util.toString(t2) + Util.toString(t3));
+      }
+    // last round is special
+    Ker = Ke[ROUNDS];
+    int tt = Ker[0];
+    out[j++] = (byte)(S[(t0 >>> 24)       ] ^ (tt >>> 24));
+    out[j++] = (byte)(S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(S[(t2 >>>  8) & 0xFF] ^ (tt >>>  8));
+    out[j++] = (byte)(S[ t3         & 0xFF] ^  tt        );
+    tt = Ker[1];
+    out[j++] = (byte)(S[(t1 >>> 24)       ] ^ (tt >>> 24));
+    out[j++] = (byte)(S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(S[(t3 >>>  8) & 0xFF] ^ (tt >>>  8));
+    out[j++] = (byte)(S[ t0         & 0xFF] ^  tt        );
+    tt = Ker[2];
+    out[j++] = (byte)(S[(t2 >>> 24)       ] ^ (tt >>> 24));
+    out[j++] = (byte)(S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(S[(t0 >>>  8) & 0xFF] ^ (tt >>>  8));
+    out[j++] = (byte)(S[ t1         & 0xFF] ^  tt        );
+    tt = Ker[3];
+    out[j++] = (byte)(S[(t3 >>> 24)       ] ^ (tt >>> 24));
+    out[j++] = (byte)(S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(S[(t1 >>>  8) & 0xFF] ^ (tt >>>  8));
+    out[j++] = (byte)(S[ t2         & 0xFF] ^  tt        );
+    if (Configuration.DEBUG)
+      log.fine("CT=" + Util.toString(out, j - 16, 16));
+  }
+
+  private static void aesDecrypt(byte[] in, int i, byte[] out, int j, Object key)
+  {
+    int[][] Kd = (int[][])((Object[]) key)[1]; // extract decryption round keys
+    int ROUNDS = Kd.length - 1;
+    int[] Kdr = Kd[0];
+    // ciphertext to ints + key
+    int t0 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Kdr[0];
+    int t1 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Kdr[1];
+    int t2 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Kdr[2];
+    int t3 = (in[i++]         << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ Kdr[3];
+
+    int a0, a1, a2, a3;
+    for (int r = 1; r < ROUNDS; r++) // apply round transforms
+      {
+        Kdr = Kd[r];
+        a0 = (T5[(t0 >>> 24)       ]
+            ^ T6[(t3 >>> 16) & 0xFF]
+            ^ T7[(t2 >>>  8) & 0xFF]
+            ^ T8[ t1         & 0xFF]) ^ Kdr[0];
+        a1 = (T5[(t1 >>> 24)       ]
+            ^ T6[(t0 >>> 16) & 0xFF]
+            ^ T7[(t3 >>>  8) & 0xFF]
+            ^ T8[ t2         & 0xFF]) ^ Kdr[1];
+        a2 = (T5[(t2 >>> 24)       ]
+            ^ T6[(t1 >>> 16) & 0xFF]
+            ^ T7[(t0 >>>  8) & 0xFF]
+            ^ T8[ t3         & 0xFF]) ^ Kdr[2];
+        a3 = (T5[(t3 >>> 24)       ]
+            ^ T6[(t2 >>> 16) & 0xFF]
+            ^ T7[(t1 >>>  8) & 0xFF]
+            ^ T8[ t0         & 0xFF]) ^ Kdr[3];
+        t0 = a0;
+        t1 = a1;
+        t2 = a2;
+        t3 = a3;
+        if (Configuration.DEBUG)
+          log.fine("PT" + r + "=" + Util.toString(t0) + Util.toString(t1)
+                   + Util.toString(t2) + Util.toString(t3));
+      }
+    // last round is special
+    Kdr = Kd[ROUNDS];
+    int tt = Kdr[0];
+    out[j++] = (byte)(Si[(t0 >>> 24)       ] ^ (tt >>> 24));
+    out[j++] = (byte)(Si[(t3 >>> 16) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(Si[(t2 >>>  8) & 0xFF] ^ (tt >>>  8));
+    out[j++] = (byte)(Si[ t1         & 0xFF] ^  tt        );
+    tt = Kdr[1];
+    out[j++] = (byte)(Si[(t1 >>> 24)       ] ^ (tt >>> 24));
+    out[j++] = (byte)(Si[(t0 >>> 16) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(Si[(t3 >>>  8) & 0xFF] ^ (tt >>>  8));
+    out[j++] = (byte)(Si[ t2         & 0xFF] ^  tt        );
+    tt = Kdr[2];
+    out[j++] = (byte)(Si[(t2 >>> 24)       ] ^ (tt >>> 24));
+    out[j++] = (byte)(Si[(t1 >>> 16) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(Si[(t0 >>>  8) & 0xFF] ^ (tt >>>  8));
+    out[j++] = (byte)(Si[ t3         & 0xFF] ^  tt        );
+    tt = Kdr[3];
+    out[j++] = (byte)(Si[(t3 >>> 24)       ] ^ (tt >>> 24));
+    out[j++] = (byte)(Si[(t2 >>> 16) & 0xFF] ^ (tt >>> 16));
+    out[j++] = (byte)(Si[(t1 >>>  8) & 0xFF] ^ (tt >>>  8));
+    out[j++] = (byte)(Si[ t0         & 0xFF] ^  tt        );
+    if (Configuration.DEBUG)
+      log.fine("PT=" + Util.toString(out, j - 16, 16));
+  }
+
+  public Object clone()
+  {
+    Rijndael result = new Rijndael();
+    result.currentBlockSize = this.currentBlockSize;
+
+    return result;
+  }
+
+  public Iterator blockSizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(128 / 8));
+    al.add(Integer.valueOf(192 / 8));
+    al.add(Integer.valueOf(256 / 8));
+
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(128 / 8));
+    al.add(Integer.valueOf(192 / 8));
+    al.add(Integer.valueOf(256 / 8));
+
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  /**
+   * Expands a user-supplied key material into a session key for a designated
+   * <i>block size</i>.
+   * 
+   * @param k the 128/192/256-bit user-key to use.
+   * @param bs the block size in bytes of this Rijndael.
+   * @return an Object encapsulating the session key.
+   * @exception IllegalArgumentException if the block size is not 16, 24 or 32.
+   * @exception InvalidKeyException if the key data is invalid.
+   */
+  public Object makeKey(byte[] k, int bs) throws InvalidKeyException
+  {
+    if (k == null)
+      throw new InvalidKeyException("Empty key");
+    if (! (k.length == 16 || k.length == 24 || k.length == 32))
+      throw new InvalidKeyException("Incorrect key length");
+    if (! (bs == 16 || bs == 24 || bs == 32))
+      throw new IllegalArgumentException();
+    int ROUNDS = getRounds(k.length, bs);
+    int BC = bs / 4;
+    int[][] Ke = new int[ROUNDS + 1][BC]; // encryption round keys
+    int[][] Kd = new int[ROUNDS + 1][BC]; // decryption round keys
+    int ROUND_KEY_COUNT = (ROUNDS + 1) * BC;
+    int KC = k.length / 4;
+    int[] tk = new int[KC];
+    int i, j;
+    // copy user material bytes into temporary ints
+    for (i = 0, j = 0; i < KC;)
+      tk[i++] =  k[j++]         << 24
+              | (k[j++] & 0xFF) << 16
+              | (k[j++] & 0xFF) << 8
+              | (k[j++] & 0xFF);
+    // copy values into round key arrays
+    int t = 0;
+    for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++)
+      {
+        Ke[t / BC][t % BC] = tk[j];
+        Kd[ROUNDS - (t / BC)][t % BC] = tk[j];
+      }
+    int tt, rconpointer = 0;
+    while (t < ROUND_KEY_COUNT)
+      {
+        // extrapolate using phi (the round key evolution function)
+        tt = tk[KC - 1];
+        tk[0] ^= (S[(tt >>> 16) & 0xFF] & 0xFF) << 24
+               ^ (S[(tt >>>  8) & 0xFF] & 0xFF) << 16
+               ^ (S[ tt         & 0xFF] & 0xFF) <<  8
+               ^ (S[(tt >>> 24)       ] & 0xFF) ^ rcon[rconpointer++] << 24;
+        if (KC != 8)
+          for (i = 1, j = 0; i < KC;)
+            tk[i++] ^= tk[j++];
+        else
+          {
+            for (i = 1, j = 0; i < KC / 2;)
+              tk[i++] ^= tk[j++];
+            tt = tk[KC / 2 - 1];
+            tk[KC / 2] ^= (S[ tt         & 0xFF] & 0xFF)
+                        ^ (S[(tt >>>  8) & 0xFF] & 0xFF) << 8
+                        ^ (S[(tt >>> 16) & 0xFF] & 0xFF) << 16
+                        ^  S[(tt >>> 24) & 0xFF]         << 24;
+            for (j = KC / 2, i = j + 1; i < KC;)
+              tk[i++] ^= tk[j++];
+          }
+        // copy values into round key arrays
+        for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++)
+          {
+            Ke[t / BC][t % BC] = tk[j];
+            Kd[ROUNDS - (t / BC)][t % BC] = tk[j];
+          }
+      }
+    for (int r = 1; r < ROUNDS; r++) // inverse MixColumn where needed
+      for (j = 0; j < BC; j++)
+        {
+          tt = Kd[r][j];
+          Kd[r][j] = U1[(tt >>> 24)       ]
+                   ^ U2[(tt >>> 16) & 0xFF]
+                   ^ U3[(tt >>>  8) & 0xFF]
+                   ^ U4[ tt         & 0xFF];
+        }
+    return new Object[] { Ke, Kd };
+  }
+
+  public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (! (bs == 16 || bs == 24 || bs == 32))
+      throw new IllegalArgumentException();
+    if (bs == DEFAULT_BLOCK_SIZE)
+      aesEncrypt(in, i, out, j, k);
+    else
+      rijndaelEncrypt(in, i, out, j, k, bs);
+  }
+
+  public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (! (bs == 16 || bs == 24 || bs == 32))
+      throw new IllegalArgumentException();
+    if (bs == DEFAULT_BLOCK_SIZE)
+      aesDecrypt(in, i, out, j, k);
+    else
+      rijndaelDecrypt(in, i, out, j, k, bs);
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        boolean result = super.selfTest(); // do symmetry tests
+        if (result)
+          result = testKat(KAT_KEY, KAT_CT);
+        valid = Boolean.valueOf(result);
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/Serpent.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,1781 @@
+/* Serpent.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * Serpent is a 32-round substitution-permutation network block cipher,
+ * operating on 128-bit blocks and accepting keys of 128, 192, and 256 bits in
+ * length. At each round the plaintext is XORed with a 128 bit portion of the
+ * session key -- a 4224 bit key computed from the input key -- then one of
+ * eight S-boxes are applied, and finally a simple linear transformation is
+ * done. Decryption does the exact same thing in reverse order, and using the
+ * eight inverses of the S-boxes.
+ * <p>
+ * Serpent was designed by Ross Anderson, Eli Biham, and Lars Knudsen as a
+ * proposed cipher for the Advanced Encryption Standard.
+ * <p>
+ * Serpent can be sped up greatly by replacing S-box substitution with a
+ * sequence of binary operations, and the optimal implementation depends upon
+ * finding the fastest sequence of binary operations that reproduce this
+ * substitution. This implementation uses the S-boxes discovered by <a
+ * href="http://www.ii.uib.no/~osvik/">Dag Arne Osvik</a>, which are optimized
+ * for the Pentium family of processors.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.cl.cam.ac.uk/~rja14/serpent.html">Serpent: A
+ * Candidate Block Cipher for the Advanced Encryption Standard.</a></li>
+ * </ol>
+ */
+public class Serpent
+    extends BaseCipher
+{
+  private static final int DEFAULT_KEY_SIZE = 16;
+  private static final int DEFAULT_BLOCK_SIZE = 16;
+  private static final int ROUNDS = 32;
+  /** The fractional part of the golden ratio, (sqrt(5)+1)/2. */
+  private static final int PHI = 0x9e3779b9;
+  /**
+   * KAT vector (from ecb_vk): I=9
+   * KEY=008000000000000000000000000000000000000000000000
+   * CT=5587B5BCB9EE5A28BA2BACC418005240
+   */
+  private static final byte[] KAT_KEY = Util.toReversedBytesFromString(
+      "008000000000000000000000000000000000000000000000");
+  private static final byte[] KAT_CT =
+      Util.toReversedBytesFromString("5587B5BCB9EE5A28BA2BACC418005240");
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+  private int x0, x1, x2, x3, x4;
+
+  /** Trivial zero-argument constructor. */
+  public Serpent()
+  {
+    super(Registry.SERPENT_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
+  }
+
+  public Object clone()
+  {
+    Serpent result = new Serpent();
+    result.currentBlockSize = this.currentBlockSize;
+    return result;
+  }
+
+  public Iterator blockSizes()
+  {
+    return Collections.singleton(Integer.valueOf(DEFAULT_BLOCK_SIZE)).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    ArrayList keySizes = new ArrayList();
+    keySizes.add(Integer.valueOf(16));
+    keySizes.add(Integer.valueOf(24));
+    keySizes.add(Integer.valueOf(32));
+    return Collections.unmodifiableList(keySizes).iterator();
+  }
+
+  public Object makeKey(byte[] kb, int blockSize) throws InvalidKeyException
+  {
+    // Not strictly true, but here to conform with the AES proposal.
+    // This restriction can be removed if deemed necessary.
+    if (kb.length != 16 && kb.length != 24 && kb.length != 32)
+      throw new InvalidKeyException("Key length is not 16, 24, or 32 bytes");
+    Key key = new Key();
+    // Here w is our "pre-key".
+    int[] w = new int[4 * (ROUNDS + 1)];
+    int i, j;
+    for (i = 0, j = 0; i < 8 && j < kb.length; i++)
+      w[i] = (kb[j++] & 0xff)
+           | (kb[j++] & 0xff) << 8
+           | (kb[j++] & 0xff) << 16
+           | (kb[j++] & 0xff) << 24;
+    // Pad key if < 256 bits.
+    if (i != 8)
+      w[i] = 1;
+    // Transform using w_i-8 ... w_i-1
+    for (i = 8, j = 0; i < 16; i++)
+      {
+        int t = w[j] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ j++;
+        w[i] = t << 11 | t >>> 21;
+      }
+    // Translate by 8.
+    for (i = 0; i < 8; i++)
+      w[i] = w[i + 8];
+    // Transform the rest of the key.
+    for (; i < w.length; i++)
+      {
+        int t = w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i;
+        w[i] = t << 11 | t >>> 21;
+      }
+    // After these s-boxes the pre-key (w, above) will become the
+    // session key (key, below).
+    sbox3(w[0], w[1], w[2], w[3]);
+    key.k0 = x0;
+    key.k1 = x1;
+    key.k2 = x2;
+    key.k3 = x3;
+    sbox2(w[4], w[5], w[6], w[7]);
+    key.k4 = x0;
+    key.k5 = x1;
+    key.k6 = x2;
+    key.k7 = x3;
+    sbox1(w[8], w[9], w[10], w[11]);
+    key.k8 = x0;
+    key.k9 = x1;
+    key.k10 = x2;
+    key.k11 = x3;
+    sbox0(w[12], w[13], w[14], w[15]);
+    key.k12 = x0;
+    key.k13 = x1;
+    key.k14 = x2;
+    key.k15 = x3;
+    sbox7(w[16], w[17], w[18], w[19]);
+    key.k16 = x0;
+    key.k17 = x1;
+    key.k18 = x2;
+    key.k19 = x3;
+    sbox6(w[20], w[21], w[22], w[23]);
+    key.k20 = x0;
+    key.k21 = x1;
+    key.k22 = x2;
+    key.k23 = x3;
+    sbox5(w[24], w[25], w[26], w[27]);
+    key.k24 = x0;
+    key.k25 = x1;
+    key.k26 = x2;
+    key.k27 = x3;
+    sbox4(w[28], w[29], w[30], w[31]);
+    key.k28 = x0;
+    key.k29 = x1;
+    key.k30 = x2;
+    key.k31 = x3;
+    sbox3(w[32], w[33], w[34], w[35]);
+    key.k32 = x0;
+    key.k33 = x1;
+    key.k34 = x2;
+    key.k35 = x3;
+    sbox2(w[36], w[37], w[38], w[39]);
+    key.k36 = x0;
+    key.k37 = x1;
+    key.k38 = x2;
+    key.k39 = x3;
+    sbox1(w[40], w[41], w[42], w[43]);
+    key.k40 = x0;
+    key.k41 = x1;
+    key.k42 = x2;
+    key.k43 = x3;
+    sbox0(w[44], w[45], w[46], w[47]);
+    key.k44 = x0;
+    key.k45 = x1;
+    key.k46 = x2;
+    key.k47 = x3;
+    sbox7(w[48], w[49], w[50], w[51]);
+    key.k48 = x0;
+    key.k49 = x1;
+    key.k50 = x2;
+    key.k51 = x3;
+    sbox6(w[52], w[53], w[54], w[55]);
+    key.k52 = x0;
+    key.k53 = x1;
+    key.k54 = x2;
+    key.k55 = x3;
+    sbox5(w[56], w[57], w[58], w[59]);
+    key.k56 = x0;
+    key.k57 = x1;
+    key.k58 = x2;
+    key.k59 = x3;
+    sbox4(w[60], w[61], w[62], w[63]);
+    key.k60 = x0;
+    key.k61 = x1;
+    key.k62 = x2;
+    key.k63 = x3;
+    sbox3(w[64], w[65], w[66], w[67]);
+    key.k64 = x0;
+    key.k65 = x1;
+    key.k66 = x2;
+    key.k67 = x3;
+    sbox2(w[68], w[69], w[70], w[71]);
+    key.k68 = x0;
+    key.k69 = x1;
+    key.k70 = x2;
+    key.k71 = x3;
+    sbox1(w[72], w[73], w[74], w[75]);
+    key.k72 = x0;
+    key.k73 = x1;
+    key.k74 = x2;
+    key.k75 = x3;
+    sbox0(w[76], w[77], w[78], w[79]);
+    key.k76 = x0;
+    key.k77 = x1;
+    key.k78 = x2;
+    key.k79 = x3;
+    sbox7(w[80], w[81], w[82], w[83]);
+    key.k80 = x0;
+    key.k81 = x1;
+    key.k82 = x2;
+    key.k83 = x3;
+    sbox6(w[84], w[85], w[86], w[87]);
+    key.k84 = x0;
+    key.k85 = x1;
+    key.k86 = x2;
+    key.k87 = x3;
+    sbox5(w[88], w[89], w[90], w[91]);
+    key.k88 = x0;
+    key.k89 = x1;
+    key.k90 = x2;
+    key.k91 = x3;
+    sbox4(w[92], w[93], w[94], w[95]);
+    key.k92 = x0;
+    key.k93 = x1;
+    key.k94 = x2;
+    key.k95 = x3;
+    sbox3(w[96], w[97], w[98], w[99]);
+    key.k96 = x0;
+    key.k97 = x1;
+    key.k98 = x2;
+    key.k99 = x3;
+    sbox2(w[100], w[101], w[102], w[103]);
+    key.k100 = x0;
+    key.k101 = x1;
+    key.k102 = x2;
+    key.k103 = x3;
+    sbox1(w[104], w[105], w[106], w[107]);
+    key.k104 = x0;
+    key.k105 = x1;
+    key.k106 = x2;
+    key.k107 = x3;
+    sbox0(w[108], w[109], w[110], w[111]);
+    key.k108 = x0;
+    key.k109 = x1;
+    key.k110 = x2;
+    key.k111 = x3;
+    sbox7(w[112], w[113], w[114], w[115]);
+    key.k112 = x0;
+    key.k113 = x1;
+    key.k114 = x2;
+    key.k115 = x3;
+    sbox6(w[116], w[117], w[118], w[119]);
+    key.k116 = x0;
+    key.k117 = x1;
+    key.k118 = x2;
+    key.k119 = x3;
+    sbox5(w[120], w[121], w[122], w[123]);
+    key.k120 = x0;
+    key.k121 = x1;
+    key.k122 = x2;
+    key.k123 = x3;
+    sbox4(w[124], w[125], w[126], w[127]);
+    key.k124 = x0;
+    key.k125 = x1;
+    key.k126 = x2;
+    key.k127 = x3;
+    sbox3(w[128], w[129], w[130], w[131]);
+    key.k128 = x0;
+    key.k129 = x1;
+    key.k130 = x2;
+    key.k131 = x3;
+    return key;
+  }
+
+  public synchronized void encrypt(byte[] in, int i, byte[] out, int o,
+                                   Object K, int bs)
+  {
+    Key key = (Key) K;
+    x0 = (in[i     ] & 0xff)
+       | (in[i +  1] & 0xff) << 8
+       | (in[i +  2] & 0xff) << 16
+       | (in[i +  3] & 0xff) << 24;
+    x1 = (in[i +  4] & 0xff)
+       | (in[i +  5] & 0xff) << 8
+       | (in[i +  6] & 0xff) << 16
+       | (in[i +  7] & 0xff) << 24;
+    x2 = (in[i +  8] & 0xff)
+       | (in[i +  9] & 0xff) << 8
+       | (in[i + 10] & 0xff) << 16
+       | (in[i + 11] & 0xff) << 24;
+    x3 = (in[i + 12] & 0xff)
+       | (in[i + 13] & 0xff) << 8
+       | (in[i + 14] & 0xff) << 16
+       | (in[i + 15] & 0xff) << 24;
+    x0 ^= key.k0;
+    x1 ^= key.k1;
+    x2 ^= key.k2;
+    x3 ^= key.k3;
+    sbox0();
+    x1 ^= key.k4;
+    x4 ^= key.k5;
+    x2 ^= key.k6;
+    x0 ^= key.k7;
+    sbox1();
+    x0 ^= key.k8;
+    x4 ^= key.k9;
+    x2 ^= key.k10;
+    x1 ^= key.k11;
+    sbox2();
+    x2 ^= key.k12;
+    x1 ^= key.k13;
+    x4 ^= key.k14;
+    x3 ^= key.k15;
+    sbox3();
+    x1 ^= key.k16;
+    x4 ^= key.k17;
+    x3 ^= key.k18;
+    x0 ^= key.k19;
+    sbox4();
+    x4 ^= key.k20;
+    x2 ^= key.k21;
+    x1 ^= key.k22;
+    x0 ^= key.k23;
+    sbox5();
+    x2 ^= key.k24;
+    x0 ^= key.k25;
+    x4 ^= key.k26;
+    x1 ^= key.k27;
+    sbox6();
+    x2 ^= key.k28;
+    x0 ^= key.k29;
+    x3 ^= key.k30;
+    x4 ^= key.k31;
+    sbox7();
+    x0 = x3;
+    x3 = x2;
+    x2 = x4;
+    x0 ^= key.k32;
+    x1 ^= key.k33;
+    x2 ^= key.k34;
+    x3 ^= key.k35;
+    sbox0();
+    x1 ^= key.k36;
+    x4 ^= key.k37;
+    x2 ^= key.k38;
+    x0 ^= key.k39;
+    sbox1();
+    x0 ^= key.k40;
+    x4 ^= key.k41;
+    x2 ^= key.k42;
+    x1 ^= key.k43;
+    sbox2();
+    x2 ^= key.k44;
+    x1 ^= key.k45;
+    x4 ^= key.k46;
+    x3 ^= key.k47;
+    sbox3();
+    x1 ^= key.k48;
+    x4 ^= key.k49;
+    x3 ^= key.k50;
+    x0 ^= key.k51;
+    sbox4();
+    x4 ^= key.k52;
+    x2 ^= key.k53;
+    x1 ^= key.k54;
+    x0 ^= key.k55;
+    sbox5();
+    x2 ^= key.k56;
+    x0 ^= key.k57;
+    x4 ^= key.k58;
+    x1 ^= key.k59;
+    sbox6();
+    x2 ^= key.k60;
+    x0 ^= key.k61;
+    x3 ^= key.k62;
+    x4 ^= key.k63;
+    sbox7();
+    x0 = x3;
+    x3 = x2;
+    x2 = x4;
+    x0 ^= key.k64;
+    x1 ^= key.k65;
+    x2 ^= key.k66;
+    x3 ^= key.k67;
+    sbox0();
+    x1 ^= key.k68;
+    x4 ^= key.k69;
+    x2 ^= key.k70;
+    x0 ^= key.k71;
+    sbox1();
+    x0 ^= key.k72;
+    x4 ^= key.k73;
+    x2 ^= key.k74;
+    x1 ^= key.k75;
+    sbox2();
+    x2 ^= key.k76;
+    x1 ^= key.k77;
+    x4 ^= key.k78;
+    x3 ^= key.k79;
+    sbox3();
+    x1 ^= key.k80;
+    x4 ^= key.k81;
+    x3 ^= key.k82;
+    x0 ^= key.k83;
+    sbox4();
+    x4 ^= key.k84;
+    x2 ^= key.k85;
+    x1 ^= key.k86;
+    x0 ^= key.k87;
+    sbox5();
+    x2 ^= key.k88;
+    x0 ^= key.k89;
+    x4 ^= key.k90;
+    x1 ^= key.k91;
+    sbox6();
+    x2 ^= key.k92;
+    x0 ^= key.k93;
+    x3 ^= key.k94;
+    x4 ^= key.k95;
+    sbox7();
+    x0 = x3;
+    x3 = x2;
+    x2 = x4;
+    x0 ^= key.k96;
+    x1 ^= key.k97;
+    x2 ^= key.k98;
+    x3 ^= key.k99;
+    sbox0();
+    x1 ^= key.k100;
+    x4 ^= key.k101;
+    x2 ^= key.k102;
+    x0 ^= key.k103;
+    sbox1();
+    x0 ^= key.k104;
+    x4 ^= key.k105;
+    x2 ^= key.k106;
+    x1 ^= key.k107;
+    sbox2();
+    x2 ^= key.k108;
+    x1 ^= key.k109;
+    x4 ^= key.k110;
+    x3 ^= key.k111;
+    sbox3();
+    x1 ^= key.k112;
+    x4 ^= key.k113;
+    x3 ^= key.k114;
+    x0 ^= key.k115;
+    sbox4();
+    x4 ^= key.k116;
+    x2 ^= key.k117;
+    x1 ^= key.k118;
+    x0 ^= key.k119;
+    sbox5();
+    x2 ^= key.k120;
+    x0 ^= key.k121;
+    x4 ^= key.k122;
+    x1 ^= key.k123;
+    sbox6();
+    x2 ^= key.k124;
+    x0 ^= key.k125;
+    x3 ^= key.k126;
+    x4 ^= key.k127;
+    sbox7noLT();
+    x0 = x3;
+    x3 = x2;
+    x2 = x4;
+    x0 ^= key.k128;
+    x1 ^= key.k129;
+    x2 ^= key.k130;
+    x3 ^= key.k131;
+    out[o     ] = (byte) x0;
+    out[o +  1] = (byte)(x0 >>> 8);
+    out[o +  2] = (byte)(x0 >>> 16);
+    out[o +  3] = (byte)(x0 >>> 24);
+    out[o +  4] = (byte) x1;
+    out[o +  5] = (byte)(x1 >>> 8);
+    out[o +  6] = (byte)(x1 >>> 16);
+    out[o +  7] = (byte)(x1 >>> 24);
+    out[o +  8] = (byte) x2;
+    out[o +  9] = (byte)(x2 >>> 8);
+    out[o + 10] = (byte)(x2 >>> 16);
+    out[o + 11] = (byte)(x2 >>> 24);
+    out[o + 12] = (byte) x3;
+    out[o + 13] = (byte)(x3 >>> 8);
+    out[o + 14] = (byte)(x3 >>> 16);
+    out[o + 15] = (byte)(x3 >>> 24);
+  }
+
+  public synchronized void decrypt(byte[] in, int i, byte[] out, int o,
+                                   Object K, int bs)
+  {
+    Key key = (Key) K;
+    x0 = (in[i     ] & 0xff)
+       | (in[i +  1] & 0xff) << 8
+       | (in[i +  2] & 0xff) << 16
+       | (in[i +  3] & 0xff) << 24;
+    x1 = (in[i +  4] & 0xff)
+       | (in[i +  5] & 0xff) << 8
+       | (in[i +  6] & 0xff) << 16
+       | (in[i +  7] & 0xff) << 24;
+    x2 = (in[i +  8] & 0xff)
+       | (in[i +  9] & 0xff) << 8
+       | (in[i + 10] & 0xff) << 16
+       | (in[i + 11] & 0xff) << 24;
+    x3 = (in[i + 12] & 0xff)
+       | (in[i + 13] & 0xff) << 8
+       | (in[i + 14] & 0xff) << 16
+       | (in[i + 15] & 0xff) << 24;
+    x0 ^= key.k128;
+    x1 ^= key.k129;
+    x2 ^= key.k130;
+    x3 ^= key.k131;
+    sboxI7noLT();
+    x3 ^= key.k124;
+    x0 ^= key.k125;
+    x1 ^= key.k126;
+    x4 ^= key.k127;
+    sboxI6();
+    x0 ^= key.k120;
+    x1 ^= key.k121;
+    x2 ^= key.k122;
+    x4 ^= key.k123;
+    sboxI5();
+    x1 ^= key.k116;
+    x3 ^= key.k117;
+    x4 ^= key.k118;
+    x2 ^= key.k119;
+    sboxI4();
+    x1 ^= key.k112;
+    x2 ^= key.k113;
+    x4 ^= key.k114;
+    x0 ^= key.k115;
+    sboxI3();
+    x0 ^= key.k108;
+    x1 ^= key.k109;
+    x4 ^= key.k110;
+    x2 ^= key.k111;
+    sboxI2();
+    x1 ^= key.k104;
+    x3 ^= key.k105;
+    x4 ^= key.k106;
+    x2 ^= key.k107;
+    sboxI1();
+    x0 ^= key.k100;
+    x1 ^= key.k101;
+    x2 ^= key.k102;
+    x4 ^= key.k103;
+    sboxI0();
+    x0 ^= key.k96;
+    x3 ^= key.k97;
+    x1 ^= key.k98;
+    x4 ^= key.k99;
+    sboxI7();
+    x1 = x3;
+    x3 = x4;
+    x4 = x2;
+    x3 ^= key.k92;
+    x0 ^= key.k93;
+    x1 ^= key.k94;
+    x4 ^= key.k95;
+    sboxI6();
+    x0 ^= key.k88;
+    x1 ^= key.k89;
+    x2 ^= key.k90;
+    x4 ^= key.k91;
+    sboxI5();
+    x1 ^= key.k84;
+    x3 ^= key.k85;
+    x4 ^= key.k86;
+    x2 ^= key.k87;
+    sboxI4();
+    x1 ^= key.k80;
+    x2 ^= key.k81;
+    x4 ^= key.k82;
+    x0 ^= key.k83;
+    sboxI3();
+    x0 ^= key.k76;
+    x1 ^= key.k77;
+    x4 ^= key.k78;
+    x2 ^= key.k79;
+    sboxI2();
+    x1 ^= key.k72;
+    x3 ^= key.k73;
+    x4 ^= key.k74;
+    x2 ^= key.k75;
+    sboxI1();
+    x0 ^= key.k68;
+    x1 ^= key.k69;
+    x2 ^= key.k70;
+    x4 ^= key.k71;
+    sboxI0();
+    x0 ^= key.k64;
+    x3 ^= key.k65;
+    x1 ^= key.k66;
+    x4 ^= key.k67;
+    sboxI7();
+    x1 = x3;
+    x3 = x4;
+    x4 = x2;
+    x3 ^= key.k60;
+    x0 ^= key.k61;
+    x1 ^= key.k62;
+    x4 ^= key.k63;
+    sboxI6();
+    x0 ^= key.k56;
+    x1 ^= key.k57;
+    x2 ^= key.k58;
+    x4 ^= key.k59;
+    sboxI5();
+    x1 ^= key.k52;
+    x3 ^= key.k53;
+    x4 ^= key.k54;
+    x2 ^= key.k55;
+    sboxI4();
+    x1 ^= key.k48;
+    x2 ^= key.k49;
+    x4 ^= key.k50;
+    x0 ^= key.k51;
+    sboxI3();
+    x0 ^= key.k44;
+    x1 ^= key.k45;
+    x4 ^= key.k46;
+    x2 ^= key.k47;
+    sboxI2();
+    x1 ^= key.k40;
+    x3 ^= key.k41;
+    x4 ^= key.k42;
+    x2 ^= key.k43;
+    sboxI1();
+    x0 ^= key.k36;
+    x1 ^= key.k37;
+    x2 ^= key.k38;
+    x4 ^= key.k39;
+    sboxI0();
+    x0 ^= key.k32;
+    x3 ^= key.k33;
+    x1 ^= key.k34;
+    x4 ^= key.k35;
+    sboxI7();
+    x1 = x3;
+    x3 = x4;
+    x4 = x2;
+    x3 ^= key.k28;
+    x0 ^= key.k29;
+    x1 ^= key.k30;
+    x4 ^= key.k31;
+    sboxI6();
+    x0 ^= key.k24;
+    x1 ^= key.k25;
+    x2 ^= key.k26;
+    x4 ^= key.k27;
+    sboxI5();
+    x1 ^= key.k20;
+    x3 ^= key.k21;
+    x4 ^= key.k22;
+    x2 ^= key.k23;
+    sboxI4();
+    x1 ^= key.k16;
+    x2 ^= key.k17;
+    x4 ^= key.k18;
+    x0 ^= key.k19;
+    sboxI3();
+    x0 ^= key.k12;
+    x1 ^= key.k13;
+    x4 ^= key.k14;
+    x2 ^= key.k15;
+    sboxI2();
+    x1 ^= key.k8;
+    x3 ^= key.k9;
+    x4 ^= key.k10;
+    x2 ^= key.k11;
+    sboxI1();
+    x0 ^= key.k4;
+    x1 ^= key.k5;
+    x2 ^= key.k6;
+    x4 ^= key.k7;
+    sboxI0();
+    x2 = x1;
+    x1 = x3;
+    x3 = x4;
+    x0 ^= key.k0;
+    x1 ^= key.k1;
+    x2 ^= key.k2;
+    x3 ^= key.k3;
+    out[o     ] = (byte) x0;
+    out[o +  1] = (byte)(x0 >>> 8);
+    out[o +  2] = (byte)(x0 >>> 16);
+    out[o +  3] = (byte)(x0 >>> 24);
+    out[o +  4] = (byte) x1;
+    out[o +  5] = (byte)(x1 >>> 8);
+    out[o +  6] = (byte)(x1 >>> 16);
+    out[o +  7] = (byte)(x1 >>> 24);
+    out[o +  8] = (byte) x2;
+    out[o +  9] = (byte)(x2 >>> 8);
+    out[o + 10] = (byte)(x2 >>> 16);
+    out[o + 11] = (byte)(x2 >>> 24);
+    out[o + 12] = (byte) x3;
+    out[o + 13] = (byte)(x3 >>> 8);
+    out[o + 14] = (byte)(x3 >>> 16);
+    out[o + 15] = (byte)(x3 >>> 24);
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        boolean result = super.selfTest(); // do symmetry tests
+        if (result)
+          result = testKat(KAT_KEY, KAT_CT);
+        valid = Boolean.valueOf(result);
+      }
+    return valid.booleanValue();
+  }
+
+  // These first few S-boxes operate directly on the "registers",
+  // x0..x4, and perform the linear transform.
+  private void sbox0()
+  {
+    x3 ^= x0;
+    x4 = x1;
+    x1 &= x3;
+    x4 ^= x2;
+    x1 ^= x0;
+    x0 |= x3;
+    x0 ^= x4;
+    x4 ^= x3;
+    x3 ^= x2;
+    x2 |= x1;
+    x2 ^= x4;
+    x4 ^= -1;
+    x4 |= x1;
+    x1 ^= x3;
+    x1 ^= x4;
+    x3 |= x0;
+    x1 ^= x3;
+    x4 ^= x3;
+
+    x1 = (x1 << 13) | (x1 >>> 19);
+    x4 ^= x1;
+    x3 = x1 << 3;
+    x2 = (x2 << 3) | (x2 >>> 29);
+    x4 ^= x2;
+    x0 ^= x2;
+    x4 = (x4 << 1) | (x4 >>> 31);
+    x0 ^= x3;
+    x0 = (x0 << 7) | (x0 >>> 25);
+    x3 = x4;
+    x1 ^= x4;
+    x3 <<= 7;
+    x1 ^= x0;
+    x2 ^= x0;
+    x2 ^= x3;
+    x1 = (x1 << 5) | (x1 >>> 27);
+    x2 = (x2 << 22) | (x2 >>> 10);
+  }
+
+  private void sbox1()
+  {
+    x4 = ~x4;
+    x3 = x1;
+    x1 ^= x4;
+    x3 |= x4;
+    x3 ^= x0;
+    x0 &= x1;
+    x2 ^= x3;
+    x0 ^= x4;
+    x0 |= x2;
+    x1 ^= x3;
+    x0 ^= x1;
+    x4 &= x2;
+    x1 |= x4;
+    x4 ^= x3;
+    x1 ^= x2;
+    x3 |= x0;
+    x1 ^= x3;
+    x3 = ~x3;
+    x4 ^= x0;
+    x3 &= x2;
+    x4 = ~x4;
+    x3 ^= x1;
+    x4 ^= x3;
+
+    x0 = (x0 << 13) | (x0 >>> 19);
+    x4 ^= x0;
+    x3 = x0 << 3;
+    x2 = (x2 << 3) | (x2 >>> 29);
+    x4 ^= x2;
+    x1 ^= x2;
+    x4 = (x4 << 1) | (x4 >>> 31);
+    x1 ^= x3;
+    x1 = (x1 << 7) | (x1 >>> 25);
+    x3 = x4;
+    x0 ^= x4;
+    x3 <<= 7;
+    x0 ^= x1;
+    x2 ^= x1;
+    x2 ^= x3;
+    x0 = (x0 << 5) | (x0 >>> 27);
+    x2 = (x2 << 22) | (x2 >>> 10);
+  }
+
+  private void sbox2()
+  {
+    x3 = x0;
+    x0 = x0 & x2;
+    x0 = x0 ^ x1;
+    x2 = x2 ^ x4;
+    x2 = x2 ^ x0;
+    x1 = x1 | x3;
+    x1 = x1 ^ x4;
+    x3 = x3 ^ x2;
+    x4 = x1;
+    x1 = x1 | x3;
+    x1 = x1 ^ x0;
+    x0 = x0 & x4;
+    x3 = x3 ^ x0;
+    x4 = x4 ^ x1;
+    x4 = x4 ^ x3;
+    x3 = ~x3;
+
+    x2 = (x2 << 13) | (x2 >>> 19);
+    x1 ^= x2;
+    x0 = x2 << 3;
+    x4 = (x4 << 3) | (x4 >>> 29);
+    x1 ^= x4;
+    x3 ^= x4;
+    x1 = (x1 << 1) | (x1 >>> 31);
+    x3 ^= x0;
+    x3 = (x3 << 7) | (x3 >>> 25);
+    x0 = x1;
+    x2 ^= x1;
+    x0 <<= 7;
+    x2 ^= x3;
+    x4 ^= x3;
+    x4 ^= x0;
+    x2 = (x2 << 5) | (x2 >>> 27);
+    x4 = (x4 << 22) | (x4 >>> 10);
+  }
+
+  private void sbox3()
+  {
+    x0 = x2;
+    x2 = x2 | x3;
+    x3 = x3 ^ x1;
+    x1 = x1 & x0;
+    x0 = x0 ^ x4;
+    x4 = x4 ^ x3;
+    x3 = x3 & x2;
+    x0 = x0 | x1;
+    x3 = x3 ^ x0;
+    x2 = x2 ^ x1;
+    x0 = x0 & x2;
+    x1 = x1 ^ x3;
+    x0 = x0 ^ x4;
+    x1 = x1 | x2;
+    x1 = x1 ^ x4;
+    x2 = x2 ^ x3;
+    x4 = x1;
+    x1 = x1 | x3;
+    x1 = x1 ^ x2;
+
+    x1 = (x1 << 13) | (x1 >>> 19);
+    x4 ^= x1;
+    x2 = x1 << 3;
+    x3 = (x3 << 3) | (x3 >>> 29);
+    x4 ^= x3;
+    x0 ^= x3;
+    x4 = (x4 << 1) | (x4 >>> 31);
+    x0 ^= x2;
+    x0 = (x0 << 7) | (x0 >>> 25);
+    x2 = x4;
+    x1 ^= x4;
+    x2 <<= 7;
+    x1 ^= x0;
+    x3 ^= x0;
+    x3 ^= x2;
+    x1 = (x1 << 5) | (x1 >>> 27);
+    x3 = (x3 << 22) | (x3 >>> 10);
+  }
+
+  private void sbox4()
+  {
+    x4 = x4 ^ x0;
+    x0 = ~x0;
+    x3 = x3 ^ x0;
+    x0 = x0 ^ x1;
+    x2 = x4;
+    x4 = x4 & x0;
+    x4 = x4 ^ x3;
+    x2 = x2 ^ x0;
+    x1 = x1 ^ x2;
+    x3 = x3 & x2;
+    x3 = x3 ^ x1;
+    x1 = x1 & x4;
+    x0 = x0 ^ x1;
+    x2 = x2 | x4;
+    x2 = x2 ^ x1;
+    x1 = x1 | x0;
+    x1 = x1 ^ x3;
+    x3 = x3 & x0;
+    x1 = ~x1;
+    x2 = x2 ^ x3;
+
+    x4 = (x4 << 13) | (x4 >>> 19);
+    x2 ^= x4;
+    x3 = x4 << 3;
+    x1 = (x1 << 3) | (x1 >>> 29);
+    x2 ^= x1;
+    x0 ^= x1;
+    x2 = (x2 << 1) | (x2 >>> 31);
+    x0 ^= x3;
+    x0 = (x0 << 7) | (x0 >>> 25);
+    x3 = x2;
+    x4 ^= x2;
+    x3 <<= 7;
+    x4 ^= x0;
+    x1 ^= x0;
+    x1 ^= x3;
+    x4 = (x4 << 5) | (x4 >>> 27);
+    x1 = (x1 << 22) | (x1 >>> 10);
+  }
+
+  private void sbox5()
+  {
+    x4 = x4 ^ x2;
+    x2 = x2 ^ x0;
+    x0 = ~x0;
+    x3 = x2;
+    x2 = x2 & x4;
+    x1 = x1 ^ x0;
+    x2 = x2 ^ x1;
+    x1 = x1 | x3;
+    x3 = x3 ^ x0;
+    x0 = x0 & x2;
+    x0 = x0 ^ x4;
+    x3 = x3 ^ x2;
+    x3 = x3 ^ x1;
+    x1 = x1 ^ x4;
+    x4 = x4 & x0;
+    x1 = ~x1;
+    x4 = x4 ^ x3;
+    x3 = x3 | x0;
+    x1 = x1 ^ x3;
+
+    x2 = (x2 << 13) | (x2 >>> 19);
+    x0 ^= x2;
+    x3 = x2 << 3;
+    x4 = (x4 << 3) | (x4 >>> 29);
+    x0 ^= x4;
+    x1 ^= x4;
+    x0 = (x0 << 1) | (x0 >>> 31);
+    x1 ^= x3;
+    x1 = (x1 << 7) | (x1 >>> 25);
+    x3 = x0;
+    x2 ^= x0;
+    x3 <<= 7;
+    x2 ^= x1;
+    x4 ^= x1;
+    x4 ^= x3;
+    x2 = (x2 << 5) | (x2 >>> 27);
+    x4 = (x4 << 22) | (x4 >>> 10);
+  }
+
+  private void sbox6()
+  {
+    x4 = ~x4;
+    x3 = x1;
+    x1 = x1 & x2;
+    x2 = x2 ^ x3;
+    x1 = x1 ^ x4;
+    x4 = x4 | x3;
+    x0 = x0 ^ x1;
+    x4 = x4 ^ x2;
+    x2 = x2 | x0;
+    x4 = x4 ^ x0;
+    x3 = x3 ^ x2;
+    x2 = x2 | x1;
+    x2 = x2 ^ x4;
+    x3 = x3 ^ x1;
+    x3 = x3 ^ x2;
+    x1 = ~x1;
+    x4 = x4 & x3;
+    x4 = x4 ^ x1;
+    x2 = (x2 << 13) | (x2 >>> 19);
+    x0 ^= x2;
+    x1 = x2 << 3;
+    x3 = (x3 << 3) | (x3 >>> 29);
+    x0 ^= x3;
+    x4 ^= x3;
+    x0 = (x0 << 1) | (x0 >>> 31);
+    x4 ^= x1;
+    x4 = (x4 << 7) | (x4 >>> 25);
+    x1 = x0;
+    x2 ^= x0;
+    x1 <<= 7;
+    x2 ^= x4;
+    x3 ^= x4;
+    x3 ^= x1;
+    x2 = (x2 << 5) | (x2 >>> 27);
+    x3 = (x3 << 22) | (x3 >>> 10);
+  }
+
+  private void sbox7()
+  {
+    x1 = x3;
+    x3 = x3 & x0;
+    x3 = x3 ^ x4;
+    x4 = x4 & x0;
+    x1 = x1 ^ x3;
+    x3 = x3 ^ x0;
+    x0 = x0 ^ x2;
+    x2 = x2 | x1;
+    x2 = x2 ^ x3;
+    x4 = x4 ^ x0;
+    x3 = x3 ^ x4;
+    x4 = x4 & x2;
+    x4 = x4 ^ x1;
+    x1 = x1 ^ x3;
+    x3 = x3 & x2;
+    x1 = ~x1;
+    x3 = x3 ^ x1;
+    x1 = x1 & x2;
+    x0 = x0 ^ x4;
+    x1 = x1 ^ x0;
+    x3 = (x3 << 13) | (x3 >>> 19);
+    x1 ^= x3;
+    x0 = x3 << 3;
+    x4 = (x4 << 3) | (x4 >>> 29);
+    x1 ^= x4;
+    x2 ^= x4;
+    x1 = (x1 << 1) | (x1 >>> 31);
+    x2 ^= x0;
+    x2 = (x2 << 7) | (x2 >>> 25);
+    x0 = x1;
+    x3 ^= x1;
+    x0 <<= 7;
+    x3 ^= x2;
+    x4 ^= x2;
+    x4 ^= x0;
+    x3 = (x3 << 5) | (x3 >>> 27);
+    x4 = (x4 << 22) | (x4 >>> 10);
+  }
+
+  /** The final S-box, with no transform. */
+  private void sbox7noLT()
+  {
+    x1 = x3;
+    x3 = x3 & x0;
+    x3 = x3 ^ x4;
+    x4 = x4 & x0;
+    x1 = x1 ^ x3;
+    x3 = x3 ^ x0;
+    x0 = x0 ^ x2;
+    x2 = x2 | x1;
+    x2 = x2 ^ x3;
+    x4 = x4 ^ x0;
+    x3 = x3 ^ x4;
+    x4 = x4 & x2;
+    x4 = x4 ^ x1;
+    x1 = x1 ^ x3;
+    x3 = x3 & x2;
+    x1 = ~x1;
+    x3 = x3 ^ x1;
+    x1 = x1 & x2;
+    x0 = x0 ^ x4;
+    x1 = x1 ^ x0;
+  }
+
+  private void sboxI7noLT()
+  {
+    x4 = x2;
+    x2 ^= x0;
+    x0 &= x3;
+    x2 = ~x2;
+    x4 |= x3;
+    x3 ^= x1;
+    x1 |= x0;
+    x0 ^= x2;
+    x2 &= x4;
+    x1 ^= x2;
+    x2 ^= x0;
+    x0 |= x2;
+    x3 &= x4;
+    x0 ^= x3;
+    x4 ^= x1;
+    x3 ^= x4;
+    x4 |= x0;
+    x3 ^= x2;
+    x4 ^= x2;
+  }
+
+  private void sboxI6()
+  {
+    x1 = (x1 >>> 22) | (x1 << 10);
+    x3 = (x3 >>> 5) | (x3 << 27);
+    x2 = x0;
+    x1 ^= x4;
+    x2 <<= 7;
+    x3 ^= x4;
+    x1 ^= x2;
+    x3 ^= x0;
+    x4 = (x4 >>> 7) | (x4 << 25);
+    x0 = (x0 >>> 1) | (x0 << 31);
+    x0 ^= x3;
+    x2 = x3 << 3;
+    x4 ^= x2;
+    x3 = (x3 >>> 13) | (x3 << 19);
+    x0 ^= x1;
+    x4 ^= x1;
+    x1 = (x1 >>> 3) | (x1 << 29);
+    x3 ^= x1;
+    x2 = x1;
+    x1 &= x3;
+    x2 ^= x4;
+    x1 = ~x1;
+    x4 ^= x0;
+    x1 ^= x4;
+    x2 |= x3;
+    x3 ^= x1;
+    x4 ^= x2;
+    x2 ^= x0;
+    x0 &= x4;
+    x0 ^= x3;
+    x3 ^= x4;
+    x3 |= x1;
+    x4 ^= x0;
+    x2 ^= x3;
+  }
+
+  private void sboxI5()
+  {
+    x2 = (x2 >>> 22) | (x2 << 10);
+    x0 = (x0 >>> 5) | (x0 << 27);
+    x3 = x1;
+    x2 ^= x4;
+    x3 <<= 7;
+    x0 ^= x4;
+    x2 ^= x3;
+    x0 ^= x1;
+    x4 = (x4 >>> 7) | (x4 << 25);
+    x1 = (x1 >>> 1) | (x1 << 31);
+    x1 ^= x0;
+    x3 = x0 << 3;
+    x4 ^= x3;
+    x0 = (x0 >>> 13) | (x0 << 19);
+    x1 ^= x2;
+    x4 ^= x2;
+    x2 = (x2 >>> 3) | (x2 << 29);
+    x1 = ~x1;
+    x3 = x4;
+    x2 ^= x1;
+    x4 |= x0;
+    x4 ^= x2;
+    x2 |= x1;
+    x2 &= x0;
+    x3 ^= x4;
+    x2 ^= x3;
+    x3 |= x0;
+    x3 ^= x1;
+    x1 &= x2;
+    x1 ^= x4;
+    x3 ^= x2;
+    x4 &= x3;
+    x3 ^= x1;
+    x4 ^= x0;
+    x4 ^= x3;
+    x3 = ~x3;
+  }
+
+  private void sboxI4()
+  {
+    x4 = (x4 >>> 22) | (x4 << 10);
+    x1 = (x1 >>> 5) | (x1 << 27);
+    x0 = x3;
+    x4 ^= x2;
+    x0 <<= 7;
+    x1 ^= x2;
+    x4 ^= x0;
+    x1 ^= x3;
+    x2 = (x2 >>> 7) | (x2 << 25);
+    x3 = (x3 >>> 1) | (x3 << 31);
+    x3 ^= x1;
+    x0 = x1 << 3;
+    x2 ^= x0;
+    x1 = (x1 >>> 13) | (x1 << 19);
+    x3 ^= x4;
+    x2 ^= x4;
+    x4 = (x4 >>> 3) | (x4 << 29);
+    x0 = x4;
+    x4 &= x2;
+    x4 ^= x3;
+    x3 |= x2;
+    x3 &= x1;
+    x0 ^= x4;
+    x0 ^= x3;
+    x3 &= x4;
+    x1 = ~x1;
+    x2 ^= x0;
+    x3 ^= x2;
+    x2 &= x1;
+    x2 ^= x4;
+    x1 ^= x3;
+    x4 &= x1;
+    x2 ^= x1;
+    x4 ^= x0;
+    x4 |= x2;
+    x2 ^= x1;
+    x4 ^= x3;
+  }
+
+  private void sboxI3()
+  {
+    x4 = (x4 >>> 22) | (x4 << 10);
+    x1 = (x1 >>> 5) | (x1 << 27);
+    x3 = x2;
+    x4 ^= x0;
+    x3 <<= 7;
+    x1 ^= x0;
+    x4 ^= x3;
+    x1 ^= x2;
+    x0 = (x0 >>> 7) | (x0 << 25);
+    x2 = (x2 >>> 1) | (x2 << 31);
+    x2 ^= x1;
+    x3 = x1 << 3;
+    x0 ^= x3;
+    x1 = (x1 >>> 13) | (x1 << 19);
+    x2 ^= x4;
+    x0 ^= x4;
+    x4 = (x4 >>> 3) | (x4 << 29);
+    x3 = x4;
+    x4 ^= x2;
+    x2 &= x4;
+    x2 ^= x1;
+    x1 &= x3;
+    x3 ^= x0;
+    x0 |= x2;
+    x0 ^= x4;
+    x1 ^= x3;
+    x4 ^= x1;
+    x1 |= x0;
+    x1 ^= x2;
+    x3 ^= x4;
+    x4 &= x0;
+    x2 |= x0;
+    x2 ^= x4;
+    x3 ^= x1;
+    x4 ^= x3;
+  }
+
+  private void sboxI2()
+  {
+    x4 = (x4 >>> 22) | (x4 << 10);
+    x0 = (x0 >>> 5) | (x0 << 27);
+    x3 = x1;
+    x4 ^= x2;
+    x3 <<= 7;
+    x0 ^= x2;
+    x4 ^= x3;
+    x0 ^= x1;
+    x2 = (x2 >>> 7) | (x2 << 25);
+    x1 = (x1 >>> 1) | (x1 << 31);
+    x1 ^= x0;
+    x3 = x0 << 3;
+    x2 ^= x3;
+    x0 = (x0 >>> 13) | (x0 << 19);
+    x1 ^= x4;
+    x2 ^= x4;
+    x4 = (x4 >>> 3) | (x4 << 29);
+    x4 ^= x2;
+    x2 ^= x0;
+    x3 = x2;
+    x2 &= x4;
+    x2 ^= x1;
+    x1 |= x4;
+    x1 ^= x3;
+    x3 &= x2;
+    x4 ^= x2;
+    x3 &= x0;
+    x3 ^= x4;
+    x4 &= x1;
+    x4 |= x0;
+    x2 = ~x2;
+    x4 ^= x2;
+    x0 ^= x2;
+    x0 &= x1;
+    x2 ^= x3;
+    x2 ^= x0;
+  }
+
+  private void sboxI1()
+  {
+    x4 = (x4 >>> 22) | (x4 << 10);
+    x1 = (x1 >>> 5) | (x1 << 27);
+    x0 = x3;
+    x4 ^= x2;
+    x0 <<= 7;
+    x1 ^= x2;
+    x4 ^= x0;
+    x1 ^= x3;
+    x2 = (x2 >>> 7) | (x2 << 25);
+    x3 = (x3 >>> 1) | (x3 << 31);
+    x3 ^= x1;
+    x0 = x1 << 3;
+    x2 ^= x0;
+    x1 = (x1 >>> 13) | (x1 << 19);
+    x3 ^= x4;
+    x2 ^= x4;
+    x4 = (x4 >>> 3) | (x4 << 29);
+    x0 = x3;
+    x3 ^= x2;
+    x2 &= x3;
+    x0 ^= x4;
+    x2 ^= x1;
+    x1 |= x3;
+    x4 ^= x2;
+    x1 ^= x0;
+    x1 |= x4;
+    x3 ^= x2;
+    x1 ^= x3;
+    x3 |= x2;
+    x3 ^= x1;
+    x0 = ~x0;
+    x0 ^= x3;
+    x3 |= x1;
+    x3 ^= x1;
+    x3 |= x0;
+    x2 ^= x3;
+  }
+
+  private void sboxI0()
+  {
+    x2 = (x2 >>> 22) | (x2 << 10);
+    x0 = (x0 >>> 5) | (x0 << 27);
+    x3 = x1;
+    x2 ^= x4;
+    x3 <<= 7;
+    x0 ^= x4;
+    x2 ^= x3;
+    x0 ^= x1;
+    x4 = (x4 >>> 7) | (x4 << 25);
+    x1 = (x1 >>> 1) | (x1 << 31);
+    x1 ^= x0;
+    x3 = x0 << 3;
+    x4 ^= x3;
+    x0 = (x0 >>> 13) | (x0 << 19);
+    x1 ^= x2;
+    x4 ^= x2;
+    x2 = (x2 >>> 3) | (x2 << 29);
+    x2 = ~x2;
+    x3 = x1;
+    x1 |= x0;
+    x3 = ~x3;
+    x1 ^= x2;
+    x2 |= x3;
+    x1 ^= x4;
+    x0 ^= x3;
+    x2 ^= x0;
+    x0 &= x4;
+    x3 ^= x0;
+    x0 |= x1;
+    x0 ^= x2;
+    x4 ^= x3;
+    x2 ^= x1;
+    x4 ^= x0;
+    x4 ^= x1;
+    x2 &= x4;
+    x3 ^= x2;
+  }
+
+  private void sboxI7()
+  {
+    x1 = (x1 >>> 22) | (x1 << 10);
+    x0 = (x0 >>> 5) | (x0 << 27);
+    x2 = x3;
+    x1 ^= x4;
+    x2 <<= 7;
+    x0 ^= x4;
+    x1 ^= x2;
+    x0 ^= x3;
+    x4 = (x4 >>> 7) | (x4 << 25);
+    x3 = (x3 >>> 1) | (x3 << 31);
+    x3 ^= x0;
+    x2 = x0 << 3;
+    x4 ^= x2;
+    x0 = (x0 >>> 13) | (x0 << 19);
+    x3 ^= x1;
+    x4 ^= x1;
+    x1 = (x1 >>> 3) | (x1 << 29);
+    x2 = x1;
+    x1 ^= x0;
+    x0 &= x4;
+    x1 = ~x1;
+    x2 |= x4;
+    x4 ^= x3;
+    x3 |= x0;
+    x0 ^= x1;
+    x1 &= x2;
+    x3 ^= x1;
+    x1 ^= x0;
+    x0 |= x1;
+    x4 &= x2;
+    x0 ^= x4;
+    x2 ^= x3;
+    x4 ^= x2;
+    x2 |= x0;
+    x4 ^= x1;
+    x2 ^= x1;
+  }
+
+  /** S-Box 0. */
+  private void sbox0(int r0, int r1, int r2, int r3)
+  {
+    int r4 = r1 ^ r2;
+    r3 ^= r0;
+    r1 = r1 & r3 ^ r0;
+    r0 = (r0 | r3) ^ r4;
+    r4 ^= r3;
+    r3 ^= r2;
+    r2 = (r2 | r1) ^ r4;
+    r4 = ~r4 | r1;
+    r1 ^= r3 ^ r4;
+    r3 |= r0;
+    x0 = r1 ^ r3;
+    x1 = r4 ^ r3;
+    x2 = r2;
+    x3 = r0;
+  }
+
+  /** S-Box 1. */
+  private void sbox1(int r0, int r1, int r2, int r3)
+  {
+    r0 = ~r0;
+    int r4 = r0;
+    r2 = ~r2;
+    r0 &= r1;
+    r2 ^= r0;
+    r0 |= r3;
+    r3 ^= r2;
+    r1 ^= r0;
+    r0 ^= r4;
+    r4 |= r1;
+    r1 ^= r3;
+    r2 = (r2 | r0) & r4;
+    r0 ^= r1;
+    x0 = r2;
+    x1 = r0 & r2 ^ r4;
+    x2 = r3;
+    x3 = r1 & r2 ^ r0;
+  }
+
+  /** S-Box 2. */
+  private void sbox2(int r0, int r1, int r2, int r3)
+  {
+    int r4 = r0;
+    r0 = r0 & r2 ^ r3;
+    r2 = r2 ^ r1 ^ r0;
+    r3 = (r3 | r4) ^ r1;
+    r4 ^= r2;
+    r1 = r3;
+    r3 = (r3 | r4) ^ r0;
+    r0 &= r1;
+    r4 ^= r0;
+    x0 = r2;
+    x1 = r3;
+    x2 = r1 ^ r3 ^ r4;
+    x3 = ~r4;
+  }
+
+  /** S-Box 3. */
+  private void sbox3(int r0, int r1, int r2, int r3)
+  {
+    int r4 = r0;
+    r0 |= r3;
+    r3 ^= r1;
+    r1 &= r4;
+    r4 = r4 ^ r2 | r1;
+    r2 ^= r3;
+    r3 = r3 & r0 ^ r4;
+    r0 ^= r1;
+    r4 = r4 & r0 ^ r2;
+    r1 = (r1 ^ r3 | r0) ^ r2;
+    r0 ^= r3;
+    x0 = (r1 | r3) ^ r0;
+    x1 = r1;
+    x2 = r3;
+    x3 = r4;
+  }
+
+  /** S-Box 4. */
+  private void sbox4(int r0, int r1, int r2, int r3)
+  {
+    r1 ^= r3;
+    int r4 = r1;
+    r3 = ~r3;
+    r2 ^= r3;
+    r3 ^= r0;
+    r1 = r1 & r3 ^ r2;
+    r4 ^= r3;
+    r0 ^= r4;
+    r2 = r2 & r4 ^ r0;
+    r0 &= r1;
+    r3 ^= r0;
+    r4 = (r4 | r1) ^ r0;
+    x0 = r1;
+    x1 = r4 ^ (r2 & r3);
+    x2 = ~((r0 | r3) ^ r2);
+    x3 = r3;
+  }
+
+  /** S-Box 5. */
+  private void sbox5(int r0, int r1, int r2, int r3)
+  {
+    r0 ^= r1;
+    r1 ^= r3;
+    int r4 = r1;
+    r3 = ~r3;
+    r1 &= r0;
+    r2 ^= r3;
+    r1 ^= r2;
+    r2 |= r4;
+    r4 ^= r3;
+    r3 = r3 & r1 ^ r0;
+    r4 = r4 ^ r1 ^ r2;
+    x0 = r1;
+    x1 = r3;
+    x2 = r0 & r3 ^ r4;
+    x3 = ~(r2 ^ r0) ^ (r4 | r3);
+  }
+
+  /** S-Box 6. */
+  private void sbox6(int r0, int r1, int r2, int r3)
+  {
+    int r4 = r3;
+    r2 = ~r2;
+    r3 = r3 & r0 ^ r2;
+    r0 ^= r4;
+    r2 = (r2 | r4) ^ r0;
+    r1 ^= r3;
+    r0 |= r1;
+    r2 ^= r1;
+    r4 ^= r0;
+    r0 = (r0 | r3) ^ r2;
+    r4 = r4 ^ r3 ^ r0;
+    x0 = r0;
+    x1 = r1;
+    x2 = r4;
+    x3 = r2 & r4 ^ ~r3;
+  }
+
+  /** S-Box 7. */
+  private void sbox7(int r0, int r1, int r2, int r3)
+  {
+    int r4 = r1;
+    r1 = (r1 | r2) ^ r3;
+    r4 ^= r2;
+    r2 ^= r1;
+    r3 = (r3 | r4) & r0;
+    r4 ^= r2;
+    r3 ^= r1;
+    r1 = (r1 | r4) ^ r0;
+    r0 = (r0 | r4) ^ r2;
+    r1 ^= r4;
+    r2 ^= r1;
+    x0 = r4 ^ (~r2 | r0);
+    x1 = r3;
+    x2 = r1 & r0 ^ r4;
+    x3 = r0;
+  }
+
+  private class Key
+      implements Cloneable
+  {
+    int k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15,
+        k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29,
+        k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43,
+        k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57,
+        k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71,
+        k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85,
+        k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99,
+        k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111,
+        k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123,
+        k124, k125, k126, k127, k128, k129, k130, k131;
+
+    /** Trivial 0-arguments constructor. */
+    Key()
+    {
+    }
+
+    /** Cloning constructor. */
+    private Key(Key that)
+    {
+      this.k0 = that.k0;
+      this.k1 = that.k1;
+      this.k2 = that.k2;
+      this.k3 = that.k3;
+      this.k4 = that.k4;
+      this.k5 = that.k5;
+      this.k6 = that.k6;
+      this.k7 = that.k7;
+      this.k8 = that.k8;
+      this.k9 = that.k9;
+      this.k10 = that.k10;
+      this.k11 = that.k11;
+      this.k12 = that.k12;
+      this.k13 = that.k13;
+      this.k14 = that.k14;
+      this.k15 = that.k15;
+      this.k16 = that.k16;
+      this.k17 = that.k17;
+      this.k18 = that.k18;
+      this.k19 = that.k19;
+      this.k20 = that.k20;
+      this.k21 = that.k21;
+      this.k22 = that.k22;
+      this.k23 = that.k23;
+      this.k24 = that.k24;
+      this.k25 = that.k25;
+      this.k26 = that.k26;
+      this.k27 = that.k27;
+      this.k28 = that.k28;
+      this.k29 = that.k29;
+      this.k30 = that.k30;
+      this.k31 = that.k31;
+      this.k32 = that.k32;
+      this.k33 = that.k33;
+      this.k34 = that.k34;
+      this.k35 = that.k35;
+      this.k36 = that.k36;
+      this.k37 = that.k37;
+      this.k38 = that.k38;
+      this.k39 = that.k39;
+      this.k40 = that.k40;
+      this.k41 = that.k41;
+      this.k42 = that.k42;
+      this.k43 = that.k43;
+      this.k44 = that.k44;
+      this.k45 = that.k45;
+      this.k46 = that.k46;
+      this.k47 = that.k47;
+      this.k48 = that.k48;
+      this.k49 = that.k49;
+      this.k50 = that.k50;
+      this.k51 = that.k51;
+      this.k52 = that.k52;
+      this.k53 = that.k53;
+      this.k54 = that.k54;
+      this.k55 = that.k55;
+      this.k56 = that.k56;
+      this.k57 = that.k57;
+      this.k58 = that.k58;
+      this.k59 = that.k59;
+      this.k60 = that.k60;
+      this.k61 = that.k61;
+      this.k62 = that.k62;
+      this.k63 = that.k63;
+      this.k64 = that.k64;
+      this.k65 = that.k65;
+      this.k66 = that.k66;
+      this.k67 = that.k67;
+      this.k68 = that.k68;
+      this.k69 = that.k69;
+      this.k70 = that.k70;
+      this.k71 = that.k71;
+      this.k72 = that.k72;
+      this.k73 = that.k73;
+      this.k74 = that.k74;
+      this.k75 = that.k75;
+      this.k76 = that.k76;
+      this.k77 = that.k77;
+      this.k78 = that.k78;
+      this.k79 = that.k79;
+      this.k80 = that.k80;
+      this.k81 = that.k81;
+      this.k82 = that.k82;
+      this.k83 = that.k83;
+      this.k84 = that.k84;
+      this.k85 = that.k85;
+      this.k86 = that.k86;
+      this.k87 = that.k87;
+      this.k88 = that.k88;
+      this.k89 = that.k89;
+      this.k90 = that.k90;
+      this.k91 = that.k91;
+      this.k92 = that.k92;
+      this.k93 = that.k93;
+      this.k94 = that.k94;
+      this.k95 = that.k95;
+      this.k96 = that.k96;
+      this.k97 = that.k97;
+      this.k98 = that.k98;
+      this.k99 = that.k99;
+      this.k100 = that.k100;
+      this.k101 = that.k101;
+      this.k102 = that.k102;
+      this.k103 = that.k103;
+      this.k104 = that.k104;
+      this.k105 = that.k105;
+      this.k106 = that.k106;
+      this.k107 = that.k107;
+      this.k108 = that.k108;
+      this.k109 = that.k109;
+      this.k110 = that.k110;
+      this.k111 = that.k111;
+      this.k112 = that.k112;
+      this.k113 = that.k113;
+      this.k114 = that.k114;
+      this.k115 = that.k115;
+      this.k116 = that.k116;
+      this.k117 = that.k117;
+      this.k118 = that.k118;
+      this.k119 = that.k119;
+      this.k120 = that.k120;
+      this.k121 = that.k121;
+      this.k122 = that.k122;
+      this.k123 = that.k123;
+      this.k124 = that.k124;
+      this.k125 = that.k125;
+      this.k126 = that.k126;
+      this.k127 = that.k127;
+      this.k128 = that.k128;
+      this.k129 = that.k129;
+      this.k130 = that.k130;
+      this.k131 = that.k131;
+    }
+
+    public Object clone()
+    {
+      return new Key(this);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/Square.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,425 @@
+/* Square.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * Square is a 128-bit key, 128-bit block cipher algorithm developed by Joan
+ * Daemen, Lars Knudsen and Vincent Rijmen.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.esat.kuleuven.ac.be/~rijmen/square/">The block
+ * cipher Square</a>.<br>
+ * <a href="mailto:daemen.j@protonworld.com">Joan Daemen</a>, <a
+ * href="mailto:lars.knudsen@esat.kuleuven.ac.be">Lars Knudsen</a> and <a
+ * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li>
+ * </ol>
+ */
+public final class Square
+    extends BaseCipher
+{
+  private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes
+  private static final int DEFAULT_KEY_SIZE = 16; // in bytes
+  private static final int ROUNDS = 8;
+  private static final int ROOT = 0x1F5; // for generating GF(2**8)
+  private static final int[] OFFSET = new int[ROUNDS];
+  private static final String Sdata =
+      "\uB1CE\uC395\u5AAD\uE702\u4D44\uFB91\u0C87\uA150"
+    + "\uCB67\u54DD\u468F\uE14E\uF0FD\uFCEB\uF9C4\u1A6E"
+    + "\u5EF5\uCC8D\u1C56\u43FE\u0761\uF875\u59FF\u0322"
+    + "\u8AD1\u13EE\u8800\u0E34\u1580\u94E3\uEDB5\u5323"
+    + "\u4B47\u17A7\u9035\uABD8\uB8DF\u4F57\u9A92\uDB1B"
+    + "\u3CC8\u9904\u8EE0\uD77D\u85BB\u402C\u3A45\uF142"
+    + "\u6520\u4118\u7225\u9370\u3605\uF20B\uA379\uEC08"
+    + "\u2731\u32B6\u7CB0\u0A73\u5B7B\uB781\uD20D\u6A26"
+    + "\u9E58\u9C83\u74B3\uAC30\u7A69\u770F\uAE21\uDED0"
+    + "\u2E97\u10A4\u98A8\uD468\u2D62\u296D\u1649\u76C7"
+    + "\uE8C1\u9637\uE5CA\uF4E9\u6312\uC2A6\u14BC\uD328"
+    + "\uAF2F\uE624\u52C6\uA009\uBD8C\uCF5D\u115F\u01C5"
+    + "\u9F3D\uA29B\uC93B\uBE51\u191F\u3F5C\uB2EF\u4ACD"
+    + "\uBFBA\u6F64\uD9F3\u3EB4\uAADC\uD506\uC07E\uF666"
+    + "\u6C84\u7138\uB91D\u7F9D\u488B\u2ADA\uA533\u8239"
+    + "\uD678\u86FA\uE42B\uA91E\u8960\u6BEA\u554C\uF7E2";
+  /** Substitution boxes for encryption and decryption. */
+  private static final byte[] Se = new byte[256];
+  private static final byte[] Sd = new byte[256];
+  /** Transposition boxes for encryption and decryption. */
+  private static final int[] Te = new int[256];
+  private static final int[] Td = new int[256];
+  /**
+   * KAT vector (from ecb_vk): I=87 KEY=00000000000000000000020000000000
+   * CT=A9DF031B4E25E89F527EFFF89CB0BEBA
+   */
+  private static final byte[] KAT_KEY =
+      Util.toBytesFromString("00000000000000000000020000000000");
+  private static final byte[] KAT_CT =
+      Util.toBytesFromString("A9DF031B4E25E89F527EFFF89CB0BEBA");
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+  static
+    {
+      int i, j;
+      // re-construct Se box values
+      int limit = Sdata.length();
+      char c1;
+      for (i = 0, j = 0; i < limit; i++)
+        {
+          c1 = Sdata.charAt(i);
+          Se[j++] = (byte)(c1 >>> 8);
+          Se[j++] = (byte) c1;
+        }
+      // compute Sd box values
+      for (i = 0; i < 256; i++)
+        Sd[Se[i] & 0xFF] = (byte) i;
+      // generate OFFSET values
+      OFFSET[0] = 1;
+      for (i = 1; i < ROUNDS; i++)
+        {
+          OFFSET[i] = mul(OFFSET[i - 1], 2);
+          OFFSET[i - 1] <<= 24;
+        }
+      OFFSET[ROUNDS - 1] <<= 24;
+      // generate Te and Td boxes if we're not reading their values
+      // Notes:
+      // (1) The function mul() computes the product of two elements of GF(2**8)
+      // with ROOT as reduction polynomial.
+      // (2) the values used in computing the Te and Td are the GF(2**8)
+      // coefficients of the diffusion polynomial c(x) and its inverse
+      // (modulo x**4 + 1) d(x), defined in sections 2.1 and 4 of the Square
+      // paper.
+      for (i = 0; i < 256; i++)
+        {
+          j = Se[i] & 0xFF;
+          Te[i] = (Se[i & 3] == 0) ? 0
+                                   : mul(j, 2) << 24
+                                   | j << 16
+                                   | j << 8
+                                   | mul(j, 3);
+          j = Sd[i] & 0xFF;
+          Td[i] = (Sd[i & 3] == 0) ? 0
+                                   : mul(j, 14) << 24
+                                   | mul(j,  9) << 16
+                                   | mul(j, 13) << 8
+                                   | mul(j, 11);
+        }
+    }
+
+  /** Trivial 0-arguments constructor. */
+  public Square()
+  {
+    super(Registry.SQUARE_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
+  }
+
+  private static void square(byte[] in, int i, byte[] out, int j, int[][] K,
+                             int[] T, byte[] S)
+  {
+    int a = ((in[i++])        << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ K[0][0];
+    int b = ((in[i++])        << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ K[0][1];
+    int c = ((in[i++])        << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i++] & 0xFF)      ) ^ K[0][2];
+    int d = ((in[i++])        << 24
+           | (in[i++] & 0xFF) << 16
+           | (in[i++] & 0xFF) <<  8
+           | (in[i  ] & 0xFF)      ) ^ K[0][3];
+    int r, aa, bb, cc, dd;
+    for (r = 1; r < ROUNDS; r++)
+      { // R - 1 full rounds
+        aa =        T[(a >>> 24)       ]
+           ^ rot32R(T[(b >>> 24)       ], 8)
+           ^ rot32R(T[(c >>> 24)       ], 16)
+           ^ rot32R(T[(d >>> 24)       ], 24) ^ K[r][0];
+        bb =        T[(a >>> 16) & 0xFF]
+           ^ rot32R(T[(b >>> 16) & 0xFF], 8)
+           ^ rot32R(T[(c >>> 16) & 0xFF], 16)
+           ^ rot32R(T[(d >>> 16) & 0xFF], 24) ^ K[r][1];
+        cc =        T[(a >>>  8) & 0xFF]
+           ^ rot32R(T[(b >>>  8) & 0xFF], 8)
+           ^ rot32R(T[(c >>>  8) & 0xFF], 16)
+           ^ rot32R(T[(d >>>  8) & 0xFF], 24) ^ K[r][2];
+        dd =        T[ a         & 0xFF]
+           ^ rot32R(T[ b         & 0xFF], 8)
+           ^ rot32R(T[ c         & 0xFF], 16)
+           ^ rot32R(T[ d         & 0xFF], 24) ^ K[r][3];
+        a = aa;
+        b = bb;
+        c = cc;
+        d = dd;
+      }
+    // last round (diffusion becomes only transposition)
+    aa = ((S[(a >>> 24)       ]       ) << 24
+        | (S[(b >>> 24)       ] & 0xFF) << 16
+        | (S[(c >>> 24)       ] & 0xFF) <<  8
+        | (S[(d >>> 24)       ] & 0xFF)      ) ^ K[r][0];
+    bb = ((S[(a >>> 16) & 0xFF]       ) << 24
+        | (S[(b >>> 16) & 0xFF] & 0xFF) << 16
+        | (S[(c >>> 16) & 0xFF] & 0xFF) <<  8
+        | (S[(d >>> 16) & 0xFF] & 0xFF)      ) ^ K[r][1];
+    cc = ((S[(a >>>  8) & 0xFF]       ) << 24
+        | (S[(b >>>  8) & 0xFF] & 0xFF) << 16
+        | (S[(c >>>  8) & 0xFF] & 0xFF) <<  8
+        | (S[(d >>>  8) & 0xFF] & 0xFF)      ) ^ K[r][2];
+    dd = ((S[ a         & 0xFF]       ) << 24
+        | (S[ b         & 0xFF] & 0xFF) << 16
+        | (S[ c         & 0xFF] & 0xFF) <<  8
+        | (S[ d         & 0xFF] & 0xFF)      ) ^ K[r][3];
+    out[j++] = (byte)(aa >>> 24);
+    out[j++] = (byte)(aa >>> 16);
+    out[j++] = (byte)(aa >>> 8);
+    out[j++] = (byte) aa;
+    out[j++] = (byte)(bb >>> 24);
+    out[j++] = (byte)(bb >>> 16);
+    out[j++] = (byte)(bb >>> 8);
+    out[j++] = (byte) bb;
+    out[j++] = (byte)(cc >>> 24);
+    out[j++] = (byte)(cc >>> 16);
+    out[j++] = (byte)(cc >>> 8);
+    out[j++] = (byte) cc;
+    out[j++] = (byte)(dd >>> 24);
+    out[j++] = (byte)(dd >>> 16);
+    out[j++] = (byte)(dd >>> 8);
+    out[j  ] = (byte) dd;
+  }
+
+  /**
+   * Applies the Theta function to an input <i>in</i> in order to produce in
+   * <i>out</i> an internal session sub-key.
+   * <p>
+   * Both <i>in</i> and <i>out</i> are arrays of four ints.
+   * <p>
+   * Pseudo-code is:
+   * <pre>
+   * for (i = 0; i &lt; 4; i++)
+   *   {
+   *     out[i] = 0;
+   *     for (j = 0, n = 24; j &lt; 4; j++, n -= 8)
+   *       {
+   *         k = mul(in[i] &gt;&gt;&gt; 24, G[0][j]) &circ; mul(in[i] &gt;&gt;&gt; 16, G[1][j])
+   *             &circ; mul(in[i] &gt;&gt;&gt; 8, G[2][j]) &circ; mul(in[i], G[3][j]);
+   *         out[i] &circ;= k &lt;&lt; n;
+   *       }
+   *   }
+   * </pre>
+   */
+  private static void transform(int[] in, int[] out)
+  {
+    int l3, l2, l1, l0, m;
+    for (int i = 0; i < 4; i++)
+      {
+        l3 = in[i];
+        l2 = l3 >>> 8;
+        l1 = l3 >>> 16;
+        l0 = l3 >>> 24;
+        m = ((mul(l0, 2) ^ mul(l1, 3) ^ l2 ^ l3) & 0xFF) << 24;
+        m ^= ((l0 ^ mul(l1, 2) ^ mul(l2, 3) ^ l3) & 0xFF) << 16;
+        m ^= ((l0 ^ l1 ^ mul(l2, 2) ^ mul(l3, 3)) & 0xFF) << 8;
+        m ^= ((mul(l0, 3) ^ l1 ^ l2 ^ mul(l3, 2)) & 0xFF);
+        out[i] = m;
+      }
+  }
+
+  /**
+   * Left rotate a 32-bit chunk.
+   * 
+   * @param x the 32-bit data to rotate
+   * @param s number of places to left-rotate by
+   * @return the newly permutated value.
+   */
+  private static int rot32L(int x, int s)
+  {
+    return x << s | x >>> (32 - s);
+  }
+
+  /**
+   * Right rotate a 32-bit chunk.
+   * 
+   * @param x the 32-bit data to rotate
+   * @param s number of places to right-rotate by
+   * @return the newly permutated value.
+   */
+  private static int rot32R(int x, int s)
+  {
+    return x >>> s | x << (32 - s);
+  }
+
+  /**
+   * Returns the product of two binary numbers a and b, using the generator ROOT
+   * as the modulus: p = (a * b) mod ROOT. ROOT Generates a suitable Galois
+   * Field in GF(2**8).
+   * <p>
+   * For best performance call it with abs(b) &lt; abs(a).
+   * 
+   * @param a operand for multiply.
+   * @param b operand for multiply.
+   * @return the result of (a * b) % ROOT.
+   */
+  private static final int mul(int a, int b)
+  {
+    if (a == 0)
+      return 0;
+    a &= 0xFF;
+    b &= 0xFF;
+    int result = 0;
+    while (b != 0)
+      {
+        if ((b & 0x01) != 0)
+          result ^= a;
+        b >>>= 1;
+        a <<= 1;
+        if (a > 0xFF)
+          a ^= ROOT;
+      }
+    return result & 0xFF;
+  }
+
+  public Object clone()
+  {
+    Square result = new Square();
+    result.currentBlockSize = this.currentBlockSize;
+
+    return result;
+  }
+
+  public Iterator blockSizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
+
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(DEFAULT_KEY_SIZE));
+
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Object makeKey(byte[] uk, int bs) throws InvalidKeyException
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    if (uk == null)
+      throw new InvalidKeyException("Empty key");
+    if (uk.length != DEFAULT_KEY_SIZE)
+      throw new InvalidKeyException("Key is not 128-bit.");
+    int[][] Ke = new int[ROUNDS + 1][4];
+    int[][] Kd = new int[ROUNDS + 1][4];
+    int[][] tK = new int[ROUNDS + 1][4];
+    int i = 0;
+    Ke[0][0] = (uk[i++] & 0xFF) << 24
+             | (uk[i++] & 0xFF) << 16
+             | (uk[i++] & 0xFF) << 8
+             | (uk[i++] & 0xFF);
+    tK[0][0] = Ke[0][0];
+    Ke[0][1] = (uk[i++] & 0xFF) << 24
+             | (uk[i++] & 0xFF) << 16
+             | (uk[i++] & 0xFF) << 8
+             | (uk[i++] & 0xFF);
+    tK[0][1] = Ke[0][1];
+    Ke[0][2] = (uk[i++] & 0xFF) << 24
+             | (uk[i++] & 0xFF) << 16
+             | (uk[i++] & 0xFF) << 8
+             | (uk[i++] & 0xFF);
+    tK[0][2] = Ke[0][2];
+    Ke[0][3] = (uk[i++] & 0xFF) << 24
+             | (uk[i++] & 0xFF) << 16
+             | (uk[i++] & 0xFF) << 8
+             | (uk[i  ] & 0xFF);
+    tK[0][3] = Ke[0][3];
+    int j;
+    for (i = 1, j = 0; i < ROUNDS + 1; i++, j++)
+      {
+        tK[i][0] = tK[j][0] ^ rot32L(tK[j][3], 8) ^ OFFSET[j];
+        tK[i][1] = tK[j][1] ^ tK[i][0];
+        tK[i][2] = tK[j][2] ^ tK[i][1];
+        tK[i][3] = tK[j][3] ^ tK[i][2];
+        System.arraycopy(tK[i], 0, Ke[i], 0, 4);
+        transform(Ke[j], Ke[j]);
+      }
+    for (i = 0; i < ROUNDS; i++)
+      System.arraycopy(tK[ROUNDS - i], 0, Kd[i], 0, 4);
+    transform(tK[0], Kd[ROUNDS]);
+    return new Object[] { Ke, Kd };
+  }
+
+  public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    int[][] K = (int[][])((Object[]) k)[0];
+    square(in, i, out, j, K, Te, Se);
+  }
+
+  public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    int[][] K = (int[][])((Object[]) k)[1];
+    square(in, i, out, j, K, Td, Sd);
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        boolean result = super.selfTest(); // do symmetry tests
+        if (result)
+          result = testKat(KAT_KEY, KAT_CT);
+        valid = Boolean.valueOf(result);
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/TripleDES.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,257 @@
+/* TripleDES.java -- 
+   Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Registry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.security.InvalidKeyException;
+
+/**
+ * Triple-DES, 3DES, or DESede is a <i>combined cipher</i> that uses three
+ * iterations of the Data Encryption Standard cipher to theoretically improve
+ * the security of plain DES, at the cost of speed.
+ * <p>
+ * Triple-DES runs the DES algorithm three times with one, two or three
+ * independent 56-bit (DES) keys. When used with one DES key, the cipher behaves
+ * exactly like a (slower) DES.
+ * <p>
+ * To encrypt:
+ * <blockquote><i>C<sub>i</sub> = E<sub>k3</sub> ( E<sub>k2</sub><sup>-1</sup> (
+ * E<sub>k1</sub> ( P<sub>i</sub> )))</i>
+ * </blockquote>
+ * <p>
+ * And to decrypt:
+ * <blockquote><i>P<sub>i</sub> = E<sub>k1</sub><sup>-1</sup> (
+ * E<sub>k2</sub> ( E<sub>k3</sub><sup>-1</sup> ( C<sub>i</sub> )))</i>
+ * </blockquote>
+ * <p>
+ * (The "ede" comes from the encryption operation, which runs
+ * Encrypt-Decrypt-Encrypt)
+ * <p>
+ * References:
+ * <ol>
+ * <li>Bruce Schneier, <i>Applied Cryptography: Protocols, Algorithms, and
+ * Source Code in C, Second Edition</i>. (1996 John Wiley and Sons) ISBN
+ * 0-471-11709-9. Page 294--295.</li>
+ * </ol>
+ */
+public class TripleDES
+    extends BaseCipher
+{
+  /** Triple-DES only operates on 64 bit blocks. */
+  public static final int BLOCK_SIZE = 8;
+  /** By default, Triple-DES uses 168 bits of a parity-adjusted 192 bit key. */
+  public static final int KEY_SIZE = 24;
+  /** The underlying DES instance. */
+  private DES des;
+
+  /**
+   * Default 0-arguments constructor.
+   */
+  public TripleDES()
+  {
+    super(Registry.TRIPLEDES_CIPHER, BLOCK_SIZE, KEY_SIZE);
+    des = new DES();
+  }
+
+  /**
+   * Convenience method which calls the method with same name and three
+   * arguments, passing <code>3</code> as the value of the first parameter.
+   * 
+   * @param kb The key bytes to adjust.
+   * @param offset The starting offset into the key bytes.
+   */
+  public static void adjustParity(byte[] kb, int offset)
+  {
+    adjustParity(3, kb, offset);
+  }
+
+  /**
+   * Adjusts, in-situ, the parity of the designated bytes, so they can be used
+   * as DES keys for a 3-DES 1-, 2- or 3-key cipher.
+   * 
+   * @param keyCount the number of independent DES keys. Can be either
+   *          <code>1</code>, <code>2</code> or <code>3</code>. Any other value
+   *          will cause an {@link IllegalArgumentException} to be raised.
+   * @param kb the array containing the key bytes to adjust. MUST have at least
+   *          <code>8 * keyCount</code> bytes starting at offset position
+   *          <code>offset</code>, otherwise an
+   *          {@link ArrayIndexOutOfBoundsException} will be raised.
+   * @param offset the starting offset into the array.
+   * @see DES#adjustParity(byte[],int)
+   */
+  public static void adjustParity(int keyCount, byte[] kb, int offset)
+  {
+    if (keyCount < 1 || keyCount > 3)
+      throw new IllegalArgumentException("Invalid keyCount value: " + keyCount);
+    DES.adjustParity(kb, offset);
+    if (keyCount > 1)
+      DES.adjustParity(kb, offset + 8);
+    if (keyCount > 2)
+      DES.adjustParity(kb, offset + 16);
+  }
+
+  /**
+   * Convenience method which calls the method with same name and three
+   * arguments, passing <code>3</code> as the value of the first parameter.
+   * 
+   * @param kb The key bytes to test.
+   * @param offset The starting offset into the key bytes.
+   * @return <code>true</code> if the bytes in <i>kb</i> starting at
+   *         <i>offset</i> are parity adjusted.
+   * @see DES#isParityAdjusted(byte[],int)
+   * @see #adjustParity(byte[],int)
+   */
+  public static boolean isParityAdjusted(byte[] kb, int offset)
+  {
+    return isParityAdjusted(3, kb, offset);
+  }
+
+  /**
+   * Tests if enough bytes, expected to be used as DES keys for a 3-DES 1-, 2-
+   * or 3-key cipher, located in a designated byte array, has already been
+   * parity adjusted.
+   * 
+   * @param keyCount the number of independent DES keys. Can be either
+   *          <code>1</code>, <code>2</code> or <code>3</code>. Any other value
+   *          will cause an {@link IllegalArgumentException} to be raised.
+   * @param kb the array containing the key bytes to test. MUST have at least
+   *          <code>8 * keyCount</code> bytes starting at offset position
+   *          <code>offset</code>, otherwise an
+   *          {@link ArrayIndexOutOfBoundsException} will be raised.
+   * @param offset the starting offset into the array.
+   * @return <code>true</code> if the bytes in <i>kb</i> starting at
+   *         <i>offset</i> are parity adjusted.
+   * @see DES#isParityAdjusted(byte[],int)
+   * @see #adjustParity(int,byte[],int)
+   */
+  public static boolean isParityAdjusted(int keyCount, byte[] kb, int offset)
+  {
+    if (keyCount < 1 || keyCount > 3)
+      throw new IllegalArgumentException("Invalid keyCount value: " + keyCount);
+    boolean result = DES.isParityAdjusted(kb, offset);
+    if (keyCount > 1)
+      result = result && DES.isParityAdjusted(kb, offset + 8);
+    if (keyCount > 2)
+      result = result && DES.isParityAdjusted(kb, offset + 16);
+    return result;
+  }
+
+  public Object clone()
+  {
+    return new TripleDES();
+  }
+
+  public Iterator blockSizes()
+  {
+    return Collections.singleton(Integer.valueOf(BLOCK_SIZE)).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(8));
+    al.add(Integer.valueOf(16));
+    al.add(Integer.valueOf(24));
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Object makeKey(byte[] kb, int bs) throws InvalidKeyException
+  {
+    if (kb.length != 8 && kb.length != 16 && kb.length != 24)
+      throw new InvalidKeyException("TripleDES key must be 8, 16 or 24 bytes: "
+                                    + kb.length);
+    Context ctx = new Context();
+    byte[] k1 = new byte[DES.KEY_SIZE];
+    System.arraycopy(kb, 0, k1, 0, DES.KEY_SIZE);
+    if (! DES.isParityAdjusted(k1, 0))
+      DES.adjustParity(k1, 0);
+    ctx.k1 = (DES.Context) des.makeKey(k1, bs);
+
+    if (kb.length == 8)
+      {
+        ctx.k2 = (DES.Context) des.makeKey(k1, bs);
+        ctx.k3 = (DES.Context) des.makeKey(k1, bs);
+      }
+    else
+      {
+        byte[] k2 = new byte[DES.KEY_SIZE];
+        System.arraycopy(kb, DES.KEY_SIZE, k2, 0, DES.KEY_SIZE);
+        if (! DES.isParityAdjusted(k2, 0))
+          DES.adjustParity(k2, 0);
+        ctx.k2 = (DES.Context) des.makeKey(k2, bs);
+
+        byte[] k3 = new byte[DES.KEY_SIZE];
+        if (kb.length == 16)
+          ctx.k3 = (DES.Context) des.makeKey(k1, bs);
+        else
+          {
+            System.arraycopy(kb, 2 * DES.KEY_SIZE, k3, 0, DES.KEY_SIZE);
+            if (! DES.isParityAdjusted(k3, 0))
+              DES.adjustParity(k3, 0);
+            ctx.k3 = (DES.Context) des.makeKey(k3, bs);
+          }
+      }
+    return ctx;
+  }
+
+  public void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs)
+  {
+    byte[] temp = new byte[BLOCK_SIZE];
+    des.encrypt(in, i, temp, 0, ((Context) K).k1, bs);
+    des.decrypt(temp, 0, temp, 0, ((Context) K).k2, bs);
+    des.encrypt(temp, 0, out, o, ((Context) K).k3, bs);
+  }
+
+  public void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs)
+  {
+    byte[] temp = new byte[BLOCK_SIZE];
+    des.decrypt(in, i, temp, 0, ((Context) K).k3, bs);
+    des.encrypt(temp, 0, temp, 0, ((Context) K).k2, bs);
+    des.decrypt(temp, 0, out, o, ((Context) K).k1, bs);
+  }
+
+  private final class Context
+  {
+    DES.Context k1, k2, k3;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/Twofish.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,737 @@
+/* Twofish.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+/**
+ * Twofish is a balanced 128-bit Feistel cipher, consisting of 16 rounds. In
+ * each round, a 64-bit S-box value is computed from 64 bits of the block, and
+ * this value is xored into the other half of the block. The two half-blocks are
+ * then exchanged, and the next round begins. Before the first round, all input
+ * bits are xored with key-dependent "whitening" subkeys, and after the final
+ * round the output bits are xored with other key-dependent whitening subkeys;
+ * these subkeys are not used anywhere else in the algorithm.
+ * <p>
+ * Twofish is designed by Bruce Schneier, Doug Whiting, John Kelsey, Chris
+ * Hall, David Wagner and Niels Ferguson.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://www.counterpane.com/twofish-paper.html">Twofish: A
+ *    128-bit Block Cipher</a>.</li>
+ * </ol>
+ */
+public final class Twofish
+    extends BaseCipher
+{
+  private static final Logger log = Logger.getLogger(Twofish.class.getName());
+  private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes
+  private static final int DEFAULT_KEY_SIZE = 16; // in bytes
+  private static final int MAX_ROUNDS = 16; // max # rounds (for allocating subkeys)
+  private static final int ROUNDS = MAX_ROUNDS;
+  // subkey array indices
+  private static final int INPUT_WHITEN = 0;
+  private static final int OUTPUT_WHITEN = INPUT_WHITEN + DEFAULT_BLOCK_SIZE / 4;
+  private static final int ROUND_SUBKEYS = OUTPUT_WHITEN + DEFAULT_BLOCK_SIZE / 4;
+  private static final int SK_STEP = 0x02020202;
+  private static final int SK_BUMP = 0x01010101;
+  private static final int SK_ROTL = 9;
+  private static final String[] Pm = new String[] {
+      // p0
+      "\uA967\uB3E8\u04FD\uA376\u9A92\u8078\uE4DD\uD138"
+    + "\u0DC6\u3598\u18F7\uEC6C\u4375\u3726\uFA13\u9448"
+    + "\uF2D0\u8B30\u8454\uDF23\u195B\u3D59\uF3AE\uA282"
+    + "\u6301\u832E\uD951\u9B7C\uA6EB\uA5BE\u160C\uE361"
+    + "\uC08C\u3AF5\u732C\u250B\uBB4E\u896B\u536A\uB4F1"
+    + "\uE1E6\uBD45\uE2F4\uB666\uCC95\u0356\uD41C\u1ED7"
+    + "\uFBC3\u8EB5\uE9CF\uBFBA\uEA77\u39AF\u33C9\u6271"
+    + "\u8179\u09AD\u24CD\uF9D8\uE5C5\uB94D\u4408\u86E7"
+    + "\uA11D\uAAED\u0670\uB2D2\u417B\uA011\u31C2\u2790"
+    + "\u20F6\u60FF\u965C\uB1AB\u9E9C\u521B\u5F93\u0AEF"
+    + "\u9185\u49EE\u2D4F\u8F3B\u4787\u6D46\uD63E\u6964"
+    + "\u2ACE\uCB2F\uFC97\u057A\uAC7F\uD51A\u4B0E\uA75A"
+    + "\u2814\u3F29\u883C\u4C02\uB8DA\uB017\u551F\u8A7D"
+    + "\u57C7\u8D74\uB7C4\u9F72\u7E15\u2212\u5807\u9934"
+    + "\u6E50\uDE68\u65BC\uDBF8\uC8A8\u2B40\uDCFE\u32A4"
+    + "\uCA10\u21F0\uD35D\u0F00\u6F9D\u3642\u4A5E\uC1E0",
+      // p1
+      "\u75F3\uC6F4\uDB7B\uFBC8\u4AD3\uE66B\u457D\uE84B"
+    + "\uD632\uD8FD\u3771\uF1E1\u300F\uF81B\u87FA\u063F"
+    + "\u5EBA\uAE5B\u8A00\uBC9D\u6DC1\uB10E\u805D\uD2D5"
+    + "\uA084\u0714\uB590\u2CA3\uB273\u4C54\u9274\u3651"
+    + "\u38B0\uBD5A\uFC60\u6296\u6C42\uF710\u7C28\u278C"
+    + "\u1395\u9CC7\u2446\u3B70\uCAE3\u85CB\u11D0\u93B8"
+    + "\uA683\u20FF\u9F77\uC3CC\u036F\u08BF\u40E7\u2BE2"
+    + "\u790C\uAA82\u413A\uEAB9\uE49A\uA497\u7EDA\u7A17"
+    + "\u6694\uA11D\u3DF0\uDEB3\u0B72\uA71C\uEFD1\u533E"
+    + "\u8F33\u265F\uEC76\u2A49\u8188\uEE21\uC41A\uEBD9"
+    + "\uC539\u99CD\uAD31\u8B01\u1823\uDD1F\u4E2D\uF948"
+    + "\u4FF2\u658E\u785C\u5819\u8DE5\u9857\u677F\u0564"
+    + "\uAF63\uB6FE\uF5B7\u3CA5\uCEE9\u6844\uE04D\u4369"
+    + "\u292E\uAC15\u59A8\u0A9E\u6E47\uDF34\u356A\uCFDC"
+    + "\u22C9\uC09B\u89D4\uEDAB\u12A2\u0D52\uBB02\u2FA9"
+    + "\uD761\u1EB4\u5004\uF6C2\u1625\u8656\u5509\uBE91" };
+  /** Fixed 8x8 permutation S-boxes */
+  private static final byte[][] P = new byte[2][256]; // blank final
+  /**
+   * Define the fixed p0/p1 permutations used in keyed S-box lookup. By
+   * changing the following constant definitions, the S-boxes will
+   * automatically get changed in the Twofish engine.
+   */
+  private static final int P_00 = 1;
+  private static final int P_01 = 0;
+  private static final int P_02 = 0;
+  private static final int P_03 = P_01 ^ 1;
+  private static final int P_04 = 1;
+  private static final int P_10 = 0;
+  private static final int P_11 = 0;
+  private static final int P_12 = 1;
+  private static final int P_13 = P_11 ^ 1;
+  private static final int P_14 = 0;
+  private static final int P_20 = 1;
+  private static final int P_21 = 1;
+  private static final int P_22 = 0;
+  private static final int P_23 = P_21 ^ 1;
+  private static final int P_24 = 0;
+  private static final int P_30 = 0;
+  private static final int P_31 = 1;
+  private static final int P_32 = 1;
+  private static final int P_33 = P_31 ^ 1;
+  private static final int P_34 = 1;
+  /** Primitive polynomial for GF(256) */
+  private static final int GF256_FDBK_2 = 0x169 / 2;
+  private static final int GF256_FDBK_4 = 0x169 / 4;
+  /** MDS matrix */
+  private static final int[][] MDS = new int[4][256]; // blank final
+  private static final int RS_GF_FDBK = 0x14D; // field generator
+  /**
+   * KAT vector (from ecb_vk):
+   * I=183
+   * KEY=0000000000000000000000000000000000000000000002000000000000000000
+   * CT=F51410475B33FBD3DB2117B5C17C82D4
+   */
+  private static final byte[] KAT_KEY = Util.toBytesFromString(
+      "0000000000000000000000000000000000000000000002000000000000000000");
+  private static final byte[] KAT_CT =
+      Util.toBytesFromString("F51410475B33FBD3DB2117B5C17C82D4");
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+  static
+    {
+      long time = System.currentTimeMillis();
+      // expand the P arrays
+      int i;
+      char c;
+      for (i = 0; i < 256; i++)
+        {
+          c = Pm[0].charAt(i >>> 1);
+          P[0][i] = (byte)((i & 1) == 0 ? c >>> 8 : c);
+          c = Pm[1].charAt(i >>> 1);
+          P[1][i] = (byte)((i & 1) == 0 ? c >>> 8 : c);
+        }
+      // precompute the MDS matrix
+      int[] m1 = new int[2];
+      int[] mX = new int[2];
+      int[] mY = new int[2];
+      int j;
+      for (i = 0; i < 256; i++)
+        {
+          j = P[0][i] & 0xFF; // compute all the matrix elements
+          m1[0] = j;
+          mX[0] = Mx_X(j) & 0xFF;
+          mY[0] = Mx_Y(j) & 0xFF;
+          j = P[1][i] & 0xFF;
+          m1[1] = j;
+          mX[1] = Mx_X(j) & 0xFF;
+          mY[1] = Mx_Y(j) & 0xFF;
+          MDS[0][i] = m1[P_00] << 0
+                    | mX[P_00] << 8
+                    | mY[P_00] << 16
+                    | mY[P_00] << 24;
+          MDS[1][i] = mY[P_10] << 0
+                    | mY[P_10] << 8
+                    | mX[P_10] << 16
+                    | m1[P_10] << 24;
+          MDS[2][i] = mX[P_20] << 0
+                    | mY[P_20] << 8
+                    | m1[P_20] << 16
+                    | mY[P_20] << 24;
+          MDS[3][i] = mX[P_30] << 0
+                    | m1[P_30] << 8
+                    | mY[P_30] << 16
+                    | mX[P_30] << 24;
+        }
+      time = System.currentTimeMillis() - time;
+      if (Configuration.DEBUG)
+        {
+          log.fine("Static Data");
+          log.fine("MDS[0][]:");
+          StringBuilder sb;
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(MDS[0][i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("MDS[1][]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(MDS[1][i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("MDS[2][]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(MDS[2][i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("MDS[3][]:");
+          for (i = 0; i < 64; i++)
+            {
+              sb = new StringBuilder();
+              for (j = 0; j < 4; j++)
+                sb.append("0x").append(Util.toString(MDS[3][i * 4 + j])).append(", ");
+              log.fine(sb.toString());
+            }
+          log.fine("Total initialization time: " + time + " ms.");
+        }
+    }
+
+  private static final int LFSR1(int x)
+  {
+    return (x >> 1) ^ ((x & 0x01) != 0 ? GF256_FDBK_2 : 0);
+  }
+
+  private static final int LFSR2(int x)
+  {
+    return (x >> 2)
+        ^ ((x & 0x02) != 0 ? GF256_FDBK_2 : 0)
+        ^ ((x & 0x01) != 0 ? GF256_FDBK_4 : 0);
+  }
+
+  private static final int Mx_X(int x)
+  { // 5B
+    return x ^ LFSR2(x);
+  }
+
+  private static final int Mx_Y(int x)
+  { // EF
+    return x ^ LFSR1(x) ^ LFSR2(x);
+  }
+
+  /** Trivial 0-arguments constructor. */
+  public Twofish()
+  {
+    super(Registry.TWOFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
+  }
+
+  private static final int b0(int x)
+  {
+    return x & 0xFF;
+  }
+
+  private static final int b1(int x)
+  {
+    return (x >>> 8) & 0xFF;
+  }
+
+  private static final int b2(int x)
+  {
+    return (x >>> 16) & 0xFF;
+  }
+
+  private static final int b3(int x)
+  {
+    return (x >>> 24) & 0xFF;
+  }
+
+  /**
+   * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box 32-bit
+   * entity from two key material 32-bit entities.
+   *
+   * @param k0 1st 32-bit entity.
+   * @param k1 2nd 32-bit entity.
+   * @return remainder polynomial generated using RS code
+   */
+  private static final int RS_MDS_Encode(int k0, int k1)
+  {
+    int r = k1;
+    int i;
+    for (i = 0; i < 4; i++) // shift 1 byte at a time
+      r = RS_rem(r);
+    r ^= k0;
+    for (i = 0; i < 4; i++)
+      r = RS_rem(r);
+    return r;
+  }
+
+  /**
+   * Reed-Solomon code parameters: (12, 8) reversible code:<p>
+   * <pre>
+   *   g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1
+   * </pre>
+   * where a = primitive root of field generator 0x14D
+   */
+  private static final int RS_rem(int x)
+  {
+    int b = (x >>> 24) & 0xFF;
+    int g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xFF;
+    int g3 = (b >>> 1) ^ ((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0) ^ g2;
+    int result = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b;
+    return result;
+  }
+
+  private static final int F32(int k64Cnt, int x, int[] k32)
+  {
+    int b0 = b0(x);
+    int b1 = b1(x);
+    int b2 = b2(x);
+    int b3 = b3(x);
+    int k0 = k32[0];
+    int k1 = k32[1];
+    int k2 = k32[2];
+    int k3 = k32[3];
+    int result = 0;
+    switch (k64Cnt & 3)
+      {
+      case 1:
+        result = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)]
+               ^ MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)]
+               ^ MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)]
+               ^ MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)];
+        break;
+      case 0: // same as 4
+        b0 = (P[P_04][b0] & 0xFF) ^ b0(k3);
+        b1 = (P[P_14][b1] & 0xFF) ^ b1(k3);
+        b2 = (P[P_24][b2] & 0xFF) ^ b2(k3);
+        b3 = (P[P_34][b3] & 0xFF) ^ b3(k3);
+      case 3:
+        b0 = (P[P_03][b0] & 0xFF) ^ b0(k2);
+        b1 = (P[P_13][b1] & 0xFF) ^ b1(k2);
+        b2 = (P[P_23][b2] & 0xFF) ^ b2(k2);
+        b3 = (P[P_33][b3] & 0xFF) ^ b3(k2);
+      case 2: // 128-bit keys (optimize for this case)
+        result = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) ^ b0(k0)]
+               ^ MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) ^ b1(k0)]
+               ^ MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) ^ b2(k0)]
+               ^ MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) ^ b3(k0)];
+        break;
+      }
+    return result;
+  }
+
+  private static final int Fe32(int[] sBox, int x, int R)
+  {
+    return sBox[        2 * _b(x, R    )    ]
+         ^ sBox[        2 * _b(x, R + 1) + 1]
+         ^ sBox[0x200 + 2 * _b(x, R + 2)    ]
+         ^ sBox[0x200 + 2 * _b(x, R + 3) + 1];
+  }
+
+  private static final int _b(int x, int N)
+  {
+    switch (N % 4)
+      {
+      case 0:
+        return x & 0xFF;
+      case 1:
+        return (x >>> 8) & 0xFF;
+      case 2:
+        return (x >>> 16) & 0xFF;
+      default:
+        return x >>> 24;
+      }
+  }
+
+  public Object clone()
+  {
+    Twofish result = new Twofish();
+    result.currentBlockSize = this.currentBlockSize;
+    return result;
+  }
+
+  public Iterator blockSizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE));
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  public Iterator keySizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(8)); //   64-bit
+    al.add(Integer.valueOf(16)); // 128-bit
+    al.add(Integer.valueOf(24)); // 192-bit
+    al.add(Integer.valueOf(32)); // 256-bit
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  /**
+   * Expands a user-supplied key material into a session key for a designated
+   * <i>block size</i>.
+   *
+   * @param k the 64/128/192/256-bit user-key to use.
+   * @param bs the desired block size in bytes.
+   * @return an Object encapsulating the session key.
+   * @exception IllegalArgumentException if the block size is not 16 (128-bit).
+   * @exception InvalidKeyException if the key data is invalid.
+   */
+  public Object makeKey(byte[] k, int bs) throws InvalidKeyException
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    if (k == null)
+      throw new InvalidKeyException("Empty key");
+    int length = k.length;
+    if (! (length == 8 || length == 16 || length == 24 || length == 32))
+      throw new InvalidKeyException("Incorrect key length");
+    int k64Cnt = length / 8;
+    int subkeyCnt = ROUND_SUBKEYS + 2 * ROUNDS;
+    int[] k32e = new int[4]; // even 32-bit entities
+    int[] k32o = new int[4]; // odd 32-bit entities
+    int[] sBoxKey = new int[4];
+    // split user key material into even and odd 32-bit entities and
+    // compute S-box keys using (12, 8) Reed-Solomon code over GF(256)
+    int i, j, offset = 0;
+    for (i = 0, j = k64Cnt - 1; i < 4 && offset < length; i++, j--)
+      {
+        k32e[i] = (k[offset++] & 0xFF)
+                | (k[offset++] & 0xFF) << 8
+                | (k[offset++] & 0xFF) << 16
+                | (k[offset++] & 0xFF) << 24;
+        k32o[i] = (k[offset++] & 0xFF)
+                | (k[offset++] & 0xFF) << 8
+                | (k[offset++] & 0xFF) << 16
+                | (k[offset++] & 0xFF) << 24;
+        sBoxKey[j] = RS_MDS_Encode(k32e[i], k32o[i]); // reverse order
+      }
+    // compute the round decryption subkeys for PHT. these same subkeys
+    // will be used in encryption but will be applied in reverse order.
+    int q, A, B;
+    int[] subKeys = new int[subkeyCnt];
+    for (i = q = 0; i < subkeyCnt / 2; i++, q += SK_STEP)
+      {
+        A = F32(k64Cnt, q, k32e); // A uses even key entities
+        B = F32(k64Cnt, q + SK_BUMP, k32o); // B uses odd  key entities
+        B = B << 8 | B >>> 24;
+        A += B;
+        subKeys[2 * i] = A; // combine with a PHT
+        A += B;
+        subKeys[2 * i + 1] = A << SK_ROTL | A >>> (32 - SK_ROTL);
+      }
+    // fully expand the table for speed
+    int k0 = sBoxKey[0];
+    int k1 = sBoxKey[1];
+    int k2 = sBoxKey[2];
+    int k3 = sBoxKey[3];
+    int b0, b1, b2, b3;
+    int[] sBox = new int[4 * 256];
+    for (i = 0; i < 256; i++)
+      {
+        b0 = b1 = b2 = b3 = i;
+        switch (k64Cnt & 3)
+          {
+          case 1:
+            sBox[        2 * i    ] = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)];
+            sBox[        2 * i + 1] = MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)];
+            sBox[0x200 + 2 * i    ] = MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)];
+            sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)];
+            break;
+          case 0: // same as 4
+            b0 = (P[P_04][b0] & 0xFF) ^ b0(k3);
+            b1 = (P[P_14][b1] & 0xFF) ^ b1(k3);
+            b2 = (P[P_24][b2] & 0xFF) ^ b2(k3);
+            b3 = (P[P_34][b3] & 0xFF) ^ b3(k3);
+          case 3:
+            b0 = (P[P_03][b0] & 0xFF) ^ b0(k2);
+            b1 = (P[P_13][b1] & 0xFF) ^ b1(k2);
+            b2 = (P[P_23][b2] & 0xFF) ^ b2(k2);
+            b3 = (P[P_33][b3] & 0xFF) ^ b3(k2);
+          case 2: // 128-bit keys
+            sBox[        2 * i    ] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF)
+                                                      ^ b0(k1)] & 0xFF) ^ b0(k0)];
+            sBox[        2 * i + 1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF)
+                                                      ^ b1(k1)] & 0xFF) ^ b1(k0)];
+            sBox[0x200 + 2 * i    ] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF)
+                                                      ^ b2(k1)] & 0xFF) ^ b2(k0)];
+            sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF)
+                                                      ^ b3(k1)] & 0xFF) ^ b3(k0)];
+          }
+      }
+    if (Configuration.DEBUG)
+      {
+        StringBuilder sb;
+        log.fine("S-box[]:");
+        for (i = 0; i < 64; i++)
+          {
+            sb = new StringBuilder();
+            for (j = 0; j < 4; j++)
+              sb.append("0x").append(Util.toString(sBox[i * 4 + j])).append(", ");
+            log.fine(sb.toString());
+          }
+        log.fine("");
+        for (i = 0; i < 64; i++)
+          {
+            sb = new StringBuilder();
+            for (j = 0; j < 4; j++)
+              sb.append("0x").append(Util.toString(sBox[256 + i * 4 + j])).append(", ");
+            log.fine(sb.toString());
+          }
+        log.fine("");
+        for (i = 0; i < 64; i++)
+          {
+            sb = new StringBuilder();
+            for (j = 0; j < 4; j++)
+              sb.append("0x").append(Util.toString(sBox[512 + i * 4 + j])).append(", ");
+            log.fine(sb.toString());
+          }
+        log.fine("");
+        for (i = 0; i < 64; i++)
+          {
+            sb = new StringBuilder();
+            for (j = 0; j < 4; j++)
+              sb.append("0x").append(Util.toString(sBox[768 + i * 4 + j])).append(", ");
+            log.fine(sb.toString());
+          }
+        log.fine("User (odd, even) keys  --> S-Box keys:");
+        for (i = 0; i < k64Cnt; i++)
+          log.fine("0x" + Util.toString(k32o[i])
+                   + "  0x" + Util.toString(k32e[i])
+                   + " --> 0x" + Util.toString(sBoxKey[k64Cnt - 1 - i]));
+        log.fine("Round keys:");
+        for (i = 0; i < ROUND_SUBKEYS + 2 * ROUNDS; i += 2)
+          log.fine("0x" + Util.toString(subKeys[i])
+                   + "  0x" + Util.toString(subKeys[i + 1]));
+      }
+    return new Object[] { sBox, subKeys };
+  }
+
+  public void encrypt(byte[] in, int inOffset, byte[] out, int outOffset,
+                      Object sessionKey, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    Object[] sk = (Object[]) sessionKey; // extract S-box and session key
+    int[] sBox = (int[]) sk[0];
+    int[] sKey = (int[]) sk[1];
+    if (Configuration.DEBUG)
+      log.fine("PT=" + Util.toString(in, inOffset, bs));
+    int x0 = (in[inOffset++] & 0xFF)
+           | (in[inOffset++] & 0xFF) << 8
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) << 24;
+    int x1 = (in[inOffset++] & 0xFF)
+           | (in[inOffset++] & 0xFF) << 8
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) << 24;
+    int x2 = (in[inOffset++] & 0xFF)
+           | (in[inOffset++] & 0xFF) << 8
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) << 24;
+    int x3 = (in[inOffset++] & 0xFF)
+           | (in[inOffset++] & 0xFF) << 8
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) << 24;
+    x0 ^= sKey[INPUT_WHITEN];
+    x1 ^= sKey[INPUT_WHITEN + 1];
+    x2 ^= sKey[INPUT_WHITEN + 2];
+    x3 ^= sKey[INPUT_WHITEN + 3];
+    if (Configuration.DEBUG)
+      log.fine("PTw=" + Util.toString(x0) + Util.toString(x1)
+               + Util.toString(x2) + Util.toString(x3));
+    int t0, t1;
+    int k = ROUND_SUBKEYS;
+    for (int R = 0; R < ROUNDS; R += 2)
+      {
+        t0 = Fe32(sBox, x0, 0);
+        t1 = Fe32(sBox, x1, 3);
+        x2 ^= t0 + t1 + sKey[k++];
+        x2 = x2 >>> 1 | x2 << 31;
+        x3 = x3 << 1 | x3 >>> 31;
+        x3 ^= t0 + 2 * t1 + sKey[k++];
+        if (Configuration.DEBUG)
+          log.fine("CT" + (R) + "=" + Util.toString(x0) + Util.toString(x1)
+                   + Util.toString(x2) + Util.toString(x3));
+        t0 = Fe32(sBox, x2, 0);
+        t1 = Fe32(sBox, x3, 3);
+        x0 ^= t0 + t1 + sKey[k++];
+        x0 = x0 >>> 1 | x0 << 31;
+        x1 = x1 << 1 | x1 >>> 31;
+        x1 ^= t0 + 2 * t1 + sKey[k++];
+        if (Configuration.DEBUG)
+          log.fine("CT" + (R + 1) + "=" + Util.toString(x0) + Util.toString(x1)
+                   + Util.toString(x2) + Util.toString(x3));
+      }
+    x2 ^= sKey[OUTPUT_WHITEN];
+    x3 ^= sKey[OUTPUT_WHITEN + 1];
+    x0 ^= sKey[OUTPUT_WHITEN + 2];
+    x1 ^= sKey[OUTPUT_WHITEN + 3];
+    if (Configuration.DEBUG)
+      log.fine("CTw=" + Util.toString(x0) + Util.toString(x1)
+               + Util.toString(x2) + Util.toString(x3));
+    out[outOffset++] = (byte) x2;
+    out[outOffset++] = (byte)(x2 >>> 8);
+    out[outOffset++] = (byte)(x2 >>> 16);
+    out[outOffset++] = (byte)(x2 >>> 24);
+    out[outOffset++] = (byte) x3;
+    out[outOffset++] = (byte)(x3 >>> 8);
+    out[outOffset++] = (byte)(x3 >>> 16);
+    out[outOffset++] = (byte)(x3 >>> 24);
+    out[outOffset++] = (byte) x0;
+    out[outOffset++] = (byte)(x0 >>> 8);
+    out[outOffset++] = (byte)(x0 >>> 16);
+    out[outOffset++] = (byte)(x0 >>> 24);
+    out[outOffset++] = (byte) x1;
+    out[outOffset++] = (byte)(x1 >>> 8);
+    out[outOffset++] = (byte)(x1 >>> 16);
+    out[outOffset  ] = (byte)(x1 >>> 24);
+    if (Configuration.DEBUG)
+      log.fine("CT=" + Util.toString(out, outOffset - 15, 16) + "\n");
+  }
+
+  public void decrypt(byte[] in, int inOffset, byte[] out, int outOffset,
+                      Object sessionKey, int bs)
+  {
+    if (bs != DEFAULT_BLOCK_SIZE)
+      throw new IllegalArgumentException();
+    Object[] sk = (Object[]) sessionKey; // extract S-box and session key
+    int[] sBox = (int[]) sk[0];
+    int[] sKey = (int[]) sk[1];
+    if (Configuration.DEBUG)
+      log.fine("CT=" + Util.toString(in, inOffset, bs));
+    int x2 = (in[inOffset++] & 0xFF)
+           | (in[inOffset++] & 0xFF) << 8
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) << 24;
+    int x3 = (in[inOffset++] & 0xFF)
+           | (in[inOffset++] & 0xFF) << 8
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) << 24;
+    int x0 = (in[inOffset++] & 0xFF)
+           | (in[inOffset++] & 0xFF) << 8
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) << 24;
+    int x1 = (in[inOffset++] & 0xFF)
+           | (in[inOffset++] & 0xFF) << 8
+           | (in[inOffset++] & 0xFF) << 16
+           | (in[inOffset++] & 0xFF) << 24;
+    x2 ^= sKey[OUTPUT_WHITEN];
+    x3 ^= sKey[OUTPUT_WHITEN + 1];
+    x0 ^= sKey[OUTPUT_WHITEN + 2];
+    x1 ^= sKey[OUTPUT_WHITEN + 3];
+    if (Configuration.DEBUG)
+      log.fine("CTw=" + Util.toString(x2) + Util.toString(x3)
+               + Util.toString(x0) + Util.toString(x1));
+    int k = ROUND_SUBKEYS + 2 * ROUNDS - 1;
+    int t0, t1;
+    for (int R = 0; R < ROUNDS; R += 2)
+      {
+        t0 = Fe32(sBox, x2, 0);
+        t1 = Fe32(sBox, x3, 3);
+        x1 ^= t0 + 2 * t1 + sKey[k--];
+        x1 = x1 >>> 1 | x1 << 31;
+        x0 = x0 << 1 | x0 >>> 31;
+        x0 ^= t0 + t1 + sKey[k--];
+        if (Configuration.DEBUG)
+          log.fine("PT" + (ROUNDS - R) + "=" + Util.toString(x2)
+                   + Util.toString(x3) + Util.toString(x0) + Util.toString(x1));
+        t0 = Fe32(sBox, x0, 0);
+        t1 = Fe32(sBox, x1, 3);
+        x3 ^= t0 + 2 * t1 + sKey[k--];
+        x3 = x3 >>> 1 | x3 << 31;
+        x2 = x2 << 1 | x2 >>> 31;
+        x2 ^= t0 + t1 + sKey[k--];
+        if (Configuration.DEBUG)
+          log.fine("PT" + (ROUNDS - R - 1) + "=" + Util.toString(x2)
+                   + Util.toString(x3) + Util.toString(x0) + Util.toString(x1));
+      }
+    x0 ^= sKey[INPUT_WHITEN];
+    x1 ^= sKey[INPUT_WHITEN + 1];
+    x2 ^= sKey[INPUT_WHITEN + 2];
+    x3 ^= sKey[INPUT_WHITEN + 3];
+    if (Configuration.DEBUG)
+      log.fine("PTw=" + Util.toString(x2) + Util.toString(x3)
+               + Util.toString(x0) + Util.toString(x1));
+    out[outOffset++] = (byte) x0;
+    out[outOffset++] = (byte)(x0 >>> 8);
+    out[outOffset++] = (byte)(x0 >>> 16);
+    out[outOffset++] = (byte)(x0 >>> 24);
+    out[outOffset++] = (byte) x1;
+    out[outOffset++] = (byte)(x1 >>> 8);
+    out[outOffset++] = (byte)(x1 >>> 16);
+    out[outOffset++] = (byte)(x1 >>> 24);
+    out[outOffset++] = (byte) x2;
+    out[outOffset++] = (byte)(x2 >>> 8);
+    out[outOffset++] = (byte)(x2 >>> 16);
+    out[outOffset++] = (byte)(x2 >>> 24);
+    out[outOffset++] = (byte) x3;
+    out[outOffset++] = (byte)(x3 >>> 8);
+    out[outOffset++] = (byte)(x3 >>> 16);
+    out[outOffset  ] = (byte)(x3 >>> 24);
+    if (Configuration.DEBUG)
+      log.fine("PT=" + Util.toString(out, outOffset - 15, 16) + "\n");
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        boolean result = super.selfTest(); // do symmetry tests
+        if (result)
+          result = testKat(KAT_KEY, KAT_CT);
+        valid = Boolean.valueOf(result);
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/cipher/WeakKeyException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,59 @@
+/* WeakKeyException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.cipher;
+
+import java.security.InvalidKeyException;
+
+/**
+ * Checked exception thrown to indicate that a weak key has been generated and
+ * or specified instead of a valid non-weak value.
+ */
+public class WeakKeyException
+    extends InvalidKeyException
+{
+  public WeakKeyException()
+  {
+    super();
+  }
+
+  public WeakKeyException(String msg)
+  {
+    super(msg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/DiffieHellmanImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,172 @@
+/* DiffieHellmanImpl.java -- implementation of the Diffie-Hellman key agreement.
+   Copyright (C) 2005, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * The JCE implementation of a 2-party Diffie-Hellman key agreement.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public final class DiffieHellmanImpl
+    extends KeyAgreementSpi
+{
+  /** The private key being used for this agreement. */
+  private DHPrivateKey key;
+
+  /** The current result. */
+  private byte[] result;
+
+  /** True if the caller told us we are done. */
+  private boolean last_phase_done;
+
+  /** Trivial default constructor. */
+  public DiffieHellmanImpl()
+  {
+    super();
+
+    key = null;
+    result = null;
+    last_phase_done = false;
+  }
+
+  protected Key engineDoPhase(Key incoming, boolean lastPhase)
+      throws InvalidKeyException
+  {
+    if (key == null)
+      throw new IllegalStateException("Not initialized");
+
+    if (last_phase_done)
+      throw new IllegalStateException("Last phase already done");
+
+    if (! (incoming instanceof DHPublicKey))
+      throw new InvalidKeyException("Key MUST be a DHPublicKey");
+
+    DHPublicKey pub = (DHPublicKey) incoming;
+    DHParameterSpec s1 = key.getParams();
+    DHParameterSpec s2 = pub.getParams();
+    if (! s1.getG().equals(s2.getG()) || ! s1.getP().equals(s2.getP())
+        || s1.getL() != s2.getL())
+      throw new InvalidKeyException("Incompatible key");
+    if (! lastPhase)
+      throw new IllegalArgumentException(
+          "This key-agreement MUST be concluded in one step only");
+    BigInteger resultBI = pub.getY().modPow(key.getX(), s1.getP());
+    result = resultBI.toByteArray();
+    if (result[0] == 0x00)
+      {
+        byte[] buf = new byte[result.length - 1];
+        System.arraycopy(result, 1, buf, 0, buf.length);
+        result = buf;
+      }
+    last_phase_done = true;
+    return null;
+  }
+
+  protected byte[] engineGenerateSecret()
+  {
+    checkState();
+    byte[] res = (byte[]) result.clone();
+    reset();
+    return res;
+  }
+
+  protected int engineGenerateSecret(byte[] secret, int offset)
+      throws ShortBufferException
+  {
+    checkState();
+    if (result.length > secret.length - offset)
+      throw new ShortBufferException();
+    System.arraycopy(result, 0, secret, offset, result.length);
+    int res = result.length;
+    reset();
+    return res;
+  }
+
+  protected SecretKey engineGenerateSecret(String algorithm)
+      throws InvalidKeyException
+  {
+    checkState();
+    byte[] s = (byte[]) result.clone();
+    SecretKey res = new SecretKeySpec(s, algorithm);
+    reset();
+    return res;
+  }
+
+  protected void engineInit(Key key, SecureRandom random)
+      throws InvalidKeyException
+  {
+    if (! (key instanceof DHPrivateKey))
+      throw new InvalidKeyException("Key MUST be a DHPrivateKey");
+    this.key = (DHPrivateKey) key;
+    reset();
+  }
+
+  protected void engineInit(Key key, AlgorithmParameterSpec params,
+                            SecureRandom random)
+      throws InvalidKeyException
+  {
+    engineInit(key, random);
+  }
+
+  private void reset()
+  {
+    result = null;
+    last_phase_done = false;
+  }
+
+  private void checkState()
+  {
+    if (result == null || ! last_phase_done)
+      throw new IllegalStateException("Not finished");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/GnuCrypto.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,598 @@
+/* GnuCrypto.java -- 
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.mac.MacFactory;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * The additional GNU algorithm implementation as a Java Cryptographic Extension
+ * (JCE) Provider.
+ * 
+ * @see java.security.Provider
+ */
+public final class GnuCrypto
+    extends Provider
+{
+  public GnuCrypto()
+  {
+    super(Registry.GNU_CRYPTO, 2.1, "GNU Crypto JCE Provider");
+
+    AccessController.doPrivileged(new PrivilegedAction()
+    {
+      public Object run()
+      {
+        // Cipher
+        put("Cipher.ANUBIS",
+            gnu.javax.crypto.jce.cipher.AnubisSpi.class.getName());
+        put("Cipher.ANUBIS ImplementedIn", "Software");
+        put("Cipher.ARCFOUR",
+            gnu.javax.crypto.jce.cipher.ARCFourSpi.class.getName());
+        put("Cipher.ARCFOUR ImplementedIn", "Software");
+        put("Cipher.BLOWFISH",
+            gnu.javax.crypto.jce.cipher.BlowfishSpi.class.getName());
+        put("Cipher.BLOWFISH ImplementedIn", "Software");
+        put("Cipher.DES", gnu.javax.crypto.jce.cipher.DESSpi.class.getName());
+        put("Cipher.DES ImplementedIn", "Software");
+        put("Cipher.KHAZAD",
+            gnu.javax.crypto.jce.cipher.KhazadSpi.class.getName());
+        put("Cipher.KHAZAD ImplementedIn", "Software");
+        put("Cipher.NULL",
+            gnu.javax.crypto.jce.cipher.NullCipherSpi.class.getName());
+        put("Cipher.NULL ImplementedIn", "Software");
+        put("Cipher.AES",
+            gnu.javax.crypto.jce.cipher.RijndaelSpi.class.getName());
+        put("Cipher.AES ImplementedIn", "Software");
+        put("Cipher.RIJNDAEL",
+            gnu.javax.crypto.jce.cipher.RijndaelSpi.class.getName());
+        put("Cipher.RIJNDAEL ImplementedIn", "Software");
+        put("Cipher.SERPENT",
+            gnu.javax.crypto.jce.cipher.SerpentSpi.class.getName());
+        put("Cipher.SERPENT ImplementedIn", "Software");
+        put("Cipher.SQUARE",
+            gnu.javax.crypto.jce.cipher.SquareSpi.class.getName());
+        put("Cipher.SQUARE ImplementedIn", "Software");
+        put("Cipher.TRIPLEDES",
+            gnu.javax.crypto.jce.cipher.TripleDESSpi.class.getName());
+        put("Cipher.TRIPLEDES ImplementedIn", "Software");
+        put("Cipher.TWOFISH",
+            gnu.javax.crypto.jce.cipher.TwofishSpi.class.getName());
+        put("Cipher.TWOFISH ImplementedIn", "Software");
+        put("Cipher.CAST5",
+            gnu.javax.crypto.jce.cipher.Cast5Spi.class.getName());
+        put("Cipher.CAST5 ImplementedIn", "Software");
+
+        // PBES2 ciphers.
+        put("Cipher.PBEWithHMacHavalAndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.AES.class.getName());
+        put("Cipher.PBEWithHMacHavalAndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Anubis.class.getName());
+        put("Cipher.PBEWithHMacHavalAndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacHavalAndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Cast5.class.getName());
+        put("Cipher.PBEWithHMacHavalAndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.DES.class.getName());
+        put("Cipher.PBEWithHMacHavalAndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Khazad.class.getName());
+        put("Cipher.PBEWithHMacHavalAndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Serpent.class.getName());
+        put("Cipher.PBEWithHMacHavalAndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Square.class.getName());
+        put("Cipher.PBEWithHMacHavalAndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacHavalAndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Twofish.class.getName());
+
+        put("Cipher.PBEWithHMacMD2AndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.AES.class.getName());
+        put("Cipher.PBEWithHMacMD2AndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Anubis.class.getName());
+        put("Cipher.PBEWithHMacMD2AndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacMD2AndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Cast5.class.getName());
+        put("Cipher.PBEWithHMacMD2AndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.DES.class.getName());
+        put("Cipher.PBEWithHMacMD2AndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Khazad.class.getName());
+        put("Cipher.PBEWithHMacMD2AndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Serpent.class.getName());
+        put("Cipher.PBEWithHMacMD2AndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Square.class.getName());
+        put("Cipher.PBEWithHMacMD2AndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacMD2AndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Twofish.class.getName());
+
+        put("Cipher.PBEWithHMacMD4AndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.AES.class.getName());
+        put("Cipher.PBEWithHMacMD4AndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Anubis.class.getName());
+        put("Cipher.PBEWithHMacMD4AndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacMD4AndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Cast5.class.getName());
+        put("Cipher.PBEWithHMacMD4AndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.DES.class.getName());
+        put("Cipher.PBEWithHMacMD4AndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Khazad.class.getName());
+        put("Cipher.PBEWithHMacMD4AndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Serpent.class.getName());
+        put("Cipher.PBEWithHMacMD4AndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Square.class.getName());
+        put("Cipher.PBEWithHMacMD4AndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacMD4AndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Twofish.class.getName());
+
+        put("Cipher.PBEWithHMacMD5AndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.AES.class.getName());
+        put("Cipher.PBEWithHMacMD5AndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Anubis.class.getName());
+        put("Cipher.PBEWithHMacMD5AndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacMD5AndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Cast5.class.getName());
+        put("Cipher.PBEWithHMacMD5AndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.DES.class.getName());
+        put("Cipher.PBEWithHMacMD5AndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Khazad.class.getName());
+        put("Cipher.PBEWithHMacMD5AndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Serpent.class.getName());
+        put("Cipher.PBEWithHMacMD5AndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Square.class.getName());
+        put("Cipher.PBEWithHMacMD5AndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacMD5AndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Twofish.class.getName());
+
+        put("Cipher.PBEWithHMacSHA1AndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.AES.class.getName());
+        put("Cipher.PBEWithHMacSHA1AndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Anubis.class.getName());
+        put("Cipher.PBEWithHMacSHA1AndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacSHA1AndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Cast5.class.getName());
+        put("Cipher.PBEWithHMacSHA1AndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.DES.class.getName());
+        put("Cipher.PBEWithHMacSHA1AndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Khazad.class.getName());
+        put("Cipher.PBEWithHMacSHA1AndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Serpent.class.getName());
+        put("Cipher.PBEWithHMacSHA1AndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Square.class.getName());
+        put(
+            "Cipher.PBEWithHMacSHA1AndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacSHA1AndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Twofish.class.getName());
+
+        put("Cipher.PBEWithHMacSHA256AndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.AES.class.getName());
+        put("Cipher.PBEWithHMacSHA256AndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Anubis.class.getName());
+        put("Cipher.PBEWithHMacSHA256AndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacSHA256AndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Cast5.class.getName());
+        put("Cipher.PBEWithHMacSHA256AndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.DES.class.getName());
+        put("Cipher.PBEWithHMacSHA256AndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Khazad.class.getName());
+        put("Cipher.PBEWithHMacSHA256AndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Serpent.class.getName());
+        put("Cipher.PBEWithHMacSHA256AndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Square.class.getName());
+        put("Cipher.PBEWithHMacSHA256AndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacSHA256AndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Twofish.class.getName());
+
+        put("Cipher.PBEWithHMacSHA384AndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.AES.class.getName());
+        put("Cipher.PBEWithHMacSHA384AndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Anubis.class.getName());
+        put("Cipher.PBEWithHMacSHA384AndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacSHA384AndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Cast5.class.getName());
+        put("Cipher.PBEWithHMacSHA384AndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.DES.class.getName());
+        put("Cipher.PBEWithHMacSHA384AndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Khazad.class.getName());
+        put("Cipher.PBEWithHMacSHA384AndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Serpent.class.getName());
+        put("Cipher.PBEWithHMacSHA384AndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Square.class.getName());
+        put("Cipher.PBEWithHMacSHA384AndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacSHA384AndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Twofish.class.getName());
+
+        put("Cipher.PBEWithHMacSHA512AndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.AES.class.getName());
+        put("Cipher.PBEWithHMacSHA512AndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Anubis.class.getName());
+        put("Cipher.PBEWithHMacSHA512AndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacSHA512AndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Cast5.class.getName());
+        put("Cipher.PBEWithHMacSHA512AndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.DES.class.getName());
+        put("Cipher.PBEWithHMacSHA512AndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Khazad.class.getName());
+        put("Cipher.PBEWithHMacSHA512AndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Serpent.class.getName());
+        put("Cipher.PBEWithHMacSHA512AndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Square.class.getName());
+        put("Cipher.PBEWithHMacSHA512AndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacSHA512AndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Twofish.class.getName());
+
+        put("Cipher.PBEWithHMacTigerAndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.AES.class.getName());
+        put("Cipher.PBEWithHMacTigerAndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Anubis.class.getName());
+        put("Cipher.PBEWithHMacTigerAndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacTigerAndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Cast5.class.getName());
+        put("Cipher.PBEWithHMacTigerAndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.DES.class.getName());
+        put("Cipher.PBEWithHMacTigerAndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Khazad.class.getName());
+        put("Cipher.PBEWithHMacTigerAndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Serpent.class.getName());
+        put("Cipher.PBEWithHMacTigerAndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Square.class.getName());
+        put("Cipher.PBEWithHMacTigerAndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacTigerAndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Twofish.class.getName());
+
+        put("Cipher.PBEWithHMacWhirlpoolAndAES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.AES.class.getName());
+        put("Cipher.PBEWithHMacWhirlpoolAndAnubis",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Anubis.class.getName());
+        put("Cipher.PBEWithHMacWhirlpoolAndBlowfish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Blowfish.class.getName());
+        put("Cipher.PBEWithHMacWhirlpoolAndCast5",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Cast5.class.getName());
+        put("Cipher.PBEWithHMacWhirlpoolAndDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.DES.class.getName());
+        put("Cipher.PBEWithHMacWhirlpoolAndKhazad",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Khazad.class.getName());
+        put("Cipher.PBEWithHMacWhirlpoolAndSerpent",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Serpent.class.getName());
+        put("Cipher.PBEWithHMacWhirlpoolAndSquare",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Square.class.getName());
+        put("Cipher.PBEWithHMacWhirlpoolAndTripleDES",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.TripleDES.class.getName());
+        put("Cipher.PBEWithHMacWhirlpoolAndTwofish",
+            gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Twofish.class.getName());
+
+        // Key Wrapping Algorithm cipher
+        put("Cipher." + Registry.AES128_KWA,
+            gnu.javax.crypto.jce.cipher.AES128KeyWrapSpi.class.getName());
+        put("Cipher." + Registry.AES192_KWA,
+            gnu.javax.crypto.jce.cipher.AES192KeyWrapSpi.class.getName());
+        put("Cipher." + Registry.AES256_KWA,
+            gnu.javax.crypto.jce.cipher.AES256KeyWrapSpi.class.getName());
+        put("Cipher." + Registry.TRIPLEDES_KWA,
+            gnu.javax.crypto.jce.cipher.TripleDESKeyWrapSpi.class.getName());
+
+        // SecretKeyFactory interface to PBKDF2.
+        put("SecretKeyFactory.PBKDF2WithHMacHaval",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacHaval.class.getName());
+        put("SecretKeyFactory.PBKDF2WithHMacMD2",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD2.class.getName());
+        put("SecretKeyFactory.PBKDF2WithHMacMD4",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD4.class.getName());
+        put("SecretKeyFactory.PBKDF2WithHMacMD5",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD5.class.getName());
+        put("SecretKeyFactory.PBKDF2WithHMacSHA1",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA1.class.getName());
+        put("SecretKeyFactory.PBKDF2WithHMacSHA256",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA256.class.getName());
+        put("SecretKeyFactory.PBKDF2WithHMacSHA384",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA384.class.getName());
+        put("SecretKeyFactory.PBKDF2WithHMacSHA512",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA512.class.getName());
+        put("SecretKeyFactory.PBKDF2WithHMacTiger",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacTiger.class.getName());
+        put("SecretKeyFactory.PBKDF2WithHMacWhirlpool",
+            gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacWhirlpool.class.getName());
+
+        // Simple SecretKeyFactory implementations.
+        put("SecretKeyFactory.Anubis",
+            gnu.javax.crypto.jce.key.AnubisSecretKeyFactoryImpl.class.getName());
+        put("SecretKeyFactory.Blowfish",
+            gnu.javax.crypto.jce.key.BlowfishSecretKeyFactoryImpl.class.getName());
+        put("SecretKeyFactory.Cast5",
+            gnu.javax.crypto.jce.key.Cast5SecretKeyFactoryImpl.class.getName());
+        put("SecretKeyFactory.DES",
+            gnu.javax.crypto.jce.key.DESSecretKeyFactoryImpl.class.getName());
+        put("SecretKeyFactory.Khazad",
+            gnu.javax.crypto.jce.key.KhazadSecretKeyFactoryImpl.class.getName());
+        put("SecretKeyFactory.Rijndael",
+            gnu.javax.crypto.jce.key.RijndaelSecretKeyFactoryImpl.class.getName());
+        put("SecretKeyFactory.Serpent",
+            gnu.javax.crypto.jce.key.SerpentSecretKeyFactoryImpl.class.getName());
+        put("SecretKeyFactory.Square",
+            gnu.javax.crypto.jce.key.SquareSecretKeyFactoryImpl.class.getName());
+        put("SecretKeyFactory.TripleDES",
+            gnu.javax.crypto.jce.key.DESedeSecretKeyFactoryImpl.class.getName());
+        put("Alg.Alias.SecretKeyFactory.AES", "Rijndael");
+        put("Alg.Alias.SecretKeyFactory.DESede", "TripleDES");
+        put("Alg.Alias.SecretKeyFactory.3-DES", "TripleDES");
+        put("Alg.Alias.SecretKeyFactory.3DES", "TripleDES");
+
+        put("AlgorithmParameters.BlockCipherParameters",
+            gnu.javax.crypto.jce.params.BlockCipherParameters.class.getName());
+        put("Alg.Alias.AlgorithmParameters.Anubis", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.Blowfish", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.Cast5", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.DES", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.Khazad", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.Rijndael", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.AES", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.Serpent", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.Square", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.TripleDES", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.DESede", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.3-DES", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.3DES", "BlockCipherParameters");
+
+        // KeyGenerator Adapter implementations
+        put("KeyGenerator.Anubis",
+            gnu.javax.crypto.jce.key.AnubisKeyGeneratorImpl.class.getName());
+        put("KeyGenerator.Blowfish",
+            gnu.javax.crypto.jce.key.BlowfishKeyGeneratorImpl.class.getName());
+        put("KeyGenerator.Cast5",
+            gnu.javax.crypto.jce.key.Cast5KeyGeneratorImpl.class.getName());
+        put("KeyGenerator.DES",
+            gnu.javax.crypto.jce.key.DESKeyGeneratorImpl.class.getName());
+        put("KeyGenerator.Khazad",
+            gnu.javax.crypto.jce.key.KhazadKeyGeneratorImpl.class.getName());
+        put("KeyGenerator.Rijndael",
+            gnu.javax.crypto.jce.key.RijndaelKeyGeneratorImpl.class.getName());
+        put("KeyGenerator.Serpent",
+            gnu.javax.crypto.jce.key.SerpentKeyGeneratorImpl.class.getName());
+        put("KeyGenerator.Square",
+            gnu.javax.crypto.jce.key.SquareKeyGeneratorImpl.class.getName());
+        put("KeyGenerator.TripleDES",
+            gnu.javax.crypto.jce.key.TripleDESKeyGeneratorImpl.class.getName());
+        put("Alg.Alias.KeyGenerator.AES", "Rijndael");
+        put("Alg.Alias.KeyGenerator.DESede", "TripleDES");
+        put("Alg.Alias.KeyGenerator.3-DES", "TripleDES");
+        put("Alg.Alias.KeyGenerator.3DES", "TripleDES");
+
+        // MAC
+        put("Mac.HMAC-MD2", gnu.javax.crypto.jce.mac.HMacMD2Spi.class.getName());
+        put("Mac.HMAC-MD4", gnu.javax.crypto.jce.mac.HMacMD4Spi.class.getName());
+        put("Mac.HMAC-MD5", gnu.javax.crypto.jce.mac.HMacMD5Spi.class.getName());
+        put("Mac.HMAC-RIPEMD128",
+            gnu.javax.crypto.jce.mac.HMacRipeMD128Spi.class.getName());
+        put("Mac.HMAC-RIPEMD160",
+            gnu.javax.crypto.jce.mac.HMacRipeMD160Spi.class.getName());
+        put("Mac.HMAC-SHA160",
+            gnu.javax.crypto.jce.mac.HMacSHA160Spi.class.getName());
+        put("Mac.HMAC-SHA256",
+            gnu.javax.crypto.jce.mac.HMacSHA256Spi.class.getName());
+        put("Mac.HMAC-SHA384",
+            gnu.javax.crypto.jce.mac.HMacSHA384Spi.class.getName());
+        put("Mac.HMAC-SHA512",
+            gnu.javax.crypto.jce.mac.HMacSHA512Spi.class.getName());
+        put("Mac.HMAC-TIGER",
+            gnu.javax.crypto.jce.mac.HMacTigerSpi.class.getName());
+        put("Mac.HMAC-HAVAL",
+            gnu.javax.crypto.jce.mac.HMacHavalSpi.class.getName());
+        put("Mac.HMAC-WHIRLPOOL",
+            gnu.javax.crypto.jce.mac.HMacWhirlpoolSpi.class.getName());
+        put("Mac.TMMH16", gnu.javax.crypto.jce.mac.TMMH16Spi.class.getName());
+        put("Mac.UHASH32", gnu.javax.crypto.jce.mac.UHash32Spi.class.getName());
+        put("Mac.UMAC32", gnu.javax.crypto.jce.mac.UMac32Spi.class.getName());
+
+        put("Mac.OMAC-ANUBIS",
+            gnu.javax.crypto.jce.mac.OMacAnubisImpl.class.getName());
+        put("Mac.OMAC-BLOWFISH",
+            gnu.javax.crypto.jce.mac.OMacBlowfishImpl.class.getName());
+        put("Mac.OMAC-CAST5",
+            gnu.javax.crypto.jce.mac.OMacCast5Impl.class.getName());
+        put("Mac.OMAC-DES",
+            gnu.javax.crypto.jce.mac.OMacDESImpl.class.getName());
+        put("Mac.OMAC-KHAZAD",
+            gnu.javax.crypto.jce.mac.OMacKhazadImpl.class.getName());
+        put("Mac.OMAC-RIJNDAEL",
+            gnu.javax.crypto.jce.mac.OMacRijndaelImpl.class.getName());
+        put("Mac.OMAC-SERPENT",
+            gnu.javax.crypto.jce.mac.OMacSerpentImpl.class.getName());
+        put("Mac.OMAC-SQUARE",
+            gnu.javax.crypto.jce.mac.OMacSquareImpl.class.getName());
+        put("Mac.OMAC-TRIPLEDES",
+            gnu.javax.crypto.jce.mac.OMacTripleDESImpl.class.getName());
+        put("Mac.OMAC-TWOFISH",
+            gnu.javax.crypto.jce.mac.OMacTwofishImpl.class.getName());
+
+        // Aliases
+        put("Alg.Alias.AlgorithmParameters.AES", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.BLOWFISH", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.ANUBIS", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.KHAZAD", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.NULL", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.RIJNDAEL", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.SERPENT", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.SQUARE", "BlockCipherParameters");
+        put("Alg.Alias.AlgorithmParameters.TWOFISH", "BlockCipherParameters");
+        put("Alg.Alias.Cipher.RC4", "ARCFOUR");
+        put("Alg.Alias.Cipher.3-DES", "TRIPLEDES");
+        put("Alg.Alias.Cipher.3DES", "TRIPLEDES");
+        put("Alg.Alias.Cipher.DES-EDE", "TRIPLEDES");
+        put("Alg.Alias.Cipher.DESede", "TRIPLEDES");
+        put("Alg.Alias.Cipher.CAST128", "CAST5");
+        put("Alg.Alias.Cipher.CAST-128", "CAST5");
+        put("Alg.Alias.Mac.HMAC-SHS", "HMAC-SHA160");
+        put("Alg.Alias.Mac.HMAC-SHA", "HMAC-SHA160");
+        put("Alg.Alias.Mac.HMAC-SHA1", "HMAC-SHA160");
+        put("Alg.Alias.Mac.HMAC-SHA-160", "HMAC-SHA160");
+        put("Alg.Alias.Mac.HMAC-SHA-256", "HMAC-SHA256");
+        put("Alg.Alias.Mac.HMAC-SHA-384", "HMAC-SHA384");
+        put("Alg.Alias.Mac.HMAC-SHA-512", "HMAC-SHA512");
+        put("Alg.Alias.Mac.HMAC-RIPEMD-160", "HMAC-RIPEMD160");
+        put("Alg.Alias.Mac.HMAC-RIPEMD-128", "HMAC-RIPEMD128");
+        put("Alg.Alias.Mac.OMAC-AES", "OMAC-RIJNDAEL");
+        put("Alg.Alias.Mac.OMAC-3DES", "OMAC-3DES");
+        put("Alg.Alias.Mac.HmacMD4", "HMAC-MD4");
+        put("Alg.Alias.Mac.HmacMD5", "HMAC-MD5");
+        put("Alg.Alias.Mac.HmacSHA-1", "HMAC-SHA-1");
+        put("Alg.Alias.Mac.HmacSHA1", "HMAC-SHA1");
+        put("Alg.Alias.Mac.HmacSHA-160", "HMAC-SHA-160");
+        put("Alg.Alias.Mac.HmacSHA160", "HMAC-SHA-160");
+        put("Alg.Alias.Mac.HmacSHA-256", "HMAC-SHA-256");
+        put("Alg.Alias.Mac.HmacSHA256", "HMAC-SHA-256");
+        put("Alg.Alias.Mac.HmacSHA-384", "HMAC-SHA-384");
+        put("Alg.Alias.Mac.HmacSHA384", "HMAC-SHA-384");
+        put("Alg.Alias.Mac.HmacSHA-512", "HMAC-SHA-512");
+        put("Alg.Alias.Mac.HmacSHA512", "HMAC-SHA-512");
+        put("Alg.Alias.Mac.HmacRIPEMD128", "HMAC-RIPEMD128");
+        put("Alg.Alias.Mac.HmacRIPEMD-128", "HMAC-RIPEMD128");
+        put("Alg.Alias.Mac.HmacRIPEMD160", "HMAC-RIPEMD160");
+        put("Alg.Alias.Mac.HmacRIPEMD-160", "HMAC-RIPEMD160");
+        put("Alg.Alias.Mac.HmacTiger", "HMAC-TIGER");
+        put("Alg.Alias.Mac.HmacHaval", "HMAC-HAVAL");
+        put("Alg.Alias.Mac.HmacWhirlpool", "HMAC-WHIRLPOOL");
+
+        // KeyAgreement
+        put("KeyAgreement.DH",
+            gnu.javax.crypto.jce.DiffieHellmanImpl.class.getName());
+        put("Alg.Alias.KeyAgreement.DiffieHellman", "DH");
+
+        // Cipher
+        put("Cipher.RSAES-PKCS1-v1_5",
+            gnu.javax.crypto.RSACipherImpl.class.getName());
+        put("Alg.Alias.Cipher.RSA", "RSAES-PKCS1-v1_5");
+
+        // SecureRandom
+        put("SecureRandom.ARCFOUR",
+            gnu.javax.crypto.jce.prng.ARCFourRandomSpi.class.getName());
+        put("SecureRandom.ARCFOUR ImplementedIn", "Software");
+        put("SecureRandom.CSPRNG",
+            gnu.javax.crypto.jce.prng.CSPRNGSpi.class.getName());
+        put("SecureRandom.CSPRNG ImplementedIn", "Software");
+        put("SecureRandom.ICM",
+            gnu.javax.crypto.jce.prng.ICMRandomSpi.class.getName());
+        put("SecureRandom.ICM ImplementedIn", "Software");
+        put("SecureRandom.UMAC-KDF",
+            gnu.javax.crypto.jce.prng.UMacRandomSpi.class.getName());
+        put("SecureRandom.UMAC-KDF ImplementedIn", "Software");
+        put("SecureRandom.Fortuna",
+            gnu.javax.crypto.jce.prng.FortunaImpl.class.getName());
+        put("SecureRandom.Fortuna ImplementedIn", "Software");
+
+        // KeyStore
+        put("KeyStore.GKR",
+            gnu.javax.crypto.jce.keyring.GnuKeyring.class.getName());
+        put("Alg.Alias.KeyStore.GnuKeyring", "GKR");
+
+        // KeyPairGenerator ---------------------------------------------------
+        put("KeyPairGenerator.DH",
+            gnu.javax.crypto.jce.sig.DHKeyPairGeneratorSpi.class.getName());
+        put("KeyPairGenerator.DH KeySize", "512");
+        put("KeyPairGenerator.DH ImplementedIn", "Software");
+
+        put("Alg.Alias.KeyPairGenerator.DiffieHellman", "DH");
+
+        // KeyFactory ---------------------------------------------------------
+        put("KeyFactory.DH",
+            gnu.javax.crypto.jce.sig.DHKeyFactory.class.getName());
+
+        put("Alg.Alias,KeyFactory.DiffieHellman", "DH");
+
+        // Algorithm Parameters -----------------------------------------------
+        put("AlgorithmParameters.DH",
+            gnu.javax.crypto.jce.sig.DHParameters.class.getName());
+
+        put("Alg.Alias.AlgorithmParameters.DiffieHellman", "DH");
+
+        // Algorithm Parameters Generator -------------------------------------
+        put("AlgorithmParameterGenerator.DH",
+            gnu.javax.crypto.jce.sig.DHParametersGenerator.class.getName());
+
+        put("Alg.Alias.AlgorithmParameterGenerator.DiffieHellman", "DH");
+
+        return null;
+      }
+    });
+  }
+
+  /**
+   * Returns a {@link Set} of names of symmetric key block cipher algorithms
+   * available from this {@link Provider}.
+   * 
+   * @return a {@link Set} of cipher names (Strings).
+   */
+  public static final Set getCipherNames()
+  {
+    HashSet s = new HashSet();
+    s.addAll(CipherFactory.getNames());
+    s.add(Registry.ARCFOUR_PRNG);
+    return s;
+  }
+
+  /**
+   * Returns a {@link Set} of names of MAC algorithms available from this
+   * {@link Provider}.
+   * 
+   * @return a {@link Set} of MAC names (Strings).
+   */
+  public static final Set getMacNames()
+  {
+    return MacFactory.getNames();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/GnuSasl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,124 @@
+/* GnuSasl.java -- javax.security.sasl algorithms.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.ClientFactory;
+import gnu.javax.crypto.sasl.ServerFactory;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.util.Set;
+
+public final class GnuSasl
+    extends Provider
+{
+  public GnuSasl()
+  {
+    super(Registry.GNU_SASL, 2.1, "GNU SASL Provider");
+
+    AccessController.doPrivileged(new PrivilegedAction()
+    {
+      public Object run()
+      {
+        // SASL Client and Server mechanisms
+        put("SaslClientFactory.ANONYMOUS",
+            gnu.javax.crypto.sasl.ClientFactory.class.getName());
+        put("SaslClientFactory.PLAIN",
+            gnu.javax.crypto.sasl.ClientFactory.class.getName());
+        put("SaslClientFactory.CRAM-MD5",
+            gnu.javax.crypto.sasl.ClientFactory.class.getName());
+        put("SaslClientFactory.SRP",
+            gnu.javax.crypto.sasl.ClientFactory.class.getName());
+
+        put("SaslServerFactory.ANONYMOUS",
+            gnu.javax.crypto.sasl.ServerFactory.class.getName());
+        put("SaslServerFactory.PLAIN",
+            gnu.javax.crypto.sasl.ServerFactory.class.getName());
+        put("SaslServerFactory.CRAM-MD5",
+            gnu.javax.crypto.sasl.ServerFactory.class.getName());
+        put("SaslServerFactory.SRP-MD5",
+            gnu.javax.crypto.sasl.ServerFactory.class.getName());
+        put("SaslServerFactory.SRP-SHA-160",
+            gnu.javax.crypto.sasl.ServerFactory.class.getName());
+        put("SaslServerFactory.SRP-RIPEMD128",
+            gnu.javax.crypto.sasl.ServerFactory.class.getName());
+        put("SaslServerFactory.SRP-RIPEMD160",
+            gnu.javax.crypto.sasl.ServerFactory.class.getName());
+        put("SaslServerFactory.SRP-TIGER",
+            gnu.javax.crypto.sasl.ServerFactory.class.getName());
+        put("SaslServerFactory.SRP-WHIRLPOOL",
+            gnu.javax.crypto.sasl.ServerFactory.class.getName());
+
+        put("Alg.Alias.SaslServerFactory.SRP-SHS", "SRP-SHA-160");
+        put("Alg.Alias.SaslServerFactory.SRP-SHA", "SRP-SHA-160");
+        put("Alg.Alias.SaslServerFactory.SRP-SHA1", "SRP-SHA-160");
+        put("Alg.Alias.SaslServerFactory.SRP-SHA-1", "SRP-SHA-160");
+        put("Alg.Alias.SaslServerFactory.SRP-SHA160", "SRP-SHA-160");
+        put("Alg.Alias.SaslServerFactory.SRP-RIPEMD-128", "SRP-RIPEMD128");
+        put("Alg.Alias.SaslServerFactory.SRP-RIPEMD-160", "SRP-RIPEMD160");
+
+        return null;
+      }
+    });
+  }
+
+  /**
+   * Returns a {@link Set} of names of SASL Client mechanisms available from
+   * this {@link Provider}.
+   * 
+   * @return a {@link Set} of SASL Client mechanisms (Strings).
+   */
+  public static final Set getSaslClientMechanismNames()
+  {
+    return ClientFactory.getNames();
+  }
+
+  /**
+   * Returns a {@link Set} of names of SASL Server mechanisms available from
+   * this {@link Provider}.
+   * 
+   * @return a {@link Set} of SASL Server mechanisms (Strings).
+   */
+  public static final Set getSaslServerMechanismNames()
+  {
+    return ServerFactory.getNames();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,218 @@
+/* PBKDF2SecretKeyFactory.java -- 
+   Copyright (C) 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import java.util.HashMap;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import gnu.javax.crypto.prng.IPBE;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.prng.PRNGFactory;
+
+public abstract class PBKDF2SecretKeyFactory
+    extends SecretKeyFactorySpi
+{
+  protected String macName;
+  private static final int DEFAULT_ITERATION_COUNT = 1000;
+  private static final int DEFAULT_KEY_LEN = 32;
+
+  protected PBKDF2SecretKeyFactory(String macName)
+  {
+    this.macName = macName;
+  }
+
+  protected SecretKey engineGenerateSecret(KeySpec spec)
+      throws InvalidKeySpecException
+  {
+    if (! (spec instanceof PBEKeySpec))
+      throw new InvalidKeySpecException("not a PBEKeySpec");
+    IRandom kdf = PRNGFactory.getInstance("PBKDF2-" + macName);
+    HashMap attr = new HashMap();
+    attr.put(IPBE.PASSWORD, ((PBEKeySpec) spec).getPassword());
+    byte[] salt = ((PBEKeySpec) spec).getSalt();
+    if (salt == null)
+      salt = new byte[0];
+    attr.put(IPBE.SALT, salt);
+    int ic = ((PBEKeySpec) spec).getIterationCount();
+    if (ic <= 0)
+      ic = DEFAULT_ITERATION_COUNT;
+    attr.put(IPBE.ITERATION_COUNT, Integer.valueOf(ic));
+    kdf.init(attr);
+    int len = ((PBEKeySpec) spec).getKeyLength();
+    if (len <= 0)
+      len = DEFAULT_KEY_LEN;
+    byte[] dk = new byte[len];
+    try
+      {
+        kdf.nextBytes(dk, 0, len);
+      }
+    catch (LimitReachedException lre)
+      {
+        throw new IllegalArgumentException(lre.toString());
+      }
+    return new SecretKeySpec(dk, "PBKDF2");
+  }
+
+  protected KeySpec engineGetKeySpec(SecretKey key, Class clazz)
+      throws InvalidKeySpecException
+  {
+    throw new InvalidKeySpecException("not supported");
+  }
+
+  protected SecretKey engineTranslateKey(SecretKey key)
+  {
+    return new SecretKeySpec(key.getEncoded(), key.getAlgorithm());
+  }
+
+  public static class HMacHaval
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacHaval()
+    {
+      super("HMAC-HAVAL");
+    }
+  }
+
+  public static class HMacMD2
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacMD2()
+    {
+      super("HMAC-MD2");
+    }
+  }
+
+  public static class HMacMD4
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacMD4()
+    {
+      super("HMAC-MD4");
+    }
+  }
+
+  public static class HMacMD5
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacMD5()
+    {
+      super("HMAC-MD5");
+    }
+  }
+
+  public static class HMacRipeMD128
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacRipeMD128()
+    {
+      super("HMAC-RIPEMD128");
+    }
+  }
+
+  public static class HMacRipeMD160
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacRipeMD160()
+    {
+      super("HMAC-RIPEMD160");
+    }
+  }
+
+  public static class HMacSHA1
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacSHA1()
+    {
+      super("HMAC-SHA1");
+    }
+  }
+
+  public static class HMacSHA256
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacSHA256()
+    {
+      super("HMAC-SHA256");
+    }
+  }
+
+  public static class HMacSHA384
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacSHA384()
+    {
+      super("HMAC-SHA384");
+    }
+  }
+
+  public static class HMacSHA512
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacSHA512()
+    {
+      super("HMAC-SHA512");
+    }
+  }
+
+  public static class HMacTiger
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacTiger()
+    {
+      super("HMAC-TIGER");
+    }
+  }
+
+  public static class HMacWhirlpool
+      extends PBKDF2SecretKeyFactory
+  {
+    public HMacWhirlpool()
+    {
+      super("HMAC-WHIRLPOOL");
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* AESKeyWrapSpi.java -- AES (128-bit key) Key Wrapping Algorithm JCE Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping
+ * Algorithm with a 128-bit key-size.
+ */
+public final class AES128KeyWrapSpi
+    extends AESKeyWrapSpi
+{
+  public AES128KeyWrapSpi()
+  {
+    super(Registry.AES128_KWA, 128 / 8, Registry.ECB_MODE);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* AES192KeyWrapSpi.java -- AES (192-bit key) Key Wrapping Algorithm JCE Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping
+ * Algorithm with a 192-bit key-size.
+ */
+public final class AES192KeyWrapSpi
+    extends AESKeyWrapSpi
+{
+  public AES192KeyWrapSpi()
+  {
+    super(Registry.AES192_KWA, 192 / 8, Registry.ECB_MODE);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* AES256KeyWrapSpi.java -- AES (256-bit key) Key Wrapping Algorithm JCE Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping
+ * Algorithm with a 256-bit key-size.
+ */
+public final class AES256KeyWrapSpi
+    extends AESKeyWrapSpi
+{
+  public AES256KeyWrapSpi()
+  {
+    super(Registry.AES256_KWA, 256 / 8, Registry.ECB_MODE);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,88 @@
+/* AESKeyWrapSpi.java -- Common AES Key Wrapping Algorithm methods
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+/**
+ * Base abstract class to group common AES Key Wrapping Algorithm Adapter
+ * methods.
+ */
+abstract class AESKeyWrapSpi
+    extends KeyWrappingAlgorithmAdapter
+{
+  protected AESKeyWrapSpi(String name, int keySize, String supportedMode)
+  {
+    super(name, 16, keySize, supportedMode);
+  }
+
+  /**
+   * AES Key Wrapping algorithms operate on an 8-byte block; a block half the
+   * size of the AES block itself.
+   * <p>
+   * In wrapping, the number of 8-byte output blocks is ALWAYS one block longer
+   * than the input.
+   * 
+   * @param inputLength the size of the plain text.
+   * @return the size in bytes of <code>n + 1</code> 8-byte blocks where
+   * <code>n</code> is the smallest number of 8-byte blocks that contain the
+   * designated number of input bytes.
+   */
+  protected int getOutputSizeForWrap(int inputLength)
+  {
+    int n = (inputLength + 7) / 8;
+    return 8 * (n + 1);
+  }
+
+  /**
+   * AES Key Wrapping algorithms operate on an 8-byte block; a block half the
+   * size of the AES block itself.
+   * <p>
+   * In unwrapping, the number of 8-byte output blocks is ALWAYS one block
+   * shorter than the input.
+   * 
+   * @param inputLength the size of the cipher text.
+   * @return the size in bytes of <code>n - 1</code> 8-byte blocks where
+   * <code>n</code> is the smallest number of 8-byte blocks that contain the
+   * designated number of input bytes.
+   */
+  protected int getOutputSizeForUnwrap(int inputLength)
+  {
+    int n = (inputLength + 7) / 8;
+    return 8 * (n - 1);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/AESSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,92 @@
+/* AESSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * The implementation of the AES <i>Service Provider Interface</i> (<b>SPI</b>)
+ * adapter.
+ */
+public final class AESSpi
+    extends CipherAdapter
+{
+  public AESSpi()
+  {
+    super(Registry.AES_CIPHER, 16);
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+                            SecureRandom random) throws InvalidKeyException,
+      InvalidAlgorithmParameterException
+  {
+    if (params instanceof BlockCipherParameterSpec)
+      {
+        if (((BlockCipherParameterSpec) params).getBlockSize() != 16)
+          throw new InvalidAlgorithmParameterException(
+              "AES block size must be 16 bytes");
+      }
+    super.engineInit(opmode, key, params, random);
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+                            SecureRandom random) throws InvalidKeyException,
+      InvalidAlgorithmParameterException
+  {
+    AlgorithmParameterSpec spec = null;
+    try
+      {
+        if (params != null)
+          spec = params.getParameterSpec(BlockCipherParameterSpec.class);
+      }
+    catch (InvalidParameterSpecException ipse)
+      {
+      }
+    engineInit(opmode, key, spec, random);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/ARCFourSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,183 @@
+/* ARCFourSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.prng.ARCFour;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.prng.PRNGFactory;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import java.util.HashMap;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+
+/**
+ * The <i>Service Provider Interface</i> (<b>SPI</b>) for the ARCFOUR stream
+ * cipher.
+ */
+public class ARCFourSpi
+    extends CipherSpi
+{
+  private IRandom keystream;
+
+  public ARCFourSpi()
+  {
+    super();
+    keystream = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG);
+  }
+
+  protected int engineGetBlockSize()
+  {
+    return 0; // stream cipher.
+  }
+
+  protected void engineSetMode(String s) throws NoSuchAlgorithmException
+  {
+    // ignored.
+  }
+
+  protected void engineSetPadding(String s) throws NoSuchPaddingException
+  {
+    // ignored.
+  }
+
+  protected byte[] engineGetIV()
+  {
+    return null;
+  }
+
+  protected int engineGetOutputSize(int in)
+  {
+    return in;
+  }
+
+  protected AlgorithmParameters engineGetParameters()
+  {
+    return null;
+  }
+
+  protected void engineInit(int mode, Key key, SecureRandom r)
+      throws InvalidKeyException
+  {
+    if (mode != Cipher.ENCRYPT_MODE && mode != Cipher.DECRYPT_MODE)
+      throw new IllegalArgumentException(
+          "arcfour is for encryption or decryption only");
+    if (key == null || ! key.getFormat().equalsIgnoreCase("RAW"))
+      throw new InvalidKeyException("key must be non-null raw bytes");
+    HashMap attrib = new HashMap();
+    attrib.put(ARCFour.ARCFOUR_KEY_MATERIAL, key.getEncoded());
+    keystream.init(attrib);
+  }
+
+  protected void engineInit(int mode, Key key, AlgorithmParameterSpec p,
+                            SecureRandom r) throws InvalidKeyException,
+      InvalidAlgorithmParameterException
+  {
+    engineInit(mode, key, r);
+  }
+
+  protected void engineInit(int mode, Key key, AlgorithmParameters p,
+                            SecureRandom r) throws InvalidKeyException,
+      InvalidAlgorithmParameterException
+  {
+    engineInit(mode, key, r);
+  }
+
+  protected byte[] engineUpdate(byte[] in, int offset, int length)
+  {
+    if (length < 0 || offset < 0 || length + offset > in.length)
+      throw new ArrayIndexOutOfBoundsException();
+    byte[] result = new byte[length];
+    try
+      {
+        for (int i = 0; i < length; i++)
+          result[i] = (byte)(in[i + offset] ^ keystream.nextByte());
+      }
+    catch (LimitReachedException wontHappen)
+      {
+      }
+    return result;
+  }
+
+  protected int engineUpdate(byte[] in, int inOffset, int length, byte[] out,
+                             int outOffset) throws ShortBufferException
+  {
+    if (length < 0 || inOffset < 0 || length + inOffset > in.length
+        || outOffset < 0)
+      throw new ArrayIndexOutOfBoundsException();
+    if (outOffset + length > out.length)
+      throw new ShortBufferException();
+    try
+      {
+        for (int i = 0; i < length; i++)
+          out[i + outOffset] = (byte)(in[i + inOffset] ^ keystream.nextByte());
+      }
+    catch (LimitReachedException wontHappen)
+      {
+      }
+    return length;
+  }
+
+  protected byte[] engineDoFinal(byte[] in, int offset, int length)
+      throws IllegalBlockSizeException, BadPaddingException
+  {
+    return engineUpdate(in, offset, length);
+  }
+
+  protected int engineDoFinal(byte[] in, int inOffset, int length, byte[] out,
+                              int outOffset) throws ShortBufferException,
+      IllegalBlockSizeException, BadPaddingException
+  {
+    return engineUpdate(in, inOffset, length, out, outOffset);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/AnubisSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* AnubisSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Anubis <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class AnubisSpi
+    extends CipherAdapter
+{
+  public AnubisSpi()
+  {
+    super(Registry.ANUBIS_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/BlowfishSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* BlowfishSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Blowfish <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class BlowfishSpi
+    extends CipherAdapter
+{
+  public BlowfishSpi()
+  {
+    super(Registry.BLOWFISH_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/Cast5Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* Cast5Spi.java -- 
+   Copyright (C) 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the <code>CAST5</code> (a.k.a. CAST-128) <i>Service
+ * Provider Interface</i> (<b>SPI</b>) Adapter.
+ */
+public class Cast5Spi
+    extends CipherAdapter
+{
+  public Cast5Spi()
+  {
+    super(Registry.CAST5_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/CipherAdapter.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,531 @@
+/* CipherAdapter.java -- 
+   Copyright (C) 2002, 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec;
+import gnu.javax.crypto.mode.IMode;
+import gnu.javax.crypto.mode.ModeFactory;
+import gnu.javax.crypto.pad.IPad;
+import gnu.javax.crypto.pad.PadFactory;
+import gnu.javax.crypto.pad.WrongPaddingException;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * The implementation of a generic {@link Cipher} <i>Adapter</i> class to wrap
+ * GNU cipher instances.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link Cipher} class, which provides the functionality of symmetric-key
+ * block ciphers, such as the AES.
+ * <p>
+ * This base class defines all of the abstract methods in {@link CipherSpi},
+ * but does not define the (non-abstract) key wrapping functions that extended
+ * the base cipher SPI, and these methods thus immediately throw an
+ * {@link UnsupportedOperationException}. If a cipher implementation provides
+ * this functionality, or if it in fact accepts parameters other than the key
+ * and the initialization vector, the subclass should override those methods.
+ * Otherwise a subclass need only call the {@link #CipherAdapter(String)}
+ * constructor with the name of the cipher.
+ */
+class CipherAdapter
+    extends CipherSpi
+{
+  /** Our cipher instance. */
+  protected IBlockCipher cipher;
+  /** Our mode instance. */
+  protected IMode mode;
+  /** Our padding instance. */
+  protected IPad pad;
+  /** The current key size. */
+  protected int keyLen;
+  /** Our attributes map. */
+  protected Map attributes;
+  /** An incomplete block. */
+  protected byte[] partBlock;
+  /** The number of bytes in {@link #partBlock}. */
+  protected int partLen;
+  /** The length of blocks we are processing. */
+  protected int blockLen;
+
+  /**
+   * Protected constructor to be called by subclasses. The cipher name argument
+   * should be the appropriate one listed in {@link Registry}. The basic cipher
+   * instance is created, along with an instance of the
+   * {@link gnu.javax.crypto.mode.ECB} mode and no padding.
+   * 
+   * @param cipherName The cipher to instantiate.
+   * @param blockLen The block length to use.
+   */
+  protected CipherAdapter(String cipherName, int blockLen)
+  {
+    cipher = CipherFactory.getInstance(cipherName);
+    attributes = new HashMap();
+    this.blockLen = blockLen;
+    mode = ModeFactory.getInstance("ECB", cipher, blockLen);
+    attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen));
+  }
+
+  /**
+   * Creates a new cipher adapter with the default block size.
+   * 
+   * @param cipherName The cipher to instantiate.
+   */
+  protected CipherAdapter(String cipherName)
+  {
+    cipher = CipherFactory.getInstance(cipherName);
+    blockLen = cipher.defaultBlockSize();
+    attributes = new HashMap();
+    mode = ModeFactory.getInstance("ECB", cipher, blockLen);
+    attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen));
+  }
+
+  protected void engineSetMode(String modeName) throws NoSuchAlgorithmException
+  {
+    if (modeName.length() >= 3
+        && modeName.substring(0, 3).equalsIgnoreCase("CFB"))
+      {
+        if (modeName.length() > 3)
+          {
+            try
+              {
+                int bs = Integer.parseInt(modeName.substring(3));
+                attributes.put(IMode.MODE_BLOCK_SIZE, Integer.valueOf(bs / 8));
+              }
+            catch (NumberFormatException nfe)
+              {
+                throw new NoSuchAlgorithmException(modeName);
+              }
+            modeName = "CFB";
+          }
+      }
+    else
+      attributes.remove(IMode.MODE_BLOCK_SIZE);
+    mode = ModeFactory.getInstance(modeName, cipher, blockLen);
+    if (mode == null)
+      throw new NoSuchAlgorithmException(modeName);
+  }
+
+  protected void engineSetPadding(String padName) throws NoSuchPaddingException
+  {
+    if (padName.equalsIgnoreCase("NoPadding"))
+      {
+        pad = null;
+        return;
+      }
+    pad = PadFactory.getInstance(padName);
+    if (pad == null)
+      throw new NoSuchPaddingException(padName);
+  }
+
+  protected int engineGetBlockSize()
+  {
+    if (cipher != null)
+      return blockLen;
+    return 0;
+  }
+
+  protected int engineGetOutputSize(int inputLen)
+  {
+    final int blockSize = mode.currentBlockSize();
+    return ((inputLen + partLen) / blockSize) * blockSize;
+  }
+
+  protected byte[] engineGetIV()
+  {
+    byte[] iv = (byte[]) attributes.get(IMode.IV);
+    if (iv == null)
+      return null;
+    return (byte[]) iv.clone();
+  }
+
+  protected AlgorithmParameters engineGetParameters()
+  {
+    byte[] iv = (byte[]) attributes.get(IMode.IV);
+    int cipherBlockSize = cipher.currentBlockSize();
+    BlockCipherParameterSpec spec = new BlockCipherParameterSpec(iv,
+                                                                 cipherBlockSize,
+                                                                 keyLen);
+    AlgorithmParameters params;
+    try
+      {
+        params = AlgorithmParameters.getInstance("BlockCipherParameters");
+        params.init(spec);
+      }
+    catch (NoSuchAlgorithmException nsae)
+      {
+        return null;
+      }
+    catch (InvalidParameterSpecException ipse)
+      {
+        return null;
+      }
+    return params;
+  }
+
+  protected void engineInit(int opmode, Key key, SecureRandom random)
+      throws InvalidKeyException
+  {
+    try
+      {
+        engineInit(opmode, key, (AlgorithmParameterSpec) null, random);
+      }
+    catch (InvalidAlgorithmParameterException e)
+      {
+        throw new InvalidKeyException(e.getMessage(), e);
+      }
+  }
+
+  /**
+   * Executes initialization logic after all parameters have been handled by the
+   * engineInit()s.
+   * 
+   * @param opmode the desired mode of operation for this instance.
+   * @param key the key material to use for initialization.
+   * @param random a source of randmoness to use if/when needed.
+   * @throws InvalidKeyException if <code>key</code> is invalid or the cipher
+   *           needs extra parameters which can not be derived from
+   *           <code>key</code>; e.g. an IV.
+   */
+  private void engineInitHandler(int opmode, Key key, SecureRandom random)
+      throws InvalidKeyException
+  {
+    switch (opmode)
+      {
+      case Cipher.ENCRYPT_MODE:
+        attributes.put(IMode.STATE, Integer.valueOf(IMode.ENCRYPTION));
+        break;
+      case Cipher.DECRYPT_MODE:
+        attributes.put(IMode.STATE, Integer.valueOf(IMode.DECRYPTION));
+        break;
+      }
+    if (! key.getFormat().equalsIgnoreCase("RAW"))
+      throw new InvalidKeyException("bad key format " + key.getFormat());
+    byte[] kb = key.getEncoded();
+    int kbLength = kb.length;
+    if (keyLen == 0)
+      {
+        // no key-size given; instead key-material is provided in kb --which
+        // can be more than what we need.  if we don't cull this down to what
+        // the cipher likes/wants we may get an InvalidKeyException.
+        //
+        // try to find the largest key-size value that is less than or equal
+        // to kbLength
+        for (Iterator it = cipher.keySizes(); it.hasNext();)
+          {
+            int aKeySize = ((Integer) it.next()).intValue();
+            if (aKeySize == kbLength)
+              {
+                keyLen = aKeySize;
+                break;
+              }
+            else if (aKeySize < kbLength)
+              keyLen = aKeySize;
+            else // all remaining key-sizes are longer than kb.length
+              break;
+          }
+      }
+    if (keyLen == 0)
+      {
+        // we were unable to find a key-size, among those advertised by the
+        // cipher, that is less than or equal to the length of the kb array.
+        // set keyLen to kbLength.  either the cipher implementation will throw
+        // an InvalidKeyException, or it is implemented in a way which can deal
+        // with an unsupported key-size. 
+        keyLen = kbLength;
+      }
+    if (keyLen < kbLength)
+      {
+        byte[] kbb = kb;
+        kb = new byte[keyLen];
+        System.arraycopy(kbb, 0, kb, 0, keyLen);
+      }
+    attributes.put(IBlockCipher.KEY_MATERIAL, kb);
+    reset();
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+                            SecureRandom random) throws InvalidKeyException,
+      InvalidAlgorithmParameterException
+  {
+    if (params == null)
+      {
+        // All cipher modes require parameters (like an IV) except ECB. When
+        // these cant be derived from the given key then it must be generated
+        // randomly if in ENCRYPT or WRAP mode. Parameters that have defaults
+        // for our cipher must be set to these defaults.
+        if (! mode.name().toLowerCase().startsWith(Registry.ECB_MODE + "("))
+          {
+            switch (opmode)
+              {
+              case Cipher.ENCRYPT_MODE:
+              case Cipher.WRAP_MODE:
+                byte[] iv = new byte[blockLen];
+                random.nextBytes(iv);
+                attributes.put(IMode.IV, iv);
+                break;
+              default:
+                throw new InvalidAlgorithmParameterException(
+                    "Required algorithm parameters are missing for mode: "
+                    + mode.name());
+              }
+          }
+        // Add default for block length etc.
+        blockLen = cipher.defaultBlockSize();
+        attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE,
+                       Integer.valueOf(blockLen));
+        keyLen = 0;
+      }
+    else if (params instanceof BlockCipherParameterSpec)
+      {
+        BlockCipherParameterSpec bcps = (BlockCipherParameterSpec) params;
+        blockLen = bcps.getBlockSize();
+        attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen));
+        attributes.put(IMode.IV, bcps.getIV());
+        keyLen = bcps.getKeySize();
+      }
+    else if (params instanceof IvParameterSpec)
+      {
+        // The size of the IV must match the block size
+        if (((IvParameterSpec) params).getIV().length != cipher.defaultBlockSize())
+          {
+            throw new InvalidAlgorithmParameterException();
+          }
+        
+        attributes.put(IMode.IV, ((IvParameterSpec) params).getIV());
+        blockLen = cipher.defaultBlockSize();
+        attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen));
+        keyLen = 0;
+      }
+    engineInitHandler(opmode, key, random);
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+                            SecureRandom random) throws InvalidKeyException,
+      InvalidAlgorithmParameterException
+  {
+    AlgorithmParameterSpec spec = null;
+    try
+      {
+        if (params != null)
+          spec = params.getParameterSpec(BlockCipherParameterSpec.class);
+      }
+    catch (InvalidParameterSpecException ignored)
+      {
+      }
+    engineInit(opmode, key, spec, random);
+  }
+
+  protected byte[] engineUpdate(byte[] input, int inOff, int inLen)
+  {
+    if (inLen == 0) // nothing to process
+      return new byte[0];
+    final int blockSize = mode.currentBlockSize();
+    int blockCount = (partLen + inLen) / blockSize;
+
+    // always keep data for unpadding in padded decryption mode;
+    // might even be a complete block
+    if (pad != null
+        && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION
+        && (partLen + inLen) % blockSize == 0)
+      blockCount--;
+
+    final byte[] out = new byte[blockCount * blockSize];
+    try
+      {
+        engineUpdate(input, inOff, inLen, out, 0);
+      }
+    catch (ShortBufferException x) // should not happen
+      {
+        x.printStackTrace(System.err);
+      }
+    return out;
+  }
+
+  protected int engineUpdate(byte[] in, int inOff, int inLen, byte[] out,
+                             int outOff) throws ShortBufferException
+  {
+    if (inLen == 0) // nothing to process
+      return 0;
+    final int blockSize = mode.currentBlockSize();
+    int blockCount = (partLen + inLen) / blockSize;
+
+    // always keep data for unpadding in padded decryption mode;
+    // might even be a complete block
+    if (pad != null
+        && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION
+        && (partLen + inLen) % blockSize == 0)
+      blockCount--;
+
+    final int result = blockCount * blockSize;
+    if (result > out.length - outOff)
+      throw new ShortBufferException();
+    if (blockCount == 0) // not enough bytes for even 1 block
+      {
+        System.arraycopy(in, inOff, partBlock, partLen, inLen);
+        partLen += inLen;
+        return 0;
+      }
+    final byte[] buf;
+    // we have enough bytes for at least 1 block
+    if (partLen == 0) // if no cached bytes use input
+      buf = in;
+    else // prefix input with cached bytes
+      {
+        buf = new byte[partLen + inLen];
+        System.arraycopy(partBlock, 0, buf, 0, partLen);
+        if (in != null && inLen > 0)
+          System.arraycopy(in, inOff, buf, partLen, inLen);
+        inOff = 0;
+      }
+    for (int i = 0; i < blockCount; i++) // update blockCount * blockSize
+      {
+        mode.update(buf, inOff, out, outOff);
+        inOff += blockSize;
+        outOff += blockSize;
+      }
+    partLen += inLen - result;
+    if (partLen > 0) // cache remaining bytes from buf
+      System.arraycopy(buf, inOff, partBlock, 0, partLen);
+    return result;
+  }
+
+  protected byte[] engineDoFinal(byte[] input, int off, int len)
+      throws IllegalBlockSizeException, BadPaddingException
+  {
+    final byte[] result;
+    final byte[] buf = engineUpdate(input, off, len);
+    if (pad != null)
+      {
+        switch (((Integer) attributes.get(IMode.STATE)).intValue())
+          {
+          case IMode.ENCRYPTION:
+            byte[] padding = pad.pad(partBlock, 0, partLen);
+            byte[] buf2 = engineUpdate(padding, 0, padding.length);
+            result = new byte[buf.length + buf2.length];
+            System.arraycopy(buf, 0, result, 0, buf.length);
+            System.arraycopy(buf2, 0, result, buf.length, buf2.length);
+            break;
+          case IMode.DECRYPTION:
+            int padLen;
+            byte[] buf3 = new byte[buf.length + partLen];
+            try
+              {
+                if (partLen != mode.currentBlockSize())
+                  throw new WrongPaddingException();
+                System.arraycopy(buf, 0, buf3, 0, buf.length);
+                mode.update(partBlock, 0, buf3, buf.length);
+                padLen = pad.unpad(buf3, 0, buf3.length);
+              }
+            catch (WrongPaddingException wpe)
+              {
+                throw new BadPaddingException(wpe.getMessage());
+              }
+            result = new byte[buf3.length - padLen];
+            System.arraycopy(buf3, 0, result, 0, result.length);
+            break;
+          default:
+            throw new IllegalStateException();
+          }
+      }
+    else
+      {
+        if (partLen > 0)
+          throw new IllegalBlockSizeException(partLen + " trailing bytes");
+        result = buf;
+      }
+
+    try
+      {
+        reset();
+      }
+    catch (InvalidKeyException ike)
+      {
+        // Should not happen; if we initialized it with the current
+        // parameters before, we should be able to do it again.
+        throw new Error(ike);
+      }
+    return result;
+  }
+
+  protected int engineDoFinal(byte[] in, int inOff, int inLen, byte[] out,
+                              int outOff) throws BadPaddingException,
+      IllegalBlockSizeException, ShortBufferException
+  {
+    byte[] buf = engineDoFinal(in, inOff, inLen);
+    if (out.length + outOff < buf.length)
+      throw new ShortBufferException();
+    System.arraycopy(buf, 0, out, outOff, buf.length);
+    return buf.length;
+  }
+
+  private void reset() throws InvalidKeyException
+  {
+    mode.reset();
+    mode.init(attributes);
+    if (pad != null)
+      {
+        pad.reset();
+        pad.init(blockLen);
+      }
+    partBlock = new byte[blockLen];
+    partLen = 0;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/DESSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* DESSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the DES <i>Service Provider Interface</i> (<b>SPI</b>)
+ * adapter.
+ */
+public final class DESSpi
+    extends CipherAdapter
+{
+  public DESSpi()
+  {
+    super(Registry.DES_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,423 @@
+/* KeyWrappingAlgorithmAdapter.java -- Base Adapter for Key Wrapping algorithms
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec;
+import gnu.javax.crypto.kwa.IKeyWrappingAlgorithm;
+import gnu.javax.crypto.kwa.KeyUnwrappingException;
+import gnu.javax.crypto.kwa.KeyWrappingAlgorithmFactory;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * An abstract base class to facilitate implementations of JCE Adapters for
+ * symmetric key block ciphers capable of providing key-wrapping functionality.
+ */
+abstract class KeyWrappingAlgorithmAdapter
+    extends CipherSpi
+{
+  private static final Logger log = Logger.getLogger(KeyWrappingAlgorithmAdapter.class.getName());
+  /** JCE canonical name of a null-padder. */
+  private static final String NO_PADDING = "nopadding";
+  /** Concrete Key Wrapping Algorithm SPI. */
+  protected IKeyWrappingAlgorithm kwAlgorithm;
+  /** Size in bytes of the padding block to be provided by external padders. */
+  protected int kwaBlockSize;
+  /** KEK size in bytes. */
+  protected int kwaKeySize;
+  /** Name of the supported mode. */
+  protected String supportedMode;
+  /** Operational mode in which this instance was initialised. */
+  protected int opmode = -1;
+  /** Initialisation Vector if/when user wants to override default one. */
+  byte[] iv;
+
+  /**
+   * Creates a new JCE Adapter for the designated Key Wrapping Algorithm name.
+   * 
+   * @param name the canonical name of the key-wrapping algorithm.
+   * @param blockSize the block size in bytes of the underlying symmetric-key
+   *          block cipher algorithm.
+   * @param keySize the allowed size in bytes of the KEK bytes to initialise the
+   *          underlying symmetric-key block cipher algorithm with.
+   * @param supportedMode canonical name of the block mode the underlying cipher
+   *          is supporting.
+   */
+  protected KeyWrappingAlgorithmAdapter(String name, int blockSize, int keySize,
+                                        String supportedMode)
+  {
+    super();
+
+    this.kwAlgorithm = KeyWrappingAlgorithmFactory.getInstance(name);
+    this.kwaBlockSize = blockSize;
+    this.kwaKeySize = keySize;
+    this.supportedMode = supportedMode;
+  }
+
+  /**
+   * Wraps the encoded form of a designated {@link Key}.
+   * 
+   * @param key the key-material to wrap.
+   * @return the wrapped key.
+   * @throws InvalidKeyException If the key cannot be wrapped.
+   */
+  protected byte[] engineWrap(Key key)
+      throws InvalidKeyException, IllegalBlockSizeException
+  {
+    byte[] keyMaterial = key.getEncoded();
+    byte[] result = kwAlgorithm.wrap(keyMaterial, 0, keyMaterial.length);
+    return result;
+  }
+
+  /**
+   * Unwraps a previously-wrapped key-material.
+   * 
+   * @param wrappedKey the wrapped key-material to unwrap.
+   * @param wrappedKeyAlgorithm the canonical name of the algorithm, which the
+   *          unwrapped key-material represents. This name is used to
+   *          instantiate a concrete instance of a {@link Key} for that
+   *          algorithm. For example, if the value of this parameter is
+   *          <code>DSS</code> and the type (the next parameter) is
+   *          {@link Cipher#PUBLIC_KEY} then an attempt to construct a concrete
+   *          instance of a {@link java.security.interfaces.DSAPublicKey},
+   *          using the unwrapped key material, shall be made.
+   * @param wrappedKeyType the type of wrapped key-material. MUST be one of
+   *          {@link Cipher#PRIVATE_KEY}, {@link Cipher#PUBLIC_KEY}, or
+   *          {@link Cipher#SECRET_KEY}.
+   * @return the unwrapped key-material as an instance of {@link Key} or one of
+   *         its subclasses.
+   * @throws InvalidKeyException If the key cannot be unwrapped, or if
+   *           <code>wrappedKeyType</code> is an inappropriate type for the
+   *           unwrapped key.
+   * @throws NoSuchAlgorithmException If the <code>wrappedKeyAlgorithm</code>
+   *           is unknown to every currently installed Security Provider.
+   */
+  protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
+                             int wrappedKeyType)
+      throws InvalidKeyException, NoSuchAlgorithmException
+  {
+    byte[] keyBytes;
+    try
+      {
+        keyBytes = kwAlgorithm.unwrap(wrappedKey, 0, wrappedKey.length);
+      }
+    catch (KeyUnwrappingException x)
+      {
+        InvalidKeyException y = new InvalidKeyException("engineUnwrap()");
+        y.initCause(x);
+        throw y;
+      }
+    Key result;
+    switch (wrappedKeyType)
+      {
+      case Cipher.SECRET_KEY:
+        result = new SecretKeySpec(keyBytes, wrappedKeyAlgorithm);
+        break;
+      case Cipher.PRIVATE_KEY:
+      case Cipher.PUBLIC_KEY:
+        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
+        try
+          {
+            if (wrappedKeyType == Cipher.PRIVATE_KEY)
+              result = keyFactory.generatePrivate(keySpec);
+            else
+              result = keyFactory.generatePublic(keySpec);
+          }
+        catch (InvalidKeySpecException x)
+          {
+            InvalidKeyException y = new InvalidKeyException("engineUnwrap()");
+            y.initCause(x);
+            throw y;
+          }
+        break;
+      default:
+        IllegalArgumentException x = new IllegalArgumentException("Invalid 'wrappedKeyType': "
+                                                                  + wrappedKeyType);
+        InvalidKeyException y = new InvalidKeyException("engineUnwrap()");
+        y.initCause(x);
+        throw y;
+      }
+    return result;
+  }
+
+  protected int engineGetBlockSize()
+  {
+    return kwaBlockSize;
+  }
+
+  protected byte[] engineGetIV()
+  {
+    return iv == null ? null : (byte[]) iv.clone();
+  }
+
+  protected int engineGetOutputSize(int inputLength)
+  {
+    switch (opmode)
+    {
+      case Cipher.WRAP_MODE:
+        return getOutputSizeForWrap(inputLength);
+      case Cipher.UNWRAP_MODE:
+        return getOutputSizeForUnwrap(inputLength);
+      default:
+        throw new IllegalStateException();
+    }
+  }
+
+  protected AlgorithmParameters engineGetParameters()
+  {
+    BlockCipherParameterSpec spec = new BlockCipherParameterSpec(iv,
+                                                                 kwaBlockSize,
+                                                                 kwaKeySize);
+    AlgorithmParameters result = null;
+    try
+      {
+        result = AlgorithmParameters.getInstance("BlockCipherParameters");
+        result.init(spec);
+      }
+    catch (NoSuchAlgorithmException x)
+      {
+        if (Configuration.DEBUG)
+          log.fine("Unable to find BlockCipherParameters. Return null");
+      }
+    catch (InvalidParameterSpecException x)
+      {
+        if (Configuration.DEBUG)
+          log.fine("Unable to initialise BlockCipherParameters. Return null");
+      }
+    return result;
+  }
+
+  protected void engineInit(int opmode, Key key, SecureRandom random)
+      throws InvalidKeyException
+  {
+    checkOpMode(opmode);
+    byte[] kekBytes = checkAndGetKekBytes(key);
+    initAlgorithm(opmode, kekBytes, null, random);
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+                            SecureRandom random)
+      throws InvalidAlgorithmParameterException, InvalidKeyException
+  {
+    AlgorithmParameterSpec spec = null;
+    try
+      {
+        if (params != null)
+          spec = params.getParameterSpec(BlockCipherParameterSpec.class);
+      }
+    catch (InvalidParameterSpecException x)
+      {
+        if (Configuration.DEBUG)
+          log.fine("Unable to translate algorithm parameters into an instance "
+                   + "of BlockCipherParameterSpec. Discard");
+      }
+    engineInit(opmode, key, spec, random);
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+                            SecureRandom random)
+      throws InvalidAlgorithmParameterException, InvalidKeyException
+  {
+    checkOpMode(opmode);
+    byte[] kekBytes = checkAndGetKekBytes(key);
+    byte[] ivBytes = null;
+    if (params instanceof BlockCipherParameterSpec)
+      ivBytes = ((BlockCipherParameterSpec) params).getIV();
+    else if (params instanceof IvParameterSpec)
+      ivBytes = ((IvParameterSpec) params).getIV();
+    
+    initAlgorithm(opmode, kekBytes, ivBytes, random);
+  }
+
+  protected void engineSetMode(String mode) throws NoSuchAlgorithmException
+  {
+    if (! supportedMode.equalsIgnoreCase(mode))
+      throw new UnsupportedOperationException("Only " + supportedMode
+                                              + " is supported");
+  }
+
+  /**
+   * NoPadding is the only padding algorithm supported by Key Wrapping Algorithm
+   * implementations in RI.
+   */
+  protected void engineSetPadding(String padding) throws NoSuchPaddingException
+  {
+    if (! NO_PADDING.equalsIgnoreCase(padding))
+      throw new UnsupportedOperationException("Only NoPadding is supported");
+  }
+
+  protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLength)
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  protected int engineUpdate(byte[] input, int inputOffset, int inputLength,
+                             byte[] output, int outputOffset)
+      throws ShortBufferException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLength)
+      throws IllegalBlockSizeException, BadPaddingException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  protected int engineDoFinal(byte[] input, int inputOffset, int inputLength,
+                              byte[] output, int outputOffset)
+      throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * Return the minimum size in bytes of a place holder large enough to receive
+   * the cipher text resulting from a wrap method with the designated size of
+   * the plain text.
+   * <p>
+   * This default implementation ALWAYS returns the smallest multiple of the
+   * <code>kwaBlockSize</code> --passed to this method through its
+   * constructor-- greater than or equal to the designated
+   * <code>inputLength</code>.
+   * 
+   * @param inputLength the size of a plain text.
+   * @return an estimate of the size, in bytes, of the place holder to receive
+   * the resulting bytes of a wrap method.
+   */
+  protected int getOutputSizeForWrap(int inputLength)
+  {
+    return kwaBlockSize * (inputLength + kwaBlockSize - 1) / kwaBlockSize;
+  }
+
+  /**
+   * Return the minimum size in bytes of a place holder large enough to receive
+   * the plain text resulting from an unwrap method with the designated size of
+   * the cipher text.
+   * <p>
+   * This default implementation ALWAYS returns the smallest multiple of the
+   * <code>paddingBlockSize</code> --passed to this method through its
+   * constructor-- greater than or equal to the designated
+   * <code>inputLength</code>.
+   * 
+   * @param inputLength the size of a cipher text.
+   * @return an estimate of the size, in bytes, of the place holder to receive
+   *         the resulting bytes of an uwrap method.
+   */
+  protected int getOutputSizeForUnwrap(int inputLength)
+  {
+    return kwaBlockSize * (inputLength + kwaBlockSize - 1) / kwaBlockSize;
+  }
+
+  private void checkOpMode(int opmode)
+  {
+    switch (opmode)
+    {
+      case Cipher.WRAP_MODE:
+      case Cipher.UNWRAP_MODE:
+        return;
+    }
+    throw new IllegalArgumentException("Unsupported operational mode: " + opmode);
+  }
+
+  /**
+   * Returns the key bytes, iff it was in RAW format.
+   * 
+   * @param key the opaque JCE secret key to use as the KEK.
+   * @return the bytes of the encoded form of the designated kek, iff it was in
+   *         RAW format.
+   * @throws InvalidKeyException if the designated key is not in the RAW format.
+   */
+  private byte[] checkAndGetKekBytes(Key key) throws InvalidKeyException
+  {
+    if (! Registry.RAW_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat()))
+      throw new InvalidKeyException("Only RAW key format is supported");
+    byte[] result = key.getEncoded();
+    int kekSize = result.length;
+    if (kekSize != kwaKeySize)
+      throw new InvalidKeyException("Invalid key material size. Expected "
+                                    + kwaKeySize + " but found " + kekSize);
+    return result;
+  }
+
+  private void initAlgorithm(int opmode, byte[] kek, byte[] ivBytes,
+                             SecureRandom rnd)
+      throws InvalidKeyException
+  {
+    this.opmode = opmode;
+    Map attributes = new HashMap();
+    attributes.put(IKeyWrappingAlgorithm.KEY_ENCRYPTION_KEY_MATERIAL, kek);
+    if (ivBytes != null)
+      {
+        this.iv = (byte[]) ivBytes.clone();
+        attributes.put(IKeyWrappingAlgorithm.INITIAL_VALUE, this.iv);
+      }
+    else
+      this.iv = null;
+    if (rnd != null)
+      attributes.put(IKeyWrappingAlgorithm.SOURCE_OF_RANDOMNESS, rnd);
+
+    kwAlgorithm.init(attributes);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/KhazadSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* KhazadSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Khazad <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class KhazadSpi
+    extends CipherAdapter
+{
+  public KhazadSpi()
+  {
+    super(Registry.KHAZAD_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/NullCipherSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* NullCipherSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Null cipher <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class NullCipherSpi
+    extends CipherAdapter
+{
+  public NullCipherSpi()
+  {
+    super(Registry.NULL_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/PBES2.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,1379 @@
+/* PBES2.java -- 
+   Copyright (C) 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.javax.crypto.prng.IPBE;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.prng.PRNGFactory;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ */
+public abstract class PBES2
+    extends CipherAdapter
+{
+  /** The HMac (PRF) algorithm name. */
+  protected String macName;
+
+  protected PBES2(String cipherName, int blockLen, String macName)
+  {
+    super(cipherName, blockLen);
+    this.macName = macName;
+  }
+
+  protected PBES2(String cipherName, String macName)
+  {
+    super(cipherName);
+    this.macName = macName;
+  }
+
+  protected void engineInit(int opmode, Key key, SecureRandom random)
+      throws InvalidKeyException
+  {
+    if (! (key instanceof PBEKey))
+      throw new InvalidKeyException("not a PBE key");
+    super.engineInit(opmode, genkey((PBEKey) key), random);
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+                            SecureRandom random) throws InvalidKeyException,
+      InvalidAlgorithmParameterException
+  {
+    if (! (key instanceof PBEKey))
+      throw new InvalidKeyException("not a PBE key");
+    super.engineInit(opmode, genkey((PBEKey) key), params, random);
+  }
+
+  protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+                            SecureRandom random) throws InvalidKeyException,
+      InvalidAlgorithmParameterException
+  {
+    if (! (key instanceof PBEKey))
+      throw new InvalidKeyException("not a PBE key");
+    super.engineInit(opmode, genkey((PBEKey) key), params, random);
+  }
+
+  private SecretKeySpec genkey(PBEKey key) throws InvalidKeyException
+  {
+    IRandom kdf = PRNGFactory.getInstance("PBKDF2-" + macName);
+    if (kdf == null)
+      throw new IllegalArgumentException("no such KDF: PBKDF2-" + macName);
+    HashMap attrib = new HashMap();
+    attrib.put(IPBE.ITERATION_COUNT, Integer.valueOf(key.getIterationCount()));
+    attrib.put(IPBE.PASSWORD, key.getPassword());
+    attrib.put(IPBE.SALT, key.getSalt());
+    try
+      {
+        kdf.init(attrib);
+      }
+    catch (IllegalArgumentException iae)
+      {
+        throw new InvalidKeyException(iae.toString());
+      }
+    byte[] dk = new byte[mode.defaultKeySize()];
+    try
+      {
+        kdf.nextBytes(dk, 0, dk.length);
+      }
+    catch (LimitReachedException shouldNotHappen)
+      {
+        throw new Error(String.valueOf(shouldNotHappen));
+      }
+    return new SecretKeySpec(dk, cipher.name());
+  }
+
+  public static class HMacSHA1
+      extends PBES2
+  {
+    public HMacSHA1(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-SHA1");
+    }
+
+    public HMacSHA1(String cipher)
+    {
+      super(cipher, "HMAC-SHA1");
+    }
+
+    public static class AES
+        extends HMacSHA1
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacSHA1
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacSHA1
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacSHA1
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacSHA1
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacSHA1
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacSHA1
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacSHA1
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacSHA1
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacSHA1
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacMD5
+      extends PBES2
+  {
+    public HMacMD5(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-MD5");
+    }
+
+    public HMacMD5(String cipher)
+    {
+      super(cipher, "HMAC-MD5");
+    }
+
+    public static class AES
+        extends HMacMD5
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacMD5
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacMD5
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacMD5
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacMD5
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacMD5
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacMD5
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacMD5
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacMD5
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacMD5
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacMD2
+      extends PBES2
+  {
+    public HMacMD2(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-MD2");
+    }
+
+    public HMacMD2(String cipher)
+    {
+      super(cipher, "HMAC-MD2");
+    }
+
+    public static class AES
+        extends HMacMD2
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacMD2
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacMD2
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacMD2
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacMD2
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacMD2
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacMD2
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacMD2
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacMD2
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacMD2
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacMD4
+      extends PBES2
+  {
+    public HMacMD4(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-MD4");
+    }
+
+    public HMacMD4(String cipher)
+    {
+      super(cipher, "HMAC-MD4");
+    }
+
+    public static class AES
+        extends HMacMD4
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacMD4
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacMD4
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacMD4
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacMD4
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacMD4
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacMD4
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacMD4
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacMD4
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacMD4
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacHaval
+      extends PBES2
+  {
+    public HMacHaval(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-HAVAL");
+    }
+
+    public HMacHaval(String cipher)
+    {
+      super(cipher, "HMAC-HAVAL");
+    }
+
+    public static class AES
+        extends HMacHaval
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacHaval
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacHaval
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacHaval
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacHaval
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacHaval
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacHaval
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacHaval
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacHaval
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacHaval
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacRipeMD128
+      extends PBES2
+  {
+    public HMacRipeMD128(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-RIPEMD128");
+    }
+
+    public HMacRipeMD128(String cipher)
+    {
+      super(cipher, "HMAC-RIPEMD128");
+    }
+
+    public static class AES
+        extends HMacRipeMD128
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacRipeMD128
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacRipeMD128
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacRipeMD128
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacRipeMD128
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacRipeMD128
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacRipeMD128
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacRipeMD128
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacRipeMD128
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacRipeMD128
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacRipeMD160
+      extends PBES2
+  {
+    public HMacRipeMD160(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-RIPEMD160");
+    }
+
+    public HMacRipeMD160(String cipher)
+    {
+      super(cipher, "HMAC-RIPEMD160");
+    }
+
+    public static class AES
+        extends HMacRipeMD160
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacRipeMD160
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacRipeMD160
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacRipeMD160
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacRipeMD160
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacRipeMD160
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacRipeMD160
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacRipeMD160
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacRipeMD160
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacRipeMD160
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacSHA256
+      extends PBES2
+  {
+    public HMacSHA256(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-SHA-256");
+    }
+
+    public HMacSHA256(String cipher)
+    {
+      super(cipher, "HMAC-SHA-256");
+    }
+
+    public static class AES
+        extends HMacSHA256
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacSHA256
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacSHA256
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacSHA256
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacSHA256
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacSHA256
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacSHA256
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacSHA256
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacSHA256
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacSHA256
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacSHA384
+      extends PBES2
+  {
+    public HMacSHA384(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-SHA-384");
+    }
+
+    public HMacSHA384(String cipher)
+    {
+      super(cipher, "HMAC-SHA-384");
+    }
+
+    public static class AES
+        extends HMacSHA384
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacSHA384
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacSHA384
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacSHA384
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacSHA384
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacSHA384
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacSHA384
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacSHA384
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacSHA384
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacSHA384
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacSHA512
+      extends PBES2
+  {
+    public HMacSHA512(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-SHA-512");
+    }
+
+    public HMacSHA512(String cipher)
+    {
+      super(cipher, "HMAC-SHA-512");
+    }
+
+    public static class AES
+        extends HMacSHA512
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacSHA512
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacSHA512
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacSHA512
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacSHA512
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacSHA512
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacSHA512
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacSHA512
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacSHA512
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacSHA512
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacTiger
+      extends PBES2
+  {
+    public HMacTiger(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-TIGER");
+    }
+
+    public HMacTiger(String cipher)
+    {
+      super(cipher, "HMAC-TIGER");
+    }
+
+    public static class AES
+        extends HMacTiger
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacTiger
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacTiger
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacTiger
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacTiger
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacTiger
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacTiger
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacTiger
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacTiger
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacTiger
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+
+  public static class HMacWhirlpool
+      extends PBES2
+  {
+    public HMacWhirlpool(String cipher, int blockLen)
+    {
+      super(cipher, blockLen, "HMAC-WHIRLPOOL");
+    }
+
+    public HMacWhirlpool(String cipher)
+    {
+      super(cipher, "HMAC-WHIRLPOOL");
+    }
+
+    public static class AES
+        extends HMacWhirlpool
+    {
+      public AES()
+      {
+        super("AES");
+      }
+    }
+
+    public static class Anubis
+        extends HMacWhirlpool
+    {
+      public Anubis()
+      {
+        super("Anubis");
+      }
+    }
+
+    public static class Blowfish
+        extends HMacWhirlpool
+    {
+      public Blowfish()
+      {
+        super("Blowfish");
+      }
+    }
+
+    public static class Cast5
+        extends HMacWhirlpool
+    {
+      public Cast5()
+      {
+        super("Cast5");
+      }
+    }
+
+    public static class DES
+        extends HMacWhirlpool
+    {
+      public DES()
+      {
+        super("DES");
+      }
+    }
+
+    public static class Khazad
+        extends HMacWhirlpool
+    {
+      public Khazad()
+      {
+        super("Khazad");
+      }
+    }
+
+    public static class Serpent
+        extends HMacWhirlpool
+    {
+      public Serpent()
+      {
+        super("Serpent");
+      }
+    }
+
+    public static class Square
+        extends HMacWhirlpool
+    {
+      public Square()
+      {
+        super("Square");
+      }
+    }
+
+    public static class TripleDES
+        extends HMacWhirlpool
+    {
+      public TripleDES()
+      {
+        super("TripleDES");
+      }
+    }
+
+    public static class Twofish
+        extends HMacWhirlpool
+    {
+      public Twofish()
+      {
+        super("Twofish");
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/RijndaelSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* RijndaelSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Rijndael <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class RijndaelSpi
+    extends CipherAdapter
+{
+  public RijndaelSpi()
+  {
+    super(Registry.RIJNDAEL_CIPHER, 16);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/SerpentSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* SerpentSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Serpent <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class SerpentSpi
+    extends CipherAdapter
+{
+  public SerpentSpi()
+  {
+    super(Registry.SERPENT_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/SquareSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* SquareSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Square <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class SquareSpi
+    extends CipherAdapter
+{
+  public SquareSpi()
+  {
+    super(Registry.SQUARE_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* TripleDESKeyWrapSpi.java -- DES-EDE Key Wrapping Algorithm JCE Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The JCE Cipher Adapter implementation over the GNU TripleDES Key Wrapping
+ * Algorithm.
+ */
+public final class TripleDESKeyWrapSpi
+    extends KeyWrappingAlgorithmAdapter
+{
+  public TripleDESKeyWrapSpi()
+  {
+    super(Registry.TRIPLEDES_KWA, 8, 192 / 8, Registry.CBC_MODE);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/TripleDESSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* TripleDESSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Triple-DES <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class TripleDESSpi
+    extends CipherAdapter
+{
+  public TripleDESSpi()
+  {
+    super(Registry.TRIPLEDES_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/cipher/TwofishSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* TwofishSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.cipher;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Twofish <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class TwofishSpi
+    extends CipherAdapter
+{
+  public TwofishSpi()
+  {
+    super(Registry.TWOFISH_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* AnubisKeyGeneratorImpl.java -- Anubis key generator.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+
+public class AnubisKeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public AnubisKeyGeneratorImpl()
+  {
+    super(Registry.ANUBIS_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,47 @@
+/* AnubisSecretKeyFactoryImpl.java -- 
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+public class AnubisSecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+  public AnubisSecretKeyFactoryImpl()
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* BlowfishKeyGeneratorImpl.java -- Blowfish key generator.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+
+public class BlowfishKeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public BlowfishKeyGeneratorImpl()
+  {
+    super(Registry.BLOWFISH_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,47 @@
+/* BlowfishSecretKeyFactoryImpl.java -- 
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+public class BlowfishSecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+  public BlowfishSecretKeyFactoryImpl()
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* Cast5KeyGeneratorImpl.java -- CAST-5 key generator.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+
+public class Cast5KeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public Cast5KeyGeneratorImpl()
+  {
+    super(Registry.CAST5_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,47 @@
+/* Cast5SecretKeyFactoryImpl.java -- 
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+public class Cast5SecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+  public Cast5SecretKeyFactoryImpl()
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,68 @@
+/* DESKeyGeneratorImpl.java -- DES key generator.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.DES;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+public class DESKeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public DESKeyGeneratorImpl()
+  {
+    super(Registry.DES_CIPHER);
+  }
+
+  protected SecretKey engineGenerateKey()
+  {
+    if (! init)
+      throw new IllegalStateException("not initialized");
+    byte[] buf = new byte[currentKeySize];
+    do
+      {
+        random.nextBytes(buf);
+      }
+    while (DES.isWeak(buf) || DES.isSemiWeak(buf));
+    DES.adjustParity(buf, 0);
+    return new SecretKeySpec(buf, algorithm);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,82 @@
+/* DESSecretKeyFactoryImpl.java -- DES key factory.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class DESSecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+
+  public DESSecretKeyFactoryImpl()
+  {
+  }
+
+  protected SecretKey engineGenerateSecret(KeySpec spec)
+      throws InvalidKeySpecException
+  {
+    if (spec instanceof DESKeySpec)
+      return new SecretKeySpec(((DESKeySpec) spec).getKey(), "DES");
+    return super.engineGenerateSecret(spec);
+  }
+
+  protected KeySpec engineGetKeySpec(SecretKey key, Class spec)
+      throws InvalidKeySpecException
+  {
+    if (spec.isAssignableFrom(DESKeySpec.class))
+      try
+        {
+          return new DESKeySpec(key.getEncoded());
+        }
+      catch (InvalidKeyException ike)
+        {
+          InvalidKeySpecException ikse = new InvalidKeySpecException(
+              "can't create DES key spec");
+          ikse.initCause(ike);
+          throw ikse;
+        }
+    return super.engineGetKeySpec(key, spec);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,82 @@
+/* DESedeSecretKeyFactoryImpl.java -- DESede key factory.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESedeKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class DESedeSecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+
+  public DESedeSecretKeyFactoryImpl()
+  {
+  }
+
+  protected SecretKey engineGenerateSecret(KeySpec spec)
+      throws InvalidKeySpecException
+  {
+    if (spec instanceof DESedeKeySpec)
+      return new SecretKeySpec(((DESedeKeySpec) spec).getKey(), "DESede");
+    return super.engineGenerateSecret(spec);
+  }
+
+  protected KeySpec engineGetKeySpec(SecretKey key, Class spec)
+      throws InvalidKeySpecException
+  {
+    if (spec.equals(DESedeKeySpec.class))
+      try
+        {
+          return new DESedeKeySpec(key.getEncoded());
+        }
+      catch (InvalidKeyException ike)
+        {
+          InvalidKeySpecException ikse = new InvalidKeySpecException(
+              "can't create DESede key spec");
+          ikse.initCause(ike);
+          throw ikse;
+        }
+    return super.engineGetKeySpec(key, spec);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* KhazadKeyGeneratorImpl.java -- Khazad key generator.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+
+public class KhazadKeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public KhazadKeyGeneratorImpl()
+  {
+    super(Registry.KHAZAD_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,47 @@
+/* KhazadSecretKeyFactoryImpl.java -- simple byte array-wrapping factory.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+public class KhazadSecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+  public KhazadSecretKeyFactoryImpl()
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* RijndaelKeyGeneratorImpl.java -- Rijndael key generator.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+
+public class RijndaelKeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public RijndaelKeyGeneratorImpl()
+  {
+    super(Registry.RIJNDAEL_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,47 @@
+/* RijndaelSecretKeyFactoryImpl.java -- simple byte array-wrapping factory.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+public class RijndaelSecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+  public RijndaelSecretKeyFactoryImpl()
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,87 @@
+/* SecretKeyFactoryImpl.java -- simple byte array-wrapping factory.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.SecretKeySpec;
+
+public abstract class SecretKeyFactoryImpl
+    extends SecretKeyFactorySpi
+{
+
+  protected SecretKeyFactoryImpl()
+  {
+  }
+
+  protected SecretKey engineGenerateSecret(KeySpec spec)
+      throws InvalidKeySpecException
+  {
+    if (spec instanceof SecretKeySpec)
+      return (SecretKey) spec;
+    throw new InvalidKeySpecException("unknown key spec: "
+                                      + spec.getClass().getName());
+  }
+
+  protected KeySpec engineGetKeySpec(SecretKey key, Class spec)
+      throws InvalidKeySpecException
+  {
+    if (spec.equals(SecretKeySpec.class))
+      {
+        if (key instanceof SecretKeySpec)
+          return (KeySpec) key;
+        else
+          return new SecretKeySpec(key.getEncoded(), key.getAlgorithm());
+      }
+    throw new InvalidKeySpecException("unsupported key spec: " + spec.getName());
+  }
+
+  protected SecretKey engineTranslateKey(SecretKey key)
+      throws InvalidKeyException
+  {
+    if (! "RAW".equals(key.getFormat()))
+      throw new InvalidKeyException("only raw keys are supported");
+    // SecretKeySpec is good enough for our purposes.
+    return new SecretKeySpec(key.getEncoded(), key.getAlgorithm());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,110 @@
+/* SecretKeyGeneratorImpl.java -- symmetric key pair generator.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.crypto.KeyGeneratorSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+public class SecretKeyGeneratorImpl
+    extends KeyGeneratorSpi
+{
+  protected final int defaultKeySize;
+  protected final List keySizes;
+  protected final String algorithm;
+  protected boolean init;
+  protected int currentKeySize;
+  protected SecureRandom random;
+
+  protected SecretKeyGeneratorImpl(final String algorithm)
+  {
+    this.algorithm = algorithm;
+    IBlockCipher cipher = CipherFactory.getInstance(algorithm);
+    if (cipher == null)
+      throw new IllegalArgumentException("no such cipher: " + algorithm);
+    defaultKeySize = cipher.defaultKeySize();
+    keySizes = new LinkedList();
+    for (Iterator it = cipher.keySizes(); it.hasNext();)
+      keySizes.add(it.next());
+    init = false;
+  }
+
+  protected SecretKey engineGenerateKey()
+  {
+    if (! init)
+      throw new IllegalStateException("not initialized");
+    byte[] buf = new byte[currentKeySize];
+    random.nextBytes(buf);
+    return new SecretKeySpec(buf, algorithm);
+  }
+
+  protected void engineInit(AlgorithmParameterSpec params, SecureRandom random)
+      throws InvalidAlgorithmParameterException
+  {
+    throw new InvalidAlgorithmParameterException(
+        algorithm + " does not support algorithm paramaters");
+  }
+
+  protected void engineInit(int keySize, SecureRandom random)
+  {
+    keySize >>>= 3; // Use bytes.
+    if (! keySizes.contains(Integer.valueOf(keySize)))
+      throw new InvalidParameterException("unsupported key size: " + keySize);
+    currentKeySize = keySize;
+    this.random = random;
+    init = true;
+  }
+
+  protected void engineInit(SecureRandom random)
+  {
+    engineInit(defaultKeySize << 3, random);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* SerpentKeyGeneratorImpl.java -- Serpent key generator.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+
+public class SerpentKeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public SerpentKeyGeneratorImpl()
+  {
+    super(Registry.SERPENT_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,47 @@
+/* SerpentSecretKeyFactoryImpl.java -- simple byte array-wrapping factory.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+public class SerpentSecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+  public SerpentSecretKeyFactoryImpl()
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* SquareKeyGeneratorImpl.java -- Square key generator.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+
+public class SquareKeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public SquareKeyGeneratorImpl()
+  {
+    super(Registry.SQUARE_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,47 @@
+/* SquareSecretKeyFactoryImpl.java -- simple byte array-wrapping factory.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+public class SquareSecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+  public SquareSecretKeyFactoryImpl()
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* TripleDESKeyGeneratorImpl.java -- TripleDES key generator.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+
+public class TripleDESKeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public TripleDESKeyGeneratorImpl()
+  {
+    super(Registry.TRIPLEDES_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* TwofishKeyGeneratorImpl.java -- Twofish key generator.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+import gnu.java.security.Registry;
+
+public class TwofishKeyGeneratorImpl
+    extends SecretKeyGeneratorImpl
+{
+  public TwofishKeyGeneratorImpl()
+  {
+    super(Registry.TWOFISH_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,47 @@
+/* TwofishSecretKeyFactoryImpl.java -- simple byte array-wrapping factory.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.key;
+
+public class TwofishSecretKeyFactoryImpl
+    extends SecretKeyFactoryImpl
+{
+  public TwofishSecretKeyFactoryImpl()
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/keyring/GnuKeyring.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,507 @@
+/* GnuKeyring.java -- KeyStore adapter for a pair of private and public Keyrings
+   Copyright (C) 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.keyring;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.javax.crypto.keyring.GnuPrivateKeyring;
+import gnu.javax.crypto.keyring.GnuPublicKeyring;
+import gnu.javax.crypto.keyring.IKeyring;
+import gnu.javax.crypto.keyring.IPrivateKeyring;
+import gnu.javax.crypto.keyring.IPublicKeyring;
+import gnu.javax.crypto.keyring.MalformedKeyringException;
+import gnu.javax.crypto.keyring.PrimitiveEntry;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import javax.crypto.SecretKey;
+
+/**
+ * An <i>Adapter</i> over a pair of one private, and one public keyrings to
+ * emulate the keystore operations.
+ */
+public class GnuKeyring
+    extends KeyStoreSpi
+{
+  private static final Logger log = Logger.getLogger(GnuKeyring.class.getName());
+  private static final String NOT_LOADED = "not loaded";
+
+  /** TRUE if the keystore is loaded; FALSE otherwise. */
+  private boolean loaded;
+  /** our underlying private keyring. */
+  private IPrivateKeyring privateKR;
+  /** our underlying public keyring. */
+  private IPublicKeyring publicKR;
+
+  // default 0-arguments constructor
+
+  public Enumeration engineAliases()
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineAliases");
+    ensureLoaded();
+    Enumeration result;
+    if (privateKR == null)
+      result = Collections.enumeration(Collections.EMPTY_SET);
+    else
+      {
+        Set aliases = new HashSet();
+        for (Enumeration e = privateKR.aliases(); e.hasMoreElements();)
+          {
+            String alias = (String) e.nextElement();
+            if (alias != null)
+              {
+                alias = alias.trim();
+                if (alias.length() > 0)
+                  {
+                    if (Configuration.DEBUG)
+                      log.fine("Adding alias (from private keyring): " + alias);
+                    aliases.add(alias);
+                  }
+              }
+          }
+        for (Enumeration e = publicKR.aliases(); e.hasMoreElements();)
+          {
+            String alias = (String) e.nextElement();
+            if (alias != null)
+              {
+                alias = alias.trim();
+                if (alias.length() > 0)
+                  {
+                    if (Configuration.DEBUG)
+                      log.fine("Adding alias (from public keyring): " + alias);
+                    aliases.add(alias);
+                  }
+              }
+          }
+        if (Configuration.DEBUG)
+          log.fine("Will enumerate: " + aliases);
+        result = Collections.enumeration(aliases);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineAliases");
+    return result;
+  }
+
+  public boolean engineContainsAlias(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineContainsAlias", alias);
+    ensureLoaded();
+    boolean inPrivateKR = privateKR.containsAlias(alias);
+    if (Configuration.DEBUG)
+      log.fine("inPrivateKR=" + inPrivateKR);
+    boolean inPublicKR = publicKR.containsAlias(alias);
+    if (Configuration.DEBUG)
+      log.fine("inPublicKR=" + inPublicKR);
+    boolean result = inPrivateKR || inPublicKR;
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineContainsAlias",
+                  Boolean.valueOf(result));
+    return result;
+  }
+
+  public void engineDeleteEntry(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineDeleteEntry", alias);
+    ensureLoaded();
+    if (privateKR.containsAlias(alias))
+      privateKR.remove(alias);
+    else if (publicKR.containsAlias(alias))
+      publicKR.remove(alias);
+    else if (Configuration.DEBUG)
+      log.fine("Unknwon alias: " + alias);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineDeleteEntry");
+  }
+
+  public Certificate engineGetCertificate(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineGetCertificate", alias);
+    ensureLoaded();
+    Certificate result = publicKR.getCertificate(alias);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineGetCertificate", result);
+    return result;
+  }
+
+  public String engineGetCertificateAlias(Certificate cert)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineGetCertificateAlias", cert);
+    ensureLoaded();
+    String result = null;
+    for (Enumeration aliases = publicKR.aliases(); aliases.hasMoreElements();)
+      {
+        String alias = (String) aliases.nextElement();
+        Certificate cert2 = publicKR.getCertificate(alias);
+        if (cert.equals(cert2))
+          {
+            result = alias;
+            break;
+          }
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineGetCertificateAlias", result);
+    return result;
+  }
+
+  public void engineSetCertificateEntry(String alias, Certificate cert)
+      throws KeyStoreException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineSetCertificateEntry",
+                   new Object[] { alias, cert });
+    ensureLoaded();
+    if (privateKR.containsAlias(alias))
+      throw new KeyStoreException("Alias [" + alias
+                                  + "] already exists and DOES NOT identify a "
+                                  + "Trusted Certificate Entry");
+    if (publicKR.containsCertificate(alias))
+      {
+        if (Configuration.DEBUG)
+          log.fine("Public keyring already contains Alias [" + alias
+                   + "]. Will remove it");
+        publicKR.remove(alias);
+      }
+    publicKR.putCertificate(alias, cert);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineSetCertificateEntry");
+  }
+
+  public Certificate[] engineGetCertificateChain(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineGetCertificateChain", alias);
+    ensureLoaded();
+    Certificate[] result = privateKR.getCertPath(alias);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineGetCertificateChain", result);
+    return result;
+  }
+
+  public Date engineGetCreationDate(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineGetCreationDate", alias);
+    ensureLoaded();
+    Date result = getCreationDate(alias, privateKR);
+    if (result == null)
+      result = getCreationDate(alias, publicKR);
+
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineGetCreationDate", result);
+    return result;
+  }
+
+  public Key engineGetKey(String alias, char[] password)
+      throws UnrecoverableKeyException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineGetKey", alias);
+    ensureLoaded();
+    Key result = null;
+    if (password == null)
+      {
+        if (privateKR.containsPublicKey(alias))
+          result = privateKR.getPublicKey(alias);
+      }
+    else if (privateKR.containsPrivateKey(alias))
+      result = privateKR.getPrivateKey(alias, password); 
+
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineGetKey",
+                  result == null ? "null" : result.getClass().getName());
+    return result;
+  }
+
+  public void engineSetKeyEntry(String alias, Key key, char[] password,
+                                Certificate[] chain)
+      throws KeyStoreException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineSetKeyEntry",
+                   new Object[] { alias, key.getClass().getName(), chain });
+    ensureLoaded();
+    if (publicKR.containsAlias(alias))
+      throw new KeyStoreException("Alias [" + alias
+                                  + "] already exists and DOES NOT identify a "
+                                  + "Key Entry");
+    if (key instanceof PublicKey)
+      {
+        privateKR.remove(alias);
+        PublicKey pk = (PublicKey) key;
+        privateKR.putPublicKey(alias, pk);
+      }
+    else
+      {
+        if (! (key instanceof PrivateKey) && ! (key instanceof SecretKey))
+          throw new KeyStoreException("cannot store keys of type "
+                                      + key.getClass().getName());
+        privateKR.remove(alias);
+        privateKR.putCertPath(alias, chain);
+        if (Configuration.DEBUG)
+          log.fine("About to put private key in keyring...");
+        privateKR.putPrivateKey(alias, key, password);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineSetKeyEntry");
+  }
+
+  public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain)
+      throws KeyStoreException
+  {
+    KeyStoreException x = new KeyStoreException("method not supported");
+    if (Configuration.DEBUG)
+      log.throwing(this.getClass().getName(), "engineSetKeyEntry(3)", x);
+    throw x;
+  }
+
+  public boolean engineIsCertificateEntry(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineIsCertificateEntry", alias);
+    ensureLoaded();
+    boolean result = publicKR.containsCertificate(alias);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineIsCertificateEntry",
+                  Boolean.valueOf(result));
+    return result;
+  }
+
+  public boolean engineIsKeyEntry(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineIsKeyEntry", alias);
+    ensureLoaded();
+    boolean result = privateKR.containsPublicKey(alias)
+                  || privateKR.containsPrivateKey(alias);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineIsKeyEntry",
+                  Boolean.valueOf(result));
+    return result;
+  }
+
+  public void engineLoad(InputStream in, char[] password) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineLoad");
+    if (in != null)
+      {
+        if (! in.markSupported())
+          in = new BufferedInputStream(in);
+
+        loadPrivateKeyring(in, password);
+        loadPublicKeyring(in, password);
+      }
+    else
+      createNewKeyrings();
+
+    loaded = true;
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineLoad");
+  }
+
+  public void engineStore(OutputStream out, char[] password) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineStore");
+    ensureLoaded();
+    HashMap attr = new HashMap();
+    attr.put(IKeyring.KEYRING_DATA_OUT, out);
+    attr.put(IKeyring.KEYRING_PASSWORD, password);
+
+    privateKR.store(attr);
+    publicKR.store(attr);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineStore");
+  }
+
+  public int engineSize()
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineSize");
+    int result = 0;
+    for (Enumeration e = engineAliases(); e.hasMoreElements(); result++)
+      e.nextElement();
+
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineSize", Integer.valueOf(result));
+    return result;
+  }
+
+  /**
+   * Ensure that the underlying keyring pair is loaded. Throw an exception if it
+   * isn't; otherwise returns silently.
+   *
+   * @throws IllegalStateException if the keyring is not loaded.
+   */
+  private void ensureLoaded()
+  {
+    if (! loaded)
+      throw new IllegalStateException(NOT_LOADED);
+  }
+
+  /**
+   * Load the private keyring from the designated input stream.
+   * 
+   * @param in the input stream to process.
+   * @param password the password protecting the keyring.
+   * @throws MalformedKeyringException if the keyring is not a private one.
+   * @throws IOException if an I/O related exception occurs during the process.
+   */
+  private void loadPrivateKeyring(InputStream in, char[] password)
+      throws MalformedKeyringException, IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "loadPrivateKeyring");
+    in.mark(5);
+    for (int i = 0; i < 4; i++)
+      if (in.read() != Registry.GKR_MAGIC[i])
+        throw new MalformedKeyringException("incorrect magic");
+
+    int usage = in.read();
+    in.reset();
+    if (usage != GnuPrivateKeyring.USAGE)
+      throw new MalformedKeyringException(
+          "Was expecting a private keyring but got a wrong USAGE: "
+          + Integer.toBinaryString(usage));
+    HashMap attr = new HashMap();
+    attr.put(IKeyring.KEYRING_DATA_IN, in);
+    attr.put(IKeyring.KEYRING_PASSWORD, password);
+    privateKR = new GnuPrivateKeyring();
+    privateKR.load(attr);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "loadPrivateKeyring");
+  }
+
+  /**
+   * Load the public keyring from the designated input stream.
+   * 
+   * @param in the input stream to process.
+   * @param password the password protecting the keyring.
+   * @throws MalformedKeyringException if the keyring is not a public one.
+   * @throws IOException if an I/O related exception occurs during the process.
+   */
+  private void loadPublicKeyring(InputStream in, char[] password)
+      throws MalformedKeyringException, IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "loadPublicKeyring");
+    in.mark(5);
+    for (int i = 0; i < 4; i++)
+      if (in.read() != Registry.GKR_MAGIC[i])
+        throw new MalformedKeyringException("incorrect magic");
+
+    int usage = in.read();
+    in.reset();
+    if (usage != GnuPublicKeyring.USAGE)
+      throw new MalformedKeyringException(
+          "Was expecting a public keyring but got a wrong USAGE: "
+          + Integer.toBinaryString(usage));
+    HashMap attr = new HashMap();
+    attr.put(IKeyring.KEYRING_DATA_IN, in);
+    attr.put(IKeyring.KEYRING_PASSWORD, password);
+    publicKR = new GnuPublicKeyring();
+    publicKR.load(attr);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "loadPublicKeyring");
+  }
+
+  /**
+   * Return the creation date of a named alias in a designated keyring.
+   * 
+   * @param alias the alias to look for.
+   * @param keyring the keyring to search.
+   * @return the creattion date of the entry named <code>alias</code>. Return
+   *         <code>null</code> if <code>alias</code> was not found in
+   *         <code>keyring</code>.
+   */
+  private Date getCreationDate(String alias, IKeyring keyring)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "getCreationDate",
+                   new Object[] { alias, keyring });
+    Date result = null;
+    if (keyring != null)
+      for (Iterator it = keyring.get(alias).iterator(); it.hasNext();)
+        {
+          Object o = it.next();
+          if (o instanceof PrimitiveEntry)
+            {
+              result = ((PrimitiveEntry) o).getCreationDate();
+              break;
+            }
+        }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "getCreationDate", result);
+    return result;
+  }
+
+  /** Create empty keyrings. */
+  private void createNewKeyrings()
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "createNewKeyrings");
+    privateKR = new GnuPrivateKeyring("HMAC-SHA-1", 20, "AES", "OFB", 16);
+    publicKR = new GnuPublicKeyring("HMAC-SHA-1", 20);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "createNewKeyrings");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacHavalSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacHavalSpi.java -- 
+   Copyright (C) 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-HAVAL <i>Service Provider Interface</i>
+ * (<b>SPI</b>) Adapter.
+ */
+public class HMacHavalSpi
+    extends MacAdapter
+{
+  public HMacHavalSpi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.HAVAL_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacMD2Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacMD2Spi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-MD2 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class HMacMD2Spi
+    extends MacAdapter
+{
+  public HMacMD2Spi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.MD2_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacMD4Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacMD4Spi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-MD4 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class HMacMD4Spi
+    extends MacAdapter
+{
+  public HMacMD4Spi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.MD4_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacMD5Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacMD5Spi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-MD5 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class HMacMD5Spi
+    extends MacAdapter
+{
+  public HMacMD5Spi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.MD5_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacRipeMD128Spi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-RIPEMD-128 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class HMacRipeMD128Spi
+    extends MacAdapter
+{
+  public HMacRipeMD128Spi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD128_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacRipeMD160Spi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-RIPEMD-160 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class HMacRipeMD160Spi
+    extends MacAdapter
+{
+  public HMacRipeMD160Spi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD160_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacSHA160Spi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-SHA-160 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class HMacSHA160Spi
+    extends MacAdapter
+{
+  public HMacSHA160Spi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.SHA160_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacSHA256Spi.java -- 
+   Copyright (C) 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-SHA-256 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class HMacSHA256Spi
+    extends MacAdapter
+{
+  public HMacSHA256Spi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.SHA256_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacSHA384Spi.java -- 
+   Copyright (C) 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-SHA-384 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class HMacSHA384Spi
+    extends MacAdapter
+{
+  public HMacSHA384Spi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.SHA384_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacSHA512Spi.java -- 
+   Copyright (C) 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-SHA-512 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public class HMacSHA512Spi
+    extends MacAdapter
+{
+  public HMacSHA512Spi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.SHA512_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacTigerSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacTigerSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the Tiger <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class HMacTigerSpi
+    extends MacAdapter
+{
+  public HMacTigerSpi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.TIGER_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* HMacWhirlpoolSpi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the HMAC-Whirlpool <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class HMacWhirlpoolSpi
+    extends MacAdapter
+{
+  public HMacWhirlpoolSpi()
+  {
+    super(Registry.HMAC_NAME_PREFIX + Registry.WHIRLPOOL_HASH);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/MacAdapter.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,136 @@
+/* MacAdapter.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mac.MacFactory;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.Map;
+import javax.crypto.MacSpi;
+
+/**
+ * The implementation of a generic {@link javax.crypto.Mac} adapter class to
+ * wrap GNU MAC instances.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link javax.crypto.Mac} class, which provides the functionality of a
+ * message authentication code algorithm, such as the <i>Hashed Message
+ * Authentication Code</i> (<b>HMAC</b>) algorithms.
+ */
+class MacAdapter
+    extends MacSpi
+    implements Cloneable
+{
+  /** Our MAC instance. */
+  protected IMac mac;
+  /** Our MAC attributes. */
+  protected Map attributes;
+
+  /**
+   * Creates a new Mac instance for the given name.
+   * 
+   * @param name The name of the mac to create.
+   */
+  protected MacAdapter(String name)
+  {
+    mac = MacFactory.getInstance(name);
+    attributes = new HashMap();
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   * 
+   * @param mac a clone of the internal {@link IMac} instance.
+   * @param attributes a clone of the current {@link Map} of attributes.
+   */
+  private MacAdapter(IMac mac, Map attributes)
+  {
+    super();
+
+    this.mac = mac;
+    this.attributes = attributes;
+  }
+
+  public Object clone() throws CloneNotSupportedException
+  {
+    return new MacAdapter((IMac) mac.clone(), new HashMap(attributes));
+  }
+
+  protected byte[] engineDoFinal()
+  {
+    byte[] result = mac.digest();
+    engineReset();
+    return result;
+  }
+
+  protected int engineGetMacLength()
+  {
+    return mac.macSize();
+  }
+
+  protected void engineInit(Key key, AlgorithmParameterSpec params)
+      throws InvalidKeyException, InvalidAlgorithmParameterException
+  {
+    if (! key.getFormat().equalsIgnoreCase("RAW"))
+      throw new InvalidKeyException("unknown key format " + key.getFormat());
+    attributes.put(IMac.MAC_KEY_MATERIAL, key.getEncoded());
+    mac.reset();
+    mac.init(attributes);
+  }
+
+  protected void engineReset()
+  {
+    mac.reset();
+  }
+
+  protected void engineUpdate(byte b)
+  {
+    mac.update(b);
+  }
+
+  protected void engineUpdate(byte[] in, int off, int len)
+  {
+    mac.update(in, off, len);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacAnubisImpl.java -- OMAC-ANUBIS adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacAnubisImpl
+    extends MacAdapter
+{
+  public OMacAnubisImpl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.ANUBIS_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacBlowfishImpl.java -- OMAC-BLOWFISH adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacBlowfishImpl
+    extends MacAdapter
+{
+  public OMacBlowfishImpl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.BLOWFISH_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacCast5Impl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacCast5Impl.java -- OMAC-CAST5 adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacCast5Impl
+    extends MacAdapter
+{
+  public OMacCast5Impl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.CAST5_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacDESImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacDESImpl.java -- OMAC-DES adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacDESImpl
+    extends MacAdapter
+{
+  public OMacDESImpl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.DES_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,140 @@
+/* OMacImpl.java -- OMAC adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public abstract class OMacImpl
+    extends MacAdapter
+{
+  protected OMacImpl(String name)
+  {
+    super(Registry.OMAC_PREFIX + name);
+  }
+
+  public class Anubis
+      extends OMacImpl
+  {
+    public Anubis()
+    {
+      super(Registry.ANUBIS_CIPHER);
+    }
+  }
+
+  public class Blowfish
+      extends OMacImpl
+  {
+    public Blowfish()
+    {
+      super(Registry.BLOWFISH_CIPHER);
+    }
+  }
+
+  public class Cast5
+      extends OMacImpl
+  {
+    public Cast5()
+    {
+      super(Registry.CAST5_CIPHER);
+    }
+  }
+
+  public class DES
+      extends OMacImpl
+  {
+    public DES()
+    {
+      super(Registry.DES_CIPHER);
+    }
+  }
+
+  public class Khazad
+      extends OMacImpl
+  {
+    public Khazad()
+    {
+      super(Registry.KHAZAD_CIPHER);
+    }
+  }
+
+  public class Rijndael
+      extends OMacImpl
+  {
+    public Rijndael()
+    {
+      super(Registry.RIJNDAEL_CIPHER);
+    }
+  }
+
+  public class Serpent
+      extends OMacImpl
+  {
+    public Serpent()
+    {
+      super(Registry.SERPENT_CIPHER);
+    }
+  }
+
+  public class Square
+      extends OMacImpl
+  {
+    public Square()
+    {
+      super(Registry.SQUARE_CIPHER);
+    }
+  }
+
+  public class TripleDES
+      extends OMacImpl
+  {
+    public TripleDES()
+    {
+      super(Registry.TRIPLEDES_CIPHER);
+    }
+  }
+
+  public class Twofish
+      extends OMacImpl
+  {
+    public Twofish()
+    {
+      super(Registry.TWOFISH_CIPHER);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacKhazadImpl.java -- OMAC-KHAZAD adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacKhazadImpl
+    extends MacAdapter
+{
+  public OMacKhazadImpl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.KHAZAD_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacRijndaelImpl.java -- OMAC-RIJNDAEL adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacRijndaelImpl
+    extends MacAdapter
+{
+  public OMacRijndaelImpl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.RIJNDAEL_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacSerpentImpl.java -- OMAC-SERPENT adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacSerpentImpl
+    extends MacAdapter
+{
+  public OMacSerpentImpl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.SERPENT_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacSquareImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacSquareImpl.java -- OMAC-SQUARE adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacSquareImpl
+    extends MacAdapter
+{
+  public OMacSquareImpl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.SQUARE_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacTripleDESImpl.java -- OMAC-TRIPLEDES adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacTripleDESImpl
+    extends MacAdapter
+{
+  public OMacTripleDESImpl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.TRIPLEDES_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,50 @@
+/* OMacTwofishImpl.java -- OMAC-TWOFISH adapter.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+public class OMacTwofishImpl
+    extends MacAdapter
+{
+  public OMacTwofishImpl()
+  {
+    super(Registry.OMAC_PREFIX + Registry.TWOFISH_CIPHER);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/TMMH16Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,81 @@
+/* TMMH16Spi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.mac.TMMH16;
+import gnu.javax.crypto.jce.spec.TMMHParameterSpec;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * The implementation of the TMMH16 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class TMMH16Spi
+    extends MacAdapter
+{
+  public TMMH16Spi()
+  {
+    super(Registry.TMMH16);
+  }
+
+  protected void engineInit(Key key, AlgorithmParameterSpec params)
+      throws InvalidKeyException, InvalidAlgorithmParameterException
+  {
+    if (! (params instanceof TMMHParameterSpec))
+      throw new InvalidAlgorithmParameterException();
+    TMMHParameterSpec spec = (TMMHParameterSpec) params;
+    attributes.put(TMMH16.TAG_LENGTH, spec.getTagLength());
+    attributes.put(TMMH16.KEYSTREAM, spec.getKeystream());
+    attributes.put(TMMH16.PREFIX, spec.getPrefix());
+    try
+      {
+        mac.reset();
+        mac.init(attributes);
+      }
+    catch (IllegalArgumentException iae)
+      {
+        throw new InvalidAlgorithmParameterException(iae.getMessage());
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/UHash32Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* UHash32Spi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+
+/**
+ * The implementation of the UHash-32 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class UHash32Spi
+    extends MacAdapter
+{
+  public UHash32Spi()
+  {
+    super(Registry.UHASH32);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/mac/UMac32Spi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,79 @@
+/* UMac32Spi.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.mac;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.mac.UMac32;
+import gnu.javax.crypto.jce.spec.UMac32ParameterSpec;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * The implementation of the UMAC-32 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) adapter.
+ */
+public final class UMac32Spi
+    extends MacAdapter
+{
+  public UMac32Spi()
+  {
+    super(Registry.UMAC32);
+  }
+
+  protected void engineInit(Key key, AlgorithmParameterSpec params)
+      throws InvalidKeyException, InvalidAlgorithmParameterException
+  {
+    if (! (params instanceof UMac32ParameterSpec))
+      throw new InvalidAlgorithmParameterException();
+    if (params != null)
+      attributes.put(UMac32.NONCE_MATERIAL,
+                     ((UMac32ParameterSpec) params).getNonce());
+    try
+      {
+        super.engineInit(key, null);
+      }
+    catch (IllegalArgumentException iae)
+      {
+        throw new InvalidAlgorithmParameterException(iae.getMessage());
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/params/BlockCipherParameters.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,149 @@
+/* BlockCipherParameters.java -- 
+   Copyright (C) 2002, 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.params;
+
+import gnu.java.security.Configuration;
+import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.logging.Logger;
+
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * An implementation of algorithm parameters for the GNU block ciphers. This
+ * encompasses the cipher's block size, its key size, and an optional
+ * initialization vector (IV).
+ */
+public class BlockCipherParameters
+    extends AlgorithmParametersSpi
+{
+  private static final Logger log = Logger.getLogger(BlockCipherParameters.class.getName());
+  /** The underlying block cipher specification. */
+  protected BlockCipherParameterSpec cipherSpec;
+  private static final String DEFAULT_FORMAT = "ASN.1";
+
+  /**
+   * Return these parameters encoded in ASN.1 (DER).
+   * <p>
+   * For GNU block ciphers we will define these parameters as
+   * <pre>
+   * BlockCipherParameters ::= SEQUENCE {
+   *    blockSize            INTEGER,
+   *    keySize              INTEGER,
+   *    initializationVector OCTET STRING OPTIONAL }
+   * </pre>
+   * 
+   * @return The parameters, encoded an an ASN.1 DER sequence.
+   * @throws java.io.IOException If encoding these parameters fails.
+   */
+  protected byte[] engineGetEncoded() throws IOException
+  {
+    return engineGetEncoded(DEFAULT_FORMAT);
+  }
+
+  protected byte[] engineGetEncoded(String format) throws IOException
+  {
+    if (! format.equalsIgnoreCase(DEFAULT_FORMAT)
+        && ! format.equalsIgnoreCase("asn1"))
+      throw new IOException("unknown format \"" + format + "\"");
+    DERWriter writer = new DERWriter();
+    int cipherBlockSize = cipherSpec.getBlockSize();
+    int cipherKeySize = cipherSpec.getKeySize();
+    byte[] iv = cipherSpec.getIV();
+    return writer.joinarrays(
+        writer.writeBigInteger(BigInteger.valueOf(cipherBlockSize)),
+        writer.writeBigInteger(BigInteger.valueOf(cipherKeySize)),
+        (iv != null) ? writer.writeBigInteger(new BigInteger(iv))
+                     : new byte[0]);
+  }
+
+  protected void engineInit(AlgorithmParameterSpec spec)
+      throws InvalidParameterSpecException
+  {
+    if (spec instanceof BlockCipherParameterSpec)
+      cipherSpec = (BlockCipherParameterSpec) spec;
+    else
+      throw new InvalidParameterSpecException();
+  }
+
+  protected void engineInit(byte[] encoded, String format) throws IOException
+  {
+    if (! format.equalsIgnoreCase(DEFAULT_FORMAT)
+        && ! format.equalsIgnoreCase("ASN1"))
+      throw new IOException("invalid format: only accepts ASN.1");
+    engineInit(encoded);
+  }
+
+  protected void engineInit(byte[] encoded) throws IOException
+  {
+    DERReader reader = new DERReader(encoded);
+    int bs = reader.getBigInteger().intValue();
+    int ks = reader.getBigInteger().intValue();
+    byte[] iv = null;
+    if (reader.hasMorePrimitives())
+      iv = reader.getBigInteger().toByteArray();
+    cipherSpec = new BlockCipherParameterSpec(iv, bs, ks);
+    if (Configuration.DEBUG)
+      log.fine("cipherSpec: " + cipherSpec);
+  }
+
+  protected AlgorithmParameterSpec engineGetParameterSpec(Class c)
+      throws InvalidParameterSpecException
+  {
+    if (c.isInstance(cipherSpec))
+      return cipherSpec;
+    if (IvParameterSpec.class.isAssignableFrom(c))
+      {
+        IvParameterSpec result = new IvParameterSpec(cipherSpec.getIV());
+        return result;
+      }
+    throw new InvalidParameterSpecException();
+  }
+
+  protected String engineToString()
+  {
+    return cipherSpec.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/params/DEREncodingException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,54 @@
+/* DEREncodingException.java -- 
+   Copyright (C) 1999, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.params;
+
+class DEREncodingException
+    extends java.io.IOException
+{
+
+  public DEREncodingException()
+  {
+    super();
+  }
+
+  public DEREncodingException(String msg)
+  {
+    super(msg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/params/DERReader.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,139 @@
+/* DERReader.java -- 
+   Copyright (C) 1999, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.params;
+
+import java.math.BigInteger;
+
+class DERReader
+{
+  byte source[];
+  int pos;
+  static final int UNIVERSAL = 1;
+  static final int APPLICATION = 2;
+  static final int CONTEXT_SPECIFIC = 3;
+  static final int PRIVATE = 4;
+
+  public DERReader()
+  {
+    source = null;
+    pos = 0;
+  }
+
+  public DERReader(byte source[])
+  {
+    init(source);
+  }
+
+  public void init(String source)
+  {
+    init(source.getBytes());
+  }
+
+  public void init(byte source[])
+  {
+    this.source = source;
+    pos = 0;
+  }
+
+  public boolean hasMorePrimitives()
+  {
+    return pos < source.length;
+  }
+
+  public BigInteger getBigInteger() throws DEREncodingException
+  {
+    return new BigInteger(getPrimitive());
+  }
+
+  // Reads Primitive, definite-length method
+  private byte[] getPrimitive() throws DEREncodingException
+  {
+    int tmp = pos;
+    // Read Identifier
+    byte identifier = source[tmp++];
+    if ((0x20 & identifier) != 0)
+      throw new DEREncodingException();
+    int type = translateLeadIdentifierByte(identifier);
+    // get tag
+    int tag = (0x1f & identifier);
+    // get length
+    byte len = source[tmp]; // may be length of length parameter
+    long length = 0x7f & len;
+    int i;
+    if ((0x80 & len) != 0)
+      {
+        len &= 0x7f;
+        // get length here
+        length = 0;
+        for (i = 0; i < len; i++)
+          {
+            tmp++;
+            length <<= 8;
+            length += (source[tmp] < 0) ? (256 + source[tmp]) : source[tmp];
+          }
+        tmp++;
+      }
+    else
+      tmp++;
+
+    byte tmpb[] = new byte[(int) length];
+    System.arraycopy(source, tmp, tmpb, 0, (int) length);
+    pos = (int) (tmp + length);
+    return tmpb;
+  }
+
+  private int translateLeadIdentifierByte(byte b)
+  {
+    if ((0x3f & b) == b)
+      return UNIVERSAL;
+    else if ((0x7f & b) == b)
+      return APPLICATION;
+    else if ((0xbf & b) == b)
+      return CONTEXT_SPECIFIC;
+    else
+      return PRIVATE;
+  }
+
+  private int getIdentifier(int tpos)
+  {
+    while ((0x80 & source[tpos]) != 0)
+      tpos++;
+    return tpos;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/params/DERWriter.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,143 @@
+/* DERWriter.java -- 
+   Copyright (C) 1999, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.params;
+
+import java.math.BigInteger;
+
+class DERWriter
+{
+  static final int UNIVERSAL = 1;
+  static final int APPLICATION = 2;
+  static final int CONTEXT_SPECIFIC = 3;
+  static final int PRIVATE = 4;
+
+  public DERWriter()
+  {
+  }
+
+  public byte[] writeBigInteger(BigInteger i)
+  {
+    return writePrimitive(0x02,
+                          UNIVERSAL,
+                          (int) Math.ceil((double) i.bitLength() / 8),
+                          i.toByteArray());
+  }
+
+  private byte[] writePrimitive(int identifier, int identifierencoding,
+                                int length, byte contents[])
+  {
+    return joinarrays(generateIdentifier(identifier, identifierencoding),
+                      generateLength(length), contents);
+  }
+
+  public byte[] joinarrays(byte a[], byte b[])
+  {
+    byte d[] = new byte[a.length + b.length];
+    System.arraycopy(a, 0, d, 0,        a.length);
+    System.arraycopy(b, 0, d, a.length, b.length);
+    return d;
+  }
+
+  public byte[] joinarrays(byte a[], byte b[], byte c[])
+  {
+    byte d[] = new byte[a.length + b.length + c.length];
+    System.arraycopy(a, 0, d, 0, a.length);
+    System.arraycopy(b, 0, d, a.length, b.length);
+    System.arraycopy(c, 0, d, a.length + b.length, c.length);
+    return d;
+  }
+
+  private byte[] generateIdentifier(int identifier, int identifierencoding)
+  {
+    byte b[];
+    if (identifier > 31)
+      {
+        int count = (int) (Math.log(identifier) / Math.log(256));
+        b = new byte[count + 1];
+        b[0] = (byte)(translateLeadIdentifierByte(identifierencoding) | 0x1f);
+        int i;
+        for (i = 1; i < (count + 1); i++)
+          {
+            b[i] = (byte) (0x7f & (identifier >> (7 * (count - i))));
+            b[i] |= 0x80;
+          }
+        b[i - 1] ^= 0x80;
+        return b;
+      }
+    else
+      {
+        b = new byte[1];
+        b[0] = (byte)((translateLeadIdentifierByte(identifierencoding)
+             | (byte)(identifier & 0x1f)) & 0xdf);
+        return b;
+      }
+  }
+
+  private byte translateLeadIdentifierByte(int b)
+  {
+    if (b == UNIVERSAL)
+      return (byte) 0x3f;
+    else if (b == APPLICATION)
+      return (byte) 0x7f;
+    else if (b == CONTEXT_SPECIFIC)
+      return (byte) 0xbf;
+    else
+      return (byte) 0xC0;
+  }
+
+  private byte[] generateLength(int length)
+  {
+    byte b[];
+    if (length > 127)
+      {
+        int count = (int) Math.ceil(Math.log(length) / Math.log(256));
+        b = new byte[count + 1];
+        b[0] = (byte)((count & 0x7f) | 0x80);
+        for (int i = 1; i < (count + 1); i++)
+          b[i] = (byte) (length >>> (8 * (count - i)));
+        return b;
+      }
+    else
+      {
+        b = new byte[1];
+        b[0] = (byte) (length & 0x7f);
+        return b;
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,101 @@
+/* ARCFourRandomSpi.java -- 
+   Copyright (C) 2002, 2003, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.prng;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.prng.ARCFour;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.prng.PRNGFactory;
+
+import java.security.SecureRandomSpi;
+import java.util.HashMap;
+
+/**
+ * Implementation of the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the ARCFOUR keystream generator.
+ */
+public class ARCFourRandomSpi
+    extends SecureRandomSpi
+{
+  /** Our underlying prng instance. */
+  private IRandom adaptee;
+  /** Have we been initialized? */
+  private boolean virgin;
+
+  /**
+   * Default 0-arguments constructor.
+   */
+  public ARCFourRandomSpi()
+  {
+    super();
+    adaptee = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG);
+    virgin = true;
+  }
+
+  public byte[] engineGenerateSeed(int numBytes)
+  {
+    if (numBytes < 1)
+      return new byte[0];
+    byte[] result = new byte[numBytes];
+    this.engineNextBytes(result);
+    return result;
+  }
+
+  public void engineNextBytes(byte[] bytes)
+  {
+    if (virgin)
+      this.engineSetSeed(new byte[0]);
+    try
+      {
+        adaptee.nextBytes(bytes, 0, bytes.length);
+      }
+    catch (LimitReachedException ignored)
+      {
+      }
+  }
+
+  public void engineSetSeed(byte[] seed)
+  {
+    HashMap attributes = new HashMap();
+    attributes.put(ARCFour.ARCFOUR_KEY_MATERIAL, seed);
+    adaptee.init(attributes);
+    virgin = false;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/prng/CSPRNGSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,96 @@
+/* CSPRNGSpi.java -- 
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.prng;
+
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.prng.CSPRNG;
+
+import java.net.MalformedURLException;
+import java.security.SecureRandomSpi;
+
+/**
+ * The implementation of the continuously-seeded SecureRandom <i>Service
+ * Provider Interface</i> (<b>SPI</b>) adapter.
+ */
+public class CSPRNGSpi
+    extends SecureRandomSpi
+{
+  private final IRandom adaptee;
+
+  public CSPRNGSpi() throws ClassNotFoundException, MalformedURLException,
+      NumberFormatException
+  {
+    super();
+
+    adaptee = CSPRNG.getSystemInstance();
+  }
+
+  protected byte[] engineGenerateSeed(final int count)
+  {
+    if (count < 0)
+      throw new IllegalArgumentException("count must be nonnegative");
+    byte[] buf = new byte[count];
+    if (count == 0)
+      return buf;
+    engineNextBytes(buf);
+    return buf;
+  }
+
+  protected void engineNextBytes(final byte[] buffer)
+  {
+    if (buffer == null)
+      throw new NullPointerException();
+    try
+      {
+        adaptee.nextBytes(buffer, 0, buffer.length);
+      }
+    catch (LimitReachedException lre)
+      {
+        throw new RuntimeException("random-number generator has been exhausted");
+      }
+  }
+
+  protected void engineSetSeed(final byte[] seed)
+  {
+    if (seed == null)
+      throw new NullPointerException();
+    adaptee.addRandomBytes(seed, 0, seed.length);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/prng/FortunaImpl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,87 @@
+/* FortunaImpl.java -- Fortuna SecureRandom adapter.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.prng;
+
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.prng.Fortuna;
+
+import java.security.SecureRandomSpi;
+import java.util.Collections;
+
+public final class FortunaImpl
+    extends SecureRandomSpi
+{
+  private final Fortuna adaptee;
+
+  public FortunaImpl()
+  {
+    adaptee = new Fortuna();
+    adaptee.init(Collections.singletonMap(Fortuna.SEED, new byte[0]));
+  }
+
+  protected void engineSetSeed(byte[] seed)
+  {
+    synchronized (adaptee)
+      {
+        adaptee.addRandomBytes(seed);
+      }
+  }
+
+  protected void engineNextBytes(byte[] buffer)
+  {
+    synchronized (adaptee)
+      {
+        try
+          {
+            adaptee.nextBytes(buffer);
+          }
+        catch (LimitReachedException shouldNotHappen)
+          {
+            throw new Error(shouldNotHappen);
+          }
+      }
+  }
+
+  protected byte[] engineGenerateSeed(int numbytes)
+  {
+    byte[] seed = new byte[numbytes];
+    engineNextBytes(seed);
+    return seed;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/prng/ICMRandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,217 @@
+/* ICMRandomSpi.java -- 
+   Copyright (C) 2001, 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.prng;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.prng.ICMGenerator;
+
+import java.math.BigInteger;
+import java.security.SecureRandomSpi;
+import java.util.HashMap;
+import java.util.Random;
+import java.util.logging.Logger;
+
+/**
+ * An <em>Adapter</em> class around {@link ICMGenerator} to allow using this
+ * algorithm as a JCE {@link java.security.SecureRandom}.
+ */
+public class ICMRandomSpi
+    extends SecureRandomSpi
+{
+  private static final Logger log = Logger.getLogger(ICMRandomSpi.class.getName());
+  /** Class-wide prng to generate random material for the underlying prng. */
+  private static final ICMGenerator prng; // blank final
+  static
+    {
+      prng = new ICMGenerator();
+      resetLocalPRNG();
+    }
+
+  // error messages
+  private static final String MSG = "Exception while setting up an "
+                                    + Registry.ICM_PRNG + " SPI: ";
+  private static final String RETRY = "Retry...";
+  private static final String LIMIT_REACHED_MSG = "Limit reached: ";
+  private static final String RESEED = "Re-seed...";
+  /** Our underlying prng instance. */
+  private ICMGenerator adaptee = new ICMGenerator();
+
+  // default 0-arguments constructor
+
+  private static void resetLocalPRNG()
+  {
+    if (Configuration.DEBUG)
+      log.entering(ICMRandomSpi.class.getName(), "resetLocalPRNG");
+    HashMap attributes = new HashMap();
+    attributes.put(ICMGenerator.CIPHER, Registry.AES_CIPHER);
+    byte[] key = new byte[128 / 8]; // AES default key size
+    Random rand = new Random(System.currentTimeMillis());
+    rand.nextBytes(key);
+    attributes.put(IBlockCipher.KEY_MATERIAL, key);
+    int aesBlockSize = 128 / 8; // AES block size in bytes
+    byte[] offset = new byte[aesBlockSize];
+    rand.nextBytes(offset);
+    attributes.put(ICMGenerator.OFFSET, offset);
+    int ndxLen = 0; // the segment length
+    // choose a random value between 1 and aesBlockSize / 2
+    int limit = aesBlockSize / 2;
+    while (ndxLen < 1 || ndxLen > limit)
+      ndxLen = rand.nextInt(limit + 1);
+    attributes.put(ICMGenerator.SEGMENT_INDEX_LENGTH, Integer.valueOf(ndxLen));
+    byte[] index = new byte[ndxLen];
+    rand.nextBytes(index);
+    attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index));
+    prng.setup(attributes);
+    if (Configuration.DEBUG)
+      log.exiting(ICMRandomSpi.class.getName(), "resetLocalPRNG");
+  }
+
+  public byte[] engineGenerateSeed(int numBytes)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineGenerateSeed");
+    if (numBytes < 1)
+      {
+        if (Configuration.DEBUG)
+          log.exiting(this.getClass().getName(), "engineGenerateSeed");
+        return new byte[0];
+      }
+    byte[] result = new byte[numBytes];
+    this.engineNextBytes(result);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineGenerateSeed");
+    return result;
+  }
+
+  public void engineNextBytes(byte[] bytes)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineNextBytes");
+    if (! adaptee.isInitialised())
+      this.engineSetSeed(new byte[0]);
+    while (true)
+      {
+        try
+          {
+            adaptee.nextBytes(bytes, 0, bytes.length);
+            break;
+          }
+        catch (LimitReachedException x)
+          { // reseed the generator
+            if (Configuration.DEBUG)
+              {
+                log.fine(LIMIT_REACHED_MSG + String.valueOf(x));
+                log.fine(RESEED);
+              }
+            resetLocalPRNG();
+          }
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineNextBytes");
+  }
+
+  public void engineSetSeed(byte[] seed)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineSetSeed");
+    // compute the total number of random bytes required to setup adaptee
+    int materialLength = 0;
+    materialLength += 16; // key material size
+    materialLength += 16; // offset size
+    materialLength += 8; // index size == half of an AES block
+    byte[] material = new byte[materialLength];
+    // use as much as possible bytes from the seed
+    int materialOffset = 0;
+    int materialLeft = material.length;
+    if (seed.length > 0)
+      { // copy some bytes into key and update indices
+        int lenToCopy = Math.min(materialLength, seed.length);
+        System.arraycopy(seed, 0, material, 0, lenToCopy);
+        materialOffset += lenToCopy;
+        materialLeft -= lenToCopy;
+      }
+    if (materialOffset > 0) // generate the rest
+      {
+        while (true)
+          {
+            try
+              {
+                prng.nextBytes(material, materialOffset, materialLeft);
+                break;
+              }
+            catch (IllegalStateException x)
+              { // should not happen
+                throw new InternalError(MSG + String.valueOf(x));
+              }
+            catch (LimitReachedException x)
+              {
+                if (Configuration.DEBUG)
+                  {
+                    log.fine(MSG + String.valueOf(x));
+                    log.fine(RETRY);
+                  }
+              }
+          }
+      }
+    // setup the underlying adaptee instance
+    HashMap attributes = new HashMap();
+    // use AES cipher with 128-bit block size
+    attributes.put(ICMGenerator.CIPHER, Registry.AES_CIPHER);
+    // use an index the size of quarter of an AES block
+    attributes.put(ICMGenerator.SEGMENT_INDEX_LENGTH, Integer.valueOf(4));
+    // specify the key
+    byte[] key = new byte[16];
+    System.arraycopy(material, 0, key, 0, 16);
+    attributes.put(IBlockCipher.KEY_MATERIAL, key);
+    // specify the offset
+    byte[] offset = new byte[16];
+    System.arraycopy(material, 16, offset, 0, 16);
+    attributes.put(ICMGenerator.OFFSET, offset);
+    // specify the index
+    byte[] index = new byte[8];
+    System.arraycopy(material, 32, index, 0, 8);
+    attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index));
+    adaptee.init(attributes);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineSetSeed");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/prng/UMacRandomSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,168 @@
+/* UMacRandomSpi.java -- 
+   Copyright (C) 2001, 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.prng;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.prng.UMacGenerator;
+
+import java.security.SecureRandomSpi;
+import java.util.HashMap;
+import java.util.Random;
+import java.util.logging.Logger;
+
+/**
+ * An <em>Adapter</em> class around {@link UMacGenerator} to allow using this
+ * algorithm as a JCE {@link java.security.SecureRandom}.
+ */
+public class UMacRandomSpi
+    extends SecureRandomSpi
+{
+  private static final Logger log = Logger.getLogger(UMacRandomSpi.class.getName());
+  /** Class-wide prng to generate random material for the underlying prng. */
+  private static final UMacGenerator prng; // blank final
+  static
+    {
+      prng = new UMacGenerator();
+      resetLocalPRNG();
+    }
+  // error messages
+  private static final String MSG = "Exception while setting up a "
+                                    + Registry.UMAC_PRNG + " SPI: ";
+  private static final String RETRY = "Retry...";
+  /** Our underlying prng instance. */
+  private UMacGenerator adaptee = new UMacGenerator();
+
+  // default 0-arguments constructor
+
+  private static void resetLocalPRNG()
+  {
+    HashMap attributes = new HashMap();
+    attributes.put(UMacGenerator.CIPHER, Registry.AES_CIPHER);
+    byte[] key = new byte[128 / 8]; // AES default key size
+    Random rand = new Random(System.currentTimeMillis());
+    rand.nextBytes(key);
+    attributes.put(IBlockCipher.KEY_MATERIAL, key);
+    int index = rand.nextInt() & 0xFF;
+    attributes.put(UMacGenerator.INDEX, Integer.valueOf(index));
+    prng.setup(attributes);
+  }
+
+  public byte[] engineGenerateSeed(int numBytes)
+  {
+    if (numBytes < 1)
+      return new byte[0];
+    byte[] result = new byte[numBytes];
+    this.engineNextBytes(result);
+    return result;
+  }
+
+  public void engineNextBytes(byte[] bytes)
+  {
+    if (! adaptee.isInitialised())
+      this.engineSetSeed(new byte[0]);
+    while (true)
+      {
+        try
+          {
+            adaptee.nextBytes(bytes, 0, bytes.length);
+            break;
+          }
+        catch (LimitReachedException x)
+          { // reseed the generator
+            resetLocalPRNG();
+          }
+      }
+  }
+
+  public void engineSetSeed(byte[] seed)
+  {
+    // compute the total number of random bytes required to setup adaptee
+    int materialLength = 0;
+    materialLength += 16; // key material size
+    materialLength++; // index size
+    byte[] material = new byte[materialLength];
+    // use as much as possible bytes from the seed
+    int materialOffset = 0;
+    int materialLeft = material.length;
+    if (seed.length > 0)
+      { // copy some bytes into key and update indices
+        int lenToCopy = Math.min(materialLength, seed.length);
+        System.arraycopy(seed, 0, material, 0, lenToCopy);
+        materialOffset += lenToCopy;
+        materialLeft -= lenToCopy;
+      }
+    if (materialOffset > 0) // generate the rest
+      {
+        while (true)
+          {
+            try
+              {
+                prng.nextBytes(material, materialOffset, materialLeft);
+                break;
+              }
+            catch (IllegalStateException x) // should not happen
+              {
+                throw new InternalError(MSG + String.valueOf(x));
+              }
+            catch (LimitReachedException x)
+              {
+                if (Configuration.DEBUG)
+                  {
+                    log.fine(MSG + String.valueOf(x));
+                    log.fine(RETRY);
+                  }
+              }
+          }
+      }
+    // setup the underlying adaptee instance
+    HashMap attributes = new HashMap();
+    // use AES cipher with 128-bit block size
+    attributes.put(UMacGenerator.CIPHER, Registry.AES_CIPHER);
+    // specify the key
+    byte[] key = new byte[16];
+    System.arraycopy(material, 0, key, 0, 16);
+    attributes.put(IBlockCipher.KEY_MATERIAL, key);
+    // use a 1-byte index
+    attributes.put(UMacGenerator.INDEX, Integer.valueOf(material[16] & 0xFF));
+    adaptee.init(attributes);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/sig/DHKeyFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,219 @@
+/* DHKeyFactory.java -- DH key-factory JCE Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec;
+import gnu.javax.crypto.key.dh.DHKeyPairX509Codec;
+import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+/**
+ * Implementation of a JCE Adapter for DH a key-factory.
+ */
+public class DHKeyFactory
+    extends KeyFactorySpi
+{
+  // implicit 0-arguments constructor
+
+  protected PublicKey engineGeneratePublic(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (keySpec instanceof DHPublicKeySpec)
+      {
+        DHPublicKeySpec spec = (DHPublicKeySpec) keySpec;
+        BigInteger p = spec.getP();
+        BigInteger g = spec.getG();
+        BigInteger y = spec.getY();
+        return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y);
+      }
+    if (keySpec instanceof X509EncodedKeySpec)
+      {
+        X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec;
+        byte[] encoded = spec.getEncoded();
+        PublicKey result;
+        try
+          {
+            result = new DHKeyPairX509Codec().decodePublicKey(encoded);
+            return result;
+          }
+        catch (RuntimeException x)
+          {
+            InvalidKeySpecException y = new InvalidKeySpecException();
+            y.initCause(x);
+            throw y;
+          }
+      }
+    throw new InvalidKeySpecException("Unsupported (public) key specification");
+  }
+
+  protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (keySpec instanceof DHPrivateKeySpec)
+      {
+        DHPrivateKeySpec spec = (DHPrivateKeySpec) keySpec;
+        BigInteger p = spec.getP();
+        BigInteger g = spec.getG();
+        BigInteger x = spec.getX();
+        return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x);
+      }
+    if (keySpec instanceof PKCS8EncodedKeySpec)
+      {
+        PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec;
+        byte[] encoded = spec.getEncoded();
+        PrivateKey result;
+        try
+          {
+            result = new DHKeyPairPKCS8Codec().decodePrivateKey(encoded);
+            return result;
+          }
+        catch (RuntimeException x)
+          {
+            InvalidKeySpecException y = new InvalidKeySpecException();
+            y.initCause(x);
+            throw y;
+          }
+      }
+    throw new InvalidKeySpecException("Unsupported (private) key specification");
+  }
+
+  protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+      throws InvalidKeySpecException
+  {
+    if (key instanceof DHPublicKey)
+      {
+        if (keySpec.isAssignableFrom(DHPublicKeySpec.class))
+          {
+            DHPublicKey dssKey = (DHPublicKey) key;
+            BigInteger p = dssKey.getParams().getP();
+            BigInteger g = dssKey.getParams().getG();
+            BigInteger y = dssKey.getY();
+            return new DHPublicKeySpec(y, p, g);
+          }
+        if (keySpec.isAssignableFrom(X509EncodedKeySpec.class))
+          {
+            if (key instanceof GnuDHPublicKey)
+              {
+                GnuDHPublicKey dhKey = (GnuDHPublicKey) key;
+                byte[] encoded = dhKey.getEncoded(Registry.X509_ENCODING_ID);
+                return new X509EncodedKeySpec(encoded);
+              }
+            if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat()))
+              {
+                byte[] encoded = key.getEncoded();
+                return new X509EncodedKeySpec(encoded);
+              }
+            throw new InvalidKeySpecException(
+                "Wrong key type or unsupported (public) key specification");
+          }
+        throw new InvalidKeySpecException("Unsupported (public) key specification");
+      }
+    if (key instanceof DHPrivateKey)
+      {
+        if (keySpec.isAssignableFrom(DHPrivateKeySpec.class))
+          {
+            DHPrivateKey dhKey = (DHPrivateKey) key;
+            BigInteger p = dhKey.getParams().getP();
+            BigInteger g = dhKey.getParams().getG();
+            BigInteger x = dhKey.getX();
+            return new DHPrivateKeySpec(x, p, g);
+          }
+        if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class))
+          {
+            if (key instanceof GnuDHPrivateKey)
+              {
+                GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key;
+                byte[] encoded = dhKey.getEncoded(Registry.PKCS8_ENCODING_ID);
+                return new PKCS8EncodedKeySpec(encoded);
+              }
+            if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat()))
+              {
+                byte[] encoded = key.getEncoded();
+                return new PKCS8EncodedKeySpec(encoded);
+              }
+            throw new InvalidKeySpecException(
+                "Wrong key type or unsupported (private) key specification");
+          }
+        throw new InvalidKeySpecException(
+            "Unsupported (private) key specification");
+      }
+    throw new InvalidKeySpecException(
+        "Wrong key type or unsupported key specification");
+  }
+
+  protected Key engineTranslateKey(Key key) throws InvalidKeyException
+  {
+    if ((key instanceof GnuDHPublicKey) || (key instanceof GnuDHPrivateKey))
+      return key;
+    if (key instanceof DHPublicKey)
+      {
+        DHPublicKey dsaKey = (DHPublicKey) key;
+        BigInteger p = dsaKey.getParams().getP();
+        BigInteger g = dsaKey.getParams().getG();
+        BigInteger y = dsaKey.getY();
+        return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y);
+      }
+    if (key instanceof DHPrivateKey)
+      {
+        DHPrivateKey dsaKey = (DHPrivateKey) key;
+        BigInteger p = dsaKey.getParams().getP();
+        BigInteger g = dsaKey.getParams().getG();
+        BigInteger x = dsaKey.getX();
+        return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x);
+      }
+    throw new InvalidKeyException("Wrong key type");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,93 @@
+/* DHKeyPairGeneratorSpi.java -- DH key-pair generator JCE Adapter
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.sig;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+import gnu.java.security.Registry;
+import gnu.java.security.jce.sig.KeyPairGeneratorAdapter;
+import gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator;
+
+public class DHKeyPairGeneratorSpi
+    extends KeyPairGeneratorAdapter
+{
+  public DHKeyPairGeneratorSpi()
+  {
+    super(Registry.DH_KPG);
+  }
+
+  public void initialize(int keysize, SecureRandom random)
+  {
+    HashMap attributes = new HashMap();
+    attributes.put(GnuDHKeyPairGenerator.PRIME_SIZE, Integer.valueOf(keysize));
+    if (random != null)
+      attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
+
+    attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   Integer.valueOf(Registry.ASN1_ENCODING_ID));
+    adaptee.setup(attributes);
+  }
+
+  public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+      throws InvalidAlgorithmParameterException
+  {
+    HashMap attributes = new HashMap();
+    if (params != null)
+      {
+        if (! (params instanceof DHGenParameterSpec) &&
+            ! (params instanceof DHParameterSpec))
+          throw new InvalidAlgorithmParameterException("params");
+
+        attributes.put(GnuDHKeyPairGenerator.DH_PARAMETERS, params);
+      }
+
+    if (random != null)
+      attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
+
+    attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   Integer.valueOf(Registry.ASN1_ENCODING_ID));
+    adaptee.setup(attributes);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/sig/DHParameters.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,220 @@
+/* DHParameters.java -- DH parameters DAO
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.util.DerUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.ArrayList;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+/**
+ * A JCE-specific Data Access Object (DAO) for DH parameters.
+ */
+public class DHParameters
+    extends AlgorithmParametersSpi
+{
+  /** The prime public modulus. */
+  private BigInteger p;
+
+  /** The generator. */
+  private BigInteger g;
+
+  /** A prime factor of p-1. */
+  private BigInteger q;
+
+  /** The (private) random exponent's size (in bits). */
+  private int l;
+
+  // default 0-arguments constructor
+
+  protected void engineInit(AlgorithmParameterSpec spec)
+      throws InvalidParameterSpecException
+  {
+    if (! (spec instanceof DHParameterSpec))
+      throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: "
+                                              + spec.getClass().getName());
+    DHParameterSpec dhSpec = (DHParameterSpec) spec;
+    p = dhSpec.getP();
+    g = dhSpec.getG();
+    l = dhSpec.getL();
+  }
+
+  /**
+   * Decodes the set of DH parameters as per RFC-2459; i.e. the DER-encoded
+   * form of the following ASN.1 construct: 
+   * 
+   * <pre>
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * </pre>
+   */
+  protected void engineInit(byte[] params) throws IOException
+  {
+    DERReader der = new DERReader(params);
+
+    DERValue derParams = der.read();
+    DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field");
+
+    DERValue val = der.read();
+    DerUtil.checkIsBigInteger(val, "Wrong P field");
+    p = (BigInteger) val.getValue();
+    val = der.read();
+    DerUtil.checkIsBigInteger(val, "Wrong G field");
+    g = (BigInteger) val.getValue();
+    val = der.read();
+    DerUtil.checkIsBigInteger(val, "Wrong Q field");
+    q = (BigInteger) val.getValue();
+    l = q.bitLength();
+  }
+
+  protected void engineInit(byte[] params, String format) throws IOException
+  {
+    if (format != null)
+      {
+        format = format.trim();
+        if (format.length() == 0)
+          throw new IOException("Format MUST NOT be an empty string");
+
+        if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME))
+          throw new IOException("Unknown or unsupported format: " + format);
+      }
+
+    engineInit(params);
+  }
+
+  protected AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec)
+      throws InvalidParameterSpecException
+  {
+    if (paramSpec.isAssignableFrom(DHParameterSpec.class))
+      return new DHParameterSpec(p, g, l);
+
+    if (paramSpec.isAssignableFrom(DHGenParameterSpec.class))
+      return new DHGenParameterSpec(p.bitLength(), l);
+
+    throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: "
+                                            + paramSpec.getName());
+  }
+
+  /**
+   * Encodes the set of DH parameters as per RFC-2459; i.e. as the DER-encoded
+   * form of the following ASN.1 construct: 
+   * 
+   * <pre>
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * </pre>
+   */
+  protected byte[] engineGetEncoded() throws IOException
+  {
+    DERValue derP = new DERValue(DER.INTEGER, p);
+    DERValue derG = new DERValue(DER.INTEGER, g);
+    DERValue derQ = new DERValue(DER.INTEGER, q);
+
+    ArrayList params = new ArrayList(3);
+    params.add(derP);
+    params.add(derG);
+    params.add(derQ);
+    DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    DERWriter.write(baos, derParams);
+    byte[] result = baos.toByteArray();
+
+    return result;
+  }
+
+  protected byte[] engineGetEncoded(String format) throws IOException
+  {
+    if (format != null)
+      {
+        format = format.trim();
+        if (format.length() == 0)
+          throw new IOException("Format MUST NOT be an empty string");
+
+        if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME))
+          throw new IOException("Unknown or unsupported format: " + format);
+      }
+
+    return engineGetEncoded();
+  }
+
+  protected String engineToString()
+  {
+    StringBuffer sb = new StringBuffer("p=");
+    if (p == null)
+      sb.append("???");
+    else
+      sb.append("0x").append(p.toString(16));
+
+    sb.append(", g=");
+    if (g == null)
+      sb.append("???");
+    else
+      sb.append("0x").append(g.toString(16));
+
+    sb.append(", q=");
+    if (q == null)
+      sb.append("???");
+    else
+      sb.append("0x").append(q.toString(16));
+
+    sb.append(", l=").append(l);
+
+    return sb.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/sig/DHParametersGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,152 @@
+/* DHParametersGenerator.java -- JCE Adapter for a generator of DH parameters
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.jce.GnuCrypto;
+import gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator;
+import gnu.javax.crypto.key.dh.RFC2631;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+/**
+ * A JCE Adapter for a generator of DH parameters.
+ */
+public class DHParametersGenerator
+    extends AlgorithmParameterGeneratorSpi
+{
+  private static final Provider GNU_CRYPTO = new GnuCrypto();
+
+  /** Size of the prime (public) modulus in bits. */
+  private int modulusSize = -1;
+
+  /** Size of the prime (private) modulus in bits. */
+  private int exponentSize = -1;
+
+  /** User specified source of randomness. */
+  private SecureRandom rnd;
+
+  /** Our concrete DH parameters generator. */
+  private RFC2631 rfc2631;
+
+
+  protected void engineInit(int size, SecureRandom random)
+  {
+    if ((size % 256) != 0 || size < GnuDHKeyPairGenerator.DEFAULT_PRIME_SIZE)
+      throw new InvalidParameterException("Prime modulus (p) size (in bits) "
+                                          + "MUST be a multiple of 256, and "
+                                          + "greater than or equal to 1024");
+    this.modulusSize = size;
+    this.rnd = random;
+  }
+
+  protected void engineInit(AlgorithmParameterSpec spec, SecureRandom random)
+      throws InvalidAlgorithmParameterException
+  {
+    if (spec instanceof DHParameterSpec)
+      {
+        DHParameterSpec dhSpec = (DHParameterSpec) spec;
+        BigInteger p = dhSpec.getP();
+        int size = p.bitLength();
+        this.engineInit(size, random);
+      }
+    else if (spec instanceof DHGenParameterSpec)
+      {
+        DHGenParameterSpec dhSpec = (DHGenParameterSpec) spec;
+        int size = dhSpec.getPrimeSize();
+        this.engineInit(size, random);
+        exponentSize = dhSpec.getExponentSize();
+
+        if ((exponentSize % 8) != 0
+            || exponentSize < GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE)
+          throw new InvalidParameterException("Random exponent size (in bits) "
+                                              + "MUST be a multiple of 8, and "
+                                              + "greater than or equal to "
+                                              + GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE);
+        if (exponentSize > modulusSize)
+          throw new InvalidParameterException("Random exponent size (in bits) "
+                                              + "MUST be less than that of the "
+                                              + "public prime modulus (p)");
+      }
+
+    throw new InvalidAlgorithmParameterException("Wrong AlgorithmParameterSpec type: "
+                                                 + spec.getClass().getName());
+  }
+
+  protected AlgorithmParameters engineGenerateParameters()
+  {
+    if (modulusSize < 1)
+      modulusSize = GnuDHKeyPairGenerator.DEFAULT_PRIME_SIZE;
+
+    if (exponentSize < 1)
+      exponentSize = GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE;
+
+    rfc2631 = new RFC2631(exponentSize, modulusSize, rnd);
+    BigInteger[] params = rfc2631.generateParameters();
+    BigInteger p = params[RFC2631.DH_PARAMS_P];
+    BigInteger g = params[RFC2631.DH_PARAMS_G];
+    int l = params[RFC2631.DH_PARAMS_Q].bitLength();
+    DHParameterSpec spec = new DHParameterSpec(p, g, l);
+    AlgorithmParameters result = null;
+    try
+      {
+        result = AlgorithmParameters.getInstance(Registry.DH_KPG, GNU_CRYPTO);
+        result.init(spec);
+      }
+    catch (NoSuchAlgorithmException ignore)
+      {
+      }
+    catch (InvalidParameterSpecException ignore)
+      {
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,122 @@
+/* BlockCipherParameterSpec.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.spec;
+
+import gnu.java.security.util.Util;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Block cipher parameters in GNU are the cipher's name, its block and key
+ * sizes, and an optional initialization vector.
+ */
+public class BlockCipherParameterSpec
+    implements AlgorithmParameterSpec
+{
+  /** The initialization vector. */
+  protected byte[] iv;
+  /** The cipher's block size, in bytes. */
+  protected int blockSize;
+  /** The cipher's key size, in bytes. */
+  protected int keySize;
+
+  /**
+   * Create a new parameter specification.
+   * 
+   * @param iv The initialization vector, or <code>null</code> if there is no
+   *          IV.
+   * @param blockSize The cipher's block size, in bytes.
+   * @param keySize The cipher's key size, in bytes.
+   */
+  public BlockCipherParameterSpec(byte[] iv, int blockSize, int keySize)
+  {
+    this.iv = (iv != null) ? (byte[]) iv.clone() : null;
+    this.blockSize = blockSize;
+    this.keySize = keySize;
+  }
+
+  /**
+   * Create a new parameter specification with no IV.
+   * 
+   * @param blockSize The cipher's block size, in bytes.
+   * @param keySize The cipher's key size, in bytes.
+   */
+  public BlockCipherParameterSpec(int blockSize, int keySize)
+  {
+    this(null, blockSize, keySize);
+  }
+
+  /**
+   * Get the initialization vector for the cipher, or <code>null</code> if
+   * there is no IV.
+   * 
+   * @return The IV.
+   */
+  public byte[] getIV()
+  {
+    return iv;
+  }
+
+  /**
+   * Get the block size of the cipher these parameters are for.
+   * 
+   * @return The block size.
+   */
+  public int getBlockSize()
+  {
+    return blockSize;
+  }
+
+  /**
+   * Get the key size of the cipher these parameters are for.
+   * 
+   * @return The block size.
+   */
+  public int getKeySize()
+  {
+    return keySize;
+  }
+
+  public String toString()
+  {
+    return getClass().getName() + " { "
+           + ((iv != null) ? ("IV=" + Util.toString(iv)) + ", " : "")
+           + "BS=" + blockSize + ", KS=" + keySize + " }";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,117 @@
+/* TMMHParameterSpec.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.spec;
+
+import gnu.java.security.prng.IRandom;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class represents the algorithm parameters for the Truncated
+ * Multi-Modular Hash function for use with JCE-derived instances of
+ * {@link gnu.javax.crypto.mac.TMMH16}.
+ * <p>
+ * This class is little more than a container for the key stream, tag length,
+ * and prefix parameters for the TMMH algorithm.
+ */
+public class TMMHParameterSpec
+    implements AlgorithmParameterSpec
+{
+  /** The keystream. */
+  protected IRandom keystream;
+  /** The tag length. */
+  protected Integer tagLength;
+  /** The prefix. */
+  protected byte[] prefix;
+
+  /**
+   * Create a new parameter specification.
+   * 
+   * @param keystream The (PRNG) key stream.
+   * @param tagLength The tag length.
+   * @param prefix The prefix.
+   */
+  public TMMHParameterSpec(IRandom keystream, Integer tagLength, byte[] prefix)
+  {
+    this.keystream = keystream;
+    this.tagLength = tagLength;
+    this.prefix = prefix;
+  }
+
+  /**
+   * Create a new parameter specification with no prefix.
+   * 
+   * @param keystream The (PRNG) key stream.
+   * @param tagLength The tag length.
+   */
+  public TMMHParameterSpec(IRandom keystream, Integer tagLength)
+  {
+    this(keystream, tagLength, null);
+  }
+
+  /**
+   * Return the key stream this specification was initialized with.
+   * 
+   * @return The key stream.
+   */
+  public IRandom getKeystream()
+  {
+    return keystream;
+  }
+
+  /**
+   * Return the tag length this specification was initialized with.
+   * 
+   * @return The tag length.
+   */
+  public Integer getTagLength()
+  {
+    return tagLength;
+  }
+
+  /**
+   * Return the prefix, or <code>null</code> if no prefix was specified.
+   * 
+   * @return The prefix.
+   */
+  public byte[] getPrefix()
+  {
+    return prefix;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,73 @@
+/* UMac32ParameterSpec.java -- 
+   Copyright (C) 2002, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.jce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class represents the parameters for the UMAC-32 message authentication
+ * code algorithm. In practice this means the <i>Nonce</i> material used to
+ * initialize the algorithm.
+ */
+public class UMac32ParameterSpec
+    implements AlgorithmParameterSpec
+{
+  /** The <i>Nonce</i> material. */
+  protected byte[] nonce;
+
+  /**
+   * Create a new parameter instance.
+   * 
+   * @param nonce The nonce material.
+   */
+  public UMac32ParameterSpec(byte[] nonce)
+  {
+    this.nonce = nonce;
+  }
+
+  /**
+   * Return the nonce material.
+   * 
+   * @return The nonce material.
+   */
+  public byte[] getNonce()
+  {
+    return nonce;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/BaseKeyAgreementParty.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,168 @@
+/* BaseKeyAgreementParty.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key;
+
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+/**
+ * A base abstract class to facilitate implementations of concrete key agreement
+ * protocol handlers.
+ */
+public abstract class BaseKeyAgreementParty
+    implements IKeyAgreementParty
+{
+  protected static final BigInteger TWO = BigInteger.valueOf(2L);
+  /** The canonical name of the protocol. */
+  protected String name;
+  /** Whether the instance is initialised or not. */
+  protected boolean initialised = false;
+  /** The current step index of the protocol exchange. */
+  protected int step = -1;
+  /** Whether the exchange has concluded or not. */
+  protected boolean complete = false;
+  /** The optional {@link SecureRandom} instance to use. */
+  protected SecureRandom rnd = null;
+  /** The optional {@link IRandom} instance to use. */
+  protected IRandom irnd = null;
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+
+  protected BaseKeyAgreementParty(String name)
+  {
+    super();
+
+    this.name = name;
+  }
+
+  public String name()
+  {
+    return name;
+  }
+
+  public void init(Map attributes) throws KeyAgreementException
+  {
+    if (initialised)
+      throw new IllegalStateException("already initialised");
+    this.engineInit(attributes);
+    initialised = true;
+    this.step = -1;
+    this.complete = false;
+  }
+
+  public OutgoingMessage processMessage(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    if (! initialised)
+      throw new IllegalStateException("not initialised");
+    if (complete)
+      throw new IllegalStateException("exchange has already concluded");
+    step++;
+    return this.engineProcessMessage(in);
+  }
+
+  public boolean isComplete()
+  {
+    return complete;
+  }
+
+  public byte[] getSharedSecret() throws KeyAgreementException
+  {
+    if (! initialised)
+      throw new KeyAgreementException("not yet initialised");
+    if (! isComplete())
+      throw new KeyAgreementException("not yet computed");
+    return engineSharedSecret();
+  }
+
+  public void reset()
+  {
+    if (initialised)
+      {
+        this.engineReset();
+        initialised = false;
+      }
+  }
+
+  protected abstract void engineInit(Map attributes)
+      throws KeyAgreementException;
+
+  protected abstract OutgoingMessage engineProcessMessage(IncomingMessage in)
+      throws KeyAgreementException;
+
+  protected abstract byte[] engineSharedSecret() throws KeyAgreementException;
+
+  protected abstract void engineReset();
+
+  /**
+   * Fills the designated byte array with random data.
+   * 
+   * @param buffer the byte array to fill with random data.
+   */
+  protected void nextRandomBytes(byte[] buffer)
+  {
+    if (rnd != null)
+      rnd.nextBytes(buffer);
+    else if (irnd != null)
+      try
+        {
+          irnd.nextBytes(buffer, 0, buffer.length);
+        }
+      catch (LimitReachedException lre)
+        {
+          irnd = null;
+          getDefaultPRNG().nextBytes(buffer);
+        }
+    else
+      getDefaultPRNG().nextBytes(buffer);
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/GnuPBEKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,95 @@
+/* GnuPBEKey.java -- A password-based encryption key.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.key;
+
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.PBEKeySpec;
+
+/**
+ * An implementation of a password-based encryption key.
+ * 
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class GnuPBEKey
+  implements PBEKey
+{
+  private final PBEKeySpec spec;
+
+  public GnuPBEKey (final PBEKeySpec spec)
+  {
+    if (spec == null)
+      throw new NullPointerException ();
+    this.spec = spec;
+  }
+
+  public GnuPBEKey (char[] password, byte[] salt, int iterationCount)
+  {
+    this (new PBEKeySpec (password, salt, iterationCount));
+  }
+
+  public int getIterationCount ()
+  {
+    return spec.getIterationCount ();
+  }
+
+  public char[] getPassword ()
+  {
+    return spec.getPassword ();
+  }
+
+  public byte[] getSalt ()
+  {
+    return spec.getSalt ();
+  }
+
+  public String getAlgorithm ()
+  {
+    return "PBE";
+  }
+
+  public String getFormat ()
+  {
+    return "NONE"; // FIXME?
+  }
+
+  public byte[] getEncoded ()
+  {
+    return null; // FIXME?
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/GnuSecretKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,131 @@
+/* GnuSecretKey.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key;
+
+import gnu.java.security.util.Util;
+import java.security.Key;
+
+/**
+ * A secret key composed of a sequence of raw, unformatted octets. This class is
+ * analogous to the {@link javax.crypto.spec.SecretKeySpec} class, but is
+ * provided for platforms that do not or cannot contain that class.
+ */
+public class GnuSecretKey
+    implements Key
+{
+  private final byte[] key;
+  private final String algorithm;
+
+  /**
+   * Creates a new secret key. The supplied byte array is copied by this
+   * constructor.
+   * 
+   * @param key The raw, secret key.
+   * @param algorithm The algorithm name, which can be null or empty.
+   */
+  public GnuSecretKey(byte[] key, String algorithm)
+  {
+    this(key, 0, key.length, algorithm);
+  }
+
+  /**
+   * Creates a new secret key from a portion of a byte array.
+   * 
+   * @param key The raw, secret key.
+   * @param offset The offset at which the key begins.
+   * @param length The number of bytes that comprise the key.
+   * @param algorithm The algorithm name, which can be null or empty.
+   */
+  public GnuSecretKey(byte[] key, int offset, int length, String algorithm)
+  {
+    this.key = new byte[length];
+    System.arraycopy(key, offset, this.key, 0, length);
+    this.algorithm = algorithm;
+  }
+
+  /**
+   * Returns the algorithm name, if any.
+   * 
+   * @return The algorithm name.
+   */
+  public String getAlgorithm()
+  {
+    return null;
+  }
+
+  /**
+   * Returns the encoded key, which is merely the byte array this class was
+   * created with. A reference to the internal byte array is returned, so the
+   * caller can delete this key from memory by modifying the returned array.
+   * 
+   * @return The raw key.
+   */
+  public byte[] getEncoded()
+  {
+    return key;
+  }
+
+  /**
+   * Returns the string "RAW".
+   * 
+   * @return The string "RAW".
+   */
+  public String getFormat()
+  {
+    return "RAW";
+  }
+
+  public boolean equals(Object o)
+  {
+    if (! (o instanceof GnuSecretKey))
+      return false;
+    if (key.length != ((GnuSecretKey) o).key.length)
+      return false;
+    byte[] key2 = ((GnuSecretKey) o).key;
+    for (int i = 0; i < key.length; i++)
+      if (key[i] != key2[i])
+        return false;
+    return true;
+  }
+
+  public String toString()
+  {
+    return "GnuSecretKey [ " + algorithm + " " + Util.toString(key) + " ]";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/IKeyAgreementParty.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,100 @@
+/* IKeyAgreementParty.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key;
+
+import java.util.Map;
+
+/**
+ * The visible methods of an key agreement protocol participating party.
+ */
+public interface IKeyAgreementParty
+{
+  /**
+   * Returns the canonical name of the key agreement protocol.
+   * 
+   * @return the canonical name of the key agreement protocol.
+   */
+  String name();
+
+  /**
+   * Sets up the instance to operate with specific attributes.
+   * 
+   * @param attributes a map of name-values used by concrete implementations.
+   * @throws KeyAgreementException if an exception occurs during the setup.
+   */
+  void init(Map attributes) throws KeyAgreementException;
+
+  /**
+   * Processes an incoming message at one end, generating a message that will be
+   * processed by the other party(ies).
+   * 
+   * @param in the incoming message.
+   * @return an outgoing message, or <code>null</code> if this is an
+   *         intermediary step that does not cause any output.
+   * @throws KeyAgreementException if an exception occurs during the processing
+   *           of the incoming message, or during the generation of the outgoing
+   *           message.
+   */
+  OutgoingMessage processMessage(IncomingMessage in)
+      throws KeyAgreementException;
+
+  /**
+   * Returns <code>true</code> if the party in the key agreement protocol
+   * exchange has completed its part of the exchange. If this is the case an
+   * {@link IllegalStateException} is thrown for any method invocation except
+   * <code>init()</code> or <code>reset()</code>.
+   * 
+   * @return <code>true</code> if this party has completed its part of the key
+   *         agreement protocol exchange; <code>false</code> otherwise.
+   */
+  boolean isComplete();
+
+  /**
+   * Returns the byte array containing the shared secret as generated by this
+   * party.
+   * 
+   * @return the generated shared secret.
+   * @throws KeyAgreementException if the key agreement is not yet initialised,
+   *           or is initialised but the exchange is still in progress.
+   */
+  byte[] getSharedSecret() throws KeyAgreementException;
+
+  /** Resets this instance for re-use with another set of attributes. */
+  void reset();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/IncomingMessage.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,318 @@
+/* IncomingMessage.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec;
+import gnu.java.security.key.dss.DSSKeyPairRawCodec;
+import gnu.java.security.key.dss.DSSKeyPairX509Codec;
+import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec;
+import gnu.java.security.key.rsa.RSAKeyPairRawCodec;
+import gnu.java.security.key.rsa.RSAKeyPairX509Codec;
+import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec;
+import gnu.javax.crypto.key.dh.DHKeyPairRawCodec;
+import gnu.javax.crypto.key.dh.DHKeyPairX509Codec;
+import gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec;
+
+import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * An implementation of an incoming message for use with key agreement
+ * protocols.
+ */
+public class IncomingMessage
+{
+  /** The internal buffer stream containing the message's contents. */
+  protected ByteArrayInputStream in;
+  /** The length of the message contents, according to its 4-byte header. */
+  protected int length;
+
+  /**
+   * Constructs an incoming message given the message's encoded form, including
+   * its header bytes.
+   * 
+   * @param b the encoded form, including the header bytes, of an incoming
+   *          message.
+   * @throws KeyAgreementException if the buffer is malformed.
+   */
+  public IncomingMessage(byte[] b) throws KeyAgreementException
+  {
+    this();
+
+    if (b.length < 4)
+      throw new KeyAgreementException("message header too short");
+    length =  b[0]         << 24
+           | (b[1] & 0xFF) << 16
+           | (b[2] & 0xFF) << 8
+           | (b[3] & 0xFF);
+    if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
+      throw new KeyAgreementException("message size limit exceeded");
+    in = new ByteArrayInputStream(b, 4, length);
+  }
+
+  /** Trivial private constructor for use by the class method. */
+  private IncomingMessage()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a message given its encoded contents, excluding the
+   * message's header bytes.
+   * <p>
+   * Calls the method with the same name and three arguments as:
+   * <code>getInstance(raw, 0, raw.length)</code>.
+   * 
+   * @param raw the encoded form, excluding the header bytes.
+   * @return a new instance of <code>IncomingMessage</code>.
+   */
+  public static IncomingMessage getInstance(byte[] raw)
+  {
+    return getInstance(raw, 0, raw.length);
+  }
+
+  /**
+   * Returns an instance of a message given its encoded contents, excluding the
+   * message's header bytes.
+   * 
+   * @param raw the encoded form, excluding the header bytes.
+   * @param offset offset where to start using raw bytes from.
+   * @param len number of bytes to use.
+   * @return a new instance of <code>IncomingMessage</code>.
+   */
+  public static IncomingMessage getInstance(byte[] raw, int offset, int len)
+  {
+    IncomingMessage result = new IncomingMessage();
+    result.in = new ByteArrayInputStream(raw, offset, len);
+    return result;
+  }
+
+  /**
+   * Converts two octets into the number that they represent.
+   * 
+   * @param b the two octets.
+   * @return the length.
+   */
+  public static int twoBytesToLength(byte[] b) throws KeyAgreementException
+  {
+    int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF);
+    if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+      throw new KeyAgreementException("encoded MPI size limit exceeded");
+    return result;
+  }
+
+  /**
+   * Converts four octets into the number that they represent.
+   * 
+   * @param b the four octets.
+   * @return the length.
+   */
+  public static int fourBytesToLength(byte[] b) throws KeyAgreementException
+  {
+    int result =  b[0]         << 24
+               | (b[1] & 0xFF) << 16
+               | (b[2] & 0xFF) << 8
+               | (b[3] & 0xFF);
+    if (result > Registry.SASL_FOUR_BYTE_MAX_LIMIT || result < 0)
+      throw new KeyAgreementException("encoded entity size limit exceeded");
+    return result;
+  }
+
+  public boolean hasMoreElements()
+  {
+    return (in.available() > 0);
+  }
+
+  /**
+   * Decodes a public key from the message.
+   * <p>
+   * See {@link OutgoingMessage#writePublicKey(java.security.PublicKey)} for
+   * more details on the internal format.
+   * 
+   * @throws KeyAgreementException if an encoding size constraint is violated or
+   *           a mismatch was detected in the encoding.
+   */
+  public PublicKey readPublicKey() throws KeyAgreementException
+  {
+    if (in.available() < 5)
+      throw new KeyAgreementException("not enough bytes for a public key in message");
+    byte[] elementLengthBytes = new byte[4];
+    in.read(elementLengthBytes, 0, 4);
+    int elementLength = fourBytesToLength(elementLengthBytes);
+    if (in.available() < elementLength)
+      throw new KeyAgreementException("illegal public key encoding");
+    int keyTypeAndFormatID = in.read() & 0xFF;
+    elementLength--;
+    byte[] kb = new byte[elementLength];
+    in.read(kb, 0, elementLength);
+    // instantiate the right codec and decode
+    IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID);
+    return kpc.decodePublicKey(kb);
+  }
+
+  /**
+   * Decodes a private key from the message.
+   * <p>
+   * See {@link OutgoingMessage#writePrivateKey(java.security.PrivateKey)} for
+   * more details.
+   * 
+   * @throws KeyAgreementException if an encoding size constraint is violated or
+   *           a mismatch was detected in the encoding.
+   */
+  public PrivateKey readPrivateKey() throws KeyAgreementException
+  {
+    if (in.available() < 5)
+      throw new KeyAgreementException("not enough bytes for a private key in message");
+    byte[] elementLengthBytes = new byte[4];
+    in.read(elementLengthBytes, 0, 4);
+    int elementLength = fourBytesToLength(elementLengthBytes);
+    if (in.available() < elementLength)
+      throw new KeyAgreementException("illegal private key encoding");
+    int keyTypeAndFormatID = in.read() & 0xFF;
+    elementLength--;
+    byte[] kb = new byte[elementLength];
+    in.read(kb, 0, elementLength);
+    // instantiate the right codec and decode
+    IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID);
+    return kpc.decodePrivateKey(kb);
+  }
+
+  /**
+   * Decodes an MPI from the current message's contents.
+   * 
+   * @return a native representation of an MPI.
+   * @throws KeyAgreementException if an encoding exception occurs during the
+   *           operation.
+   */
+  public BigInteger readMPI() throws KeyAgreementException
+  {
+    if (in.available() < 2)
+      throw new KeyAgreementException("not enough bytes for an MPI in message");
+    byte[] elementLengthBytes = new byte[2];
+    in.read(elementLengthBytes, 0, 2);
+    int elementLength = twoBytesToLength(elementLengthBytes);
+    if (in.available() < elementLength)
+      throw new KeyAgreementException("illegal MPI encoding");
+    byte[] element = new byte[elementLength];
+    in.read(element, 0, element.length);
+    return new BigInteger(1, element);
+  }
+
+  public String readString() throws KeyAgreementException
+  {
+    if (in.available() < 2)
+      throw new KeyAgreementException("not enough bytes for a text in message");
+    byte[] elementLengthBytes = new byte[2];
+    in.read(elementLengthBytes, 0, 2);
+    int elementLength = twoBytesToLength(elementLengthBytes);
+    if (in.available() < elementLength)
+      throw new KeyAgreementException("illegal text encoding");
+    byte[] element = new byte[elementLength];
+    in.read(element, 0, element.length);
+    String result = null;
+    try
+      {
+        result = new String(element, "UTF8");
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new KeyAgreementException("unxupported UTF8 encoding", x);
+      }
+    return result;
+  }
+
+  private IKeyPairCodec getKeyPairCodec(int keyTypeAndFormatID)
+      throws KeyAgreementException
+  {
+    int keyType = (keyTypeAndFormatID >>> 4) & 0x0F;
+    int formatID = keyTypeAndFormatID & 0x0F;
+    switch (formatID)
+      {
+      case Registry.RAW_ENCODING_ID:
+        switch (keyType)
+          {
+          case 0:
+            return new DSSKeyPairRawCodec();
+          case 1:
+            return new RSAKeyPairRawCodec();
+          case 2:
+            return new DHKeyPairRawCodec();
+          case 3:
+            return new SRPKeyPairRawCodec();
+          default:
+            throw new KeyAgreementException("Unknown key-type for Raw format: "
+                                            + keyType);
+          }
+      case Registry.X509_ENCODING_ID:
+        switch (keyType)
+          {
+          case 0:
+            return new DSSKeyPairX509Codec();
+          case 1:
+            return new RSAKeyPairX509Codec();
+          case 2:
+            return new DHKeyPairX509Codec();
+          default:
+            throw new KeyAgreementException("Unknown key-type for X.509 format: "
+                                            + keyType);
+          }
+      case Registry.PKCS8_ENCODING_ID:
+        switch (keyType)
+          {
+          case 0:
+            return new DSSKeyPairPKCS8Codec();
+          case 1:
+            return new RSAKeyPairPKCS8Codec();
+          case 2:
+            return new DHKeyPairPKCS8Codec();
+          default:
+            throw new KeyAgreementException("Unknown key-type for PKCS#8 format: "
+                                            + keyType);
+          }
+      default:
+        throw new KeyAgreementException("Unknown format identifier: "
+                                        + formatID);
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/KeyAgreementException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,166 @@
+/* KeyAgreementException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.security.KeyManagementException;
+
+/**
+ * A generic exception indicating that an unexpected condition has been detected
+ * during the setup and/or processing of a key agreement protocol exchange.
+ */
+public class KeyAgreementException
+    extends KeyManagementException
+    implements Serializable
+{
+  /** @serial The possibly <code>null</code> <i>root</i> cause exception. */
+  private Throwable cause = null;
+
+  /**
+   * Constructs a new instance of <code>KeyAgreementException</code>. The
+   * root exception and the detailed message are <code>null</code>.
+   */
+  public KeyAgreementException()
+  {
+    super();
+  }
+
+  /**
+   * Constructs a new instance of <code>KeyAgreementException</code> with a
+   * detailed message. The <i>root</i> exception is <code>null</code>.
+   * 
+   * @param detail a possibly <code>null</code> string containing details of
+   *          the exception.
+   * @see Throwable#getMessage()
+   */
+  public KeyAgreementException(String detail)
+  {
+    super(detail);
+  }
+
+  /**
+   * Constructs a new instance of <code>KeyAgreementException</code> with a
+   * detailed message and a <i>root</i> exception.
+   * 
+   * @param detail a possibly <code>null</code> string containing details of
+   *          the exception.
+   * @param cause a possibly <code>null</code> root exception that caused this
+   *          exception.
+   * @see Throwable#getMessage()
+   * @see #getCause()
+   */
+  public KeyAgreementException(String detail, Throwable cause)
+  {
+    super(detail);
+    this.cause = cause;
+  }
+
+  /**
+   * Returns the cause of this throwable or <code>null</code> if the cause is
+   * nonexistent or unknown. The <i>cause</i> is the throwable that caused this
+   * exception to be thrown.
+   * 
+   * @return the possibly <code>null</code> exception that caused this one.
+   */
+  public Throwable getCause()
+  {
+    return cause;
+  }
+
+  /**
+   * Prints this exception's stack trace to <code>System.err</code>. If this
+   * exception has a <i>root</i> exception; the stack trace of the <i>root</i>
+   * exception is also printed to <code>System.err</code>.
+   */
+  public void printStackTrace()
+  {
+    super.printStackTrace();
+    if (cause != null)
+      cause.printStackTrace();
+  }
+
+  /**
+   * Prints this exception's stack trace to a print stream. If this exception
+   * has a <i>root</i> exception; the stack trace of the <i>root</i> exception
+   * is also printed to the print stream.
+   * 
+   * @param ps the non-null print stream to which to print.
+   */
+  public void printStackTrace(PrintStream ps)
+  {
+    super.printStackTrace(ps);
+    if (cause != null)
+      cause.printStackTrace(ps);
+  }
+
+  /**
+   * Prints this exception's stack trace to a print writer. If this exception
+   * has a <i>root</i> exception; the stack trace of the <i>root</i> exception
+   * is also printed to the print writer.
+   * 
+   * @param pw the non-null print writer to use for output.
+   */
+  public void printStackTrace(PrintWriter pw)
+  {
+    super.printStackTrace(pw);
+    if (cause != null)
+      cause.printStackTrace(pw);
+  }
+
+  /**
+   * Returns the string representation of this exception. The string
+   * representation contains this exception's class name, its detailed messsage,
+   * and if it has a <i>root</i> exception, the string representation of the
+   * root exception. This string representation is meant for debugging and is
+   * not meant to be interpreted programmatically.
+   * 
+   * @return the non-null string representation of this exception.
+   * @see Throwable#getMessage()
+   */
+  public String toString()
+  {
+    StringBuffer sb = new StringBuffer(this.getClass().getName()).append(": ")
+        .append(super.toString());
+    if (cause != null)
+      sb.append("; caused by: ").append(cause.toString());
+    return sb.toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/KeyAgreementFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,143 @@
+/* KeyAgreementFactory.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key;
+
+import gnu.java.security.Registry;
+
+import gnu.javax.crypto.key.dh.DiffieHellmanSender;
+import gnu.javax.crypto.key.dh.DiffieHellmanReceiver;
+import gnu.javax.crypto.key.dh.ElGamalSender;
+import gnu.javax.crypto.key.dh.ElGamalReceiver;
+import gnu.javax.crypto.key.srp6.SRP6Host;
+import gnu.javax.crypto.key.srp6.SRP6User;
+import gnu.javax.crypto.key.srp6.SRP6SaslClient;
+import gnu.javax.crypto.key.srp6.SRP6SaslServer;
+import gnu.javax.crypto.key.srp6.SRP6TLSClient;
+import gnu.javax.crypto.key.srp6.SRP6TLSServer;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A <i>Factory</i> class to generate key agreement protocol handlers.
+ */
+public class KeyAgreementFactory
+{
+  /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+  private KeyAgreementFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a key agreeent protocol handler, for party
+   * <code>A</code> in a two-party <code>A..B</code> exchange, given the
+   * canonical name of this protocol. Party <code>A</code> is usually the
+   * initiator of the exchange.
+   * 
+   * @param name the case-insensitive key agreement protocol name.
+   * @return an instance of the key agreement protocol handler for party
+   *         <code>A</code>, or <code>null</code> if none found.
+   */
+  public static IKeyAgreementParty getPartyAInstance(String name)
+  {
+    if (name == null)
+      return null;
+    name = name.trim();
+    IKeyAgreementParty result = null;
+    if (name.equalsIgnoreCase(Registry.DH_KA))
+      result = new DiffieHellmanSender();
+    else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA))
+      result = new ElGamalSender();
+    else if (name.equalsIgnoreCase(Registry.SRP6_KA))
+      result = new SRP6User();
+    else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA))
+      result = new SRP6SaslClient();
+    else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA))
+      result = new SRP6TLSClient();
+    return result;
+  }
+
+  /**
+   * Returns an instance of a key agreeent protocol handler, for party
+   * <code>B</code> in a two-party <code>A..B</code> exchange, given the
+   * canonical name of this protocol.
+   * 
+   * @param name the case-insensitive key agreement protocol name.
+   * @return an instance of the key agreement protocol handler for party
+   *         <code>B</code>, or <code>null</code> if none found.
+   */
+  public static IKeyAgreementParty getPartyBInstance(String name)
+  {
+    if (name == null)
+      return null;
+    name = name.trim();
+    IKeyAgreementParty result = null;
+    if (name.equalsIgnoreCase(Registry.DH_KA))
+      result = new DiffieHellmanReceiver();
+    else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA))
+      result = new ElGamalReceiver();
+    else if (name.equalsIgnoreCase(Registry.SRP6_KA))
+      result = new SRP6Host();
+    else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA))
+      result = new SRP6SaslServer();
+    else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA))
+      result = new SRP6TLSServer();
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of key agreement protocol names supported by this
+   * <i>Factory</i>.
+   * 
+   * @return a {@link Set} of key agreement protocol names (Strings).
+   */
+  public static final Set getNames()
+  {
+    HashSet hs = new HashSet();
+    hs.add(Registry.DH_KA);
+    hs.add(Registry.ELGAMAL_KA);
+    hs.add(Registry.SRP6_KA);
+    hs.add(Registry.SRP_SASL_KA);
+    hs.add(Registry.SRP_TLS_KA);
+
+    return Collections.unmodifiableSet(hs);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/OutgoingMessage.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,234 @@
+/* OutgoingMessage.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.dss.DSSKey;
+import gnu.java.security.key.rsa.GnuRSAKey;
+import gnu.java.security.util.FormatUtil;
+import gnu.javax.crypto.key.dh.GnuDHKey;
+import gnu.javax.crypto.key.srp6.SRPKey;
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.math.BigInteger;
+
+/**
+ * An implementation of outgoing messages for use with key agreement protocols.
+ */
+public class OutgoingMessage
+{
+  /** The internal output stream. */
+  private ByteArrayOutputStream out;
+
+  public OutgoingMessage()
+  {
+    super();
+
+    out = new ByteArrayOutputStream();
+  }
+
+  /**
+   * Returns the encoded form of the current message including the 4-byte length
+   * header.
+   * 
+   * @throws KeyAgreementException if an encoding size constraint is violated.
+   */
+  public byte[] toByteArray() throws KeyAgreementException
+  {
+    byte[] buffer = wrap();
+    int length = buffer.length;
+    byte[] result = new byte[length + 4];
+    result[0] = (byte)(length >>> 24);
+    result[1] = (byte)(length >>> 16);
+    result[2] = (byte)(length >>> 8);
+    result[3] = (byte) length;
+    System.arraycopy(buffer, 0, result, 4, length);
+    return result;
+  }
+
+  /**
+   * Returns the encoded form of the current message excluding the 4-byte length
+   * header.
+   * 
+   * @throws KeyAgreementException if an encoding size constraint is violated.
+   */
+  public byte[] wrap() throws KeyAgreementException
+  {
+    int length = out.size();
+    if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
+      throw new KeyAgreementException("message content is too long");
+    return out.toByteArray();
+  }
+
+  /**
+   * Encodes a public key into the message.
+   * <p>
+   * When a public key is encoded into an outgoing message, the byte array of
+   * the encoded key --according to its encoding/decoding format specified when
+   * the key was first instantiated-- are put in the message (a) preceeded by
+   * one byte representing both the type of key (upper 4-bit) and the identifier
+   * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity
+   * representing the total length, excluding these 4 bytes, of the bytes
+   * representing the encoded key and the one-byte representing the key-type and
+   * format; i.e.
+   * <pre>
+   * key --&gt; 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+   * </pre>
+   * 
+   * @param k the public key to encode.
+   * @throws KeyAgreementException if an encoding size constraint is violated.
+   */
+  public void writePublicKey(PublicKey k) throws KeyAgreementException
+  {
+    writeKey(k);
+  }
+
+  /**
+   * Encodes a private key into the message.
+   * <p>
+   * When a private key is encoded into an outgoing message, the byte array of
+   * the encoded key --according to its encoding/decoding format specified when
+   * the key was first instantiated-- are put in the message (a) preceeded by
+   * one byte representing both the type of key (upper 4-bit) and the identifier
+   * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity
+   * representing the total length, excluding these 4 bytes, of the bytes
+   * representing the encoded key and the one-byte representing the key-type and
+   * format; i.e.
+   * <pre>
+   * key --&gt; 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+   * </pre>
+   * 
+   * @param k the private key to encode.
+   * @throws KeyAgreementException if an encoding size constraint is violated.
+   */
+  public void writePrivateKey(PrivateKey k) throws KeyAgreementException
+  {
+    writeKey(k);
+  }
+
+  /**
+   * Encodes an MPI into the message.
+   * 
+   * @param val the MPI to encode.
+   * @throws KeyAgreementException if an encoding size constraint is violated.
+   */
+  public void writeMPI(BigInteger val) throws KeyAgreementException
+  {
+    byte[] b = val.toByteArray();
+    int length = b.length;
+    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+      throw new KeyAgreementException("MPI is too long");
+    byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
+    out.write(lengthBytes, 0, 2);
+    out.write(b, 0, b.length);
+  }
+
+  /**
+   * Encodes a string into the message.
+   * 
+   * @param s the string to encode.
+   * @throws KeyAgreementException if the UTF8 encoding is not supported on this
+   *           platform, or if an encoding size constraint is violated.
+   */
+  public void writeString(String s) throws KeyAgreementException
+  {
+    byte[] b = null;
+    try
+      {
+        b = s.getBytes("UTF8");
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new KeyAgreementException("unxupported UTF8 encoding", x);
+      }
+    int length = b.length;
+    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+      throw new KeyAgreementException("text too long");
+    byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
+    out.write(lengthBytes, 0, 2);
+    out.write(b, 0, b.length);
+  }
+
+  /**
+   * @param k the key to encode.
+   * @throws KeyAgreementException if an encoding size constraint is violated.
+   */
+  private void writeKey(Key k) throws KeyAgreementException
+  {
+    byte[] b = k.getEncoded();
+    int keyType = getKeyType(k);
+    int formatID = FormatUtil.getFormatID(k.getFormat());
+    int length = b.length + 1;
+    if (length > Registry.SASL_FOUR_BYTE_MAX_LIMIT)
+      throw new KeyAgreementException("Encoded key is too long");
+    byte[] lengthBytes = {
+        (byte)(length >>> 24),
+        (byte)(length >>> 16),
+        (byte)(length >>> 8),
+        (byte) length };
+    out.write(lengthBytes, 0, 4);
+    out.write(((keyType & 0x0F) << 4) | (formatID & 0x0F));
+    out.write(b, 0, b.length);
+  }
+
+  /**
+   * @param k the key to find an identifier for.
+   * @return an integer from <code>0</code> to <code>3</code> identifying
+   *         the type of key.
+   * @throws KeyAgreementException if the designated key is of unknown or
+   *           unsupported type.
+   */
+  private int getKeyType(Key k) throws KeyAgreementException
+  {
+    if (k instanceof DSSKey)
+      return 0;
+    if (k instanceof GnuRSAKey)
+      return 1;
+    if (k instanceof GnuDHKey)
+      return 2;
+    if (k instanceof SRPKey)
+      return 3;
+    throw new KeyAgreementException("Unknown or unsupported key type: "
+                                    + k.getClass().getName());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,240 @@
+/* DHKeyPairPKCS8Codec.java -- PKCS#8 encoder/decoder for DH keys
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.key.dh;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+import gnu.java.security.util.Util;
+
+public class DHKeyPairPKCS8Codec
+    implements IKeyPairCodec
+{
+  private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING);
+
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return PKCS8_FORMAT;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    throw new InvalidParameterException("Wrong format for public keys");
+  }
+
+  /**
+   * Returns the DER-encoded form of the PKCS#8 ASN.1 <i>PrivateKeyInfo</i>
+   * representation of a DH private key. The ASN.1 specification is as follows:
+   * 
+   * <pre>
+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * </pre>
+   * <p>
+   * <b>IMPORTANT</b>: with RI's {@link javax.crypto.spec.DHGenParameterSpec}
+   * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with
+   * Diffie-Hellman keys that have a <code>null</code> for the <code>q</code>
+   * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that
+   * parameter, hence we replace such null values with <code>0</code>, and do
+   * the reverse in the corresponding decode method.
+   * 
+   * @return the DER encoded form of the ASN.1 representation of the
+   *         <i>PrivateKeyInfo</i> field in an X.509 certificate.
+   * @throw InvalidParameterException if an error occurs during the marshalling
+   *        process.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    if (! (key instanceof GnuDHPrivateKey))
+      throw new InvalidParameterException("Wrong key type");
+
+    DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID);
+
+    GnuDHPrivateKey pk = (GnuDHPrivateKey) key;
+    BigInteger p = pk.getParams().getP();
+    BigInteger g = pk.getParams().getG();
+    BigInteger q = pk.getQ();
+    if (q == null)
+      q = BigInteger.ZERO;
+    BigInteger x = pk.getX();
+
+    ArrayList params = new ArrayList(3);
+    params.add(new DERValue(DER.INTEGER, p));
+    params.add(new DERValue(DER.INTEGER, g));
+    params.add(new DERValue(DER.INTEGER, q));
+    DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+
+    ArrayList algorithmID = new ArrayList(2);
+    algorithmID.add(derOID);
+    algorithmID.add(derParams);
+    DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                           algorithmID);
+
+    DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, Util.trim(x));
+
+    ArrayList pki = new ArrayList(3);
+    pki.add(derVersion);
+    pki.add(derAlgorithmID);
+    pki.add(derPrivateKey);
+    DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
+
+    byte[] result;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try
+      {
+        DERWriter.write(baos, derPKI);
+        result = baos.toByteArray();
+      }
+    catch (IOException e)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(e);
+        throw y;
+      }
+
+    return result;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public PublicKey decodePublicKey(byte[] input)
+  {
+    throw new InvalidParameterException("Wrong format for public keys");
+  }
+
+  /**
+   * @param input the byte array to unmarshall into a valid DH
+   *          {@link PrivateKey} instance. MUST NOT be null.
+   * @return a new instance of a {@link GnuDHPrivateKey} decoded from the
+   *         <i>PrivateKeyInfo</i> material fed as <code>input</code>.
+   * @throw InvalidParameterException if an exception occurs during the
+   *        unmarshalling process.
+   */
+  public PrivateKey decodePrivateKey(byte[] input)
+  {
+    if (input == null)
+      throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+    BigInteger version, p, q, g, x;
+    DERReader der = new DERReader(input);
+    try
+      {
+        DERValue derPKI = der.read();
+        DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
+
+        DERValue derVersion = der.read();
+        if (! (derVersion.getValue() instanceof BigInteger))
+          throw new InvalidParameterException("Wrong Version field");
+
+        version = (BigInteger) derVersion.getValue();
+        if (version.compareTo(BigInteger.ZERO) != 0)
+          throw new InvalidParameterException("Unexpected Version: " + version);
+
+        DERValue derAlgoritmID = der.read();
+        DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
+
+        DERValue derOID = der.read();
+        OID algOID = (OID) derOID.getValue();
+        if (! algOID.equals(DH_ALG_OID))
+          throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+        DERValue derParams = der.read();
+        DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
+
+        DERValue val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong P field");
+        p = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong G field");
+        g = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong Q field");
+        q = (BigInteger) val.getValue();
+        if (q.compareTo(BigInteger.ZERO) == 0)
+          q = null;
+
+        val = der.read();
+        byte[] xBytes = (byte[]) val.getValue();
+        x = new BigInteger(1, xBytes);
+      }
+    catch (IOException e)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(e);
+        throw y;
+      }
+
+    return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, q, p, g, x);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,336 @@
+/* DHKeyPairRawCodec.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * An object that implements the {@link IKeyPairCodec} operations for the
+ * <i>Raw</i> format to use with Diffie-Hellman keypairs.
+ */
+public class DHKeyPairRawCodec
+    implements IKeyPairCodec
+{
+  public int getFormatID()
+  {
+    return RAW_FORMAT;
+  }
+
+  /**
+   * Returns the encoded form of the designated Diffie-Hellman public key
+   * according to the <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for a DH public key, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_DH_PUBLIC_KEY},</li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the DH parameter
+   * <code>q</code> in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DH parameter <code>q</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DH parameter
+   * <code>p</code> in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DH parameter <code>p</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DH parameter
+   * <code>g</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DH parameter <code>g</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DH parameter
+   * <code>y</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DH parameter <code>y</code>,
+   * </li>
+   * </ol>
+   * 
+   * @param key the key to encode.
+   * @return the <i>Raw</i> format encoding of the designated key.
+   * @throws IllegalArgumentException if the designated key is not a DH one.
+   * @see Registry#MAGIC_RAW_DH_PUBLIC_KEY
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    if (! (key instanceof GnuDHPublicKey))
+      throw new IllegalArgumentException("key");
+    GnuDHPublicKey dhKey = (GnuDHPublicKey) key;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]);
+    baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[1]);
+    baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[2]);
+    baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[3]);
+    // version
+    baos.write(0x01);
+    // q
+    byte[] buffer = dhKey.getQ().toByteArray();
+    int length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // p
+    buffer = dhKey.getParams().getP().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // g
+    buffer = dhKey.getParams().getG().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // y
+    buffer = dhKey.getY().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    return baos.toByteArray();
+  }
+
+  public PublicKey decodePublicKey(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]
+        || k[1] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[1]
+        || k[2] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[2]
+        || k[3] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[3])
+      throw new IllegalArgumentException("magic");
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+    int i = 5;
+    int l;
+    byte[] buffer;
+    // q
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger q = new BigInteger(1, buffer);
+    // p
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger p = new BigInteger(1, buffer);
+    // g
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger g = new BigInteger(1, buffer);
+    // y
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger y = new BigInteger(1, buffer);
+    return new GnuDHPublicKey(q, p, g, y);
+  }
+
+  /**
+   * Returns the encoded form of the designated Diffie-Hellman private key
+   * according to the <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for a DH private key, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_DH_PRIVATE_KEY},</li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the DH parameter
+   * <code>q</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DH parameter <code>q</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DH parameter
+   * <code>p</code> in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DH parameter <code>p</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DH parameter
+   * <code>g</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DH parameter <code>g</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the DH parameter
+   * <code>x</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the DH parameter <code>x</code>,
+   * </li>
+   * </ol>
+   * 
+   * @param key the key to encode.
+   * @return the <i>Raw</i> format encoding of the designated key.
+   * @throws IllegalArgumentException if the designated key is not a DH one.
+   * @see Registry#MAGIC_RAW_DH_PRIVATE_KEY
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    if (! (key instanceof GnuDHPrivateKey))
+      throw new IllegalArgumentException("key");
+    GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]);
+    baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[1]);
+    baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[2]);
+    baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[3]);
+    // version
+    baos.write(0x01);
+    // q
+    byte[] buffer = dhKey.getQ().toByteArray();
+    int length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // p
+    buffer = dhKey.getParams().getP().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // g
+    buffer = dhKey.getParams().getG().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // x
+    buffer = dhKey.getX().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    return baos.toByteArray();
+  }
+
+  public PrivateKey decodePrivateKey(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]
+        || k[1] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[1]
+        || k[2] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[2]
+        || k[3] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[3])
+      throw new IllegalArgumentException("magic");
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+    int i = 5;
+    int l;
+    byte[] buffer;
+    // q
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger q = new BigInteger(1, buffer);
+    // p
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger p = new BigInteger(1, buffer);
+    // g
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger g = new BigInteger(1, buffer);
+    // x
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger x = new BigInteger(1, buffer);
+    return new GnuDHPrivateKey(q, p, g, x);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,255 @@
+/* DHKeyPairX509Codec.java -- X.509 DER encoder/decoder for DH keys
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.key.dh;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+
+public class DHKeyPairX509Codec
+    implements IKeyPairCodec
+{
+  private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING);
+
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return X509_FORMAT;
+  }
+
+  /**
+   * Returns the DER-encoded form of the X.509 ASN.1 <i>SubjectPublicKeyInfo</i>
+   * representation of a DH public key. The ASN.1 specification, as defined in
+   * RFC-3280, and RFC-2459, is as follows:
+   *
+   * <pre>
+   *   SubjectPublicKeyInfo ::= SEQUENCE {
+   *     algorithm         AlgorithmIdentifier,
+   *     subjectPublicKey  BIT STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * </pre>
+   * 
+   * <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+   * DER-encoded form of the DH public key as an INTEGER.</p>
+   * 
+   * <pre>
+   *       DHPublicKey ::= INTEGER -- public key, y = g^x mod p
+   * </pre>
+   * <p>
+   * <b>IMPORTANT</b>: with RI's {@link javax.crypto.spec.DHGenParameterSpec}
+   * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with
+   * Diffie-Hellman keys that have a <code>null</code> for the <code>q</code>
+   * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that
+   * parameter, hence we replace such null values with <code>0</code>, and do
+   * the reverse in the corresponding decode method.
+   * 
+   * @param key the {@link PublicKey} instance to encode. MUST be an instance of
+   *          {@link GnuDHPublicKey}.
+   * @return the DER-encoded form of the ASN.1 representation of the
+   *         <i>SubjectPublicKeyInfo</i> in an X.509 certificate.
+   * @throw InvalidParameterException if <code>key</code> is not an instance
+   *        of {@link GnuDHPublicKey} or if an exception occurs during the
+   *        marshalling process.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    if (! (key instanceof GnuDHPublicKey))
+      throw new InvalidParameterException("Wrong key type");
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID);
+
+    GnuDHPublicKey dhKey = (GnuDHPublicKey) key;
+    BigInteger p = dhKey.getParams().getP();
+    BigInteger g = dhKey.getParams().getG();
+    BigInteger q = dhKey.getQ();
+    if (q == null)
+      q = BigInteger.ZERO;
+    BigInteger y = dhKey.getY();
+
+    DERValue derP = new DERValue(DER.INTEGER, p);
+    DERValue derG = new DERValue(DER.INTEGER, g);
+    DERValue derQ = new DERValue(DER.INTEGER, q);
+
+    ArrayList params = new ArrayList(3);
+    params.add(derP);
+    params.add(derG);
+    params.add(derQ);
+    DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+
+    ArrayList algorithmID = new ArrayList(2);
+    algorithmID.add(derOID);
+    algorithmID.add(derParams);
+    DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                           algorithmID);
+
+    DERValue derDHPublicKey = new DERValue(DER.INTEGER, y);
+    byte[] yBytes = derDHPublicKey.getEncoded();
+    DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes));
+
+    ArrayList spki = new ArrayList(2);
+    spki.add(derAlgorithmID);
+    spki.add(derSPK);
+    DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki);
+
+    byte[] result;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try
+      {
+        DERWriter.write(baos, derSPKI);
+        result = baos.toByteArray();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException e = new InvalidParameterException();
+        e.initCause(x);
+        throw e;
+      }
+
+    return result;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    throw new InvalidParameterException("Wrong format for private keys");
+  }
+
+  /**
+   * @param input the byte array to unmarshall into a valid DH
+   *          {@link PublicKey} instance. MUST NOT be null.
+   * @return a new instance of a {@link GnuDHPublicKey} decoded from the
+   *         <i>SubjectPublicKeyInfo</i> material in an X.509 certificate.
+   * @throw InvalidParameterException if an exception occurs during the
+   *        unmarshalling process.
+   */
+  public PublicKey decodePublicKey(byte[] input)
+  {
+    if (input == null)
+      throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+    BigInteger p, g, q, y;
+    DERReader der = new DERReader(input);
+    try
+      {
+        DERValue derSPKI = der.read();
+        DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field");
+
+        DERValue derAlgorithmID = der.read();
+        DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field");
+
+        DERValue derOID = der.read();
+        if (! (derOID.getValue() instanceof OID))
+          throw new InvalidParameterException("Wrong Algorithm field");
+
+        OID algOID = (OID) derOID.getValue();
+        if (! algOID.equals(DH_ALG_OID))
+          throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+        DERValue derParams = der.read();
+        DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field");
+
+        DERValue val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong P field");
+        p = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong G field");
+        g = (BigInteger) val.getValue();
+        val = der.read();
+        DerUtil.checkIsBigInteger(val, "Wrong Q field");
+        q = (BigInteger) val.getValue();
+        if (q.compareTo(BigInteger.ZERO) == 0)
+          q = null;
+
+        val = der.read();
+        if (! (val.getValue() instanceof BitString))
+          throw new InvalidParameterException("Wrong SubjectPublicKey field");
+
+        byte[] yBytes = ((BitString) val.getValue()).toByteArray();
+
+        DERReader dhPub = new DERReader(yBytes);
+        val = dhPub.read();
+        DerUtil.checkIsBigInteger(val, "Wrong Y field");
+        y = (BigInteger) val.getValue();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException e = new InvalidParameterException();
+        e.initCause(x);
+        throw e;
+      }
+
+    return new GnuDHPublicKey(Registry.X509_ENCODING_ID, q, p, g, y);
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public PrivateKey decodePrivateKey(byte[] input)
+  {
+    throw new InvalidParameterException("Wrong format for private keys");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,119 @@
+/* DiffieHellmanKeyAgreement.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.BaseKeyAgreementParty;
+import gnu.javax.crypto.key.KeyAgreementException;
+
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * The basic version of the Diffie-Hellman key agreement is described in the
+ * Handbook of Applied Cryptography [HAC] as follows:
+ * <ul>
+ * <li>An appropriate prime p and generator g of Z<sub>p</sub><sup>*</sup>
+ * (2 &lt;= g &lt;= p-2) are selected and published.</li>
+ * <li>A and B each send the other one message over an open channel; as a
+ * result, they both can then compute a shared secret key K which they can use
+ * to protect their future communication.</li>
+ * <li>A chooses a random secret x, 1 &lt;= x &lt;= p-2, and sends B message
+ * (1) which is g^x mod p.</li>
+ * <li>B chooses a random secret y, 1 &lt;= y &lt;= p-2, and sends A message
+ * (2) which is g^y mod p.</li>
+ * <li>B receives message (1) and computes the shared key as K = (g^x)^y mod p.
+ * </li>
+ * <li>A receives message (2) and computes the shared key as K = (g^y)^x mod p.
+ * </li>
+ * </ul>
+ * <p>
+ * RFC-2631 describes a <i>Static-Static Mode</i> of operations with
+ * Diffie-Hellman keypairs as follows:
+ * <pre>
+ *  &quot;In Static-Static mode, both the sender and the recipient have a
+ *  static (and certified) key pair. Since the sender's and recipient's
+ *  keys are therefore the same for each message, ZZ will be the same for
+ *  each message. Thus, partyAInfo MUST be used (and different for each
+ *  message) in order to ensure that different messages use different
+ *  KEKs. Implementations MAY implement Static-Static mode.&quot;
+ * </pre>
+ * 
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+public abstract class DiffieHellmanKeyAgreement
+    extends BaseKeyAgreementParty
+{
+  public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.ka.prng";
+  public static final String KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY =
+      "gnu.crypto.dh.ka.owner.private.key";
+  /** The key agreement party's private key. */
+  protected DHPrivateKey ownerKey;
+  /** The shared secret key. */
+  protected BigInteger ZZ;
+
+  protected DiffieHellmanKeyAgreement()
+  {
+    super(Registry.DH_KA);
+  }
+
+  protected byte[] engineSharedSecret() throws KeyAgreementException
+  {
+    return Util.trim(ZZ);
+  }
+
+  protected void engineReset()
+  {
+    ownerKey = null;
+    ZZ = null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,117 @@
+/* DiffieHellmanReceiver.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.prng.IRandom;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * This implementation is the receiver's part of the basic version of the
+ * Diffie-Hellman key agreement exchange (B in [HAC]).
+ * 
+ * @see DiffieHellmanKeyAgreement
+ */
+public class DiffieHellmanReceiver
+    extends DiffieHellmanKeyAgreement
+{
+  private BigInteger y; // the receiver's random secret
+
+  // default 0-arguments constructor
+
+  protected void engineInit(Map attributes) throws KeyAgreementException
+  {
+    Object random = attributes.get(SOURCE_OF_RANDOMNESS);
+    rnd = null;
+    irnd = null;
+    if (random instanceof SecureRandom)
+      rnd = (SecureRandom) random;
+    else if (random instanceof IRandom)
+      irnd = (IRandom) random;
+    ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY);
+    if (ownerKey == null)
+      throw new KeyAgreementException("missing owner's private key");
+  }
+
+  protected OutgoingMessage engineProcessMessage(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    switch (step)
+      {
+      case 0:
+        return computeSharedSecret(in);
+      default:
+        throw new IllegalStateException("unexpected state");
+      }
+  }
+
+  private OutgoingMessage computeSharedSecret(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    BigInteger m1 = in.readMPI();
+    if (m1 == null)
+      throw new KeyAgreementException("missing message (1)");
+    BigInteger p = ownerKey.getParams().getP();
+    BigInteger g = ownerKey.getParams().getG();
+    // B chooses a random integer y, 1 <= y <= p-2
+    // rfc-2631 restricts y to only be in [2, p-1]
+    BigInteger p_minus_2 = p.subtract(TWO);
+    byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8];
+    do
+      {
+        nextRandomBytes(xBytes);
+        y = new BigInteger(1, xBytes);
+      }
+    while (! (y.compareTo(TWO) >= 0 && y.compareTo(p_minus_2) <= 0));
+    ZZ = m1.modPow(y, p); // ZZ = (yb ^ xa) mod p
+    complete = true;
+    // B sends A the message: g^y mod p
+    OutgoingMessage result = new OutgoingMessage();
+    result.writeMPI(g.modPow(y, p)); // message (2)
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/DiffieHellmanSender.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,126 @@
+/* DiffieHellmanSender.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.prng.IRandom;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * This implementation is the sender's part of the basic version of the
+ * Diffie-Hellman key agreement exchange (A in [HAC]).
+ * 
+ * @see DiffieHellmanKeyAgreement
+ */
+public class DiffieHellmanSender
+    extends DiffieHellmanKeyAgreement
+{
+  private BigInteger x; // the sender's random secret
+
+  // default 0-arguments constructor
+
+  protected void engineInit(Map attributes) throws KeyAgreementException
+  {
+    Object random = attributes.get(SOURCE_OF_RANDOMNESS);
+    rnd = null;
+    irnd = null;
+    if (random instanceof SecureRandom)
+      rnd = (SecureRandom) random;
+    else if (random instanceof IRandom)
+      irnd = (IRandom) random;
+    ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY);
+    if (ownerKey == null)
+      throw new KeyAgreementException("missing owner's private key");
+  }
+
+  protected OutgoingMessage engineProcessMessage(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    switch (step)
+      {
+      case 0:
+        return sendRandomSecret(in);
+      case 1:
+        return computeSharedSecret(in);
+      default:
+        throw new IllegalStateException("unexpected state");
+      }
+  }
+
+  private OutgoingMessage sendRandomSecret(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    BigInteger p = ownerKey.getParams().getP();
+    BigInteger g = ownerKey.getParams().getG();
+    // A chooses a random integer x, 1 <= x <= p-2
+    // rfc-2631 restricts x to only be in [2, p-1]
+    BigInteger p_minus_2 = p.subtract(TWO);
+    byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8];
+    do
+      {
+        nextRandomBytes(xBytes);
+        x = new BigInteger(1, xBytes);
+      }
+    while (! (x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0));
+    // A sends B the message: g^x mod p
+    OutgoingMessage result = new OutgoingMessage();
+    result.writeMPI(g.modPow(x, p));
+    return result;
+  }
+
+  private OutgoingMessage computeSharedSecret(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    BigInteger m1 = in.readMPI();
+    if (m1 == null)
+      throw new KeyAgreementException("missing message (2)");
+    BigInteger p = ownerKey.getParams().getP();
+    ZZ = m1.modPow(x, p); // ZZ = (yb ^ xa) mod p
+    complete = true;
+    return null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,115 @@
+/* ElGamalKeyAgreement.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.BaseKeyAgreementParty;
+import gnu.javax.crypto.key.KeyAgreementException;
+
+import java.math.BigInteger;
+
+/**
+ * The ElGamal key agreement, also known as the half-certified Diffie-Hellman
+ * key agreement, is described in the Handbook of Applied Cryptography [HAC] as
+ * follows:
+ * <ul>
+ * <li>A sends to B a single message allowing one-pass key agreement.</li>
+ * <li>A obtains an authentic copy of B's public key (p, g, yb), where yb =
+ * g**xb.</li>
+ * <li>A chooses a random integer x, 1 &lt;= x &lt;= p-2, and sends B the
+ * message g**x. A computes the shared secret key K as yb**x.</li>
+ * <li>B computes the same key K on receipt of the previous message as
+ * (g**x)**xb.</li>
+ * </ul>
+ * <p>
+ * RFC-2631 describes an <i>Ephemeral-Static Mode</i> of operations with
+ * Diffie-Hellman keypairs as follows:
+ * <pre>
+ *  &quot;In Ephemeral-Static mode, the recipient has a static (and certified)
+ *  key pair, but the sender generates a new key pair for each message
+ *  and sends it using the originatorKey production. If the sender's key
+ *  is freshly generated for each message, the shared secret ZZ will be
+ *  similarly different for each message and partyAInfo MAY be omitted,
+ *  since it serves merely to decouple multiple KEKs generated by the
+ *  same set of pairwise keys. If, however, the same ephemeral sender key
+ *  is used for multiple messages (e.g. it is cached as a performance
+ *  optimization) then a separate partyAInfo MUST be used for each
+ *  message. All implementations of this standard MUST implement
+ *  Ephemeral-Static mode.&quot;
+ * </pre>
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+public abstract class ElGamalKeyAgreement
+    extends BaseKeyAgreementParty
+{
+  public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.elgamal.ka.prng";
+  public static final String KA_ELGAMAL_RECIPIENT_PRIVATE_KEY =
+      "gnu.crypto.elgamal.ka.recipient.private.key";
+  public static final String KA_ELGAMAL_RECIPIENT_PUBLIC_KEY =
+      "gnu.crypto.elgamal.ka.recipient.public.key";
+  /** The shared secret key. */
+  protected BigInteger ZZ;
+
+  protected ElGamalKeyAgreement()
+  {
+    super(Registry.ELGAMAL_KA);
+  }
+
+  protected byte[] engineSharedSecret() throws KeyAgreementException
+  {
+    return Util.trim(ZZ);
+  }
+
+  protected void engineReset()
+  {
+    ZZ = null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/ElGamalReceiver.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,99 @@
+/* ElGamalReceiver.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * This implementation is the receiver's part of the ElGamal key agreement
+ * exchange (B in [HAC]).
+ * 
+ * @see ElGamalKeyAgreement
+ */
+public class ElGamalReceiver
+    extends ElGamalKeyAgreement
+{
+  /** The recipient's private key. */
+  private DHPrivateKey B;
+
+  // default 0-arguments constructor
+
+  protected void engineInit(Map attributes) throws KeyAgreementException
+  {
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    // One-time setup (key generation and publication). Each user B generates
+    // a keypair and publishes its public key
+    B = (DHPrivateKey) attributes.get(KA_ELGAMAL_RECIPIENT_PRIVATE_KEY);
+    if (B == null)
+      throw new KeyAgreementException("missing recipient private key");
+  }
+
+  protected OutgoingMessage engineProcessMessage(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    switch (step)
+      {
+      case 0:
+        return computeSharedSecret(in);
+      default:
+        throw new IllegalStateException("unexpected state");
+      }
+  }
+
+  private OutgoingMessage computeSharedSecret(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    // (b) B computes the same key on receipt of message (1) as
+    // K = (g^x)^xb mod p
+    BigInteger m1 = in.readMPI();
+    if (m1 == null)
+      throw new KeyAgreementException("missing message (1)");
+    ZZ = m1.modPow(B.getX(), B.getParams().getP()); // ZZ = (ya ^ xb) mod p
+    complete = true;
+    return null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/ElGamalSender.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,112 @@
+/* ElGamalSender.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.crypto.interfaces.DHPublicKey;
+
+/**
+ * This implementation is the sender's part of the ElGamal key agreement
+ * exchange (A in [HAC]).
+ * 
+ * @see ElGamalKeyAgreement
+ */
+public class ElGamalSender
+    extends ElGamalKeyAgreement
+{
+  /** The recipient's public key. */
+  private DHPublicKey B;
+
+  // default 0-arguments constructor
+
+  protected void engineInit(Map attributes) throws KeyAgreementException
+  {
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    // One-time setup (key generation and publication). Each user B generates
+    // a keypair and publishes its public key
+    B = (DHPublicKey) attributes.get(KA_ELGAMAL_RECIPIENT_PUBLIC_KEY);
+    if (B == null)
+      throw new KeyAgreementException("missing recipient public key");
+  }
+
+  protected OutgoingMessage engineProcessMessage(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    switch (step)
+      {
+      case 0:
+        return computeSharedSecret(in);
+      default:
+        throw new IllegalStateException("unexpected state");
+      }
+  }
+
+  private OutgoingMessage computeSharedSecret(IncomingMessage in)
+      throws KeyAgreementException
+  {
+    BigInteger p = B.getParams().getP();
+    BigInteger g = B.getParams().getG();
+    BigInteger yb = B.getY();
+    // A chooses a random integer x, 1 <= x <= p-2
+    // rfc-2631 restricts x to only be in [2, p-1]
+    BigInteger p_minus_2 = p.subtract(TWO);
+    byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8];
+    BigInteger x;
+    do
+      {
+        nextRandomBytes(xBytes);
+        x = new BigInteger(1, xBytes);
+      }
+    while (x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0);
+    // A sends B the message: g^x mod p
+    OutgoingMessage result = new OutgoingMessage();
+    result.writeMPI(g.modPow(x, p));
+    // A computes the key as K = (yb)^x mod p
+    ZZ = yb.modPow(x, p); // ZZ = (yb ^ xa) mod p
+    complete = true;
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/GnuDHKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,174 @@
+/* GnuDHKey.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.util.FormatUtil;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.Key;
+
+import javax.crypto.interfaces.DHKey;
+import javax.crypto.spec.DHParameterSpec;
+
+/**
+ * A base asbtract class for both public and private Diffie-Hellman keys. It
+ * encapsulates the two DH numbers: <code>p</code>, and <code>g</code>.
+ * <p>
+ * According to the JDK, cryptographic <i>Keys</i> all have a <i>format</i>.
+ * The format used in this implementation is called <i>Raw</i>, and basically
+ * consists of the raw byte sequences of algorithm parameters. The exact order
+ * of the byte sequences and the implementation details are given in each of the
+ * relevant <code>getEncoded()</code> methods of each of the private and
+ * public keys.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public abstract class GnuDHKey
+    implements Key, DHKey
+{
+  /** The public prime q. A prime divisor of p-1. */
+  protected BigInteger q;
+  /** The public prime p. */
+  protected BigInteger p;
+  /** The generator g. */
+  protected BigInteger g;
+  /**
+   * Identifier of the default encoding format to use when externalizing the key
+   * material.
+   */
+  protected final int defaultFormat;
+  /** String representation of this key. Cached for speed. */
+  private transient String str;
+
+  /**
+   * Trivial protected constructor.
+   * 
+   * @param defaultFormat the identifier of the encoding format to use by
+   *          default when externalizing the key.
+   * @param q a prime divisor of p-1.
+   * @param p the public prime.
+   * @param g the generator of the group.
+   */
+  protected GnuDHKey(int defaultFormat, BigInteger q, BigInteger p, BigInteger g)
+  {
+    super();
+
+    this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID
+                                            : defaultFormat;
+    this.q = q;
+    this.p = p;
+    this.g = g;
+  }
+
+  public DHParameterSpec getParams()
+  {
+    if (q == null)
+      return new DHParameterSpec(p, g);
+    return new DHParameterSpec(p, g, q.bitLength());
+  }
+
+  public String getAlgorithm()
+  {
+    return Registry.DH_KPG;
+  }
+
+  /** @deprecated see getEncoded(int). */
+  public byte[] getEncoded()
+  {
+    return getEncoded(defaultFormat);
+  }
+
+  public String getFormat()
+  {
+    return FormatUtil.getEncodingShortName(defaultFormat);
+  }
+
+  public BigInteger getQ()
+  {
+    return q;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * {@link DHKey} and has the same Diffie-Hellman parameter values as this one.
+   * 
+   * @param obj the other non-null DH key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(Object obj)
+  {
+    if (obj == null)
+      return false;
+    if (! (obj instanceof DHKey))
+      return false;
+    DHKey that = (DHKey) obj;
+    return p.equals(that.getParams().getP())
+           && g.equals(that.getParams().getG());
+  }
+
+  public String toString()
+  {
+    if (str == null)
+      {
+        String ls = (String) AccessController.doPrivileged
+            (new GetPropertyAction("line.separator"));
+        StringBuilder sb = new StringBuilder(ls)
+            .append("defaultFormat=").append(defaultFormat).append(",").append(ls);
+        if (q == null)
+          sb.append("q=null,");
+        else
+          sb.append("q=0x").append(q.toString(16)).append(",");
+        sb.append(ls).append("p=0x").append(p.toString(16)).append(",").append(ls)
+            .append("g=0x").append(g.toString(16));
+        str = sb.toString();
+      }
+    return str;
+  }
+
+  public abstract byte[] getEncoded(int format);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,235 @@
+/* GnuDHKeyPairGenerator.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+/**
+ * An implementation of a Diffie-Hellman keypair generator.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public class GnuDHKeyPairGenerator
+    implements IKeyPairGenerator
+{
+  private static final Logger log = Logger.getLogger(GnuDHKeyPairGenerator.class.getName());
+  /**
+   * Property name of an optional {@link SecureRandom} instance to use. The
+   * default is to use a classloader singleton from {@link PRNG}.
+   */
+  public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.prng";
+  /**
+   * Property name of an optional {@link DHGenParameterSpec} or
+   * {@link DHParameterSpec} instance to use for this generator.
+   */
+  public static final String DH_PARAMETERS = "gnu.crypto.dh.params";
+  /** Property name of the size in bits (Integer) of the public prime (p). */
+  public static final String PRIME_SIZE = "gnu.crypto.dh.L";
+  /** Property name of the size in bits (Integer) of the private exponent (x). */
+  public static final String EXPONENT_SIZE = "gnu.crypto.dh.m";
+  /**
+   * Property name of the preferred encoding format to use when externalizing
+   * generated instance of key-pairs from this generator. The property is taken
+   * to be an {@link Integer} that encapsulates an encoding format identifier.
+   */
+  public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dh.encoding";
+  /** Default value for the size in bits of the public prime (p). */
+  public static final int DEFAULT_PRIME_SIZE = 512;
+  /** Default value for the size in bits of the private exponent (x). */
+  public static final int DEFAULT_EXPONENT_SIZE = 160;
+  /** Default encoding format to use when none was specified. */
+  private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
+  /** The SHA instance to use. */
+  private Sha160 sha = new Sha160();
+  /** The optional {@link SecureRandom} instance to use. */
+  private SecureRandom rnd = null;
+  /** The desired size in bits of the public prime (p). */
+  private int l;
+  /** The desired size in bits of the private exponent (x). */
+  private int m;
+  private BigInteger seed;
+  private BigInteger counter;
+  private BigInteger q;
+  private BigInteger p;
+  private BigInteger j;
+  private BigInteger g;
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+  /** Preferred encoding format of generated keys. */
+  private int preferredFormat;
+
+  // default 0-arguments constructor
+
+  public String name()
+  {
+    return Registry.DH_KPG;
+  }
+
+  public void setup(Map attributes)
+  {
+    // do we have a SecureRandom, or should we use our own?
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    // are we given a set of Diffie-Hellman generation parameters or we shall
+    // use our own?
+    Object params = attributes.get(DH_PARAMETERS);
+    // find out the desired sizes
+    if (params instanceof DHGenParameterSpec)
+      {
+        DHGenParameterSpec jceSpec = (DHGenParameterSpec) params;
+        l = jceSpec.getPrimeSize();
+        m = jceSpec.getExponentSize();
+      }
+    else if (params instanceof DHParameterSpec)
+      {
+        // FIXME: I'm not sure this is correct. It seems to behave the
+        // same way as Sun's RI, but I don't know if this behavior is
+        // documented anywhere.
+        DHParameterSpec jceSpec = (DHParameterSpec) params;
+        p = jceSpec.getP();
+        g = jceSpec.getG();
+        l = p.bitLength();
+        m = jceSpec.getL();
+        // If no exponent size was given, generate an exponent as
+        // large as the prime.
+        if (m == 0)
+          m = l;
+      }
+    else
+      {
+        Integer bi = (Integer) attributes.get(PRIME_SIZE);
+        l = (bi == null ? DEFAULT_PRIME_SIZE : bi.intValue());
+        bi = (Integer) attributes.get(EXPONENT_SIZE);
+        m = (bi == null ? DEFAULT_EXPONENT_SIZE : bi.intValue());
+      }
+    if ((l % 256) != 0 || l < DEFAULT_PRIME_SIZE)
+      throw new IllegalArgumentException("invalid modulus size");
+    if ((m % 8) != 0 || m < DEFAULT_EXPONENT_SIZE)
+      throw new IllegalArgumentException("invalid exponent size");
+    if (m > l)
+      throw new IllegalArgumentException("exponent size > modulus size");
+    // what is the preferred encoding format
+    Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
+    preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
+                                       : formatID.intValue();
+  }
+
+  public KeyPair generate()
+  {
+    if (p == null)
+      {
+        BigInteger[] params = new RFC2631(m, l, rnd).generateParameters();
+        seed = params[RFC2631.DH_PARAMS_SEED];
+        counter = params[RFC2631.DH_PARAMS_COUNTER];
+        q = params[RFC2631.DH_PARAMS_Q];
+        p = params[RFC2631.DH_PARAMS_P];
+        j = params[RFC2631.DH_PARAMS_J];
+        g = params[RFC2631.DH_PARAMS_G];
+        if (Configuration.DEBUG)
+          {
+            log.fine("seed: 0x" + seed.toString(16));
+            log.fine("counter: " + counter.intValue());
+            log.fine("q: 0x" + q.toString(16));
+            log.fine("p: 0x" + p.toString(16));
+            log.fine("j: 0x" + j.toString(16));
+            log.fine("g: 0x" + g.toString(16));
+          }
+      }
+    // generate a private number x of length m such as: 1 < x < q - 1
+    BigInteger q_minus_1 = null;
+    if (q != null)
+      q_minus_1 = q.subtract(BigInteger.ONE);
+    // We already check if m is modulo 8 in `setup.' This could just
+    // be m >>> 3.
+    byte[] mag = new byte[(m + 7) / 8];
+    BigInteger x;
+    while (true)
+      {
+        nextRandomBytes(mag);
+        x = new BigInteger(1, mag);
+        if (x.bitLength() == m && x.compareTo(BigInteger.ONE) > 0
+            && (q_minus_1 == null || x.compareTo(q_minus_1) < 0))
+          break;
+      }
+    BigInteger y = g.modPow(x, p);
+    PrivateKey secK = new GnuDHPrivateKey(preferredFormat, q, p, g, x);
+    PublicKey pubK = new GnuDHPublicKey(preferredFormat, q, p, g, y);
+    return new KeyPair(pubK, secK);
+  }
+
+  /**
+   * Fills the designated byte array with random data.
+   * 
+   * @param buffer the byte array to fill with random data.
+   */
+  private void nextRandomBytes(byte[] buffer)
+  {
+    if (rnd != null)
+      rnd.nextBytes(buffer);
+    else
+      getDefaultPRNG().nextBytes(buffer);
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,200 @@
+/* GnuDHPrivateKey.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * An implementation of the Diffie-Hellman private key.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public class GnuDHPrivateKey
+    extends GnuDHKey
+    implements DHPrivateKey
+{
+  /** The private exponent. */
+  private final BigInteger x;
+  /** String representation of this key. Cached for speed. */
+  private transient String str;
+
+  /**
+   * Convenience constructor. Calls the constructor with five arguments passing
+   * {@link Registry#RAW_ENCODING_ID} as the value of its first argument.
+   * 
+   * @param q a prime divisor of p-1.
+   * @param p the public prime.
+   * @param g the generator of the group.
+   * @param x the private value x.
+   */
+  public GnuDHPrivateKey(BigInteger q, BigInteger p, BigInteger g, BigInteger x)
+  {
+    this(Registry.RAW_ENCODING_ID, q, p, g, x);
+  }
+
+  /**
+   * Constructs a new instance of <code>GnuDHPrivateKey</code> given the
+   * designated parameters.
+   * 
+   * @param preferredFormat the identifier of the encoding format to use by
+   *          default when externalizing the key.
+   * @param q a prime divisor of p-1.
+   * @param p the public prime.
+   * @param g the generator of the group.
+   * @param x the private value x.
+   */
+  public GnuDHPrivateKey(int preferredFormat, BigInteger q, BigInteger p,
+                         BigInteger g, BigInteger x)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID
+                                                       : preferredFormat,
+          q, p, g);
+    this.x = x;
+  }
+
+  /**
+   * A class method that takes the output of the <code>encodePrivateKey()</code>
+   * method of a DH keypair codec object (an instance implementing
+   * {@link IKeyPairCodec} for DH keys, and re-constructs an instance of this
+   * object.
+   * 
+   * @param k the contents of a previously encoded instance of this object.
+   * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
+   *              <code>k</code>, to represent a valid encoding of an
+   *              instance of this object.
+   * @exception IllegalArgumentException if the byte sequence does not represent
+   *              a valid encoding of an instance of this object.
+   */
+  public static GnuDHPrivateKey valueOf(byte[] k)
+  {
+    // try RAW codec
+    if (k[0] == Registry.MAGIC_RAW_DH_PRIVATE_KEY[0])
+      try
+        {
+          return (GnuDHPrivateKey) new DHKeyPairRawCodec().decodePrivateKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+    // try PKCS#8 codec
+    return (GnuDHPrivateKey) new DHKeyPairPKCS8Codec().decodePrivateKey(k);
+  }
+
+  public BigInteger getX()
+  {
+    return x;
+  }
+
+  /**
+   * Returns the encoded form of this private key according to the designated
+   * format.
+   * 
+   * @param format the desired format identifier of the resulting encoding.
+   * @return the byte sequence encoding this key according to the designated
+   *         format.
+   * @exception IllegalArgumentException if the format is not supported.
+   * @see DHKeyPairRawCodec
+   */
+  public byte[] getEncoded(int format)
+  {
+    byte[] result;
+    switch (format)
+      {
+      case IKeyPairCodec.RAW_FORMAT:
+        result = new DHKeyPairRawCodec().encodePrivateKey(this);
+        break;
+      case IKeyPairCodec.PKCS8_FORMAT:
+        result = new DHKeyPairPKCS8Codec().encodePrivateKey(this);
+        break;
+      default:
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
+      }
+    return result;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * {@link DHPrivateKey} and has the same parameter values as this one.
+   * 
+   * @param obj the other non-null DH key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(Object obj)
+  {
+    if (obj == null)
+      return false;
+
+    if (! (obj instanceof DHPrivateKey))
+      return false;
+
+    DHPrivateKey that = (DHPrivateKey) obj;
+    return super.equals(that) && x.equals(that.getX());
+  }
+
+  public String toString()
+  {
+    if (str == null)
+      {
+        String ls = (String) AccessController.doPrivileged
+            (new GetPropertyAction("line.separator"));
+        str = new StringBuilder(this.getClass().getName()).append("(")
+            .append(super.toString()).append(",").append(ls)
+            .append("x=0x").append(Configuration.DEBUG ? x.toString(16)
+                                                       : "**...*").append(ls)
+            .append(")")
+            .toString();
+      }
+    return str;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/GnuDHPublicKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,196 @@
+/* GnuDHPublicKey.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+
+import javax.crypto.interfaces.DHPublicKey;
+
+/**
+ * An implementation of the Diffie-Hellman public key.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public class GnuDHPublicKey
+    extends GnuDHKey
+    implements DHPublicKey
+{
+  private BigInteger y;
+  /** String representation of this key. Cached for speed. */
+  private transient String str;
+
+  /**
+   * Convenience constructor. Calls the constructor with five arguments passing
+   * {@link Registry#RAW_ENCODING_ID} as the value of its first argument.
+   * 
+   * @param q a prime divisor of p-1.
+   * @param p the public prime.
+   * @param g the generator of the group.
+   * @param y the public value y.
+   */
+  public GnuDHPublicKey(BigInteger q, BigInteger p, BigInteger g, BigInteger y)
+  {
+    this(Registry.RAW_ENCODING_ID, q, p, g, y);
+  }
+
+  /**
+   * Constructs a new instance of <code>GnuDHPublicKey</code> given the
+   * designated parameters.
+   * 
+   * @param preferredFormat the identifier of the encoding format to use by
+   *          default when externalizing the key.
+   * @param q a prime divisor of p-1.
+   * @param p the public prime.
+   * @param g the generator of the group.
+   * @param y the public value y.
+   */
+  public GnuDHPublicKey(int preferredFormat, BigInteger q, BigInteger p,
+                        BigInteger g, BigInteger y)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID
+                                                       : preferredFormat,
+          q, p, g);
+    this.y = y;
+  }
+
+  /**
+   * A class method that takes the output of the <code>encodePublicKey()</code>
+   * method of a DH keypair codec object (an instance implementing
+   * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this
+   * object.
+   * 
+   * @param k the contents of a previously encoded instance of this object.
+   * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
+   *              <code>k</code>, to represent a valid encoding of an
+   *              instance of this object.
+   * @exception IllegalArgumentException if the byte sequence does not represent
+   *              a valid encoding of an instance of this object.
+   */
+  public static GnuDHPublicKey valueOf(byte[] k)
+  {
+    // try RAW codec
+    if (k[0] == Registry.MAGIC_RAW_DH_PUBLIC_KEY[0])
+      try
+        {
+          return (GnuDHPublicKey) new DHKeyPairRawCodec().decodePublicKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+    // try X.509 codec
+    return (GnuDHPublicKey) new DHKeyPairX509Codec().decodePublicKey(k);
+  }
+
+  public BigInteger getY()
+  {
+    return y;
+  }
+
+  /**
+   * Returns the encoded form of this public key according to the designated
+   * format.
+   * 
+   * @param format the desired format identifier of the resulting encoding.
+   * @return the byte sequence encoding this key according to the designated
+   *         format.
+   * @exception IllegalArgumentException if the format is not supported.
+   */
+  public byte[] getEncoded(int format)
+  {
+    byte[] result;
+    switch (format)
+      {
+      case IKeyPairCodec.RAW_FORMAT:
+        result = new DHKeyPairRawCodec().encodePublicKey(this);
+        break;
+      case IKeyPairCodec.X509_FORMAT:
+        result = new DHKeyPairX509Codec().encodePublicKey(this);
+        break;
+      default:
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
+      }
+    return result;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * {@link DHPublicKey} and has the same parameter values as this one.
+   * 
+   * @param obj the other non-null DH key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(Object obj)
+  {
+    if (obj == null)
+      return false;
+
+    if (! (obj instanceof DHPublicKey))
+      return false;
+
+    DHPublicKey that = (DHPublicKey) obj;
+    return super.equals(that) && y.equals(that.getY());
+  }
+
+  public String toString()
+  {
+    if (str == null)
+      {
+        String ls = (String) AccessController.doPrivileged
+            (new GetPropertyAction("line.separator"));
+        str = new StringBuilder(this.getClass().getName()).append("(")
+            .append(super.toString()).append(",").append(ls)
+            .append("y=0x").append(y.toString(16)).append(ls)
+            .append(")")
+            .toString();
+      }
+    return str;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/dh/RFC2631.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,217 @@
+/* RFC2631.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.dh;
+
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * An implementation of the Diffie-Hellman parameter generation as defined in
+ * RFC-2631.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public class RFC2631
+{
+  public static final int DH_PARAMS_SEED = 0;
+  public static final int DH_PARAMS_COUNTER = 1;
+  public static final int DH_PARAMS_Q = 2;
+  public static final int DH_PARAMS_P = 3;
+  public static final int DH_PARAMS_J = 4;
+  public static final int DH_PARAMS_G = 5;
+  private static final BigInteger TWO = BigInteger.valueOf(2L);
+  /** The SHA instance to use. */
+  private Sha160 sha = new Sha160();
+  /** Length of private modulus and of q. */
+  private int m;
+  /** Length of public modulus p. */
+  private int L;
+  /** The optional {@link SecureRandom} instance to use. */
+  private SecureRandom rnd = null;
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+
+  public RFC2631(int m, int L, SecureRandom rnd)
+  {
+    super();
+
+    this.m = m;
+    this.L = L;
+    this.rnd = rnd;
+  }
+
+  public BigInteger[] generateParameters()
+  {
+    int i, j, counter;
+    byte[] u1, u2, v;
+    byte[] seedBytes = new byte[m / 8];
+    BigInteger SEED, U, q, R, V, W, X, p, g;
+    // start by genrating p and q, where q is of length m and p is of length L
+    // 1. Set m' = m/160 where / represents integer division with rounding
+    //    upwards. I.e. 200/160 = 2.
+    int m_ = (m + 159) / 160;
+    // 2. Set L'=  L/160
+    int L_ = (L + 159) / 160;
+    // 3. Set N'=  L/1024
+    int N_ = (L + 1023) / 1024;
+    algorithm: while (true)
+      {
+        step4: while (true)
+          {
+            // 4. Select an arbitrary bit string SEED such that length of
+            //    SEED >= m
+            nextRandomBytes(seedBytes);
+            SEED = new BigInteger(1, seedBytes).setBit(m - 1).setBit(0);
+            // 5. Set U = 0
+            U = BigInteger.ZERO;
+            // 6. For i = 0 to m' - 1
+            //    U = U + (SHA1[SEED + i] XOR SHA1[(SEED + m' + i)) * 2^(160 * i)
+            //    Note that for m=160, this reduces to the algorithm of FIPS-186
+            //    U = SHA1[SEED] XOR SHA1[(SEED+1) mod 2^160 ].
+            for (i = 0; i < m_; i++)
+              {
+                u1 = SEED.add(BigInteger.valueOf(i)).toByteArray();
+                u2 = SEED.add(BigInteger.valueOf(m_ + i)).toByteArray();
+                sha.update(u1, 0, u1.length);
+                u1 = sha.digest();
+                sha.update(u2, 0, u2.length);
+                u2 = sha.digest();
+                for (j = 0; j < u1.length; j++)
+                  u1[j] ^= u2[j];
+                U = U.add(new BigInteger(1, u1).multiply(TWO.pow(160 * i)));
+              }
+            // 5. Form q from U by computing U mod (2^m) and setting the most
+            //    significant bit (the 2^(m-1) bit) and the least significant
+            //    bit to 1. In terms of boolean operations, q = U OR 2^(m-1) OR
+            //    1. Note that 2^(m-1) < q < 2^m
+            q = U.setBit(m - 1).setBit(0);
+            // 6. Use a robust primality algorithm to test whether q is prime.
+            // 7. If q is not prime then go to 4.
+            if (q.isProbablePrime(80))
+              break step4;
+          }
+        // 8. Let counter = 0
+        counter = 0;
+        step9: while (true)
+          {
+            // 9. Set R = seed + 2*m' + (L' * counter)
+            R = SEED
+                .add(BigInteger.valueOf(2 * m_))
+                .add(BigInteger.valueOf(L_ * counter));
+            // 10. Set V = 0
+            V = BigInteger.ZERO;
+            // 12. For i = 0 to L'-1 do: V = V + SHA1(R + i) * 2^(160 * i)
+            for (i = 0; i < L_; i++)
+              {
+                v = R.toByteArray();
+                sha.update(v, 0, v.length);
+                v = sha.digest();
+                V = V.add(new BigInteger(1, v).multiply(TWO.pow(160 * i)));
+              }
+            // 13. Set W = V mod 2^L
+            W = V.mod(TWO.pow(L));
+            // 14. Set X = W OR 2^(L-1)
+            //     Note that 0 <= W < 2^(L-1) and hence X >= 2^(L-1)
+            X = W.setBit(L - 1);
+            // 15. Set p = X - (X mod (2*q)) + 1
+            p = X.add(BigInteger.ONE).subtract(X.mod(TWO.multiply(q)));
+            // 16. If p > 2^(L-1) use a robust primality test to test whether p
+            //     is prime. Else go to 18.
+            // 17. If p is prime output p, q, seed, counter and stop.
+            if (p.isProbablePrime(80))
+              {
+                break algorithm;
+              }
+            // 18. Set counter = counter + 1
+            counter++;
+            // 19. If counter < (4096 * N) then go to 8.
+            // 20. Output "failure"
+            if (counter >= 4096 * N_)
+              continue algorithm;
+          }
+      }
+    // compute g. from FIPS-186, Appendix 4:
+    // 1. Generate p and q as specified in Appendix 2.
+    // 2. Let e = (p - 1) / q
+    BigInteger e = p.subtract(BigInteger.ONE).divide(q);
+    BigInteger h = TWO;
+    BigInteger p_minus_1 = p.subtract(BigInteger.ONE);
+    g = TWO;
+    // 3. Set h = any integer, where 1 < h < p - 1 and h differs from any
+    //    value previously tried
+    for (; h.compareTo(p_minus_1) < 0; h = h.add(BigInteger.ONE))
+      {
+        // 4. Set g = h**e mod p
+        g = h.modPow(e, p);
+        // 5. If g = 1, go to step 3
+        if (! g.equals(BigInteger.ONE))
+          break;
+      }
+    return new BigInteger[] { SEED, BigInteger.valueOf(counter), q, p, e, g };
+  }
+
+  /**
+   * Fills the designated byte array with random data.
+   *
+   * @param buffer the byte array to fill with random data.
+   */
+  private void nextRandomBytes(byte[] buffer)
+  {
+    if (rnd != null)
+      rnd.nextBytes(buffer);
+    else
+      getDefaultPRNG().nextBytes(buffer);
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRP6Host.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,161 @@
+/* SRP6Host.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.sasl.srp.SRP;
+import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider;
+import gnu.javax.crypto.sasl.srp.SRPRegistry;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The implementation of the Host in the SRP-6 key agreement protocol.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRP6Host
+    extends SRP6KeyAgreement
+{
+  /** The user's ephemeral key pair. */
+  private KeyPair hostKeyPair;
+
+  /** The SRP password database. */
+  private SRPAuthInfoProvider passwordDB;
+
+  // default 0-arguments constructor
+
+  protected void engineInit(final Map attributes) throws KeyAgreementException
+  {
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    N = (BigInteger) attributes.get(SHARED_MODULUS);
+    if (N == null)
+      throw new KeyAgreementException("missing shared modulus");
+    g = (BigInteger) attributes.get(GENERATOR);
+    if (g == null)
+      throw new KeyAgreementException("missing generator");
+    final String md = (String) attributes.get(HASH_FUNCTION);
+    if (md == null || md.trim().length() == 0)
+      throw new KeyAgreementException("missing hash function");
+    srp = SRP.instance(md);
+    passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB);
+    if (passwordDB == null)
+      throw new KeyAgreementException("missing SRP password database");
+  }
+
+  protected OutgoingMessage engineProcessMessage(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    switch (step)
+      {
+      case 0:
+        return computeSharedSecret(in);
+      default:
+        throw new IllegalStateException("unexpected state");
+      }
+  }
+
+  protected void engineReset()
+  {
+    hostKeyPair = null;
+    super.engineReset();
+  }
+
+  private OutgoingMessage computeSharedSecret(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    final String I = in.readString();
+    final BigInteger A = in.readMPI();
+    // get s and v for user identified by I
+    // ----------------------------------------------------------------------
+    final Map credentials;
+    try
+      {
+        final Map userID = new HashMap();
+        userID.put(Registry.SASL_USERNAME, I);
+        userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm());
+        credentials = passwordDB.lookup(userID);
+      }
+    catch (IOException x)
+      {
+        throw new KeyAgreementException("computeSharedSecret()", x);
+      }
+    final BigInteger s = new BigInteger(
+        1,Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD)));
+    final BigInteger v = new BigInteger(
+        1, Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD)));
+    final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
+    final Map attributes = new HashMap();
+    if (rnd != null)
+      attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
+    attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+    attributes.put(SRPKeyPairGenerator.GENERATOR, g);
+    attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v);
+    kpg.setup(attributes);
+    hostKeyPair = kpg.generate();
+    final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY();
+    final BigInteger u = uValue(A, B); // u = H(A | B)
+    // compute S = (Av^u) ^ b
+    final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX();
+    final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N);
+    final byte[] sBytes = Util.trim(S);
+    final IMessageDigest hash = srp.newDigest();
+    hash.update(sBytes, 0, sBytes.length);
+    K = new BigInteger(1, hash.digest());
+    final OutgoingMessage result = new OutgoingMessage();
+    result.writeMPI(s);
+    result.writeMPI(B);
+    complete = true;
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,141 @@
+/* SRP6KeyAgreement.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.BaseKeyAgreementParty;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.sasl.srp.SRP;
+
+import java.math.BigInteger;
+
+/**
+ * The Secure Remote Password (SRP) key agreement protocol, also known as SRP-6,
+ * is designed by Thomas J. Wu (see references). The protocol, and its elements
+ * are described as follows:
+ * <pre>
+ *  N    A large safe prime (N = 2q+1, where q is prime)
+ *       All arithmetic is done modulo N.
+ *  g    A generator modulo N
+ *  s    User's salt
+ *  I    Username
+ *  p    Cleartext Password
+ *  H()  One-way hash function
+ *  &circ;    (Modular) Exponentiation
+ *  u    Random scrambling parameter
+ *  a,b  Secret ephemeral values
+ *  A,B  Public ephemeral values
+ *  x    Private key (derived from p and s)
+ *  v    Password verifier
+ * 
+ *  The host stores passwords using the following formula:
+ *  x = H(s | H(I &quot;:&quot; p))           (s is chosen randomly)
+ *  v = g&circ;x                         (computes password verifier)
+ * 
+ *  The host then keeps {I, s, v} in its password database.
+ * 
+ *  The authentication protocol itself goes as follows:
+ *  User -&gt; Host:  I, A = g&circ;a         (identifies self, a = random number)
+ *  Host -&gt; User:  s, B = 3v + g&circ;b    (sends salt, b = random number)
+ * 
+ *  Both:  u = H(A, B)
+ * 
+ *  User:  x = H(s, p)               (user enters password)
+ *  User:  S = (B - 3g&circ;x) &circ; (a + ux) (computes session key)
+ *  User:  K = H(S)
+ * 
+ *  Host:  S = (Av&circ;u) &circ; b            (computes session key)
+ *  Host:  K = H(S)
+ * </pre>
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public abstract class SRP6KeyAgreement
+    extends BaseKeyAgreementParty
+{
+  public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp6.ka.prng";
+  public static final String SHARED_MODULUS = "gnu.crypto.srp6.ka.N";
+  public static final String GENERATOR = "gnu.crypto.srp6.ka.g";
+  public static final String HASH_FUNCTION = "gnu.crypto.srp6.ka.H";
+  public static final String USER_IDENTITY = "gnu.crypto.srp6.ka.I";
+  public static final String USER_PASSWORD = "gnu.crypto.srp6.ka.p";
+  public static final String HOST_PASSWORD_DB = "gnu.crypto.srp6.ka.password.db";
+  protected static final BigInteger THREE = BigInteger.valueOf(3L);
+  protected SRP srp;
+  protected BigInteger N;
+  protected BigInteger g;
+  /** The shared secret key. */
+  protected BigInteger K;
+
+  protected SRP6KeyAgreement()
+  {
+    super(Registry.SRP6_KA);
+  }
+
+  protected byte[] engineSharedSecret() throws KeyAgreementException
+  {
+    return Util.trim(K);
+  }
+
+  protected void engineReset()
+  {
+    srp = null;
+    N = null;
+    g = null;
+    K = null;
+  }
+
+  protected BigInteger uValue(final BigInteger A, final BigInteger B)
+  {
+    final IMessageDigest hash = srp.newDigest();
+    byte[] b;
+    b = Util.trim(A);
+    hash.update(b, 0, b.length);
+    b = Util.trim(B);
+    hash.update(b, 0, b.length);
+    return new BigInteger(1, hash.digest());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRP6SaslClient.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,90 @@
+/* SRP6SaslClient.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+
+/**
+ * A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for the
+ * User (client side).
+ * <p>
+ * In this alternative, the exchange goes as follows:
+ * 
+ * <pre>
+ *     C -&gt; S:  I                      (identifies self)
+ *     S -&gt; C:  N, g, s, B = 3v + g&circ;b  (sends salt, b = random number)
+ *     C -&gt; S:  A = g&circ;a                (a = random number)
+ * </pre>
+ * 
+ * <p>
+ * All elements are computed the same way as in the standard version.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a><br>
+ * K. Burdis, R. Naffah.</li>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRP6SaslClient
+    extends SRP6TLSClient
+{
+  // default 0-arguments constructor
+
+  protected OutgoingMessage computeSharedSecret(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    final OutgoingMessage result = super.computeSharedSecret(in);
+    final byte[] sBytes = Util.trim(K);
+    final IMessageDigest hash = srp.newDigest();
+    hash.update(sBytes, 0, sBytes.length);
+    K = new BigInteger(1, hash.digest());
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRP6SaslServer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,90 @@
+/* SRP6SaslServer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+
+/**
+ * A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for the
+ * Host (server side).
+ * <p>
+ * In this alternative, the exchange goes as follows:
+ * 
+ * <pre>
+ *     C -&gt; S:  I                      (identifies self)
+ *     S -&gt; C:  N, g, s, B = 3v + g&circ;b  (sends salt, b = random number)
+ *     C -&gt; S:  A = g&circ;a                (a = random number)
+ * </pre>
+ * 
+ * <p>
+ * All elements are computed the same way as in the standard version.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a><br>
+ * K. Burdis, R. Naffah.</li>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRP6SaslServer
+    extends SRP6TLSServer
+{
+  // default 0-arguments constructor
+
+  protected OutgoingMessage computeSharedSecret(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    super.computeSharedSecret(in);
+    final byte[] sBytes = Util.trim(K);
+    final IMessageDigest hash = srp.newDigest();
+    hash.update(sBytes, 0, sBytes.length);
+    K = new BigInteger(1, hash.digest());
+    return null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRP6TLSClient.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,155 @@
+/* SRP6TLSClient.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.sasl.srp.SRP;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A variation of the SRP6 key agreement protocol, for the client-side as
+ * proposed in <a
+ * href="http://www.ietf.org/internet-drafts/draft-ietf-tls-srp-05.txt">Using
+ * SRP for TLS Authentication</a>. The only difference between it and the SASL
+ * variant is that the shared secret is the entity <code>S</code> and not
+ * <code>H(S)</code>.
+ */
+public class SRP6TLSClient
+    extends SRP6KeyAgreement
+{
+  /** The user's identity. */
+  private String I;
+  /** The user's cleartext password. */
+  private byte[] p;
+  /** The user's ephemeral key pair. */
+  private KeyPair userKeyPair;
+
+  // default 0-arguments constructor
+
+  protected void engineInit(final Map attributes) throws KeyAgreementException
+  {
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    final String md = (String) attributes.get(HASH_FUNCTION);
+    if (md == null || md.trim().length() == 0)
+      throw new KeyAgreementException("missing hash function");
+    srp = SRP.instance(md);
+    I = (String) attributes.get(USER_IDENTITY);
+    if (I == null)
+      throw new KeyAgreementException("missing user identity");
+    p = (byte[]) attributes.get(USER_PASSWORD);
+    if (p == null)
+      throw new KeyAgreementException("missing user password");
+  }
+
+  protected OutgoingMessage engineProcessMessage(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    switch (step)
+      {
+      case 0:
+        return sendIdentity(in);
+      case 1:
+        return computeSharedSecret(in);
+      default:
+        throw new IllegalStateException("unexpected state");
+      }
+  }
+
+  protected void engineReset()
+  {
+    I = null;
+    p = null;
+    userKeyPair = null;
+    super.engineReset();
+  }
+
+  private OutgoingMessage sendIdentity(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    final OutgoingMessage result = new OutgoingMessage();
+    result.writeString(I);
+    return result;
+  }
+
+  protected OutgoingMessage computeSharedSecret(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    N = in.readMPI();
+    g = in.readMPI();
+    final BigInteger s = in.readMPI();
+    final BigInteger B = in.readMPI();
+    // generate an ephemeral keypair
+    final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
+    final Map attributes = new HashMap();
+    if (rnd != null)
+      attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
+    attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+    attributes.put(SRPKeyPairGenerator.GENERATOR, g);
+    kpg.setup(attributes);
+    userKeyPair = kpg.generate();
+    final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY();
+    final BigInteger u = uValue(A, B); // u = H(A | B)
+    final BigInteger x;
+    try
+      {
+        x = new BigInteger(1, srp.computeX(Util.trim(s), I, p));
+      }
+    catch (Exception e)
+      {
+        throw new KeyAgreementException("computeSharedSecret()", e);
+      }
+    // compute S = (B - 3g^x) ^ (a + ux)
+    final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX();
+    final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N)))
+                          .modPow(a.add(u.multiply(x)), N);
+    K = S;
+    final OutgoingMessage result = new OutgoingMessage();
+    result.writeMPI(A);
+    complete = true;
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRP6TLSServer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,177 @@
+/* SRP6TLSServer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.sasl.srp.SRP;
+import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider;
+import gnu.javax.crypto.sasl.srp.SRPRegistry;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A variation of the SRP6 key agreement protocol, for the server-side as
+ * proposed in <a
+ * href="http://www.ietf.org/internet-drafts/draft-ietf-tls-srp-05.txt">Using
+ * SRP for TLS Authentication</a>. The only difference between it and the SASL
+ * variant is that the shared secret is the entity <code>S</code> and not
+ * <code>H(S)</code>.
+ */
+public class SRP6TLSServer
+    extends SRP6KeyAgreement
+{
+  /** The user's ephemeral key pair. */
+  private KeyPair hostKeyPair;
+  /** The SRP password database. */
+  private SRPAuthInfoProvider passwordDB;
+
+  // default 0-arguments constructor
+
+  protected void engineInit(final Map attributes) throws KeyAgreementException
+  {
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    final String md = (String) attributes.get(HASH_FUNCTION);
+    if (md == null || md.trim().length() == 0)
+      throw new KeyAgreementException("missing hash function");
+    srp = SRP.instance(md);
+    passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB);
+    if (passwordDB == null)
+      throw new KeyAgreementException("missing SRP password database");
+  }
+
+  protected OutgoingMessage engineProcessMessage(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    switch (step)
+      {
+      case 0:
+        return sendParameters(in);
+      case 1:
+        return computeSharedSecret(in);
+      default:
+        throw new IllegalStateException("unexpected state");
+      }
+  }
+
+  protected void engineReset()
+  {
+    hostKeyPair = null;
+    super.engineReset();
+  }
+
+  private OutgoingMessage sendParameters(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    final String I = in.readString();
+    // get s and v for user identified by I
+    // ----------------------------------------------------------------------
+    final Map credentials;
+    try
+      {
+        final Map userID = new HashMap();
+        userID.put(Registry.SASL_USERNAME, I);
+        userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm());
+        credentials = passwordDB.lookup(userID);
+      }
+    catch (IOException x)
+      {
+        throw new KeyAgreementException("computeSharedSecret()", x);
+      }
+
+    final BigInteger s = new BigInteger(
+        1, Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD)));
+    final BigInteger v = new BigInteger(
+        1, Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD)));
+    final Map configuration;
+    try
+      {
+        final String mode = (String) credentials.get(SRPRegistry.CONFIG_NDX_FIELD);
+        configuration = passwordDB.getConfiguration(mode);
+      }
+    catch (IOException x)
+      {
+        throw new KeyAgreementException("computeSharedSecret()", x);
+      }
+    N = new BigInteger(
+        1, Util.fromBase64((String) configuration.get(SRPRegistry.SHARED_MODULUS)));
+    g = new BigInteger(
+        1, Util.fromBase64((String) configuration.get(SRPRegistry.FIELD_GENERATOR)));
+    // generate an ephemeral keypair
+    final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
+    final Map attributes = new HashMap();
+    if (rnd != null)
+      attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
+    attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+    attributes.put(SRPKeyPairGenerator.GENERATOR, g);
+    attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v);
+    kpg.setup(attributes);
+    hostKeyPair = kpg.generate();
+    final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY();
+    final OutgoingMessage result = new OutgoingMessage();
+    result.writeMPI(N);
+    result.writeMPI(g);
+    result.writeMPI(s);
+    result.writeMPI(B);
+    return result;
+  }
+
+  protected OutgoingMessage computeSharedSecret(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    final BigInteger A = in.readMPI();
+    final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY();
+    final BigInteger u = uValue(A, B); // u = H(A | B)
+    // compute S = (Av^u) ^ b
+    final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX();
+    final BigInteger v = ((SRPPrivateKey) hostKeyPair.getPrivate()).getV();
+    final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N);
+    K = S;
+    complete = true;
+    return null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRP6User.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,163 @@
+/* SRP6User.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.sasl.srp.SRP;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The implementation of the User in the SRP-6 protocol.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRP6User
+    extends SRP6KeyAgreement
+{
+  /** The user's identity. */
+  private String I;
+  /** The user's cleartext password. */
+  private byte[] p;
+  /** The user's ephemeral key pair. */
+  private KeyPair userKeyPair;
+
+  // default 0-arguments constructor
+
+  protected void engineInit(final Map attributes) throws KeyAgreementException
+  {
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    N = (BigInteger) attributes.get(SHARED_MODULUS);
+    if (N == null)
+      throw new KeyAgreementException("missing shared modulus");
+    g = (BigInteger) attributes.get(GENERATOR);
+    if (g == null)
+      throw new KeyAgreementException("missing generator");
+    final String md = (String) attributes.get(HASH_FUNCTION);
+    if (md == null || md.trim().length() == 0)
+      throw new KeyAgreementException("missing hash function");
+    srp = SRP.instance(md);
+    I = (String) attributes.get(USER_IDENTITY);
+    if (I == null)
+      throw new KeyAgreementException("missing user identity");
+    p = (byte[]) attributes.get(USER_PASSWORD);
+    if (p == null)
+      throw new KeyAgreementException("missing user password");
+  }
+
+  protected OutgoingMessage engineProcessMessage(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    switch (step)
+      {
+      case 0:
+        return sendIdentity(in);
+      case 1:
+        return computeSharedSecret(in);
+      default:
+        throw new IllegalStateException("unexpected state");
+      }
+  }
+
+  protected void engineReset()
+  {
+    I = null;
+    p = null;
+    userKeyPair = null;
+    super.engineReset();
+  }
+
+  private OutgoingMessage sendIdentity(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    // generate an ephemeral keypair
+    final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
+    final Map attributes = new HashMap();
+    if (rnd != null)
+      attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
+    attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+    attributes.put(SRPKeyPairGenerator.GENERATOR, g);
+    kpg.setup(attributes);
+    userKeyPair = kpg.generate();
+    final OutgoingMessage result = new OutgoingMessage();
+    result.writeString(I);
+    result.writeMPI(((SRPPublicKey) userKeyPair.getPublic()).getY());
+    return result;
+  }
+
+  private OutgoingMessage computeSharedSecret(final IncomingMessage in)
+      throws KeyAgreementException
+  {
+    final BigInteger s = in.readMPI();
+    final BigInteger B = in.readMPI();
+    final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY();
+    final BigInteger u = uValue(A, B); // u = H(A | B)
+    final BigInteger x;
+    try
+      {
+        x = new BigInteger(1, srp.computeX(Util.trim(s), I, p));
+      }
+    catch (Exception e)
+      {
+        throw new KeyAgreementException("computeSharedSecret()", e);
+      }
+    // compute S = (B - 3g^x) ^ (a + ux)
+    final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX();
+    final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N)))
+                          .modPow(a.add(u.multiply(x)), N);
+    final byte[] sBytes = Util.trim(S);
+    final IMessageDigest hash = srp.newDigest();
+    hash.update(sBytes, 0, sBytes.length);
+    K = new BigInteger(1, hash.digest());
+    complete = true;
+    return null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRPAlgorithm.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,131 @@
+/* SRPAlgorithm.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.javax.crypto.sasl.srp.SRPRegistry;
+
+import java.math.BigInteger;
+
+/**
+ * Utilities for use with SRP-6 based methods and protocols.
+ * <p>
+ * Reference:
+ * <ol>
+ *    <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ *    Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPAlgorithm
+{
+  // lifted from draft-burdis-cat-srp-sasl-09
+  public static final BigInteger N_2048 = new BigInteger(
+      "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050"
+    + "A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50"
+    + "E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B8"
+    + "55F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773B"
+    + "CA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748"
+    + "544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6"
+    + "AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6"
+    + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", 16);
+  public static final BigInteger N_1536 = new BigInteger(
+      "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D"
+    + "5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DC"
+    + "DF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC"
+    + "764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C486"
+    + "65772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E"
+    + "5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", 16);
+  public static final BigInteger N_1280 = new BigInteger(
+      "D77946826E811914B39401D56A0A7843A8E7575D738C672A090AB1187D690DC4"
+    + "3872FC06A7B6A43F3B95BEAEC7DF04B9D242EBDC481111283216CE816E004B78"
+    + "6C5FCE856780D41837D95AD787A50BBE90BD3A9C98AC0F5FC0DE744B1CDE1891"
+    + "690894BC1F65E00DE15B4B2AA6D87100C9ECC2527E45EB849DEB14BB2049B163"
+    + "EA04187FD27C1BD9C7958CD40CE7067A9C024F9B7C5A0B4F5003686161F0605B", 16);
+  public static final BigInteger N_1024 = new BigInteger(
+      "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576"
+    + "D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD1"
+    + "5DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC"
+    + "68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", 16);
+  public static final BigInteger N_768 = new BigInteger(
+      "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F40"
+    + "2653BE7147F00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF"
+    + "737D9BE9713CEF8D837ADA6380B1093E94B6A529A8C6C2BE33E0867C60C3262B", 16);
+  public static final BigInteger N_640 = new BigInteger(
+      "C94D67EB5B1A2346E8AB422FC6A0EDAEDA8C7F894C9EEEC42F9ED250FD7F0046"
+    + "E5AF2CF73D6B2FA26BB08033DA4DE322E144E7A8E9B12A0E4637F6371F34A207"
+    + "1C4B3836CBEEAB15034460FAA7ADF483", 16);
+  public static final BigInteger N_512 = new BigInteger(
+      "D4C7F8A2B32C11B8FBA9581EC4BA4F1B04215642EF7355E37C0FC0443EF756EA"
+    + "2C6B8EEB755A1C723027663CAA265EF785B8FF6A9B35227A52D86633DBDFCA43", 16);
+  public static final BigInteger N_384 = new BigInteger(
+      "8025363296FB943FCE54BE717E0E2958A02A9672EF561953B2BAA3BAACC3ED57"
+    + "54EB764C7AB7184578C57D5949CCB41B", 16);
+  public static final BigInteger N_264 = new BigInteger(
+      "115B8B692E0E045692CF280B436735C77A5A9E8A9E7ED56C965F87DB5B2A2ECE3", 16);
+  private static final BigInteger ZERO = BigInteger.ZERO;
+  private static final BigInteger ONE = BigInteger.ONE;
+  private static final BigInteger TWO = BigInteger.valueOf(2L);
+
+  /** Trivial constructor to enforce usage through class methods. */
+  private SRPAlgorithm()
+  {
+    super();
+  }
+
+  public static void checkParams(final BigInteger N, final BigInteger g)
+  {
+    // 1. N should be at least 512-bit long
+    final int blen = N.bitLength();
+    if (blen < SRPRegistry.MINIMUM_MODULUS_BITLENGTH)
+      throw new IllegalArgumentException("Bit length of N ("
+                                         + blen
+                                         + ") is too low. Should be at least "
+                                         + SRPRegistry.MINIMUM_MODULUS_BITLENGTH);
+    // 2. N should be a prime
+    if (! N.isProbablePrime(80))
+      throw new IllegalArgumentException("N should be prime but isn't");
+    // 3. N should be of the form 2*q + 1, where q is prime
+    final BigInteger q = N.subtract(ONE).divide(TWO);
+    if (! q.isProbablePrime(80))
+      throw new IllegalArgumentException("(N-1)/2 should be prime but isn't");
+    // 4. g**q should be -1 mod N
+    final BigInteger gq = g.modPow(q, N).add(ONE).mod(N);
+    if (gq.compareTo(ZERO) != 0)
+      throw new IllegalArgumentException("g**q should be -1 (mod N) but isn't");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRPKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,147 @@
+/* SRPKey.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.security.Key;
+
+/**
+ * An abstract representation of a base SRP ephemeral key.
+ * <p>
+ * This object encapsulates the two numbers:
+ * <ul>
+ * <li><b>N</b>: A large safe prime (N = 2q+1, where q is prime).</li>
+ * <li><b>g</b>: A generator modulo N.</li>
+ * </ul>
+ * <p>
+ * Note that in SRP, all arithmetic is done modulo N.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public abstract class SRPKey
+    implements Key, Serializable
+{
+  /** The public, Germaine prime, shared modulus. */
+  protected final BigInteger N;
+  /** The generator. */
+  protected final BigInteger g;
+
+  protected SRPKey(BigInteger N, BigInteger g)
+  {
+    super();
+
+    this.N = N;
+    this.g = g;
+  }
+
+  /**
+   * Returns the standard algorithm name for this key.
+   * 
+   * @return the standard algorithm name for this key.
+   */
+  public String getAlgorithm()
+  {
+    return Registry.SRP_KPG;
+  }
+
+  /** @deprecated see getEncoded(int). */
+  public byte[] getEncoded()
+  {
+    return getEncoded(IKeyPairCodec.RAW_FORMAT);
+  }
+
+  /**
+   * Returns {@link Registry#RAW_ENCODING_SHORT_NAME} which is the sole format
+   * supported for this type of keys.
+   * 
+   * @return {@link Registry#RAW_ENCODING_SHORT_NAME} ALWAYS.
+   */
+  public String getFormat()
+  {
+    return Registry.RAW_ENCODING_SHORT_NAME;
+  }
+
+  /**
+   * Returns the public shared modulus.
+   * 
+   * @return <code>N</code>.
+   */
+  public BigInteger getN()
+  {
+    return N;
+  }
+
+  /**
+   * Returns the generator.
+   * 
+   * @return <code>g</code>.
+   */
+  public BigInteger getG()
+  {
+    return g;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * <code>SRPKey</code> and has the same SRP parameter values as this one.
+   * 
+   * @param obj the other non-null SRP key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(Object obj)
+  {
+    if (obj == null)
+      return false;
+    if (! (obj instanceof SRPKey))
+      return false;
+    SRPKey that = (SRPKey) obj;
+    return N.equals(that.getN()) && g.equals(that.getG());
+  }
+
+  public abstract byte[] getEncoded(int format);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,282 @@
+/* SRPKeyPairGenerator.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPKeyPairGenerator
+    implements IKeyPairGenerator
+{
+  private static final Logger log = Logger.getLogger(SRPKeyPairGenerator.class.getName());
+  private static final BigInteger ZERO = BigInteger.ZERO;
+  private static final BigInteger ONE = BigInteger.ONE;
+  private static final BigInteger TWO = BigInteger.valueOf(2L);
+  private static final BigInteger THREE = BigInteger.valueOf(3L);
+  /** Property name of the length (Integer) of the modulus (N) of an SRP key. */
+  public static final String MODULUS_LENGTH = "gnu.crypto.srp.L";
+  /** Property name of the Boolean indicating wether or not to use defaults. */
+  public static final String USE_DEFAULTS = "gnu.crypto.srp.use.defaults";
+  /** Property name of the modulus (N) of an SRP key. */
+  public static final String SHARED_MODULUS = "gnu.crypto.srp.N";
+  /** Property name of the generator (g) of an SRP key. */
+  public static final String GENERATOR = "gnu.crypto.srp.g";
+  /** Property name of the user's verifier (v) for a Server SRP key. */
+  public static final String USER_VERIFIER = "gnu.crypto.srp.v";
+  /**
+   * Property name of an optional {@link SecureRandom} instance to use. The
+   * default is to use a classloader singleton from {@link PRNG}.
+   */
+  public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp.prng";
+  /** Default value for the modulus length. */
+  private static final int DEFAULT_MODULUS_LENGTH = 1024;
+  /** The optional {@link SecureRandom} instance to use. */
+  private SecureRandom rnd = null;
+  /** Bit length of the shared modulus. */
+  private int l;
+  /** The shared public modulus. */
+  private BigInteger N;
+  /** The Field generator. */
+  private BigInteger g;
+  /** The user's verifier MPI. */
+  private BigInteger v;
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+
+  // implicit 0-arguments constructor
+
+  public String name()
+  {
+    return Registry.SRP_KPG;
+  }
+
+  public void setup(Map attributes)
+  {
+    // do we have a SecureRandom, or should we use our own?
+    rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+    N = (BigInteger) attributes.get(SHARED_MODULUS);
+    if (N != null)
+      {
+        l = N.bitLength();
+        g = (BigInteger) attributes.get(GENERATOR);
+        if (g == null)
+          g = TWO;
+        SRPAlgorithm.checkParams(N, g);
+      }
+    else
+      { // generate or use default values for N and g
+        Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS);
+        if (useDefaults == null)
+          useDefaults = Boolean.TRUE;
+        Integer L = (Integer) attributes.get(MODULUS_LENGTH);
+        l = DEFAULT_MODULUS_LENGTH;
+        if (useDefaults.equals(Boolean.TRUE))
+          {
+            if (L != null)
+              {
+                l = L.intValue();
+                switch (l)
+                  {
+                  case 512:
+                    N = SRPAlgorithm.N_512;
+                    break;
+                  case 640:
+                    N = SRPAlgorithm.N_640;
+                    break;
+                  case 768:
+                    N = SRPAlgorithm.N_768;
+                    break;
+                  case 1024:
+                    N = SRPAlgorithm.N_1024;
+                    break;
+                  case 1280:
+                    N = SRPAlgorithm.N_1280;
+                    break;
+                  case 1536:
+                    N = SRPAlgorithm.N_1536;
+                    break;
+                  case 2048:
+                    N = SRPAlgorithm.N_2048;
+                    break;
+                  default:
+                    throw new IllegalArgumentException(
+                        "unknown default shared modulus bit length");
+                  }
+                g = TWO;
+                l = N.bitLength();
+              }
+          }
+        else // generate new N and g
+          {
+            if (L != null)
+              {
+                l = L.intValue();
+                if ((l % 256) != 0 || l < 512 || l > 2048)
+                  throw new IllegalArgumentException(
+                      "invalid shared modulus bit length");
+              }
+          }
+      }
+    // are we using this generator on the server side, or the client side?
+    v = (BigInteger) attributes.get(USER_VERIFIER);
+  }
+
+  public KeyPair generate()
+  {
+    if (N == null)
+      {
+        BigInteger[] params = generateParameters();
+        BigInteger q = params[0];
+        N = params[1];
+        g = params[2];
+        if (Configuration.DEBUG)
+          {
+            log.fine("q: " + q.toString(16));
+            log.fine("N: " + N.toString(16));
+            log.fine("g: " + g.toString(16));
+          }
+      }
+    return (v != null ? hostKeyPair() : userKeyPair());
+  }
+
+  private synchronized BigInteger[] generateParameters()
+  {
+    // N A large safe prime (N = 2q+1, where q is prime)
+    // g A generator modulo N
+    BigInteger q, p, g;
+    byte[] qBytes = new byte[l / 8];
+    do
+      {
+        do
+          {
+            nextRandomBytes(qBytes);
+            q = new BigInteger(1, qBytes);
+            q = q.setBit(0).setBit(l - 2).clearBit(l - 1);
+          }
+        while (! q.isProbablePrime(80));
+        p = q.multiply(TWO).add(ONE);
+      }
+    while (p.bitLength() != l || ! p.isProbablePrime(80));
+    // compute g. from FIPS-186, Appendix 4: e == 2
+    BigInteger p_minus_1 = p.subtract(ONE);
+    g = TWO;
+    // Set h = any integer, where 1 < h < p - 1 and
+    // h differs from any value previously tried
+    for (BigInteger h = TWO; h.compareTo(p_minus_1) < 0; h = h.add(ONE))
+      {
+        // Set g = h**2 mod p
+        g = h.modPow(TWO, p);
+        // If g = 1, go to step 3
+        if (! g.equals(ONE))
+          break;
+      }
+    return new BigInteger[] { q, p, g };
+  }
+
+  private KeyPair hostKeyPair()
+  {
+    byte[] bBytes = new byte[(l + 7) / 8];
+    BigInteger b, B;
+    do
+      {
+        do
+          {
+            nextRandomBytes(bBytes);
+            b = new BigInteger(1, bBytes);
+          }
+        while (b.compareTo(ONE) <= 0 || b.compareTo(N) >= 0);
+        B = THREE.multiply(v).add(g.modPow(b, N)).mod(N);
+      }
+    while (B.compareTo(ZERO) == 0 || B.compareTo(N) >= 0);
+    KeyPair result = new KeyPair(new SRPPublicKey(new BigInteger[] { N, g, B }),
+                                 new SRPPrivateKey(new BigInteger[] { N, g, b, v }));
+    return result;
+  }
+
+  private KeyPair userKeyPair()
+  {
+    byte[] aBytes = new byte[(l + 7) / 8];
+    BigInteger a, A;
+    do
+      {
+        do
+          {
+            nextRandomBytes(aBytes);
+            a = new BigInteger(1, aBytes);
+          }
+        while (a.compareTo(ONE) <= 0 || a.compareTo(N) >= 0);
+        A = g.modPow(a, N);
+      }
+    while (A.compareTo(ZERO) == 0 || A.compareTo(N) >= 0);
+    KeyPair result = new KeyPair(new SRPPublicKey(new BigInteger[] { N, g, A }),
+                                 new SRPPrivateKey(new BigInteger[] { N, g, a }));
+    return result;
+  }
+
+  private void nextRandomBytes(byte[] buffer)
+  {
+    if (rnd != null)
+      rnd.nextBytes(buffer);
+    else
+      getDefaultPRNG().nextBytes(buffer);
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,334 @@
+/* SRPKeyPairRawCodec.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * An object that implements the {@link IKeyPairCodec} operations for the
+ * <i>Raw</i> format to use with SRP keypairs.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPKeyPairRawCodec
+    implements IKeyPairCodec
+{
+  // implicit 0-arguments constructor
+
+  public int getFormatID()
+  {
+    return RAW_FORMAT;
+  }
+
+  /**
+   * Returns the encoded form of the designated SRP public key according to the
+   * <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for an SRP public key, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_SRP_PUBLIC_KEY},</li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the SRP parameter
+   * <code>N</code> in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the SRP parameter <code>N</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the SRP parameter
+   * <code>g</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the SRP parameter <code>g</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the SRP parameter
+   * <code>y</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the SRP parameter <code>y</code>,
+   * </li>
+   * </ol>
+   * 
+   * @param key the key to encode.
+   * @return the <i>Raw</i> format encoding of the designated key.
+   * @throws IllegalArgumentException if the designated key is not an SRP one.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    if (! (key instanceof SRPPublicKey))
+      throw new IllegalArgumentException("key");
+    SRPPublicKey srpKey = (SRPPublicKey) key;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]);
+    baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1]);
+    baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2]);
+    baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3]);
+    // version
+    baos.write(0x01);
+    // N
+    byte[] buffer = srpKey.getN().toByteArray();
+    int length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // g
+    buffer = srpKey.getG().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // y
+    buffer = srpKey.getY().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    return baos.toByteArray();
+  }
+
+  public PublicKey decodePublicKey(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]
+        || k[1] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1]
+        || k[2] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2]
+        || k[3] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3])
+      throw new IllegalArgumentException("magic");
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+    int i = 5;
+    int l;
+    byte[] buffer;
+    // N
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger N = new BigInteger(1, buffer);
+    // g
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger g = new BigInteger(1, buffer);
+    // y
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger y = new BigInteger(1, buffer);
+    return new SRPPublicKey(N, g, y);
+  }
+
+  /**
+   * Returns the encoded form of the designated SRP private key according to the
+   * <i>Raw</i> format supported by this library.
+   * <p>
+   * The <i>Raw</i> format for an SRP private key, in this implementation, is a
+   * byte sequence consisting of the following:
+   * <ol>
+   * <li>4-byte magic consisting of the value of the literal
+   * {@link Registry#MAGIC_RAW_SRP_PRIVATE_KEY},</li>
+   * <li>1-byte version consisting of the constant: 0x01,</li>
+   * <li>4-byte count of following bytes representing the SRP parameter
+   * <code>N</code> in internet order,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the SRP parameter <code>N</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the SRP parameter
+   * <code>g</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the SRP parameter <code>g</code>,
+   * </li>
+   * <li>4-byte count of following bytes representing the SRP parameter
+   * <code>x</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the SRP parameter <code>x</code>,
+   * </li>
+   * <li>one byte which indicates whether the SRP parameter <code>v</code> is
+   * included in this encoding (value <code>0x01</code>) or not (value
+   * <code>0x00</code>).</li>
+   * <li>4-byte count of following bytes representing the SRP parameter
+   * <code>v</code>,</li>
+   * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+   * the <code>toByteArray()</code> method on the SRP parameter <code>v</code>,
+   * </li>
+   * </ol>
+   * 
+   * @param key the key to encode.
+   * @return the <i>Raw</i> format encoding of the designated key.
+   * @throws IllegalArgumentException if the designated key is not an SRP one.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    if (! (key instanceof SRPPrivateKey))
+      throw new IllegalArgumentException("key");
+    SRPPrivateKey srpKey = (SRPPrivateKey) key;
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    // magic
+    baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]);
+    baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1]);
+    baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2]);
+    baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3]);
+    // version
+    baos.write(0x01);
+    // N
+    byte[] buffer = srpKey.getN().toByteArray();
+    int length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // g
+    buffer = srpKey.getG().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // x
+    buffer = srpKey.getX().toByteArray();
+    length = buffer.length;
+    baos.write( length >>> 24);
+    baos.write((length >>> 16) & 0xFF);
+    baos.write((length >>>  8) & 0xFF);
+    baos.write( length         & 0xFF);
+    baos.write(buffer, 0, length);
+    // v
+    if (srpKey.getV() != null)
+      {
+        baos.write(0x01);
+        buffer = srpKey.getV().toByteArray();
+        length = buffer.length;
+        baos.write( length >>> 24);
+        baos.write((length >>> 16) & 0xFF);
+        baos.write((length >>>  8) & 0xFF);
+        baos.write( length         & 0xFF);
+        baos.write(buffer, 0, length);
+      }
+    else
+      baos.write(0x00);
+    return baos.toByteArray();
+  }
+
+  public PrivateKey decodePrivateKey(byte[] k)
+  {
+    // magic
+    if (k[0] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]
+        || k[1] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1]
+        || k[2] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2]
+        || k[3] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3])
+      throw new IllegalArgumentException("magic");
+    // version
+    if (k[4] != 0x01)
+      throw new IllegalArgumentException("version");
+    int i = 5;
+    int l;
+    byte[] buffer;
+    // N
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger N = new BigInteger(1, buffer);
+    // g
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger g = new BigInteger(1, buffer);
+    // x
+    l =  k[i++]         << 24
+      | (k[i++] & 0xFF) << 16
+      | (k[i++] & 0xFF) << 8
+      | (k[i++] & 0xFF);
+    buffer = new byte[l];
+    System.arraycopy(k, i, buffer, 0, l);
+    i += l;
+    BigInteger x = new BigInteger(1, buffer);
+    // v
+    l = k[i++];
+    if (l == 0x01)
+      {
+        l =  k[i++]         << 24
+          | (k[i++] & 0xFF) << 16
+          | (k[i++] & 0xFF) << 8
+          | (k[i++] & 0xFF);
+        buffer = new byte[l];
+        System.arraycopy(k, i, buffer, 0, l);
+        i += l;
+        BigInteger v = new BigInteger(1, buffer);
+        return new SRPPrivateKey(N, g, x, v);
+      }
+    return new SRPPrivateKey(N, g, x);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRPPrivateKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,227 @@
+/* SRPPrivateKey.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * A representation of an SRP ephemeral private key.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPPrivateKey
+    extends SRPKey
+    implements PrivateKey
+{
+  /**
+   * The private exponent for either the server or the client engaged in the SRP
+   * protocol exchange.
+   */
+  private final BigInteger X;
+  /**
+   * The user's verifier (v) --for the server-- also computed at the client side
+   * as g.modPow(x, N), where x is the hashed output of the user name and
+   * password .
+   */
+  private final BigInteger v;
+
+  /**
+   * Public constructor for use from outside this package.
+   * 
+   * @param N the public shared modulus.
+   * @param g the generator.
+   * @param x the private exponent of the ephemeral key.
+   */
+  public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x)
+  {
+    this(N, g, x, null);
+  }
+
+  /**
+   * Public constructor for use from outside this package.
+   * 
+   * @param N the public shared modulus.
+   * @param g the generator.
+   * @param x the private exponent of the ephemeral key.
+   * @param v the user's verifier value (for the server side only).
+   */
+  public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x, BigInteger v)
+  {
+    super(N, g);
+
+    SRPAlgorithm.checkParams(N, g);
+    this.X = x;
+    this.v = v;
+  }
+
+  /**
+   * Default constructor. Assumes N and g are already validated.
+   * 
+   * @param params an array of either 3 or 4 values representing N, g, and
+   *          either v and X for the server, or just X for the client. Those
+   *          values represent the following:
+   *          <ol>
+   *          <li>v (server side): the user's verifier.</li>
+   *          <li>X (both sides): the server's or client's ephemeral private
+   *          exponent.</li>
+   *          </ol>
+   */
+  SRPPrivateKey(BigInteger[] params)
+  {
+    super(params[0], params[1]);
+
+    if (params.length == 3)
+      {
+        X = params[2];
+        v = null;
+      }
+    else if (params.length == 4)
+      {
+        X = params[2];
+        v = params[3];
+      }
+    else
+      throw new IllegalArgumentException("invalid number of SRP parameters");
+  }
+
+  /**
+   * A class method that takes the output of the <code>encodePrivateKey()</code>
+   * method of an SRP keypair codec object (an instance implementing
+   * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this
+   * object.
+   * 
+   * @param k the contents of a previously encoded instance of this object.
+   * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in
+   *           <code>k</code>, to represent a valid encoding of an instance
+   *           of this object.
+   * @throws IllegalArgumentException if the byte sequence does not represent a
+   *           valid encoding of an instance of this object.
+   */
+  public static SRPPrivateKey valueOf(byte[] k)
+  {
+    // check magic...
+    // we should parse here enough bytes to know which codec to use, and
+    // direct the byte array to the appropriate codec. since we only have one
+    // codec, we could have immediately tried it; nevertheless since testing
+    // one byte is cheaper than instatiating a codec that will fail we test
+    // the first byte before we carry on.
+    if (k[0] == Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0])
+      {
+        // it's likely to be in raw format. get a raw codec and hand it over
+        IKeyPairCodec codec = new SRPKeyPairRawCodec();
+        return (SRPPrivateKey) codec.decodePrivateKey(k);
+      }
+    throw new IllegalArgumentException("magic");
+  }
+
+  /**
+   * Returns the private exponent of the key as a {@link BigInteger}.
+   * 
+   * @return the private exponent of the key as a {@link BigInteger}.
+   */
+  public BigInteger getX()
+  {
+    return X;
+  }
+
+  /**
+   * Returns the user's verifier as a {@link BigInteger}.
+   * 
+   * @return the user's verifier as a {@link BigInteger} if this is an SRP
+   *         private key of a Host, or <code>null</code> if this is a private
+   *         SRP key for a User.
+   */
+  public BigInteger getV()
+  {
+    return v;
+  }
+
+  /**
+   * Returns the encoded form of this private key according to the designated
+   * format.
+   * 
+   * @param format the desired format identifier of the resulting encoding.
+   * @return the byte sequence encoding this key according to the designated
+   *         format.
+   * @throws IllegalArgumentException if the format is not supported.
+   */
+  public byte[] getEncoded(int format)
+  {
+    byte[] result;
+    switch (format)
+      {
+      case IKeyPairCodec.RAW_FORMAT:
+        result = new SRPKeyPairRawCodec().encodePrivateKey(this);
+        break;
+      default:
+        throw new IllegalArgumentException("format");
+      }
+    return result;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * <code>SRPPrivateKey</code> and has the same SRP parameter values as this
+   * one.
+   * 
+   * @param obj the other non-null SRP key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(Object obj)
+  {
+    if (obj == null)
+      return false;
+    if (! (obj instanceof SRPPrivateKey))
+      return false;
+    SRPPrivateKey that = (SRPPrivateKey) obj;
+    boolean result = super.equals(that) && X.equals(that.getX());
+    if (v != null)
+      result = result && v.equals(that.getV());
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/key/srp6/SRPPublicKey.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,175 @@
+/* SRPPublicKey.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+/**
+ * A representation of an SRP ephemeral public key.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPPublicKey
+    extends SRPKey
+    implements PublicKey
+{
+  /**
+   * The public exponent for either the server or the client engaged in the SRP
+   * protocol exchange.
+   */
+  private final BigInteger Y;
+
+  /**
+   * Public constructor for use from outside this package.
+   * 
+   * @param N the public shared modulus.
+   * @param g the generator.
+   * @param Y the public exponent of the ephemeral key.
+   */
+  public SRPPublicKey(BigInteger N, BigInteger g, BigInteger Y)
+  {
+    super(N, g);
+
+    SRPAlgorithm.checkParams(N, g);
+    this.Y = Y;
+  }
+
+  /**
+   * Default constructor. Assumes that N and g are already validated.
+   * 
+   * @param params an array of 3 values representing N, g and Y; the latter
+   *          being the client's or server's public exponent.
+   */
+  SRPPublicKey(BigInteger[] params)
+  {
+    super(params[0], params[1]);
+
+    this.Y = params[2];
+  }
+
+  /**
+   * A class method that takes the output of the <code>encodePublicKey()</code>
+   * method of an SRP keypair codec object (an instance implementing
+   * {@link IKeyPairCodec} for SRP keys, and re-constructs an instance of this
+   * object.
+   * 
+   * @param k the contents of a previously encoded instance of this object.
+   * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in
+   *           <code>k</code>, to represent a valid encoding of an instance
+   *           of this object.
+   * @throws IllegalArgumentException if the byte sequence does not represent a
+   *           valid encoding of an instance of this object.
+   */
+  public static SRPPublicKey valueOf(byte[] k)
+  {
+    // check magic...
+    // we should parse here enough bytes to know which codec to use, and
+    // direct the byte array to the appropriate codec. since we only have one
+    // codec, we could have immediately tried it; nevertheless since testing
+    // one byte is cheaper than instatiating a codec that will fail we test
+    // the first byte before we carry on.
+    if (k[0] == Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0])
+      {
+        // it's likely to be in raw format. get a raw codec and hand it over
+        IKeyPairCodec codec = new SRPKeyPairRawCodec();
+        return (SRPPublicKey) codec.decodePublicKey(k);
+      }
+    throw new IllegalArgumentException("magic");
+  }
+
+  /**
+   * Returns the public exponent of the key as a {@link BigInteger}.
+   * 
+   * @return the public exponent of the key as a {@link BigInteger}.
+   */
+  public BigInteger getY()
+  {
+    return Y;
+  }
+
+  /**
+   * Returns the encoded form of this public key according to the designated
+   * format.
+   * 
+   * @param format the desired format identifier of the resulting encoding.
+   * @return the byte sequence encoding this key according to the designated
+   *         format.
+   * @throws IllegalArgumentException if the format is not supported.
+   */
+  public byte[] getEncoded(int format)
+  {
+    byte[] result;
+    switch (format)
+      {
+      case IKeyPairCodec.RAW_FORMAT:
+        result = new SRPKeyPairRawCodec().encodePublicKey(this);
+        break;
+      default:
+        throw new IllegalArgumentException("format");
+      }
+    return result;
+  }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * <code>SRPPublicKey</code>and has the same SRP parameter values as this
+   * one.
+   * 
+   * @param obj the other non-null SRP key to compare to.
+   * @return <code>true</code> if the designated object is of the same type
+   *         and value as this one.
+   */
+  public boolean equals(Object obj)
+  {
+    if (obj == null)
+      return false;
+    if (! (obj instanceof SRPPublicKey))
+      return false;
+    SRPPublicKey that = (SRPPublicKey) obj;
+    return super.equals(that) && Y.equals(that.getY());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/AuthenticatedEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,176 @@
+/* AuthenticatedEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mac.MacFactory;
+import gnu.javax.crypto.mac.MacOutputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+
+public final class AuthenticatedEntry
+    extends MaskableEnvelopeEntry
+    implements Registry
+{
+  public static final int TYPE = 2;
+
+  public AuthenticatedEntry(String mac, int macLen, Properties properties)
+  {
+    super(TYPE, properties);
+    if (macLen <= 0)
+      throw new IllegalArgumentException("invalid mac length");
+    this.properties.put("mac", mac);
+    this.properties.put("maclen", String.valueOf(macLen));
+    setMasked(false);
+  }
+
+  private AuthenticatedEntry()
+  {
+    super(TYPE);
+    setMasked(true);
+  }
+
+  public static AuthenticatedEntry decode(DataInputStream in)
+      throws IOException
+  {
+    AuthenticatedEntry entry = new AuthenticatedEntry();
+    entry.properties.decode(in);
+    if (! entry.properties.containsKey("mac"))
+      throw new MalformedKeyringException("no mac specified");
+    if (! entry.properties.containsKey("maclen"))
+      throw new MalformedKeyringException("no mac length specified");
+    return entry;
+  }
+
+  /**
+   * Computes the mac over this envelope's data. This method <b>must</b> be
+   * called before this entry in encoded.
+   * 
+   * @param key The key to authenticate with.
+   * @throws IOException If encoding fails.
+   * @throws InvalidKeyException If the supplied key is bad.
+   */
+  public void authenticate(byte[] key) throws IOException, InvalidKeyException
+  {
+    if (isMasked())
+      throw new IllegalStateException("entry is masked");
+    IMac m = getMac(key);
+    ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
+    MacOutputStream macout = new MacOutputStream(bout, m);
+    DataOutputStream out2 = new DataOutputStream(macout);
+    for (Iterator it = entries.iterator(); it.hasNext();)
+      {
+        Entry entry = (Entry) it.next();
+        entry.encode(out2);
+      }
+    bout.write(m.digest());
+    payload = bout.toByteArray();
+  }
+
+  /**
+   * Verifies this entry's payload. This method will unmask this entry, thus it
+   * must be called before accessing its contents.
+   * 
+   * @param key The key to use to authenticate.
+   * @throws InvalidKeyException If the given key is improper.
+   */
+  public void verify(byte[] key) throws InvalidKeyException
+  {
+    if (! isMasked() || payload == null)
+      return;
+    IMac m = getMac(key);
+    m.update(payload, 0, payload.length - m.macSize());
+    byte[] macValue = new byte[m.macSize()];
+    System.arraycopy(payload, payload.length - macValue.length, macValue, 0,
+                     macValue.length);
+    if (! Arrays.equals(macValue, m.digest()))
+      throw new IllegalArgumentException("MAC verification failed");
+    try
+      {
+        int len = payload.length - m.macSize();
+        ByteArrayInputStream bais = new ByteArrayInputStream(payload, 0, len);
+        DataInputStream in = new DataInputStream(bais);
+        decodeEnvelope(in);
+      }
+    catch (IOException ioe)
+      {
+        throw new IllegalArgumentException("malformed keyring fragment");
+      }
+    setMasked(false);
+    payload = null;
+  }
+
+  protected void encodePayload() throws IOException
+  {
+    if (payload == null)
+      throw new IllegalStateException("not authenticated");
+  }
+
+  private IMac getMac(byte[] key) throws InvalidKeyException
+  {
+    IMac mac = MacFactory.getInstance(properties.get("mac"));
+    if (mac == null)
+      throw new IllegalArgumentException("no such mac: " + properties.get("mac"));
+    int maclen = 0;
+    if (! properties.containsKey("maclen"))
+      throw new IllegalArgumentException("no MAC length");
+    try
+      {
+        maclen = Integer.parseInt(properties.get("maclen"));
+      }
+    catch (NumberFormatException nfe)
+      {
+        throw new IllegalArgumentException("bad MAC length");
+      }
+    HashMap macAttr = new HashMap();
+    macAttr.put(IMac.MAC_KEY_MATERIAL, key);
+    macAttr.put(IMac.TRUNCATED_SIZE, Integer.valueOf(maclen));
+    mac.init(macAttr);
+    return mac;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/BaseKeyring.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,158 @@
+/* BaseKeyring.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.Registry;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+public abstract class BaseKeyring
+    implements IKeyring
+{
+  /** The top-level keyring data. */
+  protected PasswordAuthenticatedEntry keyring;
+  protected CompressedEntry keyring2;
+
+  public BaseKeyring()
+  {
+  }
+
+  public void load(Map attributes) throws IOException
+  {
+    InputStream in = (InputStream) attributes.get(KEYRING_DATA_IN);
+    if (in == null)
+      throw new IllegalArgumentException("no input stream");
+    char[] password = (char[]) attributes.get(KEYRING_PASSWORD);
+    if (password == null)
+      password = new char[0];
+
+    if (in.read() != Registry.GKR_MAGIC[0]
+        || in.read() != Registry.GKR_MAGIC[1]
+        || in.read() != Registry.GKR_MAGIC[2]
+        || in.read() != Registry.GKR_MAGIC[3])
+      throw new MalformedKeyringException("magic");
+
+    load(in, password);
+    List l = keyring.getEntries();
+    if (l.size() == 1 && (l.get(0) instanceof CompressedEntry))
+      keyring2 = (CompressedEntry) l.get(0);
+  }
+
+  public void store(Map attributes) throws IOException
+  {
+    OutputStream out = (OutputStream) attributes.get(KEYRING_DATA_OUT);
+    if (out == null)
+      throw new IllegalArgumentException("no output stream");
+    char[] password = (char[]) attributes.get(KEYRING_PASSWORD);
+    if (password == null)
+      password = new char[0];
+    if (keyring == null)
+      throw new IllegalStateException("empty keyring");
+
+    out.write(Registry.GKR_MAGIC);
+    store(out, password);
+  }
+
+  public void reset()
+  {
+    keyring = null;
+  }
+
+  public int size()
+  {
+    if (keyring == null)
+      throw new IllegalStateException("keyring not loaded");
+    return ((StringTokenizer) aliases()).countTokens();
+  }
+
+  public Enumeration aliases()
+  {
+    if (keyring == null)
+      throw new IllegalStateException("keyring not loaded");
+    return new StringTokenizer(keyring.getAliasList(), ";");
+  }
+
+  public boolean containsAlias(String alias)
+  {
+    if (keyring == null)
+      throw new IllegalStateException("keyring not loaded");
+    return keyring.containsAlias(alias);
+  }
+
+  public List get(String alias)
+  {
+    if (keyring == null)
+      throw new IllegalStateException("keyring not loaded");
+    return keyring.get(alias);
+  }
+
+  public void add(Entry entry)
+  {
+    if (keyring == null)
+      throw new IllegalStateException("keyring not loaded");
+    if (keyring2 != null)
+      keyring2.add(entry);
+    else
+      keyring.add(entry);
+  }
+
+  public void remove(String alias)
+  {
+    if (keyring == null)
+      throw new IllegalStateException("keyring not loaded");
+    keyring.remove(alias);
+  }
+
+  protected String fixAlias(String alias)
+  {
+    return alias.replace(';', '_');
+  }
+
+  protected abstract void load(InputStream in, char[] password)
+      throws IOException;
+
+  protected abstract void store(OutputStream out, char[] password)
+      throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/BinaryDataEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,111 @@
+/* BinaryDataEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * A binary data entry is a primitive entry that simply contains some amount of
+ * arbitrary binary data and an optional content type.
+ */
+public class BinaryDataEntry
+    extends PrimitiveEntry
+{
+  public static final int TYPE = 9;
+
+  /**
+   * Creates a new binary data entry.
+   * 
+   * @param contentType The content type of this entry. This parameter can be
+   *          <code>null</code> if no content type is needed.
+   * @param data The data.
+   * @param creationDate The creation date.
+   * @param properties This entry's properties.
+   */
+  public BinaryDataEntry(String contentType, byte[] data, Date creationDate,
+                         Properties properties)
+  {
+    super(TYPE, creationDate, properties);
+    if (data == null)
+      throw new IllegalArgumentException("no data");
+    payload = (byte[]) data.clone();
+    if (contentType != null)
+      this.properties.put("content-type", contentType);
+  }
+
+  private BinaryDataEntry()
+  {
+    super(TYPE);
+  }
+
+  public static BinaryDataEntry decode(DataInputStream in) throws IOException
+  {
+    BinaryDataEntry entry = new BinaryDataEntry();
+    entry.defaultDecode(in);
+    return entry;
+  }
+
+  /**
+   * Returns the content type of this entry, or <code>null</code> if this
+   * property is not set.
+   * 
+   * @return The content type.
+   */
+  public String getContentType()
+  {
+    return properties.get("content-type");
+  }
+
+  /**
+   * Returns this object's data field.
+   * 
+   * @return The data.
+   */
+  public byte[] getData()
+  {
+    return getPayload();
+  }
+
+  protected void encodePayload()
+  {
+    // Empty.
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/CertPathEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,112 @@
+/* CertPathEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.Date;
+
+/**
+ * A primitive entry that contains a path of X.509 certificates.
+ */
+public final class CertPathEntry
+    extends PrimitiveEntry
+{
+  public static final int TYPE = 8;
+  private Certificate[] path;
+
+  public CertPathEntry(Certificate[] path, Date creationDate,
+                       Properties properties)
+  {
+    super(TYPE, creationDate, properties);
+    if (path == null || path.length == 0)
+      throw new IllegalArgumentException("no certificate path");
+    this.path = (Certificate[]) path.clone();
+  }
+
+  private CertPathEntry()
+  {
+    super(TYPE);
+  }
+
+  public static CertPathEntry decode(DataInputStream in) throws IOException
+  {
+    CertPathEntry entry = new CertPathEntry();
+    entry.properties.decode(in);
+    entry.makeCreationDate();
+    int len = in.readInt();
+    MeteredInputStream in2 = new MeteredInputStream(in, len);
+    try
+      {
+        CertificateFactory fact = CertificateFactory.getInstance("X.509");
+        entry.path = (Certificate[]) fact.generateCertificates(in2).toArray(new Certificate[0]);
+      }
+    catch (CertificateException ce)
+      {
+        throw new MalformedKeyringException(ce.toString());
+      }
+    return entry;
+  }
+
+  public Certificate[] getCertPath()
+  {
+    return path;
+  }
+
+  protected void encodePayload() throws IOException
+  {
+    ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
+    byte[] enc = null;
+    try
+      {
+        for (int i = 0; i < path.length; i++)
+          bout.write(path[i].getEncoded());
+      }
+    catch (CertificateEncodingException cee)
+      {
+        throw new IOException(cee.toString());
+      }
+    payload = bout.toByteArray();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/CertificateEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,128 @@
+/* CertificateEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.Date;
+
+/**
+ * An immutable class representing a trusted certificate entry.
+ */
+public final class CertificateEntry
+    extends PrimitiveEntry
+{
+  public static final int TYPE = 5;
+  /** The certificate. */
+  private Certificate certificate;
+
+  /**
+   * Creates a new certificate entry.
+   * 
+   * @param certificate The certificate.
+   * @param creationDate The creation date.
+   * @param properties The alias.
+   * @throws IllegalArgumentException If any argument is null, or if the alias
+   *           is empty.
+   */
+  public CertificateEntry(Certificate certificate, Date creationDate,
+                          Properties properties)
+  {
+    super(TYPE, creationDate, properties);
+    if (certificate == null)
+      throw new IllegalArgumentException("no certificate");
+    this.certificate = certificate;
+    this.properties.put("type", certificate.getType());
+  }
+
+  private CertificateEntry()
+  {
+    super(TYPE);
+  }
+
+  public static CertificateEntry decode(DataInputStream in) throws IOException
+  {
+    CertificateEntry entry = new CertificateEntry();
+    entry.properties.decode(in);
+    entry.makeCreationDate();
+    String type = entry.properties.get("type");
+    if (type == null)
+      throw new MalformedKeyringException("no certificate type");
+    int len = in.readInt();
+    MeteredInputStream in2 = new MeteredInputStream(in, len);
+    try
+      {
+        CertificateFactory fact = CertificateFactory.getInstance(type);
+        entry.certificate = fact.generateCertificate(in2);
+      }
+    catch (CertificateException ce)
+      {
+        throw new MalformedKeyringException(ce.toString());
+      }
+    if (! in2.limitReached())
+      throw new MalformedKeyringException("extra data at end of payload");
+    return entry;
+  }
+
+  /**
+   * Returns this entry's certificate.
+   * 
+   * @return The certificate.
+   */
+  public Certificate getCertificate()
+  {
+    return certificate;
+  }
+
+  protected void encodePayload() throws IOException
+  {
+    try
+      {
+        payload = certificate.getEncoded();
+      }
+    catch (CertificateEncodingException cee)
+      {
+        throw new IOException(cee.toString());
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/CompressedEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,93 @@
+/* CompressedEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+public class CompressedEntry
+    extends EnvelopeEntry
+{
+  public static final int TYPE = 4;
+
+  public CompressedEntry(Properties properties)
+  {
+    super(TYPE, properties);
+    this.properties.put("algorithm", "DEFLATE");
+  }
+
+  private CompressedEntry()
+  {
+    this(new Properties());
+  }
+
+  public static CompressedEntry decode(DataInputStream in) throws IOException
+  {
+    CompressedEntry entry = new CompressedEntry();
+    entry.properties.decode(in);
+    String alg = entry.properties.get("algorithm");
+    if (alg == null)
+      throw new MalformedKeyringException("no compression algorithm");
+    if (! alg.equalsIgnoreCase("DEFLATE"))
+      throw new MalformedKeyringException("unsupported compression algorithm: "
+                                          + alg);
+    int len = in.readInt();
+    MeteredInputStream min = new MeteredInputStream(in, len);
+    InflaterInputStream infin = new InflaterInputStream(min);
+    DataInputStream in2 = new DataInputStream(infin);
+    entry.decodeEnvelope(in2);
+    return entry;
+  }
+
+  protected void encodePayload() throws IOException
+  {
+    ByteArrayOutputStream buf = new ByteArrayOutputStream(1024);
+    DeflaterOutputStream dout = new DeflaterOutputStream(buf);
+    DataOutputStream out2 = new DataOutputStream(dout);
+    for (Iterator it = entries.iterator(); it.hasNext();)
+      ((Entry) it.next()).encode(out2);
+    dout.finish();
+    payload = buf.toByteArray();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/EncryptedEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,191 @@
+/* EncryptedEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.mode.IMode;
+import gnu.javax.crypto.mode.ModeFactory;
+import gnu.javax.crypto.pad.IPad;
+import gnu.javax.crypto.pad.PadFactory;
+import gnu.javax.crypto.pad.WrongPaddingException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.util.HashMap;
+import java.util.Iterator;
+
+public class EncryptedEntry extends MaskableEnvelopeEntry implements Registry
+{
+  public static final int TYPE = 0;
+
+  public EncryptedEntry(String cipher, String mode, Properties properties)
+  {
+    super(TYPE, properties);
+    if (cipher == null || mode == null)
+      throw new IllegalArgumentException("neither cipher nor mode can be null");
+    properties.put("cipher", cipher);
+    properties.put("mode", mode);
+    setMasked(false);
+  }
+
+  private EncryptedEntry()
+  {
+    super(TYPE, new Properties());
+    setMasked(true);
+  }
+
+  public static EncryptedEntry decode(DataInputStream in) throws IOException
+  {
+    EncryptedEntry entry = new EncryptedEntry();
+    entry.defaultDecode(in);
+    if (! entry.properties.containsKey("cipher"))
+      throw new MalformedKeyringException("no cipher");
+    if (! entry.properties.containsKey("cipher"))
+      throw new MalformedKeyringException("no cipher");
+    return entry;
+  }
+
+  public void decrypt(byte[] key, byte[] iv) throws IllegalArgumentException,
+      WrongPaddingException
+  {
+    if (! isMasked() || payload == null)
+      return;
+    IMode mode = getMode(key, iv, IMode.DECRYPTION);
+    IPad padding = null;
+    padding = PadFactory.getInstance("PKCS7");
+    padding.init(mode.currentBlockSize());
+    byte[] buf = new byte[payload.length];
+    int count = 0;
+    for (int i = 0; i < payload.length; i++)
+      {
+        mode.update(payload, count, buf, count);
+        count += mode.currentBlockSize();
+      }
+    int padlen = padding.unpad(buf, 0, buf.length);
+    int len = buf.length - padlen;
+    DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf, 0, len));
+    try
+      {
+        decodeEnvelope(in);
+      }
+    catch (IOException ioe)
+      {
+        throw new IllegalArgumentException("decryption failed");
+      }
+    setMasked(false);
+    payload = null;
+  }
+
+  public void encrypt(byte[] key, byte[] iv) throws IOException
+  {
+    IMode mode = getMode(key, iv, IMode.ENCRYPTION);
+    IPad pad = PadFactory.getInstance("PKCS7");
+    pad.init(mode.currentBlockSize());
+    ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
+    DataOutputStream out2 = new DataOutputStream(bout);
+    for (Iterator it = entries.iterator(); it.hasNext();)
+      {
+        Entry entry = (Entry) it.next();
+        entry.encode(out2);
+      }
+    byte[] plaintext = bout.toByteArray();
+    byte[] padding = pad.pad(plaintext, 0, plaintext.length);
+    payload = new byte[plaintext.length + padding.length];
+    byte[] lastBlock = new byte[mode.currentBlockSize()];
+    int l = mode.currentBlockSize() - padding.length;
+    System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l);
+    System.arraycopy(padding, 0, lastBlock, l, padding.length);
+    int count = 0;
+    while (count + mode.currentBlockSize() < plaintext.length)
+      {
+        mode.update(plaintext, count, payload, count);
+        count += mode.currentBlockSize();
+      }
+    mode.update(lastBlock, 0, payload, count);
+  }
+
+  public void encodePayload() throws IOException
+  {
+    if (payload == null)
+      throw new IOException("not encrypted");
+  }
+
+  private IMode getMode(byte[] key, byte[] iv, int state)
+  {
+    IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher"));
+    if (cipher == null)
+      throw new IllegalArgumentException("no such cipher: " + properties.get("cipher"));
+    int blockSize = cipher.defaultBlockSize();
+    if (properties.containsKey("block-size"))
+      {
+        try
+          {
+            blockSize = Integer.parseInt(properties.get("block-size"));
+          }
+        catch (NumberFormatException nfe)
+          {
+            throw new IllegalArgumentException("bad block size: "
+                                               + nfe.getMessage());
+          }
+      }
+    IMode mode = ModeFactory.getInstance(properties.get("mode"), cipher, blockSize);
+    if (mode == null)
+      throw new IllegalArgumentException("no such mode: " + properties.get("mode"));
+
+    HashMap modeAttr = new HashMap();
+    modeAttr.put(IMode.KEY_MATERIAL, key);
+    modeAttr.put(IMode.STATE, Integer.valueOf(state));
+    modeAttr.put(IMode.IV, iv);
+    try
+      {
+        mode.init(modeAttr);
+      }
+    catch (InvalidKeyException ike)
+      {
+        throw new IllegalArgumentException(ike.toString());
+      }
+    return mode;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/Entry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,179 @@
+/* Entry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.Configuration;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.logging.Logger;
+
+/**
+ * An immutable class representing a single entry in a keyring.
+ */
+public abstract class Entry
+{
+  private static final Logger log = Logger.getLogger(Entry.class.getName());
+  private static final String[] TYPES = new String[] {
+      "Encrypted",
+      "PasswordEncrypted",
+      "Authenticated",
+      "PasswordAuthenticated",
+      "Compressed",
+      "Certificate",
+      "PublicKey",
+      "PrivateKey",
+      "CertPath",
+      "BinaryData" };
+  /** This entry's type identifier. */
+  protected int type;
+  /** This entry's property set. */
+  protected Properties properties;
+  /** This entry's payload. */
+  protected byte[] payload;
+
+  /**
+   * Creates a new Entry.
+   * 
+   * @param type This entry's type.
+   * @param properties This entry's properties.
+   * @throws IllegalArgumentException If the properties argument is null, or if
+   *           the type is out of range.
+   */
+  protected Entry(int type, Properties properties)
+  {
+    if (type < 0 || type > 255)
+      throw new IllegalArgumentException("invalid packet type");
+    if (properties == null)
+      throw new IllegalArgumentException("no properties");
+    this.type = type;
+    this.properties = (Properties) properties.clone();
+  }
+
+  /**
+   * Constructor for use by subclasses.
+   */
+  protected Entry(final int type)
+  {
+    if (type < 0 || type > 255)
+      throw new IllegalArgumentException("invalid packet type");
+    this.type = type;
+    properties = new Properties();
+  }
+
+  /**
+   * Returns this entry's properties object. The properties are cloned before
+   * being returned.
+   * 
+   * @return The properties.
+   */
+  public Properties getProperties()
+  {
+    return (Properties) properties.clone();
+  }
+
+  /**
+   * Returns this entry's payload data, or null if
+   */
+  public byte[] getPayload()
+  {
+    if (payload == null)
+      return null;
+    return (byte[]) payload.clone();
+  }
+
+  /**
+   * This method is called when this entry needs to be written to an output
+   * stream.
+   * 
+   * @param out The stream to write to.
+   * @throws IOException If an I/O exception occurs.
+   */
+  public void encode(DataOutputStream out) throws IOException
+  {
+    if (payload == null)
+      encodePayload();
+    if (out == null)
+      return;
+    out.write(type);
+    properties.encode(out);
+    out.writeInt(payload.length);
+    out.write(payload);
+  }
+
+  public String toString()
+  {
+    return new StringBuilder("Entry{")
+        .append("type=").append(TYPES[type])
+        .append(", properties=").append(properties)
+        .append(", payload=")
+        .append(payload == null ? "-" : "byte[" + payload.length + "]")
+        .append( "}")
+        .toString();
+  }
+
+  /**
+   * Generic decoding method, which simply decodes the properties field
+   * and reads the payload field.
+   *
+   * @param in The input data stream.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected void defaultDecode(DataInputStream in) throws IOException
+  {
+    properties = new Properties();
+    properties.decode(in);
+    int len = in.readInt();
+    if (len < 0)
+      throw new IOException("corrupt length");
+    if (Configuration.DEBUG)
+      log.fine("About to instantiate new payload byte array for " + this);
+    payload = new byte[len];
+    in.readFully(payload);
+  }
+
+  /**
+   * This method is called of subclasses when the payload data needs to be
+   * created.
+   *
+   * @throws IOException If an encoding error occurs.
+   */
+  protected abstract void encodePayload() throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/EnvelopeEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,439 @@
+/* EnvelopeEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.Configuration;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.logging.Logger;
+
+/**
+ * An envelope entry is a generic container for some number of primitive and
+ * other envelope entries.
+ */
+public abstract class EnvelopeEntry
+    extends Entry
+{
+  private static final Logger log = Logger.getLogger(EnvelopeEntry.class.getName());
+  /** The envelope that contains this one (if any). */
+  protected EnvelopeEntry containingEnvelope;
+  /** The contained entries. */
+  protected List entries;
+
+  public EnvelopeEntry(int type, Properties properties)
+  {
+    super(type, properties);
+    entries = new LinkedList();
+    if (this.properties.get("alias-list") != null)
+      this.properties.remove("alias-list");
+  }
+
+  protected EnvelopeEntry(int type)
+  {
+    super(type);
+    entries = new LinkedList();
+  }
+
+  /**
+   * Adds an entry to this envelope.
+   * 
+   * @param entry The entry to add.
+   */
+  public void add(Entry entry)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "add", entry);
+    if (! containsEntry(entry))
+      {
+        if (entry instanceof EnvelopeEntry)
+          ((EnvelopeEntry) entry).setContainingEnvelope(this);
+        entries.add(entry);
+        if (Configuration.DEBUG)
+          log.fine("Payload is " + (payload == null ? "" : "not ") + "null");
+        makeAliasList();
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "add");
+  }
+
+  /**
+   * Tests if this envelope contains a primitive entry with the given alias.
+   * 
+   * @param alias The alias to test.
+   * @return True if this envelope (or one of the contained envelopes) contains
+   *         a primitive entry with the given alias.
+   */
+  public boolean containsAlias(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "containsAlias", alias);
+    String aliases = getAliasList();
+    if (Configuration.DEBUG)
+      log.fine("aliases = [" + aliases + "]");
+    boolean result = false;
+    if (aliases != null)
+      {
+        StringTokenizer tok = new StringTokenizer(aliases, ";");
+        while (tok.hasMoreTokens())
+          if (tok.nextToken().equals(alias))
+            {
+              result = true;
+              break;
+            }
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "containsAlias",
+                  Boolean.valueOf(result));
+    return result;
+  }
+
+  /**
+   * Tests if this envelope contains the given entry.
+   * 
+   * @param entry The entry to test.
+   * @return True if this envelope contains the given entry.
+   */
+  public boolean containsEntry(Entry entry)
+  {
+    if (entry instanceof EnvelopeEntry)
+      return entries.contains(entry);
+    if (entry instanceof PrimitiveEntry)
+      for (Iterator it = entries.iterator(); it.hasNext();)
+        {
+          Entry e = (Entry) it.next();
+          if (e.equals(entry))
+            return true;
+          if ((e instanceof EnvelopeEntry)
+              && ((EnvelopeEntry) e).containsEntry(entry))
+            return true;
+        }
+    return false;
+  }
+
+  /**
+   * Returns a copy of all entries this envelope contains.
+   * 
+   * @return All contained entries.
+   */
+  public List getEntries()
+  {
+    return new ArrayList(entries);
+  }
+
+  /**
+   * Gets all primitive entries that have the given alias. If there are any
+   * masked entries that contain the given alias, they will be returned as well.
+   * 
+   * @param alias The alias of the entries to get.
+   * @return A list of all primitive entries that have the given alias.
+   */
+  public List get(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "get", alias);
+    List result = new LinkedList();
+    for (Iterator it = entries.iterator(); it.hasNext();)
+      {
+        Entry e = (Entry) it.next();
+        if (e instanceof EnvelopeEntry)
+          {
+            EnvelopeEntry ee = (EnvelopeEntry) e;
+            if (! ee.containsAlias(alias))
+              continue;
+            if (ee instanceof MaskableEnvelopeEntry)
+              {
+                MaskableEnvelopeEntry mee = (MaskableEnvelopeEntry) ee;
+                if (mee.isMasked())
+                  {
+                    if (Configuration.DEBUG)
+                      log.fine("Processing masked entry: " + mee);
+                    result.add(mee);
+                    continue;
+                  }
+              }
+            if (Configuration.DEBUG)
+              log.fine("Processing unmasked entry: " + ee);
+            result.addAll(ee.get(alias));
+          }
+        else if (e instanceof PrimitiveEntry)
+          {
+            PrimitiveEntry pe = (PrimitiveEntry) e;
+            if (pe.getAlias().equals(alias))
+              result.add(e);
+          }
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "get", result);
+    return result;
+  }
+
+  /**
+   * Returns the list of all aliases contained by this envelope, separated by a
+   * semicolon (';').
+   * 
+   * @return The list of aliases.
+   */
+  public String getAliasList()
+  {
+    String list = properties.get("alias-list");
+    if (list == null)
+      return "";
+    else
+      return list;
+  }
+
+  /**
+   * Removes the specified entry.
+   * 
+   * @param entry The entry.
+   * @return True if an entry was removed.
+   */
+  public boolean remove(Entry entry)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "remove", entry);
+    boolean ret = false;
+    for (Iterator it = entries.iterator(); it.hasNext();)
+      {
+        Entry e = (Entry) it.next();
+        if (e instanceof EnvelopeEntry)
+          {
+            if (e == entry)
+              {
+                it.remove();
+                ret = true;
+                break;
+              }
+            if (((EnvelopeEntry) e).remove(entry))
+              {
+                ret = true;
+                break;
+              }
+          }
+        else if (e instanceof PrimitiveEntry)
+          {
+            if (((PrimitiveEntry) e).equals(entry))
+              {
+                it.remove();
+                ret = true;
+                break;
+              }
+          }
+      }
+    if (ret)
+      {
+        if (Configuration.DEBUG)
+          log.fine("State before: " + this);
+        payload = null;
+        makeAliasList();
+        if (Configuration.DEBUG)
+          log.fine("State after: " + this);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(ret));
+    return ret;
+  }
+
+  /**
+   * Removes all primitive entries that have the specified alias.
+   * 
+   * @param alias The alias of the entries to remove.
+   * @return <code>true</code> if <code>alias</code> was present and was
+   *         successfully trmoved. Returns <code>false</code> if
+   *         <code>alias</code> was not present in the list of aliases in this
+   *         envelope.
+   */
+  public boolean remove(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "remove", alias);
+    boolean result = false;
+    for (Iterator it = entries.iterator(); it.hasNext();)
+      {
+        Entry e = (Entry) it.next();
+        if (e instanceof EnvelopeEntry)
+          {
+            EnvelopeEntry ee = (EnvelopeEntry) e;
+            result = ee.remove(alias) || result;
+          }
+        else if (e instanceof PrimitiveEntry)
+          {
+            PrimitiveEntry pe = (PrimitiveEntry) e;
+            if (pe.getAlias().equals(alias))
+              {
+                it.remove();
+                result = true;
+              }
+          }
+      }
+    if (result)
+      {
+        if (Configuration.DEBUG)
+          log.fine("State before: " + this);
+        payload = null;
+        makeAliasList();
+        if (Configuration.DEBUG)
+          log.fine("State after: " + this);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(result));
+    return result;
+  }
+
+  public String toString()
+  {
+    return new StringBuilder("Envelope{")
+        .append(super.toString())
+        .append(", entries=").append(entries)
+        .append("}")
+        .toString();
+  }
+
+  // Protected methods.
+  // ------------------------------------------------------------------------
+
+  protected void encodePayload() throws IOException
+  {
+    ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
+    DataOutputStream out = new DataOutputStream(bout);
+    for (Iterator it = entries.iterator(); it.hasNext();)
+      ((Entry) it.next()).encode(out);
+  }
+
+  protected void setContainingEnvelope(EnvelopeEntry e)
+  {
+    if (containingEnvelope != null)
+      throw new IllegalArgumentException("envelopes may not be shared");
+    containingEnvelope = e;
+  }
+
+  protected void decodeEnvelope(DataInputStream in) throws IOException
+  {
+    this.entries.clear();
+    while (true)
+      {
+        int type = in.read();
+        switch (type)
+          {
+          case EncryptedEntry.TYPE:
+            add(EncryptedEntry.decode(in));
+            break;
+          case PasswordEncryptedEntry.TYPE:
+            add(PasswordEncryptedEntry.decode(in));
+            break;
+          case PasswordAuthenticatedEntry.TYPE:
+            add(PasswordAuthenticatedEntry.decode(in));
+            break;
+          case AuthenticatedEntry.TYPE:
+            add(AuthenticatedEntry.decode(in));
+            break;
+          case CompressedEntry.TYPE:
+            add(CompressedEntry.decode(in));
+            break;
+          case CertificateEntry.TYPE:
+            add(CertificateEntry.decode(in));
+            break;
+          case PublicKeyEntry.TYPE:
+            add(PublicKeyEntry.decode(in));
+            break;
+          case PrivateKeyEntry.TYPE:
+            add(PrivateKeyEntry.decode(in));
+            break;
+          case CertPathEntry.TYPE:
+            add(CertPathEntry.decode(in));
+            break;
+          case BinaryDataEntry.TYPE:
+            add(BinaryDataEntry.decode(in));
+            break;
+          case -1:
+            return;
+          default:
+            throw new MalformedKeyringException("unknown type " + type);
+          }
+      }
+  }
+
+  private void makeAliasList()
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "makeAliasList");
+    if (! entries.isEmpty())
+      {
+        StringBuilder buf = new StringBuilder();
+        String aliasOrList;
+        for (Iterator it = entries.iterator(); it.hasNext();)
+          {
+            Entry entry = (Entry) it.next();
+            aliasOrList = null;
+            if (entry instanceof EnvelopeEntry)
+              aliasOrList = ((EnvelopeEntry) entry).getAliasList();
+            else if (entry instanceof PrimitiveEntry)
+              aliasOrList = ((PrimitiveEntry) entry).getAlias();
+            else if (Configuration.DEBUG)
+              log.fine("Entry with no Alias. Ignored: " + entry);
+            if (aliasOrList != null)
+              {
+                aliasOrList = aliasOrList.trim();
+                if (aliasOrList.trim().length() > 0)
+                  {
+                    buf.append(aliasOrList);
+                    if (it.hasNext())
+                      buf.append(';');
+                  }
+              }
+          }
+        String aliasList = buf.toString();
+        properties.put("alias-list", aliasList);
+        if (Configuration.DEBUG)
+          log.fine("alias-list=[" + aliasList + "]");
+        if (containingEnvelope != null)
+          containingEnvelope.makeAliasList();
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "makeAliasList");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/GnuPrivateKeyring.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,368 @@
+/* GnuPrivateKeyring.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * 
+ */
+public class GnuPrivateKeyring
+    extends BaseKeyring
+    implements IPrivateKeyring
+{
+  private static final Logger log = Logger.getLogger(GnuPrivateKeyring.class.getName());
+  public static final int USAGE = Registry.GKR_PRIVATE_KEYS
+                                  | Registry.GKR_PUBLIC_CREDENTIALS;
+  protected String mac;
+  protected int maclen;
+  protected String cipher;
+  protected String mode;
+  protected int keylen;
+
+  public GnuPrivateKeyring(String mac, int maclen, String cipher, String mode,
+                           int keylen)
+  {
+    keyring = new PasswordAuthenticatedEntry(mac, maclen, new Properties());
+    keyring2 = new CompressedEntry(new Properties());
+    keyring.add(keyring2);
+    this.mac = mac;
+    this.maclen = maclen;
+    this.cipher = cipher;
+    this.mode = mode;
+    this.keylen = keylen;
+  }
+
+  public GnuPrivateKeyring()
+  {
+    this("HMAC-SHA-1", 20, "AES", "OFB", 16);
+  }
+
+  public boolean containsPrivateKey(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "containsPrivateKey", alias);
+    boolean result = false;
+    if (containsAlias(alias))
+      for (Iterator it = get(alias).iterator(); it.hasNext();)
+        if (it.next() instanceof PasswordAuthenticatedEntry)
+          {
+            result = true;
+            break;
+          }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "containsPrivateKey",
+                  Boolean.valueOf(result));
+    return result;
+  }
+
+  public Key getPrivateKey(String alias, char[] password)
+      throws UnrecoverableKeyException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "getPrivateKey", alias);
+    Key result = null;
+    if (containsAlias(alias))
+      {
+        PasswordAuthenticatedEntry e1 = null;
+        for (Iterator it = get(alias).iterator(); it.hasNext();)
+          {
+            Entry e = (Entry) it.next();
+            if (Configuration.DEBUG)
+              log.finest("Entry: " + e);
+            if (e instanceof PasswordAuthenticatedEntry)
+              {
+                e1 = (PasswordAuthenticatedEntry) e;
+                break;
+              }
+          }
+        if (Configuration.DEBUG)
+          log.fine("e1 = " + e1);
+        if (e1 != null)
+          {
+            try
+              {
+                e1.verify(password);
+              }
+            catch (Exception e)
+              {
+                if (Configuration.DEBUG)
+                  log.throwing(this.getClass().getName(), "getPrivateKey", e);
+                throw new UnrecoverableKeyException("authentication failed");
+              }
+            PasswordEncryptedEntry e2 = null;
+            for (Iterator it = e1.getEntries().iterator(); it.hasNext();)
+              {
+                Entry e = (Entry) it.next();
+                if (e instanceof PasswordEncryptedEntry)
+                  {
+                    e2 = (PasswordEncryptedEntry) e;
+                    break;
+                  }
+              }
+            if (e2 != null)
+              {
+                try
+                  {
+                    e2.decrypt(password);
+                  }
+                catch (Exception e)
+                  {
+                    log.throwing(this.getClass().getName(), "getPrivateKey", e);
+                    throw new UnrecoverableKeyException("decryption failed");
+                  }
+                for (Iterator it = e2.get(alias).iterator(); it.hasNext();)
+                  {
+                    Entry e = (Entry) it.next();
+                    if (e instanceof PrivateKeyEntry)
+                      {
+                        result = ((PrivateKeyEntry) e).getKey();
+                        break;
+                      }
+                  }
+              }
+          }
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "getPrivateKey",
+                  result == null ? "null" : result.getClass().getName());
+    return result;
+  }
+
+  public void putPrivateKey(String alias, Key key, char[] password)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "putPrivateKey",
+                   new Object[] { alias, key.getClass().getName() });
+    if (! containsPrivateKey(alias))
+      {
+        alias = fixAlias(alias);
+        Properties p = new Properties();
+        p.put("alias", alias);
+        PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p);
+        if (Configuration.DEBUG)
+          log.fine("About to encrypt the key...");
+        PasswordEncryptedEntry enc;
+        enc = new PasswordEncryptedEntry(cipher, mode, keylen, new Properties());
+        enc.add(pke);
+        try
+          {
+            enc.encode(null, password);
+          }
+        catch (IOException x)
+          {
+            if (Configuration.DEBUG)
+              log.log(Level.FINE, "Exception while encrypting the key. "
+                                  + "Rethrow as IllegalArgumentException", x);
+            throw new IllegalArgumentException(x.toString());
+          }
+        if (Configuration.DEBUG)
+          log.fine("About to authenticate the encrypted key...");
+        PasswordAuthenticatedEntry auth;
+        auth = new PasswordAuthenticatedEntry(mac, maclen, new Properties());
+        auth.add(enc);
+        try
+          {
+            auth.encode(null, password);
+          }
+        catch (IOException x)
+          {
+            if (Configuration.DEBUG)
+              log.log(Level.FINE, "Exception while authenticating the encrypted "
+                                  + "key. Rethrow as IllegalArgumentException", x);
+            throw new IllegalArgumentException(x.toString());
+          }
+        keyring.add(auth);
+      }
+    else if (Configuration.DEBUG)
+      log.fine("Keyring already contains alias: " + alias);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "putPrivateKey");
+  }
+
+  public boolean containsPublicKey(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "containsPublicKey", alias);
+    boolean result = false;
+    if (containsAlias(alias))
+      for (Iterator it = get(alias).iterator(); it.hasNext();)
+        if (it.next() instanceof PublicKeyEntry)
+          {
+            result = true;
+            break;
+          }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "containsPublicKey",
+                  Boolean.valueOf(result));
+    return result;
+  }
+
+  public PublicKey getPublicKey(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "getPublicKey", alias);
+    PublicKey result = null;
+    if (containsAlias(alias))
+      for (Iterator it = get(alias).iterator(); it.hasNext();)
+        {
+          Entry e = (Entry) it.next();
+          if (e instanceof PublicKeyEntry)
+            {
+              result = ((PublicKeyEntry) e).getKey();
+              break;
+            }
+        }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "getPublicKey",
+                  result == null ? "null" : result.getClass().getName());
+    return result;
+  }
+
+  public void putPublicKey(String alias, PublicKey key)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "putPublicKey",
+                   new Object[] { alias, key.getClass().getName() });
+    if (! containsPublicKey(alias))
+      {
+        Properties p = new Properties();
+        p.put("alias", fixAlias(alias));
+        add(new PublicKeyEntry(key, new Date(), p));
+      }
+    else if (Configuration.DEBUG)
+      log.fine("Keyring already contains alias: " + alias);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "putPublicKey");
+  }
+
+  public boolean containsCertPath(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "containsCertPath", alias);
+    boolean result = false;
+    if (containsAlias(alias))
+      for (Iterator it = get(alias).iterator(); it.hasNext();)
+        if (it.next() instanceof CertPathEntry)
+          {
+            result = true;
+            break;
+          }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "containsCertPath",
+                  Boolean.valueOf(result));
+    return result;
+  }
+
+  public Certificate[] getCertPath(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "getCertPath", alias);
+    Certificate[] result = null;
+    if (containsAlias(alias))
+      for (Iterator it = get(alias).iterator(); it.hasNext();)
+        {
+          Entry e = (Entry) it.next();
+          if (e instanceof CertPathEntry)
+            {
+              result = ((CertPathEntry) e).getCertPath();
+              break;
+            }
+        }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "getCertPath", result);
+    return result;
+  }
+
+  public void putCertPath(String alias, Certificate[] path)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "putCertPath",
+                   new Object[] { alias, path });
+    if (! containsCertPath(alias))
+      {
+        Properties p = new Properties();
+        p.put("alias", fixAlias(alias));
+        add(new CertPathEntry(path, new Date(), p));
+      }
+    else if (Configuration.DEBUG)
+      log.fine("Keyring already contains alias: " + alias);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "putCertPath");
+  }
+
+  protected void load(InputStream in, char[] password) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "load");
+    if (in.read() != USAGE)
+      throw new MalformedKeyringException("incompatible keyring usage");
+    if (in.read() != PasswordAuthenticatedEntry.TYPE)
+      throw new MalformedKeyringException(
+          "expecting password-authenticated entry tag");
+    keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), password);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "load");
+  }
+
+  protected void store(OutputStream out, char[] password) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "store");
+    out.write(USAGE);
+    keyring.encode(new DataOutputStream(out), password);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "store");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/GnuPublicKeyring.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,151 @@
+/* GnuPublicKeyring.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+public class GnuPublicKeyring
+    extends BaseKeyring
+    implements IPublicKeyring
+{
+  private static final Logger log = Logger.getLogger(GnuPublicKeyring.class.getName());
+  public static final int USAGE = Registry.GKR_CERTIFICATES;
+
+  public GnuPublicKeyring(String mac, int macLen)
+  {
+    keyring = new PasswordAuthenticatedEntry(mac, macLen, new Properties());
+    keyring2 = new CompressedEntry(new Properties());
+    keyring.add(keyring2);
+  }
+
+  public GnuPublicKeyring()
+  {
+  }
+
+  public boolean containsCertificate(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "containsCertificate", alias);
+    boolean result = false;
+    if (containsAlias(alias))
+      for (Iterator it = get(alias).iterator(); it.hasNext();)
+        if (it.next() instanceof CertificateEntry)
+          {
+            result = true;
+            break;
+          }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "containsCertificate",
+                  Boolean.valueOf(result));
+    return result;
+  }
+
+  public Certificate getCertificate(String alias)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "getCertificate", alias);
+    Certificate result = null;
+    if (containsAlias(alias))
+      for (Iterator it = get(alias).iterator(); it.hasNext();)
+        {
+          Entry e = (Entry) it.next();
+          if (e instanceof CertificateEntry)
+            {
+              result = ((CertificateEntry) e).getCertificate();
+              break;
+            }
+        }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "getCertificate", result);
+    return result;
+  }
+
+  public void putCertificate(String alias, Certificate cert)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "putCertificate",
+                   new Object[] { alias, cert });
+    if (! containsCertificate(alias))
+      {
+        Properties p = new Properties();
+        p.put("alias", fixAlias(alias));
+        add(new CertificateEntry(cert, new Date(), p));
+      }
+    else if (Configuration.DEBUG)
+      log.fine("Keyring already contains alias: " + alias);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "putCertificate");
+  }
+
+  protected void load(InputStream in, char[] password) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "load");
+    if (in.read() != USAGE)
+      throw new MalformedKeyringException("incompatible keyring usage");
+    if (in.read() != PasswordAuthenticatedEntry.TYPE)
+      throw new MalformedKeyringException(
+          "expecting password-authenticated entry tag");
+    DataInputStream dis = new DataInputStream(in);
+    keyring = PasswordAuthenticatedEntry.decode(dis, password);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "load");
+  }
+
+  protected void store(OutputStream out, char[] password) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "store");
+    out.write(USAGE);
+    keyring.encode(new DataOutputStream(out), password);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "store");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/IKeyring.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,162 @@
+/* IKeyring.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The top-level interface to a <i>keyring:</i> a file that is used to store
+ * and protect public and private cryptographic keys.
+ * <p>
+ * A <i>keyring</i> is modelled as a mapping of one <i>alias</i> to one or
+ * more <i>entries</i> (optionally of different types).
+ * <p>
+ * See also the sub-interfaces {@link IPublicKeyring} and
+ * {@link IPrivateKeyring} for special types of <i>keyrings</i> --the
+ * difference being in the type of entries they contain.
+ */
+public interface IKeyring
+{
+  /**
+   * Property name for the source of data to load the keyring from. The value
+   * mapped must be a {@link java.io.InputStream}.
+   */
+  public static final String KEYRING_DATA_IN = "gnu.crypto.keyring.data.in";
+
+  /**
+   * Property name for the data sink to store the keyring to. The value mapped
+   * must be a {@link java.io.OutputStream}.
+   */
+  public static final String KEYRING_DATA_OUT = "gun.crypto.keyring.data.out";
+
+  /**
+   * Property name for the keyring's top-level password, used to authenticate
+   * and/or transform the store itself. The mapped value must be a char array.
+   */
+  public static final String KEYRING_PASSWORD = "gnu.crypto.keyring.password";
+
+  /**
+   * Loads a keyring into memory.
+   * <p>
+   * What happens to the current contents of this keyring? are the new ones
+   * merged with the current ones or do they simply replace them?
+   * 
+   * @param attributes The attributes that designate the source where the store
+   *          is to be loaded from. What happens
+   * @throws IllegalArgumentException If the attributes are inappropriate.
+   * @throws IOException If the keyring file cannot be read.
+   * @throws SecurityException If the given password is incorrect, or if the
+   *           top-level authentication or decryption fails.
+   */
+  void load(Map attributes) throws IOException;
+
+  /**
+   * Stores the contents of this keyring to persistent storage as specified by
+   * the designated <code>attributes</code>.
+   * 
+   * @param attributes the attributes that define where the contents of this
+   *          keyring will be stored.
+   * @throws IOException if an exception occurs during the process.
+   */
+  void store(Map attributes) throws IOException;
+
+  /**
+   * Resets this keyring, clearing all sensitive data. This method always
+   * suceeds.
+   */
+  void reset();
+
+  /**
+   * Returns the number of entries in this keyring.
+   * 
+   * @return The number of current entries in this keyring.
+   */
+  int size();
+
+  /**
+   * Returns an {@link Enumeration} of all aliases (instances of {@link String})
+   * in this keyring.
+   * 
+   * @return The enumeration of {@link String}s each representing an <i>alias</i>
+   *         found in this keyring.
+   */
+  Enumeration aliases();
+
+  /**
+   * Tests whether or not this keyring contains the given alias.
+   * 
+   * @param alias The alias to check.
+   * @return true if this keyring contains the alias.
+   */
+  boolean containsAlias(String alias);
+
+  /**
+   * Returns a {@link List} of entries (instances of {@link Entry}) for the
+   * given <code>alias</code>, or <code>null</code> if there no such entry
+   * exists.
+   * 
+   * @param alias The alias of the entry(ies) to return.
+   * @return A list of all entries (instances of {@link Entry} that have the
+   *         given <code>alias</code>, or <code>null</code> if no one
+   *         {@link Entry} can be found with the designated <code>alias</code>.
+   */
+  List get(String alias);
+
+  /**
+   * Adds a designated {@link Entry} to this keyring.
+   * <p>
+   * What happens if there is already an entry with the same alias?
+   * 
+   * @param entry The entry to put in this keyring.
+   */
+  void add(Entry entry);
+
+  /**
+   * Removes an entry with the designated <code>alias</code> from this
+   * keyring. Does nothing if there was no such entry.
+   * <p>
+   * What happens if there are more than one?
+   * 
+   * @param alias The alias of the entry to remove.
+   */
+  void remove(String alias);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/IPrivateKeyring.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,144 @@
+/* IPrivateKeyring.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.security.Key;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+
+/**
+ * An interface to private, or "personal", keyrings, which contain private
+ * credentials. The contract is that each such entry is known by a unique
+ * <i>alias</i>.
+ * <p>
+ * What about public keys? and certificate-path?
+ */
+public interface IPrivateKeyring
+    extends IKeyring
+{
+  /**
+   * Tests if this keyring contains a private key entry with the given
+   * <code>alias</code>.
+   * 
+   * @param alias The alias to check.
+   * @return <code>true</code> if this keyring contains a private key with the
+   *         given <code>alias</code>; <code>false</code> otherwise.
+   */
+  boolean containsPrivateKey(String alias);
+
+  /**
+   * Returns the private key with the given <code>alias</code>.
+   * 
+   * @param alias The alias of the private key to find.
+   * @param password The password of the private key.
+   * @return The private, or secret, key if one is found; <code>null</code> if
+   *         none were found.
+   * @throws UnrecoverableKeyException If the private key could not be
+   *           recovered, possibly due to a bad password.
+   */
+  Key getPrivateKey(String alias, char[] password)
+      throws UnrecoverableKeyException;
+
+  /**
+   * Adds a private key to this keyring.
+   * 
+   * @param alias The alias of the private key.
+   * @param key The private key.
+   * @param password The password used to protect this private key.
+   */
+  void putPrivateKey(String alias, Key key, char[] password);
+
+  /**
+   * Checks if this keyring contains a public key with the given
+   * <code>alias</code>.
+   * 
+   * @param alias The alias to test.
+   * @return <code>true</code> if this keyring contains a public key entry
+   *         with the given <code>alias</code>; <code>false</code>
+   *         otherwise.
+   */
+  boolean containsPublicKey(String alias);
+
+  /**
+   * Returns the public key with the given <code>alias</code>, or
+   * <code>null</code> if there is no such entry.
+   * 
+   * @param alias The alias of the public key to find.
+   * @return The public key; or <code>null</code> if none were found.
+   */
+  PublicKey getPublicKey(String alias);
+
+  /**
+   * Sets a public key entry.
+   * 
+   * @param alias The alias for this public key.
+   * @param key The public key.
+   */
+  void putPublicKey(String alias, PublicKey key);
+
+  /**
+   * Checks if this keyring contains a certificate path with the given
+   * <code>alias</code>.
+   * 
+   * @param alias The alias to check.
+   * @return <code>true</code> if this keyring contains a certificate path
+   *         with the given <code>alias</code>; <code>false</code>
+   *         otherwise.
+   */
+  boolean containsCertPath(String alias);
+
+  /**
+   * Returns the certificate path with the given <code>alias</code>, or
+   * <code>null</code> if there is no such entry.
+   * 
+   * @param alias The alias of the certificate path to find.
+   * @return The certificate path for the designated <code>alias</code>; or
+   *         <code>null</code> if none were found.
+   */
+  Certificate[] getCertPath(String alias);
+
+  /**
+   * Sets a certificate path entry.
+   * 
+   * @param alias The alias for this certificate path.
+   * @param path The certificate path.
+   */
+  void putCertPath(String alias, Certificate[] path);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/IPublicKeyring.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,82 @@
+/* IPublicKeyring.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.security.cert.Certificate;
+
+/**
+ * An interface for keyrings that contain trusted (by the owner) public
+ * credentials (incl. certificates).
+ * 
+ * @see IKeyring
+ */
+public interface IPublicKeyring
+    extends IKeyring
+{
+  /**
+   * Tests if this keyring contains a certificate entry with the specified
+   * <code>alias</code>.
+   * 
+   * @param alias The alias of the certificate to check.
+   * @return <code>true</code> if this keyring contains a certificate entry
+   *         that has the given <code>alias</code>; <code>false</code>
+   *         otherwise.
+   */
+  boolean containsCertificate(String alias);
+
+  /**
+   * Returns a certificate that has the given <code>alias</code>, or
+   * <code>null</code> if this keyring has no such entry.
+   * 
+   * @param alias The alias of the certificate to find.
+   * @return The certificate with the designated <code>alias</code>, or
+   *         <code>null</code> if none found.
+   */
+  Certificate getCertificate(String alias);
+
+  /**
+   * Adds a certificate in this keyring, with the given <code>alias</code>.
+   * <p>
+   * What happens if there is already a certificate entry with this alias?
+   * 
+   * @param alias The alias of this certificate entry.
+   * @param cert The certificate.
+   */
+  void putCertificate(String alias, Certificate cert);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/MalformedKeyringException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,55 @@
+/* MalformedKeyringException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.io.IOException;
+
+public class MalformedKeyringException
+    extends IOException
+{
+  public MalformedKeyringException()
+  {
+    super();
+  }
+
+  public MalformedKeyringException(String msg)
+  {
+    super(msg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,135 @@
+/* MaskableEnvelopeEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An envelope entry that can be "masked" -- placed in a state where the
+ * envelope's contents cannot be accessed, due to the envelope not being fully
+ * decoded, for example.
+ */
+public abstract class MaskableEnvelopeEntry
+    extends EnvelopeEntry
+{
+  /** The masked state. */
+  protected boolean masked;
+
+  public MaskableEnvelopeEntry(int type, Properties properties)
+  {
+    super(type, properties);
+  }
+
+  protected MaskableEnvelopeEntry(int type)
+  {
+    super(type);
+  }
+
+  /**
+   * Sets the masked state to the specified value.
+   * 
+   * @param masked The new masked state.
+   */
+  protected final void setMasked(boolean masked)
+  {
+    this.masked = masked;
+  }
+
+  /**
+   * Gets the masked state of this object. Certain operations on this object
+   * will fail if it is masked.
+   * 
+   * @return The current masked state.
+   */
+  public boolean isMasked()
+  {
+    return masked;
+  }
+
+  public void add(Entry entry)
+  {
+    if (isMasked())
+      throw new IllegalStateException("masked envelope");
+    super.add(entry);
+  }
+
+  public boolean containsEntry(Entry entry)
+  {
+    if (isMasked())
+      throw new IllegalStateException("masked envelope");
+    return super.containsEntry(entry);
+  }
+
+  public List getEntries()
+  {
+    if (isMasked())
+      throw new IllegalStateException("masked envelope");
+    return new ArrayList(entries);
+  }
+
+  public List get(String alias)
+  {
+    if (isMasked())
+      throw new IllegalStateException("masked envelope");
+    return super.get(alias);
+  }
+
+  public boolean remove(Entry entry)
+  {
+    if (isMasked())
+      throw new IllegalStateException("masked envelope");
+    return super.remove(entry);
+  }
+
+  public boolean remove(String alias)
+  {
+    if (isMasked())
+      throw new IllegalStateException("masked envelope");
+    return super.remove(alias);
+  }
+
+  public String toString()
+  {
+    return new StringBuilder("MaskableEnvelope{")
+        .append(super.toString())
+        .append(", masked=").append(masked)
+        .append("}").toString();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/MeteredInputStream.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,127 @@
+/* MeteredInputStream.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+final class MeteredInputStream
+    extends FilterInputStream
+{
+  private int count;
+  private final int limit;
+
+  MeteredInputStream(InputStream in, int limit)
+  {
+    super(in);
+    if (limit < 0)
+      throw new IllegalArgumentException("limit must be nonnegative");
+    this.limit = limit;
+    count = 0;
+  }
+
+  /**
+   * Tests if the number of bytes read has reached the limit.
+   * 
+   * @return True if the limit has been reached.
+   */
+  public boolean limitReached()
+  {
+    return count == limit;
+  }
+
+  public int available() throws IOException
+  {
+    return Math.min(in.available(), limit - count);
+  }
+
+  public void close() throws IOException
+  {
+    in.close();
+  }
+
+  public void mark(int readLimit)
+  {
+  }
+
+  public boolean markSupported()
+  {
+    return false;
+  }
+
+  public int read() throws IOException
+  {
+    if (limitReached())
+      return -1;
+    int i = in.read();
+    if (i != -1)
+      count++;
+    return i;
+  }
+
+  public int read(byte[] buf) throws IOException
+  {
+    return read(buf, 0, buf.length);
+  }
+
+  public int read(byte[] buf, int off, int len) throws IOException
+  {
+    if (limitReached())
+      return -1;
+    int i = in.read(buf, off, Math.min(len, limit - count));
+    if (i != -1)
+      count += i;
+    return i;
+  }
+
+  public void reset() throws IOException
+  {
+  }
+
+  public long skip(long len) throws IOException
+  {
+    if (limitReached())
+      return 0L;
+    len = Math.min(len, limit - count);
+    len = in.skip(len);
+    count += (int) len;
+    return len;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,286 @@
+/* PasswordAuthenticatedEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.PRNG;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mac.MacFactory;
+import gnu.javax.crypto.mac.MacInputStream;
+import gnu.javax.crypto.mac.MacOutputStream;
+import gnu.javax.crypto.prng.IPBE;
+import gnu.javax.crypto.prng.PRNGFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+/**
+ * An entry authenticated with a password-based MAC.
+ */
+public final class PasswordAuthenticatedEntry
+    extends MaskableEnvelopeEntry
+    implements PasswordProtectedEntry, Registry
+{
+  private static final Logger log = Logger.getLogger(PasswordAuthenticatedEntry.class.getName());
+  public static final int TYPE = 3;
+
+  public PasswordAuthenticatedEntry(String mac, int maclen,
+                                    Properties properties)
+  {
+    super(TYPE, properties);
+    if (mac == null || mac.length() == 0)
+      throw new IllegalArgumentException("no MAC specified");
+    this.properties.put("mac", mac);
+    this.properties.put("maclen", String.valueOf(maclen));
+    setMasked(false);
+  }
+
+  private PasswordAuthenticatedEntry()
+  {
+    super(TYPE);
+    setMasked(true);
+  }
+
+  public static PasswordAuthenticatedEntry decode(DataInputStream in,
+                                                  char[] password)
+      throws IOException
+  {
+    PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry();
+    entry.properties.decode(in);
+    IMac mac = entry.getMac(password);
+    int len = in.readInt() - mac.macSize();
+    MeteredInputStream min = new MeteredInputStream(in, len);
+    MacInputStream macin = new MacInputStream(min, mac);
+    DataInputStream in2 = new DataInputStream(macin);
+    entry.setMasked(false);
+    entry.decodeEnvelope(in2);
+    byte[] macValue = new byte[mac.macSize()];
+    in.readFully(macValue);
+    if (! Arrays.equals(macValue, mac.digest()))
+      throw new MalformedKeyringException("MAC verification failed");
+    return entry;
+  }
+
+  public static PasswordAuthenticatedEntry decode(DataInputStream in)
+      throws IOException
+  {
+    PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry();
+    entry.defaultDecode(in);
+    if (! entry.properties.containsKey("mac"))
+      throw new MalformedKeyringException("no MAC");
+    if (! entry.properties.containsKey("maclen"))
+      throw new MalformedKeyringException("no MAC length");
+    if (! entry.properties.containsKey("salt"))
+      throw new MalformedKeyringException("no salt");
+    return entry;
+  }
+
+  public void verify(char[] password)
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "verify");
+    if (isMasked() && payload != null)
+      {
+        if (Configuration.DEBUG)
+          log.fine("payload to verify: " + Util.dumpString(payload));
+        long tt = -System.currentTimeMillis();
+        IMac m = null;
+        try
+          {
+            m = getMac(password);
+          }
+        catch (Exception x)
+          {
+            throw new IllegalArgumentException(x.toString(), x);
+          }
+        int limit = payload.length - m.macSize();
+        m.update(payload, 0, limit);
+        byte[] macValue = new byte[m.macSize()];
+        System.arraycopy(payload, payload.length - macValue.length, macValue,
+                         0, macValue.length);
+        if (! Arrays.equals(macValue, m.digest()))
+          throw new IllegalArgumentException("MAC verification failed");
+        setMasked(false);
+        ByteArrayInputStream bais;
+        try
+          {
+            bais = new ByteArrayInputStream(payload, 0, limit);
+            DataInputStream in = new DataInputStream(bais);
+            decodeEnvelope(in);
+          }
+        catch (IOException ioe)
+          {
+            throw new IllegalArgumentException("malformed keyring fragment");
+          }
+        tt += System.currentTimeMillis();
+        if (Configuration.DEBUG)
+          log.fine("Verified in " + tt + "ms.");
+      }
+    else if (Configuration.DEBUG)
+      log.fine("Skip verification; "
+               + (isMasked() ? "null payload" : "unmasked"));
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "verify");
+  }
+
+  public void authenticate(char[] password) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "authenticate");
+    long tt = -System.currentTimeMillis();
+    long t1 = -System.currentTimeMillis();
+    if (isMasked())
+      throw new IllegalStateException("entry is masked");
+    byte[] salt = new byte[8];
+    PRNG.getInstance().nextBytes(salt);
+    t1 += System.currentTimeMillis();
+    if (Configuration.DEBUG)
+      log.fine("-- Generated salt in " + t1 + "ms.");
+    properties.put("salt", Util.toString(salt));
+    IMac m = getMac(password);
+    ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
+    MacOutputStream macout = new MacOutputStream(bout, m);
+    DataOutputStream out2 = new DataOutputStream(macout);
+    for (Iterator it = entries.iterator(); it.hasNext();)
+      {
+        Entry entry = (Entry) it.next();
+        if (Configuration.DEBUG)
+          log.fine("-- About to authenticate one " + entry);
+        t1 = -System.currentTimeMillis();
+        entry.encode(out2);
+        t1 += System.currentTimeMillis();
+        if (Configuration.DEBUG)
+          log.fine("-- Authenticated an Entry in " + t1 + "ms.");
+      }
+    bout.write(m.digest());
+    payload = bout.toByteArray();
+    if (Configuration.DEBUG)
+      log.fine("authenticated payload: " + Util.dumpString(payload));
+    setMasked(true);
+    tt += System.currentTimeMillis();
+    if (Configuration.DEBUG)
+      {
+        log.fine("Authenticated in " + tt + "ms.");
+        log.exiting(this.getClass().getName(), "authenticate");
+      }
+  }
+
+  public void encode(DataOutputStream out, char[] password) throws IOException
+  {
+    authenticate(password);
+    encode(out);
+  }
+
+  protected void encodePayload(DataOutputStream out) throws IOException
+  {
+    if (payload == null)
+      {
+        log.fine("Null payload: " + this);
+        throw new IllegalStateException("mac not computed");
+      }
+  }
+
+  private IMac getMac(char[] password) throws MalformedKeyringException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "getMac");
+    String saltString = properties.get("salt");
+    if (saltString == null)
+      throw new MalformedKeyringException("no salt");
+    byte[] salt = Util.toBytesFromString(saltString);
+    String macAlgorithm = properties.get("mac");
+    IMac mac = MacFactory.getInstance(macAlgorithm);
+    if (mac == null)
+      throw new MalformedKeyringException("no such mac: " + macAlgorithm);
+    String macLenString = properties.get("maclen");
+    if (macLenString == null)
+      throw new MalformedKeyringException("no MAC length");
+    int maclen;
+    try
+      {
+        maclen = Integer.parseInt(macLenString);
+      }
+    catch (NumberFormatException nfe)
+      {
+        throw new MalformedKeyringException("bad MAC length");
+      }
+    HashMap pbAttr = new HashMap();
+    pbAttr.put(IPBE.PASSWORD, password);
+    pbAttr.put(IPBE.SALT, salt);
+    pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT);
+    IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA");
+    kdf.init(pbAttr);
+    int keylen = mac.macSize();
+    byte[] dk = new byte[keylen];
+    try
+      {
+        kdf.nextBytes(dk, 0, keylen);
+      }
+    catch (LimitReachedException shouldNotHappen)
+      {
+        throw new Error(shouldNotHappen.toString());
+      }
+    HashMap macAttr = new HashMap();
+    macAttr.put(IMac.MAC_KEY_MATERIAL, dk);
+    macAttr.put(IMac.TRUNCATED_SIZE, Integer.valueOf(maclen));
+    try
+      {
+        mac.init(macAttr);
+      }
+    catch (InvalidKeyException shouldNotHappen)
+      {
+        throw new Error(shouldNotHappen.toString());
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "getMac");
+    return mac;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,293 @@
+/* PasswordEncryptedEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.PRNG;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.mode.IMode;
+import gnu.javax.crypto.mode.ModeFactory;
+import gnu.javax.crypto.pad.IPad;
+import gnu.javax.crypto.pad.PadFactory;
+import gnu.javax.crypto.pad.WrongPaddingException;
+import gnu.javax.crypto.prng.IPBE;
+import gnu.javax.crypto.prng.PRNGFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+/**
+ * An envelope that is encrypted with a password-derived key.
+ */
+public class PasswordEncryptedEntry
+    extends MaskableEnvelopeEntry
+    implements PasswordProtectedEntry, Registry
+{
+  private static final Logger log = Logger.getLogger(PasswordEncryptedEntry.class.getName());
+  public static final int TYPE = 1;
+
+  public PasswordEncryptedEntry(String cipher, String mode, int keylen,
+                                Properties properties)
+  {
+    super(TYPE, properties);
+    if ((cipher == null || cipher.length() == 0)
+        || (mode == null || mode.length() == 0))
+      throw new IllegalArgumentException("cipher nor mode can be empty");
+    this.properties.put("cipher", cipher);
+    this.properties.put("mode", mode);
+    this.properties.put("keylen", String.valueOf(keylen));
+    setMasked(false);
+  }
+
+  private PasswordEncryptedEntry()
+  {
+    super(TYPE);
+    setMasked(true);
+  }
+
+  public static PasswordEncryptedEntry decode(DataInputStream in,
+                                              char[] password)
+      throws IOException
+  {
+    PasswordEncryptedEntry entry = decode(in);
+    try
+      {
+        entry.decrypt(password);
+      }
+    catch (WrongPaddingException wpe)
+      {
+        throw new MalformedKeyringException("wrong padding in decrypted data");
+      }
+    return entry;
+  }
+
+  public static PasswordEncryptedEntry decode(DataInputStream in)
+      throws IOException
+  {
+    PasswordEncryptedEntry entry = new PasswordEncryptedEntry();
+    entry.defaultDecode(in);
+    return entry;
+  }
+
+  public void decrypt(char[] password) throws IllegalArgumentException,
+      WrongPaddingException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "decrypt");
+    if (isMasked() && payload != null)
+      {
+        long tt = -System.currentTimeMillis();
+        IMode mode = getMode(password, IMode.DECRYPTION);
+        IPad padding = PadFactory.getInstance("PKCS7");
+        padding.init(mode.currentBlockSize());
+        byte[] buf = new byte[payload.length];
+        int count = 0;
+        while (count + mode.currentBlockSize() <= payload.length)
+          {
+            mode.update(payload, count, buf, count);
+            count += mode.currentBlockSize();
+          }
+        int padlen = padding.unpad(buf, 0, buf.length);
+        setMasked(false);
+        int len = buf.length - padlen;
+        ByteArrayInputStream baos = new ByteArrayInputStream(buf, 0, len);
+        DataInputStream in = new DataInputStream(baos);
+        try
+          {
+            decodeEnvelope(in);
+          }
+        catch (IOException ioe)
+          {
+            throw new IllegalArgumentException("decryption failed");
+          }
+        tt += System.currentTimeMillis();
+        log.fine("Decrypted in " + tt + "ms.");
+      }
+    else if (Configuration.DEBUG)
+      log.fine("Skip decryption; " + (isMasked() ? "null payload" : "unmasked"));
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "decrypt");
+  }
+
+  public void encrypt(char[] password) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "encrypt", String.valueOf(password));
+    long tt = -System.currentTimeMillis();
+    long t1 = -System.currentTimeMillis();
+    byte[] salt = new byte[8];
+    PRNG.getInstance().nextBytes(salt);
+    t1 += System.currentTimeMillis();
+    if (Configuration.DEBUG)
+      log.fine("-- Generated salt in " + t1 + "ms.");
+    properties.put("salt", Util.toString(salt));
+    IMode mode = getMode(password, IMode.ENCRYPTION);
+    IPad pad = PadFactory.getInstance("PKCS7");
+    pad.init(mode.currentBlockSize());
+    ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
+    DataOutputStream out2 = new DataOutputStream(bout);
+    for (Iterator it = entries.iterator(); it.hasNext();)
+      {
+        Entry entry = (Entry) it.next();
+        if (Configuration.DEBUG)
+          log.fine("-- About to encode one " + entry);
+        t1 = -System.currentTimeMillis();
+        entry.encode(out2);
+        t1 += System.currentTimeMillis();
+        if (Configuration.DEBUG)
+          log.fine("-- Encoded an Entry in " + t1 + "ms.");
+      }
+    byte[] plaintext = bout.toByteArray();
+    byte[] padding = pad.pad(plaintext, 0, plaintext.length);
+    payload = new byte[plaintext.length + padding.length];
+    byte[] lastBlock = new byte[mode.currentBlockSize()];
+    int l = mode.currentBlockSize() - padding.length;
+    System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l);
+    System.arraycopy(padding, 0, lastBlock, l, padding.length);
+    int count = 0;
+    while (count + mode.currentBlockSize() < plaintext.length)
+      {
+        mode.update(plaintext, count, payload, count);
+        count += mode.currentBlockSize();
+      }
+    mode.update(lastBlock, 0, payload, count);
+    setMasked(true);
+    tt += System.currentTimeMillis();
+    if (Configuration.DEBUG)
+      {
+        log.fine("Encrypted in " + tt + "ms.");
+        log.exiting(this.getClass().getName(), "encrypt");
+      }
+  }
+
+  public void encode(DataOutputStream out, char[] password) throws IOException
+  {
+    encrypt(password);
+    encode(out);
+  }
+
+  protected void encodePayload() throws IOException
+  {
+    if (payload == null)
+      {
+        if (Configuration.DEBUG)
+          log.fine("Null payload: " + this);
+        throw new IllegalStateException("not encrypted");
+      }
+  }
+
+  private IMode getMode(char[] password, int state)
+  {
+    String s = properties.get("salt");
+    if (s == null)
+      throw new IllegalArgumentException("no salt");
+    byte[] salt = Util.toBytesFromString(s);
+    IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher"));
+    if (cipher == null)
+      throw new IllegalArgumentException("no such cipher: "
+                                         + properties.get("cipher"));
+    int blockSize = cipher.defaultBlockSize();
+    if (properties.containsKey("block-size"))
+      try
+        {
+          blockSize = Integer.parseInt(properties.get("block-size"));
+        }
+      catch (NumberFormatException nfe)
+        {
+          throw new IllegalArgumentException("bad block size: "
+                                             + nfe.getMessage());
+        }
+    String modeName = properties.get("mode");
+    IMode mode = ModeFactory.getInstance(modeName, cipher, blockSize);
+    if (mode == null)
+      throw new IllegalArgumentException("no such mode: " + modeName);
+    HashMap pbAttr = new HashMap();
+    pbAttr.put(IPBE.PASSWORD, password);
+    pbAttr.put(IPBE.SALT, salt);
+    pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT);
+    IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA");
+    kdf.init(pbAttr);
+    int keylen = 0;
+    if (! properties.containsKey("keylen"))
+      throw new IllegalArgumentException("no key length");
+    try
+      {
+        keylen = Integer.parseInt(properties.get("keylen"));
+      }
+    catch (NumberFormatException nfe)
+      {
+      }
+    byte[] dk = new byte[keylen];
+    byte[] iv = new byte[blockSize];
+    try
+      {
+        kdf.nextBytes(dk, 0, keylen);
+        kdf.nextBytes(iv, 0, blockSize);
+      }
+    catch (LimitReachedException shouldNotHappen)
+      {
+        throw new Error(shouldNotHappen.toString());
+      }
+    HashMap modeAttr = new HashMap();
+    modeAttr.put(IMode.KEY_MATERIAL, dk);
+    modeAttr.put(IMode.STATE, Integer.valueOf(state));
+    modeAttr.put(IMode.IV, iv);
+    try
+      {
+        mode.init(modeAttr);
+      }
+    catch (InvalidKeyException ike)
+      {
+        throw new IllegalArgumentException(ike.toString());
+      }
+    return mode;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/PasswordProtectedEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,57 @@
+/* PasswordProtectedEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public interface PasswordProtectedEntry
+{
+  /** The iteration count for password-based KDFs. */
+  Integer ITERATION_COUNT = Integer.valueOf(1000);
+
+  /**
+   * Encodes this entry, protected by a password.
+   * 
+   * @param out The output stream to encode to.
+   * @param password The password.
+   * @throws IOException If an I/O error occurs.
+   */
+  void encode(DataOutputStream out, char[] password) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/PrimitiveEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,112 @@
+/* PrimitiveEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.util.Date;
+
+/**
+ * A primitive entry is an entry that contains a single cryptographic entity.
+ */
+public abstract class PrimitiveEntry
+    extends Entry
+{
+  /** The creation date. */
+  protected Date creationDate;
+
+  protected PrimitiveEntry(int type, Date creationDate, Properties properties)
+  {
+    super(type, properties);
+    if (creationDate == null)
+      this.creationDate = new Date();
+    else
+      this.creationDate = (Date) creationDate.clone();
+    if (! this.properties.containsKey("alias")
+        || this.properties.get("alias").length() == 0)
+      throw new IllegalArgumentException("primitive entries MUST have an alias");
+    this.properties.put("creation-date",
+                        String.valueOf(this.creationDate.getTime()));
+  }
+
+  protected PrimitiveEntry(int type)
+  {
+    super(type);
+  }
+
+  /**
+   * Returns the alias of this primitive entry.
+   * 
+   * @return The alias.
+   */
+  public String getAlias()
+  {
+    return properties.get("alias");
+  }
+
+  /**
+   * Returns the creation date of this primitive entry.
+   * 
+   * @return The creation date.
+   */
+  public Date getCreationDate()
+  {
+    return (Date) creationDate.clone();
+  }
+
+  public boolean equals(Object object)
+  {
+    if (! getClass().equals(object.getClass()))
+      return false;
+    return getAlias().equals(((PrimitiveEntry) object).getAlias());
+  }
+
+  protected final void makeCreationDate() throws MalformedKeyringException
+  {
+    String s = properties.get("creation-date");
+    if (s == null)
+      throw new MalformedKeyringException("no creation date");
+    try
+      {
+        creationDate = new Date(Long.parseLong(s));
+      }
+    catch (NumberFormatException nfe)
+      {
+        throw new MalformedKeyringException("invalid creation date");
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/PrivateKeyEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,194 @@
+/* PrivateKeyEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.key.KeyPairCodecFactory;
+import gnu.java.security.key.dss.DSSPrivateKey;
+import gnu.java.security.key.rsa.GnuRSAPrivateKey;
+import gnu.javax.crypto.key.GnuSecretKey;
+import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Date;
+
+/**
+ * An immutable class representing a private or secret key entry.
+ */
+public final class PrivateKeyEntry
+    extends PrimitiveEntry
+{
+  public static final int TYPE = 7;
+  /** The key. */
+  private Key key;
+
+  /**
+   * Creates a new key entry.
+   * 
+   * @param key The key.
+   * @param creationDate The entry creation date.
+   * @param properties The entry properties.
+   * @throws IllegalArgumentException If any parameter is null.
+   */
+  public PrivateKeyEntry(Key key, Date creationDate, Properties properties)
+  {
+    super(TYPE, creationDate, properties);
+    if (key == null)
+      throw new IllegalArgumentException("no private key");
+    if (! (key instanceof PrivateKey) && ! (key instanceof GnuSecretKey))
+      throw new IllegalArgumentException("not a private or secret key");
+    this.key = key;
+  }
+
+  private PrivateKeyEntry()
+  {
+    super(TYPE);
+  }
+
+  public static PrivateKeyEntry decode(DataInputStream in) throws IOException
+  {
+    PrivateKeyEntry entry = new PrivateKeyEntry();
+    entry.defaultDecode(in);
+    String type = entry.properties.get("type");
+    if (type == null)
+      throw new MalformedKeyringException("no key type");
+    if (type.equalsIgnoreCase("RAW-DSS"))
+      {
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss");
+        entry.key = coder.decodePrivateKey(entry.payload);
+      }
+    else if (type.equalsIgnoreCase("RAW-RSA"))
+      {
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa");
+        entry.key = coder.decodePrivateKey(entry.payload);
+      }
+    else if (type.equalsIgnoreCase("RAW-DH"))
+      {
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh");
+        entry.key = coder.decodePrivateKey(entry.payload);
+      }
+    else if (type.equalsIgnoreCase("RAW"))
+      entry.key = new GnuSecretKey(entry.payload, null);
+    else if (type.equalsIgnoreCase("PKCS8"))
+      {
+        try
+          {
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload);
+            entry.key = kf.generatePrivate(ks);
+          }
+        catch (Exception ignored)
+          {
+          }
+        if (entry.key == null)
+          {
+            try
+              {
+                KeyFactory kf = KeyFactory.getInstance("DSA");
+                PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload);
+                entry.key = kf.generatePrivate(ks);
+              }
+            catch (Exception ignored)
+              {
+              }
+            if (entry.key == null)
+              throw new MalformedKeyringException("could not decode PKCS#8 key");
+          }
+      }
+    else
+      throw new MalformedKeyringException("unsupported key type " + type);
+    return entry;
+  }
+
+  /**
+   * Returns this entry's key.
+   * 
+   * @return The key.
+   */
+  public Key getKey()
+  {
+    return key;
+  }
+
+  protected void encodePayload() throws IOException
+  {
+    String format = key.getFormat();
+    if (key instanceof DSSPrivateKey)
+      {
+        properties.put("type", "RAW-DSS");
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss");
+        payload = coder.encodePrivateKey((PrivateKey) key);
+      }
+    else if (key instanceof GnuRSAPrivateKey)
+      {
+        properties.put("type", "RAW-RSA");
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa");
+        payload = coder.encodePrivateKey((PrivateKey) key);
+      }
+    else if (key instanceof GnuDHPrivateKey)
+      {
+        properties.put("type", "RAW-DH");
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh");
+        payload = coder.encodePrivateKey((PrivateKey) key);
+      }
+    else if (key instanceof GnuSecretKey)
+      {
+        properties.put("type", "RAW");
+        payload = key.getEncoded();
+      }
+    else if (format != null && format.equals("PKCS#8"))
+      {
+        properties.put("type", "PKCS8");
+        payload = key.getEncoded();
+      }
+    else
+      throw new IllegalArgumentException("unsupported private key");
+  }
+
+  public String toString()
+  {
+    return "PrivateKeyEntry{key="
+           + (key == null ? "-" : key.getClass().getName()) + "}";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/Properties.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,203 @@
+/* Properties.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A set of <code>(name =&gt; value)</code> pairs used in keyring entries.
+ * Keys and values are simple strings, with the key never being empty and always
+ * treated case-insensitively.
+ */
+public class Properties
+    implements Cloneable
+{
+  private HashMap props;
+
+  /**
+   * Creates a new properties object.
+   */
+  public Properties()
+  {
+    props = new HashMap();
+  }
+
+  /**
+   * Removes all properties from this object.
+   */
+  public void clear()
+  {
+    props.clear();
+  }
+
+  /**
+   * Creates a copy of this properties object.
+   * 
+   * @return The copy.
+   */
+  public Object clone()
+  {
+    Properties result = new Properties();
+    result.props.putAll(props);
+    return result;
+  }
+
+  /**
+   * Tests if this object contains a given property name.
+   * 
+   * @param key The key to test.
+   * @return True if this object contains the given key.
+   */
+  public boolean containsKey(String key)
+  {
+    if (key == null || key.length() == 0)
+      return false;
+    return props.containsKey(canonicalize(key));
+  }
+
+  /**
+   * Tests if this object contains a given property value.
+   * 
+   * @param value The value to test.
+   * @return True if this object contains the given value.
+   */
+  public boolean containsValue(String value)
+  {
+    if (value == null)
+      return false;
+    return props.containsValue(value);
+  }
+
+  /**
+   * Adds a new property to this object.
+   * 
+   * @param key The key, which can neither be null nor empty.
+   * @param value The value, which cannot be null.
+   * @return The old value mapped by the key, if any.
+   * @throws IllegalArgumentException If either the key or value parameter is
+   *           null, or if the key is empty.
+   */
+  public String put(String key, String value)
+  {
+    if (key == null || value == null || key.length() == 0)
+      throw new IllegalArgumentException("key nor value can be null");
+    return (String) props.put(canonicalize(key), value);
+  }
+
+  /**
+   * Returns the value mapped by the given key, or null if there is no such
+   * mapping.
+   * 
+   * @param key
+   */
+  public String get(String key)
+  {
+    if (key == null || key.length() == 0)
+      return null;
+    return (String) props.get(canonicalize(key));
+  }
+
+  /**
+   * Removes a key and its value from this object.
+   * 
+   * @param key The key of the property to remove.
+   * @return The old value mapped by the key, if any.
+   */
+  public String remove(String key)
+  {
+    if (key == null || key.length() == 0)
+      return null;
+    return (String) props.remove(canonicalize(key));
+  }
+
+  /**
+   * Decodes a set of properties from the given input stream.
+   * 
+   * @param in The input stream.
+   * @throws IOException If an I/O error occurs.
+   */
+  public void decode(DataInputStream in) throws IOException
+  {
+    int len = in.readInt();
+    MeteredInputStream min = new MeteredInputStream(in, len);
+    DataInputStream in2 = new DataInputStream(min);
+    while (! min.limitReached())
+      {
+        String name = in2.readUTF();
+        String value = in2.readUTF();
+        put(name, value);
+      }
+  }
+
+  /**
+   * Encodes this set of properties to the given output stream.
+   * 
+   * @param out The output stream to encode to.
+   * @throws IOException If an I/O error occurs.
+   */
+  public void encode(DataOutputStream out) throws IOException
+  {
+    ByteArrayOutputStream buf = new ByteArrayOutputStream();
+    DataOutputStream out2 = new DataOutputStream(buf);
+    for (Iterator it = props.entrySet().iterator(); it.hasNext();)
+      {
+        Map.Entry entry = (Map.Entry) it.next();
+        out2.writeUTF((String) entry.getKey());
+        out2.writeUTF((String) entry.getValue());
+      }
+    out.writeInt(buf.size());
+    buf.writeTo(out);
+  }
+
+  public String toString()
+  {
+    return props.toString();
+  }
+
+  private String canonicalize(String key)
+  {
+    return key.toLowerCase();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/keyring/PublicKeyEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,162 @@
+/* PublicKeyEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.keyring;
+
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.key.KeyPairCodecFactory;
+import gnu.java.security.key.dss.DSSPublicKey;
+import gnu.java.security.key.rsa.GnuRSAPublicKey;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
+
+public final class PublicKeyEntry
+    extends PrimitiveEntry
+{
+  public static final int TYPE = 6;
+  private PublicKey key;
+
+  public PublicKeyEntry(PublicKey key, Date creationDate, Properties properties)
+  {
+    super(TYPE, creationDate, properties);
+    if (key == null)
+      throw new IllegalArgumentException("no key specified");
+    this.key = key;
+  }
+
+  private PublicKeyEntry()
+  {
+    super(TYPE);
+  }
+
+  public static PublicKeyEntry decode(DataInputStream in) throws IOException
+  {
+    PublicKeyEntry entry = new PublicKeyEntry();
+    entry.defaultDecode(in);
+    String type = entry.properties.get("type");
+    if (type == null)
+      throw new MalformedKeyringException("no key type");
+    if (type.equalsIgnoreCase("RAW-DSS"))
+      {
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss");
+        entry.key = coder.decodePublicKey(entry.payload);
+      }
+    else if (type.equalsIgnoreCase("RAW-RSA"))
+      {
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa");
+        entry.key = coder.decodePublicKey(entry.payload);
+      }
+    else if (type.equalsIgnoreCase("RAW-DH"))
+      {
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh");
+        entry.key = coder.decodePublicKey(entry.payload);
+      }
+    else if (type.equalsIgnoreCase("X.509"))
+      {
+        try
+          {
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload));
+          }
+        catch (Exception x)
+          {
+          }
+        if (entry.key == null)
+          {
+            try
+              {
+                KeyFactory kf = KeyFactory.getInstance("DSA");
+                entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload));
+              }
+            catch (Exception x)
+              {
+              }
+            if (entry.key == null)
+              throw new MalformedKeyringException("could not decode X.509 key");
+          }
+      }
+    else
+      throw new MalformedKeyringException("unsupported public key type: " + type);
+    return entry;
+  }
+
+  /**
+   * Returns the public key.
+   * 
+   * @return The public key.
+   */
+  public PublicKey getKey()
+  {
+    return key;
+  }
+
+  protected void encodePayload() throws IOException
+  {
+    if (key instanceof DSSPublicKey)
+      {
+        properties.put("type", "RAW-DSS");
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss");
+        payload = coder.encodePublicKey(key);
+      }
+    else if (key instanceof GnuRSAPublicKey)
+      {
+        properties.put("type", "RAW-RSA");
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa");
+        payload = coder.encodePublicKey(key);
+      }
+    else if (key instanceof GnuDHPublicKey)
+      {
+        properties.put("type", "RAW-DH");
+        IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh");
+        payload = coder.encodePublicKey(key);
+      }
+    else if (key.getFormat() != null && key.getFormat().equals("X.509"))
+      {
+        properties.put("type", "X.509");
+        payload = key.getEncoded();
+      }
+    else
+      throw new IllegalArgumentException("cannot encode public key");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/kwa/AESKeyWrap.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,168 @@
+/* AESWrap.java -- An implementation of RFC-3394 AES Key Wrap Algorithm
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.kwa;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.cipher.Rijndael;
+
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The GNU implementation of the AES Key Wrap Algorithm as described in [1].
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf"></a>.</li>
+ * <li><a href="http://www.rfc-archive.org/getrfc.php?rfc=3394">Advanced
+ * Encryption Standard (AES) Key Wrap Algorithm</a>.</li>
+ * <li><a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and
+ * Processing</a>.</li>
+ * </ol>
+ */
+public class AESKeyWrap
+    extends BaseKeyWrappingAlgorithm
+{
+  private static final byte[] DEFAULT_IV = new byte[] {
+      (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6,
+      (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6 };
+
+  private Rijndael aes;
+  private byte[] iv;
+
+  public AESKeyWrap()
+  {
+    super(Registry.AES_KWA);
+
+    aes = new Rijndael();
+  }
+
+  protected void engineInit(Map attributes) throws InvalidKeyException
+  {
+    Map cipherAttributes = new HashMap();
+    cipherAttributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(16));
+    cipherAttributes.put(IBlockCipher.KEY_MATERIAL,
+                         attributes.get(KEY_ENCRYPTION_KEY_MATERIAL));
+    aes.reset();
+    aes.init(cipherAttributes);
+    byte[] initialValue = (byte[]) attributes.get(INITIAL_VALUE);
+    iv = initialValue == null ? DEFAULT_IV : (byte[]) initialValue.clone();
+  }
+
+  protected byte[] engineWrap(byte[] in, int inOffset, int length)
+  {
+    // TODO: handle input length which is not a multiple of 8 as suggested by
+    // section 2.2.3.2 of RFC-3394
+    if (length % 8 != 0)
+      throw new IllegalArgumentException("Input length MUST be a multiple of 8");
+    int n = length / 8;
+    // output is always one block larger than input
+    byte[] result = new byte[length + 8];
+
+    // 1. init variables: we'll use out buffer for our work buffer;
+    //    A will be the first block in out, while R will be the rest
+    System.arraycopy(iv, 0, result, 0, 8);
+    System.arraycopy(in, inOffset, result, 8, length);
+    byte[] B = new byte[2 * 8];
+    // 2. compute intermediate values
+    long t;
+    for (int j = 0; j < 6; j++)
+      for (int i = 1; i <= n; i++)
+        {
+          System.arraycopy(result, 0, B, 0, 8);
+          System.arraycopy(result, i * 8, B, 8, 8);
+          aes.encryptBlock(B, 0, B, 0);
+          t = (n * j) + i;
+          result[0] = (byte)(B[0] ^ (t >>> 56));
+          result[1] = (byte)(B[1] ^ (t >>> 48));
+          result[2] = (byte)(B[2] ^ (t >>> 40));
+          result[3] = (byte)(B[3] ^ (t >>> 32));
+          result[4] = (byte)(B[4] ^ (t >>> 24));
+          result[5] = (byte)(B[5] ^ (t >>> 16));
+          result[6] = (byte)(B[6] ^ (t >>>  8));
+          result[7] = (byte)(B[7] ^  t        );
+          System.arraycopy(B, 8, result, i * 8, 8);
+        }
+    return result;
+  }
+
+  protected byte[] engineUnwrap(byte[] in, int inOffset, int length)
+      throws KeyUnwrappingException
+  {
+    // TODO: handle input length which is not a multiple of 8 as suggested by
+    // section 2.2.3.2 of RFC-3394
+    if (length % 8 != 0)
+      throw new IllegalArgumentException("Input length MUST be a multiple of 8");
+    // output is always one block shorter than input
+    byte[] result = new byte[length - 8];
+
+    // 1. init variables: we'll use out buffer for our R work buffer
+    byte[] A = new byte[8];
+    System.arraycopy(in, inOffset, A, 0, 8);
+    System.arraycopy(in, inOffset + 8, result, 0, result.length);
+    byte[] B = new byte[2 * 8];
+    // 2. compute intermediate values
+    int n = length / 8 - 1;
+    long t;
+    for (int j = 5; j >= 0; j--)
+      for (int i = n; i >= 1; i--)
+        {
+          t = (n * j) + i;
+          B[0] = (byte)(A[0] ^ (t >>> 56));
+          B[1] = (byte)(A[1] ^ (t >>> 48));
+          B[2] = (byte)(A[2] ^ (t >>> 40));
+          B[3] = (byte)(A[3] ^ (t >>> 32));
+          B[4] = (byte)(A[4] ^ (t >>> 24));
+          B[5] = (byte)(A[5] ^ (t >>> 16));
+          B[6] = (byte)(A[6] ^ (t >>>  8));
+          B[7] = (byte)(A[7] ^  t        );
+          System.arraycopy(result, (i - 1) * 8, B, 8, 8);
+          aes.decryptBlock(B, 0, B, 0);
+          System.arraycopy(B, 0, A, 0, 8);
+          System.arraycopy(B, 8, result, (i - 1) * 8, 8);
+        }
+    if (! Arrays.equals(A, iv))
+      throw new KeyUnwrappingException();
+
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,145 @@
+/* BaseKeyWrappingAlgorithm.java -- FIXME: briefly describe file purpose
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.kwa;
+
+import gnu.java.security.util.PRNG;
+
+import java.security.InvalidKeyException;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.crypto.ShortBufferException;
+
+/**
+ * A base class to facilitate implementation of concrete Key Wrapping
+ * Algorithms.
+ */
+public abstract class BaseKeyWrappingAlgorithm
+     implements IKeyWrappingAlgorithm
+{
+  /** The canonical name of the key wrapping algorithm. */
+  protected String name;
+  /** A source of randomness if/when needed by concrete implementations. */
+  private PRNG prng;
+
+  /**
+   * Protected constructor.
+   * 
+   * @param name the key wrapping algorithm canonical name.
+   */
+  protected BaseKeyWrappingAlgorithm(String name)
+  {
+    super();
+  }
+
+  public String name()
+  {
+    return this.name;
+  }
+
+  public void init(Map attributes) throws InvalidKeyException
+  {
+    if (attributes == null)
+      attributes = Collections.EMPTY_MAP;
+
+    engineInit(attributes);
+  }
+
+  public int wrap(byte[] in, int inOffset, int length, byte[] out, int outOffset)
+      throws ShortBufferException
+  {
+    if (outOffset < 0)
+      throw new IllegalArgumentException("Output offset MUST NOT be negative");
+    byte[] result = wrap(in, inOffset, length);
+    if (outOffset + result.length > out.length)
+      throw new ShortBufferException();
+    System.arraycopy(result, 0, out, outOffset, result.length);
+    return result.length;
+  }
+
+  public byte[] wrap(byte[] in, int inOffset, int length)
+  {
+    if (inOffset < 0)
+      throw new IllegalArgumentException("Input offset MUST NOT be negative");
+    if (length < 0)
+      throw new IllegalArgumentException("Input length MUST NOT be negative");
+
+    return engineWrap(in, inOffset, length);
+  }
+
+  public int unwrap(byte[] in, int inOffset, int length,
+                    byte[] out, int outOffset)
+      throws ShortBufferException, KeyUnwrappingException
+  {
+    if (outOffset < 0)
+      throw new IllegalArgumentException("Output offset MUST NOT be negative");
+    byte[] result = engineUnwrap(in, inOffset, length);
+    if (outOffset + result.length > out.length)
+      throw new ShortBufferException();
+    System.arraycopy(result, 0, out, outOffset, result.length);
+    return result.length;
+  }
+
+  public byte[] unwrap(byte[] in, int inOffset, int length)
+      throws KeyUnwrappingException
+  {
+    if (inOffset < 0)
+      throw new IllegalArgumentException("Input offset MUST NOT be negative");
+    if (length < 0)
+      throw new IllegalArgumentException("Input length MUST NOT be negative");
+
+    return engineUnwrap(in, inOffset, length);
+  }
+
+  protected abstract void engineInit(Map attributes) throws InvalidKeyException;
+
+  protected abstract byte[] engineWrap(byte[] in, int inOffset, int length);
+
+  protected abstract byte[] engineUnwrap(byte[] in, int inOffset, int length)
+      throws KeyUnwrappingException;
+
+  /** @return a strong pseudo-random number generator if/when needed. */
+  protected PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,160 @@
+/* IKeyWrappingAlgorithm.java -- FIXME: briefly describe file purpose
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.kwa;
+
+import java.security.InvalidKeyException;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.crypto.ShortBufferException;
+
+/**
+ * Constants and visible methods available to all GNU Key Wrapping Algorithm
+ * implementations.
+ */
+public interface IKeyWrappingAlgorithm
+{
+  /**
+   * Name of the property, in the attributes map, that references the Key
+   * Wrapping Algorithm KEK (Key Encryption Key) material. The object referenced
+   * by this property is a byte array containing the keying material for the
+   * underlying block cipher.
+   */
+  String KEY_ENCRYPTION_KEY_MATERIAL = "gnu.crypto.kwa.kek";
+  /**
+   * Name of the property, in the attributes map, that references the Initial
+   * Value (IV) material. The object referenced by this property is a byte array
+   * containing the initial integrity check register value.
+   */
+  String INITIAL_VALUE = "gnu.crypto.kwa.iv";
+  /**
+   * Property name of an optional {@link SecureRandom} instance to use. The
+   * default is to use a {@link gnu.java.security.util.PRNG} instance.
+   */
+  String SOURCE_OF_RANDOMNESS = "gnu.crypto.kwa.prng";
+
+  /**
+   * Returns the canonical name of this Key Wrapping Algorithm.
+   * 
+   * @return the canonical name of this Key Wrapping Algorithm.
+   */
+  String name();
+
+  /**
+   * Initializes this instance with the designated algorithm specific
+   * attributes.
+   * 
+   * @param attributes a map of name-to-value pairs the Key Wrapping Algorithm
+   *          must use for its setup.
+   * @throws InvalidKeyException if an exception is encountered while seting up
+   *           the Key Wrapping Algorithm keying material (KEK).
+   */
+  void init(Map attributes) throws InvalidKeyException;
+
+  /**
+   * Wraps the designated plain text bytes.
+   * 
+   * @param in the input byte array containing the plain text.
+   * @param inOffset the offset into <code>in</code> where the first byte of
+   *          the plain text (key material) to wrap is located.
+   * @param length the number of bytes to wrap.
+   * @param out the output byte array where the wrapped key material will be
+   *          stored.
+   * @param outOffset the offset into <code>out</code> of the first wrapped
+   *          byte.
+   * @return the number of bytes of the wrapped key material; i.e. the length,
+   *         in <code>out</code>, starting from <code>outOffset</code>
+   *         where the cipher text (wrapped key material) are stored.
+   * @throws ShortBufferException if the output buffer is not long enough to
+   *           accomodate the number of bytes resulting from wrapping the plain
+   *           text.
+   */
+  int wrap(byte[] in, int inOffset, int length, byte[] out, int outOffset)
+      throws ShortBufferException;
+
+  /**
+   * Wraps the designated plain text bytes.
+   * 
+   * @param in the input byte array containing the plain text.
+   * @param inOffset the offset into <code>in</code> where the first byte of
+   *          the plain text (key material) to wrap is located.
+   * @param length the number of bytes to wrap.
+   * @return a newly allocated byte array containing the cipher text.
+   */
+  byte[] wrap(byte[] in, int inOffset, int length);
+
+  /**
+   * Unwraps the designated cipher text bytes.
+   * 
+   * @param in the input byte array containing the cipher text.
+   * @param inOffset the offset into <code>in</code> where the first byte of
+   *          the cipher text (already wrapped key material) to unwrap is
+   *          located.
+   * @param length the number of bytes to unwrap.
+   * @param out the output byte array where the unwrapped key material will be
+   *          stored.
+   * @param outOffset the offset into <code>out</code> of the first unwrapped
+   *          byte.
+   * @return the number of bytes of the unwrapped key material; i.e. the length,
+   *         in <code>out</code>, starting from <code>outOffset</code>
+   *         where the plain text (unwrapped key material) are stored.
+   * @throws ShortBufferException if the output buffer is not long enough to
+   *           accomodate the number of bytes resulting from unwrapping the
+   *           cipher text.
+   * @throws KeyUnwrappingException if after unwrapping the cipher text, the
+   *           bytes at the begining did not match the initial value.
+   */
+  int unwrap(byte[] in, int inOffset, int length, byte[] out, int outOffset)
+      throws ShortBufferException, KeyUnwrappingException;
+
+  /**
+   * Unwraps the designated cipher text bytes.
+   * 
+   * @param in the input byte array containing the cipher text.
+   * @param inOffset the offset into <code>in</code> where the first byte of
+   *          the cipher text (already wrapped key material) to unwrap is
+   *          located.
+   * @param length the number of bytes to unwrap.
+   * @return a newly allocated byte array containing the plain text.
+   * @throws KeyUnwrappingException if after unwrapping the cipher text, the
+   *           bytes at the begining did not match the initial value.
+   */
+  byte[] unwrap(byte[] in, int inOffset, int length)
+      throws KeyUnwrappingException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/kwa/KeyUnwrappingException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,67 @@
+/* KeyUnwrappingException.java -- FIXME: briefly describe file purpose
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.kwa;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * A checked security exception to denote an unexpected problem while unwrapping
+ * key material with a Key Wrapping Algorithm.
+ */
+public class KeyUnwrappingException
+    extends GeneralSecurityException
+{
+  /**
+   * Create a new instance with no descriptive error message.
+   */
+  public KeyUnwrappingException()
+  {
+    super();
+  }
+
+  /**
+   * Create a new instance with a descriptive error message.
+   *
+   * @param msg the descriptive error message
+   */
+  public KeyUnwrappingException(String msg)
+  {
+    super(msg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,110 @@
+/* KeyWrappingAlgorithmFactory.java -- FIXME: briefly describe file purpose
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.kwa;
+
+import gnu.java.security.Registry;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A Factory class for the Key Wrapping Algorithm implementations.
+ */
+public class KeyWrappingAlgorithmFactory
+{
+  /** Names of Key Wrapping Algorihms cached for speed. */
+  private static Set names;
+  
+  /** Trivial constructor to enforce Singleton pattern. */
+  private KeyWrappingAlgorithmFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a key-wrapping algorithm given its name.
+   * 
+   * @param name the case-insensitive name of the key-wrapping algorithm.
+   * @return an instance of the designated key-wrapping algorithm, or
+   *         <code>null</code> if none was found.
+   * @exception InternalError if the implementation does not pass its self-test.
+   */
+  public static final IKeyWrappingAlgorithm getInstance(String name)
+  {
+    if (name == null)
+      return null;
+    name = name.trim();
+    IKeyWrappingAlgorithm result = null;
+    if (name.equalsIgnoreCase(Registry.AES_KWA)
+        || name.equalsIgnoreCase(Registry.AES128_KWA)
+        || name.equalsIgnoreCase(Registry.AES192_KWA)
+        || name.equalsIgnoreCase(Registry.AES256_KWA)
+        || name.equalsIgnoreCase(Registry.RIJNDAEL_KWA))
+      result = new AESKeyWrap();
+    else if (name.equalsIgnoreCase(Registry.TRIPLEDES_KWA)
+        || name.equalsIgnoreCase(Registry.DESEDE_KWA))
+      result = new TripleDESKeyWrap();
+
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of key wrapping algorithm names supported by this
+   * <i>Factory</i>.
+   * 
+   * @return a {@link Set} of key wrapping algorithm names (Strings).
+   */
+  public static synchronized final Set getNames()
+  {
+    if (names == null)
+      {
+        HashSet hs = new HashSet();
+        hs.add(Registry.AES_KWA);
+        hs.add(Registry.AES128_KWA);
+        hs.add(Registry.AES192_KWA);
+        hs.add(Registry.AES256_KWA);
+        hs.add(Registry.RIJNDAEL_KWA);
+        hs.add(Registry.TRIPLEDES_KWA);
+        hs.add(Registry.DESEDE_KWA);
+        names = Collections.unmodifiableSet(hs);
+      }
+    return names;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/kwa/TripleDESKeyWrap.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,292 @@
+/* TripleDESKeyWrap.java -- FIXME: briefly describe file purpose
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.kwa;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.Sha160;
+import gnu.javax.crypto.assembly.Assembly;
+import gnu.javax.crypto.assembly.Cascade;
+import gnu.javax.crypto.assembly.Direction;
+import gnu.javax.crypto.assembly.Stage;
+import gnu.javax.crypto.assembly.Transformer;
+import gnu.javax.crypto.assembly.TransformerException;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.cipher.TripleDES;
+import gnu.javax.crypto.mode.IMode;
+import gnu.javax.crypto.mode.ModeFactory;
+
+import java.security.InvalidKeyException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The GNU implementation of the Triple DES Key Wrap Algorithm as described in
+ * [1].
+ * <p>
+ * <b>IMPORTANT</b>: This class is NOT thread safe.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.rfc-archive.org/getrfc.php?rfc=3217">Triple-DES and
+ * RC2 Key Wrapping</a>.</li>
+ * <li><a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and
+ * Processing</a>.</li>
+ * </ol>
+ */
+public class TripleDESKeyWrap
+    extends BaseKeyWrappingAlgorithm
+{
+  private static final byte[] DEFAULT_IV = new byte[] {
+     (byte) 0x4A, (byte) 0xDD, (byte) 0xA2, (byte) 0x2C,
+     (byte) 0x79, (byte) 0xE8, (byte) 0x21, (byte) 0x05 };
+
+  private Assembly asm;
+  private HashMap asmAttributes = new HashMap();
+  private HashMap modeAttributes = new HashMap();
+  private Sha160 sha = new Sha160();
+  private SecureRandom rnd;
+
+  public TripleDESKeyWrap()
+  {
+    super(Registry.TRIPLEDES_KWA);
+  }
+
+  protected void engineInit(Map attributes) throws InvalidKeyException
+  {
+    rnd = (SecureRandom) attributes.get(IKeyWrappingAlgorithm.SOURCE_OF_RANDOMNESS);
+    IMode des3CBC = ModeFactory.getInstance(Registry.CBC_MODE, new TripleDES(), 8);
+    Stage des3CBCStage = Stage.getInstance(des3CBC, Direction.FORWARD);
+    Cascade cascade = new Cascade();
+    Object modeNdx = cascade.append(des3CBCStage);
+
+    asmAttributes.put(modeNdx, modeAttributes);
+
+    asm = new Assembly();
+    asm.addPreTransformer(Transformer.getCascadeTransformer(cascade));
+
+    modeAttributes.put(IBlockCipher.KEY_MATERIAL,
+                       attributes.get(KEY_ENCRYPTION_KEY_MATERIAL));
+    asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD);
+  }
+
+  protected byte[] engineWrap(byte[] in, int inOffset, int length)
+  {
+    // The same key wrap algorithm is used for both Two-key Triple-DES and
+    // Three-key Triple-DES keys.  When a Two-key Triple-DES key is to be
+    // wrapped, a third DES key with the same value as the first DES key is
+    // created.  Thus, all wrapped Triple-DES keys include three DES keys.
+    if (length != 16 && length != 24)
+      throw new IllegalArgumentException("Only 2- and 3-key Triple DES keys are alowed");
+
+    byte[] CEK = new byte[24];
+    if (length == 16)
+      {
+        System.arraycopy(in, inOffset, CEK, 0,  16);
+        System.arraycopy(in, inOffset, CEK, 16, 8);
+      }
+    else
+      System.arraycopy(in, inOffset, CEK, 0, 24);
+    
+    // TODO: check for the following:
+    // However, a Two-key Triple-DES key MUST NOT be used to wrap a Three-
+    // key Triple-DES key that is comprised of three unique DES keys.
+
+    // 1. Set odd parity for each of the DES key octets comprising the
+    //    Three-Key Triple-DES key that is to be wrapped, call the result
+    //    CEK.
+    TripleDES.adjustParity(CEK, 0);
+
+    // 2. Compute an 8 octet key checksum value on CEK as described above in
+    //    Section 2, call the result ICV.
+    sha.update(CEK);
+    byte[] hash = sha.digest();
+    byte[] ICV = new byte[8];
+    System.arraycopy(hash, 0, ICV, 0, 8);
+
+    // 3. Let CEKICV = CEK || ICV.
+    byte[] CEKICV = new byte[CEK.length + ICV.length];
+    System.arraycopy(CEK, 0, CEKICV, 0,          CEK.length);
+    System.arraycopy(ICV, 0, CEKICV, CEK.length, ICV.length);
+
+    // 4. Generate 8 octets at random, call the result IV.
+    byte[] IV = new byte[8];
+    nextRandomBytes(IV);
+
+    // 5. Encrypt CEKICV in CBC mode using the key-encryption key.  Use the
+    //    random value generated in the previous step as the initialization
+    //    vector (IV).  Call the ciphertext TEMP1.
+    modeAttributes.put(IMode.IV, IV);
+    asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD);
+    byte[] TEMP1;
+    try
+      {
+        asm.init(asmAttributes);
+        TEMP1 = asm.lastUpdate(CEKICV);
+      }
+    catch (TransformerException x)
+      {
+        throw new RuntimeException(x);
+      }
+
+    // 6. Let TEMP2 = IV || TEMP1.
+    byte[] TEMP2 = new byte[IV.length + TEMP1.length];
+    System.arraycopy(IV,    0, TEMP2, 0,         IV.length);
+    System.arraycopy(TEMP1, 0, TEMP2, IV.length, TEMP1.length);
+
+    // 7. Reverse the order of the octets in TEMP2.  That is, the most
+    //    significant (first) octet is swapped with the least significant
+    //    (last) octet, and so on.  Call the result TEMP3.
+    byte[] TEMP3 = new byte[TEMP2.length];
+    for (int i = 0, j = TEMP2.length - 1; i < TEMP2.length; i++, j--)
+      TEMP3[j] = TEMP2[i];
+
+    // 8. Encrypt TEMP3 in CBC mode using the key-encryption key.  Use an
+    //    initialization vector (IV) of 0x4adda22c79e82105.  The ciphertext
+    //    is 40 octets long.
+    modeAttributes.put(IMode.IV, DEFAULT_IV);
+    asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD);
+    byte[] result;
+    try
+      {
+        asm.init(asmAttributes);
+        result = asm.lastUpdate(TEMP3);
+      }
+    catch (TransformerException x)
+      {
+        throw new RuntimeException(x);
+      }
+    return result;
+  }
+
+  protected byte[] engineUnwrap(byte[] in, int inOffset, int length)
+      throws KeyUnwrappingException
+  {
+    // 1. If the wrapped key is not 40 octets, then error.
+    if (length != 40)
+      throw new IllegalArgumentException("length MUST be 40");
+
+    // 2. Decrypt the wrapped key in CBC mode using the key-encryption key.
+    //    Use an initialization vector (IV) of 0x4adda22c79e82105.  Call the
+    //    output TEMP3.
+    modeAttributes.put(IMode.IV, DEFAULT_IV);
+    asmAttributes.put(Assembly.DIRECTION, Direction.REVERSED);
+    byte[] TEMP3;
+    try
+      {
+        asm.init(asmAttributes);
+        TEMP3 = asm.lastUpdate(in, inOffset, 40);
+      }
+    catch (TransformerException x)
+      {
+        throw new RuntimeException(x);
+      }
+
+    // 3. Reverse the order of the octets in TEMP3.  That is, the most
+    //    significant (first) octet is swapped with the least significant
+    //    (last) octet, and so on.  Call the result TEMP2.
+    byte[] TEMP2 = new byte[40];
+    for (int i = 0, j = 40 - 1; i < 40; i++, j--)
+      TEMP2[j] = TEMP3[i];
+
+    // 4. Decompose TEMP2 into IV and TEMP1.  IV is the most significant
+    //    (first) 8 octets, and TEMP1 is the least significant (last) 32
+    //    octets.
+    byte[] IV = new byte[8];
+    byte[] TEMP1 = new byte[32];
+    System.arraycopy(TEMP2, 0, IV,    0, 8);
+    System.arraycopy(TEMP2, 8, TEMP1, 0, 32);
+
+    // 5. Decrypt TEMP1 in CBC mode using the key-encryption key.  Use the
+    //    IV value from the previous step as the initialization vector.
+    //    Call the ciphertext CEKICV.
+    modeAttributes.put(IMode.IV, IV);
+    asmAttributes.put(Assembly.DIRECTION, Direction.REVERSED);
+    byte[] CEKICV;
+    try
+      {
+        asm.init(asmAttributes);
+        CEKICV = asm.lastUpdate(TEMP1, 0, 32);
+      }
+    catch (TransformerException x)
+      {
+        throw new RuntimeException(x);
+      }
+
+    // 6. Decompose CEKICV into CEK and ICV.  CEK is the most significant
+    //    (first) 24 octets, and ICV is the least significant (last) 8
+    //    octets.
+    byte[] CEK = new byte[24];
+    byte[] ICV = new byte[8];
+    System.arraycopy(CEKICV, 0,  CEK, 0, 24);
+    System.arraycopy(CEKICV, 24, ICV, 0, 8);
+
+    // 7. Compute an 8 octet key checksum value on CEK as described above in
+    //    Section 2.  If the computed key checksum value does not match the
+    //    decrypted key checksum value, ICV, then error.
+    sha.update(CEK);
+    byte[] hash = sha.digest();
+    byte[] computedICV = new byte[8];
+    System.arraycopy(hash, 0, computedICV, 0, 8);
+    if (! Arrays.equals(ICV, computedICV))
+      throw new KeyUnwrappingException("ICV and computed ICV MUST match");
+
+    // 8. Check for odd parity each of the DES key octets comprising CEK.
+    //    If parity is incorrect, then error.
+    if (! TripleDES.isParityAdjusted(CEK, 0))
+      throw new KeyUnwrappingException("Triple-DES key parity MUST be adjusted");
+
+    // 9. Use CEK as a Triple-DES key.
+    return CEK;
+  }
+  
+  /**
+   * Fills the designated byte array with random data.
+   * 
+   * @param buffer the byte array to fill with random data.
+   */
+  private void nextRandomBytes(byte[] buffer)
+  {
+    if (rnd != null)
+      rnd.nextBytes(buffer);
+    else
+      getDefaultPRNG().nextBytes(buffer);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/BaseMac.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,127 @@
+/* BaseMac.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import gnu.java.security.hash.IMessageDigest;
+
+import java.security.InvalidKeyException;
+import java.util.Map;
+
+/**
+ * A base abstract class to facilitate <i>MAC</i> (Message Authentication Code)
+ * implementations.
+ */
+public abstract class BaseMac
+    implements IMac
+{
+  /** The canonical name prefix of the <i>MAC</i>. */
+  protected String name;
+  /** Reference to the underlying hash algorithm instance. */
+  protected IMessageDigest underlyingHash;
+  /** The length of the truncated output in bytes. */
+  protected int truncatedSize;
+
+  /**
+   * Trivial constructor for use by concrete subclasses.
+   * 
+   * @param name the canonical name of this instance.
+   */
+  protected BaseMac(String name)
+  {
+    super();
+
+    this.name = name;
+  }
+
+  /**
+   * Trivial constructor for use by concrete subclasses.
+   * 
+   * @param name the canonical name of this instance.
+   * @param underlyingHash the underlying message digest algorithm instance.
+   */
+  protected BaseMac(String name, IMessageDigest underlyingHash)
+  {
+    this(name);
+
+    if (underlyingHash != null)
+      truncatedSize = underlyingHash.hashSize();
+    this.underlyingHash = underlyingHash;
+  }
+
+  public String name()
+  {
+    return name;
+  }
+
+  public int macSize()
+  {
+    return truncatedSize;
+  }
+
+  public void update(byte b)
+  {
+    underlyingHash.update(b);
+  }
+
+  public void update(byte[] b, int offset, int len)
+  {
+    underlyingHash.update(b, offset, len);
+  }
+
+  public void reset()
+  {
+    underlyingHash.reset();
+  }
+
+  public Object clone() throws CloneNotSupportedException
+  {
+    BaseMac result = (BaseMac) super.clone();
+    if (this.underlyingHash != null)
+      result.underlyingHash = (IMessageDigest) this.underlyingHash.clone();
+
+    return result;
+  }
+
+  public abstract void init(Map attributes) throws InvalidKeyException,
+      IllegalStateException;
+
+  public abstract byte[] digest();
+
+  public abstract boolean selfTest();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/HMac.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,263 @@
+/* HMac.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.hash.MD5;
+import gnu.java.security.util.Util;
+
+import java.security.InvalidKeyException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The implementation of the <i>HMAC</i> (Keyed-Hash Message Authentication
+ * Code).
+ * <p>
+ * <i>HMAC</i> can be used in combination with any iterated cryptographic hash
+ * function. <i>HMAC</i> also uses a <i>secret key</i> for calculation and
+ * verification of the message authentication values. The main goals behind this
+ * construction are:
+ * <ul>
+ * <li>To use, without modifications, available hash functions. In particular,
+ * hash functions that perform well in software, and for which code is freely
+ * and widely available.</li>
+ * <li>To preserve the original performance of the hash function without
+ * incurring a significant degradation.</li>
+ * <li>To use and handle keys in a simple way.</li>
+ * <li>To have a well understood cryptographic analysis of the strength of the
+ * authentication mechanism based on reasonable assumptions on the underlying
+ * hash function.</li>
+ * <li>To allow for easy replaceability of the underlying hash function in case
+ * that faster or more secure hash functions are found or required.</li>
+ * </ul>
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc-2104.txt">RFC 2104</a>HMAC:
+ * Keyed-Hashing for Message Authentication.<br>
+ * H. Krawczyk, M. Bellare, and R. Canetti.</li>
+ * </ol>
+ */
+public class HMac
+    extends BaseMac
+    implements Cloneable
+{
+  public static final String USE_WITH_PKCS5_V2 = "gnu.crypto.hmac.pkcs5";
+  private static final byte IPAD_BYTE = 0x36;
+  private static final byte OPAD_BYTE = 0x5C;
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+  protected int macSize;
+  protected int blockSize;
+  protected IMessageDigest ipadHash;
+  protected IMessageDigest opadHash;
+  protected byte[] ipad;
+
+  /**
+   * Trivial constructor for use by concrete subclasses.
+   *
+   * @param underlyingHash the underlying hash algorithm instance.
+   */
+  protected HMac(IMessageDigest underlyingHash)
+  {
+    super(Registry.HMAC_NAME_PREFIX + underlyingHash.name(), underlyingHash);
+
+    this.blockSize = underlyingHash.blockSize();
+    this.macSize = underlyingHash.hashSize();
+    ipadHash = opadHash = null;
+  }
+
+  public Object clone() throws CloneNotSupportedException
+  {
+    HMac result = (HMac) super.clone();
+    if (this.ipadHash != null)
+      result.ipadHash = (IMessageDigest) this.ipadHash.clone();
+    if (this.opadHash != null)
+      result.opadHash = (IMessageDigest) this.opadHash.clone();
+    if (this.ipad != null)
+      result.ipad = (byte[]) this.ipad.clone();
+
+    return result;
+  }
+
+  public void init(Map attributes) throws InvalidKeyException,
+      IllegalStateException
+  {
+    Integer ts = (Integer) attributes.get(TRUNCATED_SIZE);
+    truncatedSize = (ts == null ? macSize : ts.intValue());
+    if (truncatedSize < (macSize / 2))
+      throw new IllegalArgumentException("Truncated size too small");
+    else if (truncatedSize < 10)
+      throw new IllegalArgumentException("Truncated size less than 80 bits");
+
+    // we dont use/save the key outside this method
+    byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL);
+    if (K == null)
+      { // take it as an indication to re-use previous key if set
+        if (ipadHash == null)
+          throw new InvalidKeyException("Null key");
+        // we already went through the motions; ie. up to step #4.  re-use
+        underlyingHash = (IMessageDigest) ipadHash.clone();
+        return;
+      }
+
+    // for HMACs used in key-derivation functions (e.g. PBKDF2) the key material
+    // need not be >= the (output) block size of the underlying algorithm
+    Boolean pkcs5 = (Boolean) attributes.get(USE_WITH_PKCS5_V2);
+    if (pkcs5 == null)
+      pkcs5 = Boolean.FALSE;
+    if (K.length < macSize && ! pkcs5.booleanValue())
+      throw new InvalidKeyException("Key too short");
+
+    if (K.length > blockSize)
+      {
+        // (0) replace K with HASH(K) if K is larger than the hash's block size.
+        //     Then pad with zeros until it is the correct size (the next `if').
+        underlyingHash.update(K, 0, K.length);
+        K = underlyingHash.digest();
+      }
+    if (K.length < blockSize)
+      {
+        // (1) append zeros to the end of K to create a B byte string (e.g., if
+        //     K is of length 20 bytes and B=64, then K will be appended with 44
+        //     zero bytes 0x00)
+        int limit = (K.length > blockSize) ? blockSize : K.length;
+        byte[] newK = new byte[blockSize];
+        System.arraycopy(K, 0, newK, 0, limit);
+        K = newK;
+      }
+    underlyingHash.reset();
+    opadHash = (IMessageDigest) underlyingHash.clone();
+    if (ipad == null)
+      ipad = new byte[blockSize];
+    // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1)
+    //     with ipad
+    // (3) append the stream of data 'text' to the B byte string resulting from
+    //     step (2)
+    // (4) apply H to the stream generated in step (3)
+    for (int i = 0; i < blockSize; i++)
+      ipad[i] = (byte)(K[i] ^ IPAD_BYTE);
+    for (int i = 0; i < blockSize; i++)
+      opadHash.update((byte)(K[i] ^ OPAD_BYTE));
+    underlyingHash.update(ipad, 0, blockSize);
+    ipadHash = (IMessageDigest) underlyingHash.clone();
+    K = null;
+  }
+
+  public void reset()
+  {
+    super.reset();
+    if (ipad != null)
+      {
+        underlyingHash.update(ipad, 0, blockSize);
+        ipadHash = (IMessageDigest) underlyingHash.clone();
+      }
+  }
+
+  public byte[] digest()
+  {
+    if (ipadHash == null)
+      throw new IllegalStateException("HMAC not initialised");
+    byte[] out = underlyingHash.digest();
+    // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1)
+    //     with opad
+    underlyingHash = (IMessageDigest) opadHash.clone();
+    // (6) append the H result from step (4) to the B byte string resulting from
+    //     step (5)
+    underlyingHash.update(out, 0, macSize);
+    // (7) apply H to the stream generated in step (6) and output the result
+    out = underlyingHash.digest(); // which also resets the underlying hash
+    // truncate and return
+    if (truncatedSize == macSize)
+      return out;
+    byte[] result = new byte[truncatedSize];
+    System.arraycopy(out, 0, result, 0, truncatedSize);
+    return result;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        try
+          {
+            IMac mac = new HMac(new MD5()); // use rfc-2104 test vectors
+            String tv1 = "9294727A3638BB1C13F48EF8158BFC9D";
+            String tv3 = "56BE34521D144C88DBB8C733F0E8B3F6";
+            byte[] k1 = new byte[] {
+                0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
+                0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B };
+            byte[] k3 = new byte[] {
+                (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA,
+                (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA,
+                (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA,
+                (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA };
+            byte[] data = new byte[50];
+            for (int i = 0; i < 50;)
+              data[i++] = (byte) 0xDD;
+
+            HashMap map = new HashMap();
+            // test vector #1
+            map.put(MAC_KEY_MATERIAL, k1);
+            mac.init(map);
+            mac.update("Hi There".getBytes("ASCII"), 0, 8);
+            if (! tv1.equals(Util.toString(mac.digest())))
+              valid = Boolean.FALSE;
+
+            // test #2 is not used since it causes a "Key too short" exception
+
+            // test vector #3
+            map.put(MAC_KEY_MATERIAL, k3);
+            mac.init(map);
+            mac.update(data, 0, 50);
+            if (! tv3.equals(Util.toString(mac.digest())))
+              valid = Boolean.FALSE;
+            valid = Boolean.TRUE;
+          }
+        catch (Exception x)
+          {
+            x.printStackTrace(System.err);
+            valid = Boolean.FALSE;
+          }
+      }
+    return valid.booleanValue();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/HMacFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,111 @@
+/* HMacFactory.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.HashFactory;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A <i>Factory</i> to instantiate Keyed-Hash Message Authentication Code
+ * (HMAC) algorithm instances.
+ */
+public class HMacFactory
+    implements Registry
+{
+  /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+  private HMacFactory()
+  {
+    super();
+  }
+
+  /**
+   * Return an instance of a <i>HMAC</i> algorithm given the name of its
+   * underlying hash function, prefixed with the literal defined in
+   * {@link Registry#HMAC_NAME_PREFIX}.
+   * 
+   * @param name the fully qualified name of the underlying algorithm: composed
+   *          as the concatenation of a literal prefix (see
+   *          {@link Registry#HMAC_NAME_PREFIX}) and the name of the underlying
+   *          hash algorithm.
+   * @return an instance of the <i>HMAC</i> algorithm, or <code>null</code>
+   *         if none can be constructed.
+   * @exception InternalError if the implementation does not pass its self-test.
+   */
+  public static IMac getInstance(String name)
+  {
+    if (name == null)
+      return null;
+
+    name = name.trim();
+    name = name.toLowerCase();
+    if (! name.startsWith(HMAC_NAME_PREFIX))
+      return null;
+
+    // strip the prefix
+    name = name.substring(HMAC_NAME_PREFIX.length()).trim();
+    IMac result = new HMac(HashFactory.getInstance(name));
+    if (result != null && ! result.selfTest())
+      throw new InternalError(result.name());
+
+    return result;
+  }
+
+  /**
+   * <p>
+   * Returns a {@link java.util.Set} of names of <i>HMAC</i> algorithms
+   * supported by this <i>Factory</i>.
+   * </p>
+   * 
+   * @return a {@link java.util.Set} of HMAC algorithm names (Strings).
+   */
+  public static final Set getNames()
+  {
+    Set hashNames = HashFactory.getNames();
+    HashSet hs = new HashSet();
+    for (Iterator it = hashNames.iterator(); it.hasNext();)
+      hs.add(HMAC_NAME_PREFIX + ((String) it.next()));
+
+    return Collections.unmodifiableSet(hs);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/IMac.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,181 @@
+/* IMac.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import java.security.InvalidKeyException;
+import java.util.Map;
+
+/**
+ * The basic visible methods of any MAC (Message Authentication Code) algorithm.
+ * <p>
+ * A <i>MAC</i> provides a way to check the integrity of information
+ * transmitted over, or stored in, an unreliable medium, based on a secret key.
+ * Typically, <i>MAC</i>s are used between two parties, that share a common
+ * secret key, in order to validate information transmitted between them.
+ * <p>
+ * When a <i>MAC</i> algorithm is based on a cryptographic hash function, it is
+ * then called to a <i>HMAC</i> (Hashed Message Authentication Code) --see <a
+ * href="http://www.ietf.org/rfc/rfc-2104.txt">RFC-2104</a>.
+ * <p>
+ * Another type of <i>MAC</i> algorithms exist: UMAC or <i>Universal Message
+ * Authentication Code</i>, described in <a
+ * href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * draft-krovetz-umac-01.txt</a>.
+ * <p>
+ * With <i>UMAC</i>s, the sender and receiver share a common secret key (the
+ * <i>MAC</i> key) which determines:
+ * <ul>
+ * <li>The key for a <i>universal hash function</i>. This hash function is
+ * <i>non-cryptographic</i>, in the sense that it does not need to have any
+ * cryptographic <i>hardness</i> property. Rather, it needs to satisfy some
+ * combinatorial property, which can be proven to hold without relying on
+ * unproven hardness assumptions.</li>
+ * <li>The key for a <i>pseudorandom function</i>. This is where one needs a
+ * cryptographic hardness assumption. The pseudorandom function may be obtained
+ * from a <i>block cipher</i> or a <i>cryptographic hash function</i>. </li>
+ * </ul>
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc-2104.txt">RFC 2104</a>HMAC:
+ * Keyed-Hashing for Message Authentication.<br>
+ * H. Krawczyk, M. Bellare, and R. Canetti.</li>
+ * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
+ * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
+ * </ol>
+ */
+public interface IMac
+{
+  /**
+   * Property name of the user-supplied key material. The value associated to
+   * this property name is taken to be a byte array.
+   */
+  String MAC_KEY_MATERIAL = "gnu.crypto.mac.key.material";
+  /**
+   * Property name of the desired truncated output size in bytes. The value
+   * associated to this property name is taken to be an integer. If no value is
+   * specified in the attributes map at initialisation time, then all bytes of
+   * the underlying hash algorithm's output are emitted.
+   * <p>
+   * This implementation, follows the recommendation of the <i>RFC 2104</i>
+   * authors; specifically:
+   * <pre>
+   *     We recommend that the output length t be not less than half the
+   *     length of the hash output (to match the birthday attack bound)
+   *     and not less than 80 bits (a suitable lower bound on the number
+   *     of bits that need to be predicted by an attacker).
+   * </pre>
+   */
+  String TRUNCATED_SIZE = "gnu.crypto.mac.truncated.size";
+
+  /**
+   * Returns the canonical name of this algorithm.
+   * 
+   * @return the canonical name of this algorithm.
+   */
+  String name();
+
+  /**
+   * Returns the output length in bytes of this <i>MAC</i> algorithm.
+   * 
+   * @return the output length in bytes of this <i>MAC</i> algorithm.
+   */
+  int macSize();
+
+  /**
+   * Initialises the algorithm with designated attributes. Permissible names and
+   * values are described in the class documentation above.
+   * 
+   * @param attributes a set of name-value pairs that describe the desired
+   *          future instance behaviour.
+   * @exception InvalidKeyException if the key data is invalid.
+   * @exception IllegalStateException if the instance is already initialised.
+   * @see #MAC_KEY_MATERIAL
+   */
+  void init(Map attributes) throws InvalidKeyException, IllegalStateException;
+
+  /**
+   * Continues a <i>MAC</i> operation using the input byte.
+   * 
+   * @param b the input byte to digest.
+   */
+  void update(byte b);
+
+  /**
+   * Continues a <i>MAC</i> operation, by filling the buffer, processing data
+   * in the algorithm's MAC_SIZE-bit block(s), updating the context and count,
+   * and buffering the remaining bytes in buffer for the next operation.
+   * 
+   * @param in the input block.
+   * @param offset start of meaningful bytes in input block.
+   * @param length number of bytes, in input block, to consider.
+   */
+  void update(byte[] in, int offset, int length);
+
+  /**
+   * Completes the <i>MAC</i> by performing final operations such as padding
+   * and resetting the instance.
+   * 
+   * @return the array of bytes representing the <i>MAC</i> value.
+   */
+  byte[] digest();
+
+  /**
+   * Resets the algorithm instance for re-initialisation and use with other
+   * characteristics. This method always succeeds.
+   */
+  void reset();
+
+  /**
+   * A basic test. Ensures that the MAC of a pre-determined message is equal to
+   * a known pre-computed value.
+   * 
+   * @return <code>true</code> if the implementation passes a basic self-test.
+   *         Returns <code>false</code> otherwise.
+   */
+  boolean selfTest();
+
+  /**
+   * Returns a clone copy of this instance.
+   * 
+   * @return a clone copy of this instance.
+   */
+  Object clone() throws CloneNotSupportedException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/MacFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,130 @@
+/* MacFactory.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A <i>Factory</i> that instantiates instances of every supported Message
+ * Authentication Code algorithms, including all <i>HMAC</i> algorithms.
+ */
+public class MacFactory
+    implements Registry
+{
+  private static Set names;
+
+  /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+  private MacFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a <i>MAC</i> algorithm given its name.
+   * 
+   * @param name the name of the MAC algorithm.
+   * @return an instance of the <i>MAC</i> algorithm, or <code>null</code> if
+   *         none can be constructed.
+   * @exception InternalError if the implementation does not pass its self-test.
+   */
+  public static IMac getInstance(String name)
+  {
+    if (name == null)
+      return null;
+
+    name = name.trim();
+    name = name.toLowerCase();
+    if (name.startsWith(HMAC_NAME_PREFIX))
+      return HMacFactory.getInstance(name);
+
+    if (name.startsWith(OMAC_PREFIX))
+      {
+        name = name.substring(OMAC_PREFIX.length());
+        IBlockCipher cipher = CipherFactory.getInstance(name);
+        if (cipher == null)
+          return null;
+        return new OMAC(cipher);
+      }
+    IMac result = null;
+    if (name.equalsIgnoreCase(UHASH32))
+      result = new UHash32();
+    else if (name.equalsIgnoreCase(UMAC32))
+      result = new UMac32();
+    else if (name.equalsIgnoreCase(TMMH16))
+      result = new TMMH16();
+
+    if (result != null && ! result.selfTest())
+      throw new InternalError(result.name());
+
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of names of <i>MAC</i> algorithms supported by this
+   * <i>Factory</i>.
+   * 
+   * @return a {@link Set} of MAC names (Strings).
+   */
+  public static final Set getNames()
+  {
+    synchronized (MacFactory.class)
+      {
+        if (names == null)
+          {
+            HashSet hs = new HashSet();
+            hs.addAll(HMacFactory.getNames());
+            hs.add(UHASH32);
+            hs.add(UMAC32);
+            hs.add(TMMH16);
+            for (Iterator it = CipherFactory.getNames().iterator(); it.hasNext();)
+              hs.add(OMAC_PREFIX + it.next());
+
+            names = Collections.unmodifiableSet(hs);
+          }
+      }
+    return names;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/MacInputStream.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,124 @@
+/* MacInputStream.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * A filtering input stream that computes a MAC (message authentication code)
+ * over all data read from the stream.
+ */
+public class MacInputStream
+    extends FilterInputStream
+{
+  /** The digesting state. The MAC is updated only if this flag is true. */
+  private boolean digesting;
+  /** The MAC being updated. */
+  private IMac mac;
+
+  /**
+   * Creates a new MacInputStream. The stream is initially set to digest data
+   * written, the <i>mac</i> argument must have already been initialized, and
+   * the <i>mac</i> argument is <b>not</b> cloned.
+   * 
+   * @param in The underlying input stream.
+   * @param mac The mac instance to use.
+   */
+  public MacInputStream(InputStream in, IMac mac)
+  {
+    super(in);
+    if (mac == null)
+      throw new NullPointerException();
+    this.mac = mac;
+    digesting = true;
+  }
+
+  /**
+   * Returns the MAC this stream is updating.
+   * 
+   * @return The MAC.
+   */
+  public IMac getMac()
+  {
+    return mac;
+  }
+
+  /**
+   * Sets the MAC this stream is updating, which must have already been
+   * initialized. The argument is not cloned by this method.
+   * 
+   * @param mac The new MAC.
+   * @throws NullPointerException If the argument is null.
+   */
+  public void setMac(IMac mac)
+  {
+    if (mac == null)
+      throw new NullPointerException();
+    this.mac = mac;
+  }
+
+  /**
+   * Turns the digesting state on or off. When off, the MAC will not be updated
+   * when data is written to the stream.
+   * 
+   * @param flag The new digesting state.
+   */
+  public void on(boolean flag)
+  {
+    digesting = flag;
+  }
+
+  public int read() throws IOException
+  {
+    int i = in.read();
+    if (digesting && i != -1)
+      mac.update((byte) i);
+    return i;
+  }
+
+  public int read(byte[] buf, int off, int len) throws IOException
+  {
+    int i = in.read(buf, off, len);
+    if (digesting && i != -1)
+      mac.update(buf, off, i);
+    return i;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/MacOutputStream.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,123 @@
+/* MacOutputStream.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A filtering output stream that computes a MAC (message authentication code)
+ * over all data written to the stream.
+ */
+public class MacOutputStream
+    extends FilterOutputStream
+{
+  /** The digesting state. The MAC is updated only if this flag is true. */
+  private boolean digesting;
+  /** The MAC being updated. */
+  private IMac mac;
+
+  /**
+   * Creates a new <code>MacOutputStream</code>. The stream is initially set
+   * to digest data written, the <code>mac</code> argument must have already
+   * been initialized, and the <code>mac</code> argument is <b>not</b>
+   * cloned.
+   * 
+   * @param out The underlying output stream.
+   * @param mac The mac instance to use.
+   */
+  public MacOutputStream(OutputStream out, IMac mac)
+  {
+    super(out);
+    if (mac == null)
+      throw new NullPointerException();
+    this.mac = mac;
+    digesting = true;
+  }
+
+  /**
+   * Returns the MAC this stream is updating.
+   * 
+   * @return The MAC.
+   */
+  public IMac getMac()
+  {
+    return mac;
+  }
+
+  /**
+   * Sets the MAC this stream is updating, which must have already been
+   * initialized. The argument is not cloned by this method.
+   * 
+   * @param mac The non-null new MAC.
+   * @throws NullPointerException If the argument is null.
+   */
+  public void setMac(IMac mac)
+  {
+    if (mac == null)
+      throw new NullPointerException();
+    this.mac = mac;
+  }
+
+  /**
+   * Turns the digesting state on or off. When off, the MAC will not be updated
+   * when data is written to the stream.
+   * 
+   * @param flag The new digesting state.
+   */
+  public void on(boolean flag)
+  {
+    digesting = flag;
+  }
+
+  public void write(int b) throws IOException
+  {
+    if (digesting)
+      mac.update((byte) b);
+    out.write(b);
+  }
+
+  public void write(byte[] buf, int off, int len) throws IOException
+  {
+    if (digesting)
+      mac.update(buf, off, len);
+    out.write(buf, off, len);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/OMAC.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,303 @@
+/* OMAC.java -- 
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.mode.IMode;
+
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * The One-Key CBC MAC, OMAC. This message authentication code is based on a
+ * block cipher in CBC mode.
+ * <p>
+ * References:
+ * <ol>
+ * <li>Tetsu Iwata and Kaoru Kurosawa, <i><a
+ * href="http://crypt.cis.ibaraki.ac.jp/omac/docs/omac.pdf">OMAC: One-Key CBC
+ * MAC</a></i>.</li>
+ * </ol>
+ */
+public class OMAC
+    implements IMac
+{
+  private static final Logger log = Logger.getLogger(OMAC.class.getName());
+  private static final byte C1 = (byte) 0x87;
+  private static final byte C2 = 0x1b;
+  // Test key for OMAC-AES-128
+  private static final byte[] KEY0 =
+      Util.toBytesFromString("2b7e151628aed2a6abf7158809cf4f3c");
+  // Test MAC for zero-length input.
+  private static final byte[] DIGEST0 =
+      Util.toBytesFromString("bb1d6929e95937287fa37d129b756746");
+  private static Boolean valid;
+  private final IBlockCipher cipher;
+  private final String name;
+  private IMode mode;
+  private int blockSize;
+  private int outputSize;
+  private byte[] Lu, Lu2;
+  private byte[] M;
+  private byte[] Y;
+  private boolean init;
+  private int index;
+
+  public OMAC(IBlockCipher cipher)
+  {
+    this.cipher = cipher;
+    this.name = "OMAC-" + cipher.name();
+  }
+
+  public Object clone()
+  {
+    return new OMAC(cipher);
+  }
+
+  public String name()
+  {
+    return name;
+  }
+
+  public int macSize()
+  {
+    return outputSize;
+  }
+
+  public void init(Map attrib) throws InvalidKeyException
+  {
+    HashMap attrib2 = new HashMap();
+    attrib2.put(IBlockCipher.KEY_MATERIAL, attrib.get(MAC_KEY_MATERIAL));
+    cipher.reset();
+    cipher.init(attrib2);
+    blockSize = cipher.currentBlockSize();
+    Integer os = (Integer) attrib.get(TRUNCATED_SIZE);
+    if (os != null)
+      {
+        outputSize = os.intValue();
+        if (outputSize < 0 || outputSize > blockSize)
+          throw new IllegalArgumentException("truncated size out of range");
+      }
+    else
+      outputSize = blockSize;
+
+    byte[] L = new byte[blockSize];
+    cipher.encryptBlock(L, 0, L, 0);
+    if (Configuration.DEBUG)
+      log.fine("L = " + Util.toString(L).toLowerCase());
+    if (Lu != null)
+      {
+        Arrays.fill(Lu, (byte) 0);
+        if (Lu.length != blockSize)
+          Lu = new byte[blockSize];
+      }
+    else
+      Lu = new byte[blockSize];
+    if (Lu2 != null)
+      {
+        Arrays.fill(Lu2, (byte) 0);
+        if (Lu2.length != blockSize)
+          Lu2 = new byte[blockSize];
+      }
+    else
+      Lu2 = new byte[blockSize];
+
+    boolean msb = (L[0] & 0x80) != 0;
+    for (int i = 0; i < blockSize; i++)
+      {
+        Lu[i] = (byte)(L[i] << 1 & 0xFF);
+        if (i + 1 < blockSize)
+          Lu[i] |= (byte)((L[i + 1] & 0x80) >> 7);
+      }
+    if (msb)
+      {
+        if (blockSize == 16)
+          Lu[Lu.length - 1] ^= C1;
+        else if (blockSize == 8)
+          Lu[Lu.length - 1] ^= C2;
+        else
+          throw new IllegalArgumentException("unsupported cipher block size: "
+                                             + blockSize);
+      }
+    if (Configuration.DEBUG)
+      log.fine("Lu = " + Util.toString(Lu).toLowerCase());
+    msb = (Lu[0] & 0x80) != 0;
+    for (int i = 0; i < blockSize; i++)
+      {
+        Lu2[i] = (byte)(Lu[i] << 1 & 0xFF);
+        if (i + 1 < blockSize)
+          Lu2[i] |= (byte)((Lu[i + 1] & 0x80) >> 7);
+      }
+    if (msb)
+      {
+        if (blockSize == 16)
+          Lu2[Lu2.length - 1] ^= C1;
+        else
+          Lu2[Lu2.length - 1] ^= C2;
+      }
+    if (Configuration.DEBUG)
+      log.fine("Lu2 = " + Util.toString(Lu2).toLowerCase());
+    if (M != null)
+      {
+        Arrays.fill(M, (byte) 0);
+        if (M.length != blockSize)
+          M = new byte[blockSize];
+      }
+    else
+      M = new byte[blockSize];
+    if (Y != null)
+      {
+        Arrays.fill(Y, (byte) 0);
+        if (Y.length != blockSize)
+          Y = new byte[blockSize];
+      }
+    else
+      Y = new byte[blockSize];
+
+    index = 0;
+    init = true;
+  }
+
+  public void update(byte b)
+  {
+    if (! init)
+      throw new IllegalStateException("not initialized");
+    if (index == M.length)
+      {
+        process();
+        index = 0;
+      }
+    M[index++] = b;
+  }
+
+  public void update(byte[] buf, int off, int len)
+  {
+    if (! init)
+      throw new IllegalStateException("not initialized");
+    if (off < 0 || len < 0 || off + len > buf.length)
+      throw new IndexOutOfBoundsException("size=" + buf.length + "; off=" + off
+                                          + "; len=" + len);
+    for (int i = 0; i < len;)
+      {
+        if (index == blockSize)
+          {
+            process();
+            index = 0;
+          }
+        int count = Math.min(blockSize - index, len - i);
+        System.arraycopy(buf, off + i, M, index, count);
+        index += count;
+        i += count;
+      }
+  }
+
+  public byte[] digest()
+  {
+    byte[] b = new byte[outputSize];
+    digest(b, 0);
+    return b;
+  }
+
+  public void digest(byte[] out, int off)
+  {
+    if (! init)
+      throw new IllegalStateException("not initialized");
+    if (off < 0 || off + outputSize > out.length)
+      throw new IndexOutOfBoundsException("size=" + out.length + "; off=" + off
+                                          + "; len=" + outputSize);
+    byte[] T = new byte[blockSize];
+    byte[] L = Lu;
+    if (index < blockSize)
+      {
+        M[index++] = (byte) 0x80;
+        while (index < blockSize)
+          M[index++] = 0;
+        L = Lu2;
+      }
+    for (int i = 0; i < blockSize; i++)
+      T[i] = (byte)(M[i] ^ Y[i] ^ L[i]);
+    cipher.encryptBlock(T, 0, T, 0);
+    System.arraycopy(T, 0, out, off, outputSize);
+    reset();
+  }
+
+  public void reset()
+  {
+    index = 0;
+    if (Y != null)
+      Arrays.fill(Y, (byte) 0);
+    if (M != null)
+      Arrays.fill(M, (byte) 0);
+  }
+
+  public boolean selfTest()
+  {
+    OMAC mac = new OMAC(CipherFactory.getInstance(Registry.AES_CIPHER));
+    mac.reset();
+    Map attr = new HashMap();
+    attr.put(MAC_KEY_MATERIAL, KEY0);
+    byte[] digest = null;
+    try
+      {
+        mac.init(attr);
+        digest = mac.digest();
+      }
+    catch (Exception x)
+      {
+        return false;
+      }
+    if (digest == null)
+      return false;
+    return Arrays.equals(DIGEST0, digest);
+  }
+
+  private void process()
+  {
+    for (int i = 0; i < blockSize; i++)
+      M[i] = (byte)(M[i] ^ Y[i]);
+    cipher.encryptBlock(M, 0, Y, 0);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/TMMH16.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,339 @@
+/* TMMH16.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import gnu.java.security.Registry;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+
+import java.security.InvalidKeyException;
+import java.util.Map;
+
+/**
+ * <i>TMMH</i> is a <i>universal</i> hash function suitable for message
+ * authentication in the Wegman-Carter paradigm, as in the Stream Cipher
+ * Security Transform. It is simple, quick, and especially appropriate for
+ * Digital Signal Processors and other processors with a fast multiply
+ * operation, though a straightforward implementation requires storage equal in
+ * length to the largest message to be hashed.
+ * <p>
+ * <i>TMMH</i> is a simple hash function which maps a key and a message to a
+ * hash value. There are two versions of TMMH: TMMH/16 and TMMH/32. <i>TMMH</i>
+ * can be used as a message authentication code, as described in Section 5 (see
+ * References).
+ * <p>
+ * The key, message, and hash value are all octet strings, and the lengths of
+ * these quantities are denoted as <code>KEY_LENGTH</code>,
+ * <code>MESSAGE_LENGTH</code>, and <code>TAG_LENGTH</code>, respectively.
+ * The values of <code>KEY_LENGTH</code> and <code>TAG_LENGTH</code>
+ * <bold>MUST</bold> be fixed for any particular fixed value of the key, and
+ * must obey the alignment restrictions described below.
+ * <p>
+ * The parameter <code>MAX_HASH_LENGTH</code>, which denotes the maximum
+ * value which <code>MESSAGE_LENGTH</code> may take, is equal to
+ * <code>KEY_LENGTH - TAG_LENGTH</code>.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-tmmh-01.txt"> The
+ * Truncated Multi-Modular Hash Function (TMMH)</a>, David A. McGrew.</li>
+ * </ol>
+ */
+public class TMMH16
+    extends BaseMac
+    implements Cloneable
+{
+  public static final String TAG_LENGTH = "gnu.crypto.mac.tmmh.tag.length";
+  public static final String KEYSTREAM = "gnu.crypto.mac.tmmh.keystream";
+  public static final String PREFIX = "gnu.crypto.mac.tmmh.prefix";
+  private static final int P = (1 << 16) + 1; // the TMMH/16 prime
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+  private int tagWords = 0; // the tagLength expressed in words
+  private IRandom keystream = null; // the keystream generator
+  private byte[] prefix; // mask to use when operating as an authentication f.
+  private long keyWords; // key words counter
+  private long msgLength; // in bytes
+  private long msgWords; // should be = msgLength * WORD_LENGTH
+  private int[] context; // the tmmh running context; length == TAG_WORDS
+  private int[] K0; // the first TAG_WORDS words of the keystream
+  private int[] Ki; // the sliding TAG_WORDS words of the keystream
+  private int Mi; // current message word being constructed
+
+  /** Trivial 0-arguments constructor. */
+  public TMMH16()
+  {
+    super(Registry.TMMH16);
+  }
+
+  public int macSize()
+  {
+    return tagWords * 2;
+  }
+
+  public void init(Map attributes) throws InvalidKeyException,
+      IllegalStateException
+  {
+    int wantTagLength = 0;
+    Integer tagLength = (Integer) attributes.get(TAG_LENGTH); // get tag length
+    if (tagLength == null)
+      {
+        if (tagWords == 0) // was never set
+          throw new IllegalArgumentException(TAG_LENGTH);
+        // else re-use
+      }
+    else // check if positive and is divisible by WORD_LENGTH
+      {
+        wantTagLength = tagLength.intValue();
+        if (wantTagLength < 2 || (wantTagLength % 2 != 0))
+          throw new IllegalArgumentException(TAG_LENGTH);
+        else if (wantTagLength > (512 / 8)) // 512-bits is our maximum
+          throw new IllegalArgumentException(TAG_LENGTH);
+
+        tagWords = wantTagLength / 2; // init local vars
+        K0 = new int[tagWords];
+        Ki = new int[tagWords];
+        context = new int[tagWords];
+      }
+
+    prefix = (byte[]) attributes.get(PREFIX);
+    if (prefix == null) // default to all-zeroes
+      prefix = new byte[tagWords * 2];
+    else // ensure it's as long as it should
+      {
+        if (prefix.length != tagWords * 2)
+          throw new IllegalArgumentException(PREFIX);
+      }
+
+    IRandom prng = (IRandom) attributes.get(KEYSTREAM); // get keystream
+    if (prng == null)
+      {
+        if (keystream == null)
+          throw new IllegalArgumentException(KEYSTREAM);
+        // else reuse
+      }
+    else
+      keystream = prng;
+
+    reset(); // reset context variables
+    for (int i = 0; i < tagWords; i++) // init starting key words
+      Ki[i] = K0[i] = getNextKeyWord(keystream);
+  }
+
+  // The words of the key are denoted as K[1], K[2], ..., K[KEY_WORDS], and the
+  // words of the message (after zero padding, if needed) are denoted as M[1],
+  // M[2], ..., M[MSG_WORDS], where MSG_WORDS is the smallest number such that
+  // 2 * MSG_WORDS is at least MESSAGE_LENGTH, and KEY_WORDS is KEY_LENGTH / 2.
+  //
+  // If MESSAGE_LENGTH is greater than MAX_HASH_LENGTH, then the value of
+  // TMMH/16 is undefined. Implementations MUST indicate an error if asked to
+  // hash a message with such a length. Otherwise, the hash value is defined
+  // to be the length TAG_WORDS sequence of words in which the j-th word in the
+  // sequence is defined as
+  //
+  // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2]
+  // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16
+  //
+  // where j ranges from 1 to TAG_WORDS.
+  public void update(byte b)
+  {
+    this.update(b, keystream);
+  }
+
+  public void update(byte[] b, int offset, int len)
+  {
+    for (int i = 0; i < len; i++)
+      this.update(b[offset + i], keystream);
+  }
+
+  // For TMMH/16, KEY_LENGTH and TAG_LENGTH MUST be a multiple of two. The key,
+  // message, and hash value are treated as a sequence of unsigned sixteen bit
+  // integers in network byte order. (In this section, we call such an integer
+  // a word.) If MESSAGE_LENGTH is odd, then a zero byte is appended to the
+  // message to align it on a word boundary, though this process does not
+  // change the value of MESSAGE_LENGTH.
+  //
+  // ... Otherwise, the hash value is defined to be the length TAG_WORDS
+  // sequence of words in which the j-th word in the sequence is defined as
+  //
+  // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2]
+  // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16
+  //
+  // where j ranges from 1 to TAG_WORDS.
+  //
+  // Here, TAG_WORDS is equal to TAG_LENGTH / 2, and p is equal to 2^16 + 1.
+  // The symbol * denotes multiplication and the symbol +32 denotes addition
+  // modulo 2^32.
+  public byte[] digest()
+  {
+    return this.digest(keystream);
+  }
+
+  public void reset()
+  {
+    msgLength = msgWords = keyWords = 0L;
+    Mi = 0;
+    for (int i = 0; i < tagWords; i++)
+      context[i] = 0;
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        // TODO: compute and test equality with one known vector
+        valid = Boolean.TRUE;
+      }
+    return valid.booleanValue();
+  }
+
+  public Object clone() throws CloneNotSupportedException
+  {
+    TMMH16 result = (TMMH16) super.clone();
+    if (this.keystream != null)
+      result.keystream = (IRandom) this.keystream.clone();
+    if (this.prefix != null)
+      result.prefix = (byte[]) this.prefix.clone();
+    if (this.context != null)
+      result.context = (int[]) this.context.clone();
+    if (this.K0 != null)
+      result.K0 = (int[]) this.K0.clone();
+    if (this.Ki != null)
+      result.Ki = (int[]) this.Ki.clone();
+    return result;
+  }
+
+  /**
+   * Similar to the same method with one argument, but uses the designated
+   * random number generator to compute needed keying material.
+   * 
+   * @param b the byte to process.
+   * @param prng the source of randomness to use.
+   */
+  public void update(byte b, IRandom prng)
+  {
+    Mi <<= 8; // update message buffer
+    Mi |= b & 0xFF;
+    msgLength++; // update message length (bytes)
+    if (msgLength % 2 == 0) // got a full word
+      {
+        msgWords++; // update message words counter
+        System.arraycopy(Ki, 1, Ki, 0, tagWords - 1); // 1. shift Ki up by 1
+        Ki[tagWords - 1] = getNextKeyWord(prng); // 2. fill last box of Ki
+        long t; // temp var to allow working in modulo 2^32
+        for (int i = 0; i < tagWords; i++) // 3. update context
+          {
+            t = context[i] & 0xFFFFFFFFL;
+            t += Ki[i] * Mi;
+            context[i] = (int) t;
+          }
+        Mi = 0; // reset message buffer
+      }
+  }
+
+  /**
+   * Similar to the same method with three arguments, but uses the designated
+   * random number generator to compute needed keying material.
+   * 
+   * @param b the byte array to process.
+   * @param offset the starting offset in <code>b</code> to start considering
+   *          the bytes to process.
+   * @param len the number of bytes in <code>b</code> starting from
+   *          <code>offset</code> to process.
+   * @param prng the source of randomness to use.
+   */
+  public void update(byte[] b, int offset, int len, IRandom prng)
+  {
+    for (int i = 0; i < len; i++)
+      this.update(b[offset + i], prng);
+  }
+
+  /**
+   * Similar to the same method with no arguments, but uses the designated
+   * random number generator to compute needed keying material.
+   * 
+   * @param prng the source of randomness to use.
+   * @return the final result of the algorithm.
+   */
+  public byte[] digest(IRandom prng)
+  {
+    doFinalRound(prng);
+    byte[] result = new byte[tagWords * 2];
+    for (int i = 0, j = 0; i < tagWords; i++)
+      {
+        result[j] = (byte)((context[i] >>> 8) ^ prefix[j]);
+        j++;
+        result[j] = (byte)(context[i] ^ prefix[j]);
+        j++;
+      }
+    reset();
+    return result;
+  }
+
+  private int getNextKeyWord(IRandom prng)
+  {
+    int result = 0;
+    try
+      {
+        result = (prng.nextByte() & 0xFF) << 8 | (prng.nextByte() & 0xFF);
+      }
+    catch (LimitReachedException x)
+      {
+        throw new RuntimeException(String.valueOf(x));
+      }
+    keyWords++; // update key words counter
+    return result;
+  }
+
+  private void doFinalRound(IRandom prng)
+  {
+    long limit = msgLength; // formula works on real message length
+    while (msgLength % 2 != 0)
+      update((byte) 0x00, prng);
+    long t;
+    for (int i = 0; i < tagWords; i++)
+      {
+        t = context[i] & 0xFFFFFFFFL;
+        t += K0[i] * limit;
+        t %= P;
+        context[i] = (int) t;
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/UHash32.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,758 @@
+/* UHash32.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.prng.UMacGenerator;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <i>UHASH</i> is a keyed hash function, which takes as input a string of
+ * arbitrary length, and produces as output a string of fixed length (such as 8
+ * bytes). The actual output length depends on the parameter UMAC-OUTPUT-LEN.
+ * <p>
+ * <i>UHASH</i> has been shown to be <i>epsilon-ASU</i> ("Almost Strongly
+ * Universal"), where epsilon is a small (parameter-dependent) real number.
+ * Informally, saying that a keyed hash function is <i>epsilon-ASU</i> means
+ * that for any two distinct fixed input strings, the two outputs of the hash
+ * function with a random key "look almost like a pair of random strings". The
+ * number epsilon measures how non-random the output strings may be.
+ * <p>
+ * <i>UHASH</i> has been designed to be fast by exploiting several
+ * architectural features of modern commodity processors. It was specifically
+ * designed for use in <i>UMAC</i>. But <i>UHASH</i> is useful beyond that
+ * domain, and can be easily adopted for other purposes.
+ * <p>
+ * <i>UHASH</i> does its work in three layers. First, a hash function called
+ * <code>NH</code> is used to compress input messages into strings which are
+ * typically many times smaller than the input message. Second, the compressed
+ * message is hashed with an optimized <i>polynomial hash function</i> into a
+ * fixed-length 16-byte string. Finally, the 16-byte string is hashed using an
+ * <i>inner-product hash</i> into a string of length WORD-LEN bytes. These
+ * three layers are repeated (with a modified key) until the outputs total
+ * UMAC-OUTPUT-LEN bytes.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
+ * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
+ * </ol>
+ */
+public class UHash32
+    extends BaseMac
+{
+  // UMAC prime values
+  private static final BigInteger PRIME_19 = BigInteger.valueOf(0x7FFFFL);
+  private static final BigInteger PRIME_32 = BigInteger.valueOf(0xFFFFFFFBL);
+  private static final BigInteger PRIME_36 = BigInteger.valueOf(0xFFFFFFFFBL);
+  private static final BigInteger PRIME_64 = new BigInteger(1, new byte[] {
+      (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+      (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xC5 });
+  private static final BigInteger PRIME_128 = new BigInteger(1, new byte[] {
+      (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+      (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+      (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+      (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x61 });
+  static final BigInteger TWO = BigInteger.valueOf(2L);
+  static final long BOUNDARY = TWO.shiftLeft(17).longValue();
+  // 2**64 - 2**32
+  static final BigInteger LOWER_RANGE = TWO.pow(64).subtract(TWO.pow(32));
+  // 2**128 - 2**96
+  static final BigInteger UPPER_RANGE = TWO.pow(128).subtract(TWO.pow(96));
+  static final byte[] ALL_ZEROES = new byte[32];
+  int streams;
+  L1Hash32[] l1hash;
+
+  /** Trivial 0-arguments constructor. */
+  public UHash32()
+  {
+    super("uhash32");
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   *
+   * @param that the instance to clone.
+   */
+  private UHash32(UHash32 that)
+  {
+    this();
+
+    this.streams = that.streams;
+    if (that.l1hash != null)
+      {
+        this.l1hash = new L1Hash32[that.streams];
+        for (int i = 0; i < that.streams; i++)
+          if (that.l1hash[i] != null)
+            this.l1hash[i] = (L1Hash32) that.l1hash[i].clone();
+      }
+  }
+
+  /**
+   * The prime numbers used in UMAC are:
+   * <pre>
+   *   +-----+--------------------+---------------------------------------+
+   *   |  x  | prime(x) [Decimal] | prime(x) [Hexadecimal]                |
+   *   +-----+--------------------+---------------------------------------+
+   *   | 19  | 2^19  - 1          | 0x0007FFFF                            |
+   *   | 32  | 2^32  - 5          | 0xFFFFFFFB                            |
+   *   | 36  | 2^36  - 5          | 0x0000000F FFFFFFFB                   |
+   *   | 64  | 2^64  - 59         | 0xFFFFFFFF FFFFFFC5                   |
+   *   | 128 | 2^128 - 159        | 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFF61 |
+   *   +-----+--------------------+---------------------------------------+
+   *</pre>
+   *
+   * @param n a number of bits.
+   * @return the largest prime number less than 2**n.
+   */
+  static final BigInteger prime(int n)
+  {
+    switch (n)
+      {
+      case 19:
+        return PRIME_19;
+      case 32:
+        return PRIME_32;
+      case 36:
+        return PRIME_36;
+      case 64:
+        return PRIME_64;
+      case 128:
+        return PRIME_128;
+      default:
+        throw new IllegalArgumentException("Undefined prime("
+                                           + String.valueOf(n) + ")");
+      }
+  }
+
+  public Object clone()
+  {
+    return new UHash32(this);
+  }
+
+  public int macSize()
+  {
+    return UMac32.OUTPUT_LEN;
+  }
+
+  public void init(Map attributes) throws InvalidKeyException,
+      IllegalStateException
+  {
+    byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL);
+    if (K == null)
+      throw new InvalidKeyException("Null Key");
+    if (K.length != UMac32.KEY_LEN)
+      throw new InvalidKeyException("Invalid Key length: "
+                                    + String.valueOf(K.length));
+    // Calculate iterations needed to make UMAC-OUTPUT-LEN bytes
+    streams = (UMac32.OUTPUT_LEN + 3) / 4;
+    // Define total key needed for all iterations using UMacGenerator.
+    // L1Key and L3Key1 both reuse most key between iterations.
+    IRandom kdf1 = new UMacGenerator();
+    IRandom kdf2 = new UMacGenerator();
+    IRandom kdf3 = new UMacGenerator();
+    IRandom kdf4 = new UMacGenerator();
+    Map map = new HashMap();
+    map.put(IBlockCipher.KEY_MATERIAL, K);
+    map.put(UMacGenerator.INDEX, Integer.valueOf(0));
+    kdf1.init(map);
+    map.put(UMacGenerator.INDEX, Integer.valueOf(1));
+    kdf2.init(map);
+    map.put(UMacGenerator.INDEX, Integer.valueOf(2));
+    kdf3.init(map);
+    map.put(UMacGenerator.INDEX, Integer.valueOf(3));
+    kdf4.init(map);
+    // need to generate all bytes for use later in a Toepliz construction
+    byte[] L1Key = new byte[UMac32.L1_KEY_LEN + (streams - 1) * 16];
+    try
+      {
+        kdf1.nextBytes(L1Key, 0, L1Key.length);
+      }
+    catch (LimitReachedException x)
+      {
+        x.printStackTrace(System.err);
+        throw new RuntimeException("KDF for L1Key reached limit");
+      }
+
+    l1hash = new L1Hash32[streams];
+    for (int i = 0; i < streams; i++)
+      {
+        byte[] k1 = new byte[UMac32.L1_KEY_LEN];
+        System.arraycopy(L1Key, i * 16, k1, 0, UMac32.L1_KEY_LEN);
+        byte[] k2 = new byte[24];
+        try
+          {
+            kdf2.nextBytes(k2, 0, 24);
+          }
+        catch (LimitReachedException x)
+          {
+            x.printStackTrace(System.err);
+            throw new RuntimeException("KDF for L2Key reached limit");
+          }
+        byte[] k31 = new byte[64];
+        try
+          {
+            kdf3.nextBytes(k31, 0, 64);
+          }
+        catch (LimitReachedException x)
+          {
+            x.printStackTrace(System.err);
+            throw new RuntimeException("KDF for L3Key1 reached limit");
+          }
+        byte[] k32 = new byte[4];
+        try
+          {
+            kdf4.nextBytes(k32, 0, 4);
+          }
+        catch (LimitReachedException x)
+          {
+            x.printStackTrace(System.err);
+            throw new RuntimeException("KDF for L3Key2 reached limit");
+          }
+        L1Hash32 mac = new L1Hash32();
+        mac.init(k1, k2, k31, k32);
+        l1hash[i] = mac;
+      }
+  }
+
+  public void update(byte b)
+  {
+    for (int i = 0; i < streams; i++)
+      l1hash[i].update(b);
+  }
+
+  public void update(byte[] b, int offset, int len)
+  {
+    for (int i = 0; i < len; i++)
+      this.update(b[offset + i]);
+  }
+
+  public byte[] digest()
+  {
+    byte[] result = new byte[UMac32.OUTPUT_LEN];
+    for (int i = 0; i < streams; i++)
+      {
+        byte[] partialResult = l1hash[i].digest();
+        System.arraycopy(partialResult, 0, result, 4 * i, 4);
+      }
+    reset();
+    return result;
+  }
+
+  public void reset()
+  {
+    for (int i = 0; i < streams; i++)
+      l1hash[i].reset();
+  }
+
+  public boolean selfTest()
+  {
+    return true;
+  }
+
+  /**
+   * First hash stage of the UHash32 algorithm.
+   */
+  class L1Hash32
+      implements Cloneable
+  {
+    private int[] key; // key material as an array of 32-bit ints
+    private byte[] buffer; // work buffer L1_KEY_LEN long
+    private int count; // meaningful bytes in buffer
+    private ByteArrayOutputStream Y;
+    private long totalCount;
+    private L2Hash32 l2hash;
+    private L3Hash32 l3hash;
+
+    /** Trivial 0-arguments constructor. */
+    L1Hash32()
+    {
+      super();
+
+      key = new int[UMac32.L1_KEY_LEN / 4];
+      buffer = new byte[UMac32.L1_KEY_LEN];
+      count = 0;
+      Y = new ByteArrayOutputStream();
+      totalCount = 0L;
+    }
+
+    /**
+     * Private constructor for cloning purposes.
+     *
+     * @param that the instance to clone.
+     */
+    private L1Hash32(L1Hash32 that)
+    {
+      this();
+
+      System.arraycopy(that.key, 0, this.key, 0, that.key.length);
+      System.arraycopy(that.buffer, 0, this.buffer, 0, that.count);
+      this.count = that.count;
+      byte[] otherY = that.Y.toByteArray();
+      this.Y.write(otherY, 0, otherY.length);
+      this.totalCount = that.totalCount;
+      if (that.l2hash != null)
+        this.l2hash = (L2Hash32) that.l2hash.clone();
+      if (that.l3hash != null)
+        this.l3hash = (L3Hash32) that.l3hash.clone();
+    }
+
+    public Object clone()
+    {
+      return new L1Hash32(this);
+    }
+
+    public void init(byte[] k1, byte[] k2, byte[] k31, byte[] k32)
+    {
+      for (int i = 0, j = 0; i < (UMac32.L1_KEY_LEN / 4); i++)
+        key[i] =  k1[j++]         << 24
+               | (k1[j++] & 0xFF) << 16
+               | (k1[j++] & 0xFF) << 8
+               | (k1[j++] & 0xFF);
+      l2hash = new L2Hash32(k2);
+      l3hash = new L3Hash32(k31, k32);
+    }
+
+    public void update(byte b)
+    {
+      // Break M into L1_KEY_LEN byte chunks (final chunk may be shorter)
+
+      // Let M_1, M_2, ..., M_t be strings so that M = M_1 || M_2 || .. ||
+      // M_t, and length(M_i) = L1_KEY_LEN for all 0 < i < t.
+
+      // For each chunk, except the last: endian-adjust, NH hash
+      // and add bit-length.  Use results to build Y.
+      buffer[count] = b;
+      count++;
+      totalCount++;
+      if (count >= UMac32.L1_KEY_LEN)
+        {
+          byte[] y = nh32(UMac32.L1_KEY_LEN);
+          Y.write(y, 0, 8);
+
+          count = 0;
+
+          // For each iteration, extract key and three-layer hash.
+          // If length(M) <= L1_KEY_LEN, then skip L2-HASH.
+          if (Y.size() == 16) // we already hashed twice L1_KEY_LEN
+            {
+              byte[] A = Y.toByteArray();
+              Y.reset();
+              l2hash.update(A, 0, 16);
+            }
+        }
+    }
+
+    public byte[] digest()
+    {
+      // For the last chunk: pad to 32-byte boundary, endian-adjust,
+      // NH hash and add bit-length.  Concatenate the result to Y.
+      if (count != 0)
+        {
+          if (count % 32 != 0)
+            {
+              int limit = 32 * ((count + 31) / 32);
+              System.arraycopy(ALL_ZEROES, 0, buffer, count, limit - count);
+              count += limit - count;
+            }
+          byte[] y = nh32(count);
+          Y.write(y, 0, 8);
+        }
+      byte[] A = Y.toByteArray();
+      Y.reset();
+      byte[] B;
+      if (totalCount <= UMac32.L1_KEY_LEN)
+        {
+          // we might have 'update'd the bytes already. check
+          if (A.length == 0) // we did
+            B = l2hash.digest();
+          else // did not
+            {
+              B = new byte[16];
+              System.arraycopy(A, 0, B, 8, 8);
+            }
+        }
+      else
+        {
+          if (A.length != 0)
+            l2hash.update(A, 0, A.length);
+          B = l2hash.digest();
+        }
+      byte[] result = l3hash.digest(B);
+      reset();
+      return result;
+    }
+
+    public void reset()
+    {
+      count = 0;
+      Y.reset();
+      totalCount = 0L;
+      if (l2hash != null)
+        l2hash.reset();
+    }
+
+    /**
+     * 5.1  NH-32: NH hashing with a 32-bit word size.
+     *
+     * @param len count of bytes, divisible by 32, in buffer to process
+     * @return Y, string of length 8 bytes.
+     */
+    private byte[] nh32(int len)
+    {
+      // Break M and K into 4-byte chunks
+      int t = len / 4;
+      // Let M_1, M_2, ..., M_t be 4-byte strings
+      // so that M = M_1 || M_2 || .. || M_t.
+      // Let K_1, K_2, ..., K_t be 4-byte strings
+      // so that K_1 || K_2 || .. || K_t  is a prefix of K.
+      int[] m = new int[t];
+      int i;
+      int j = 0;
+      for (i = 0, j = 0; i < t; i++)
+        m[i] =  buffer[j++]         << 24
+             | (buffer[j++] & 0xFF) << 16
+             | (buffer[j++] & 0xFF) << 8
+             | (buffer[j++] & 0xFF);
+      // Perform NH hash on the chunks, pairing words for multiplication
+      // which are 4 apart to accommodate vector-parallelism.
+      long result = len * 8L;
+      for (i = 0; i < t; i += 8)
+        {
+          result += ((m[i + 0] + key[i + 0]) & 0xFFFFFFFFL)
+                  * ((m[i + 4] + key[i + 4]) & 0xFFFFFFFFL);
+          result += ((m[i + 1] + key[i + 1]) & 0xFFFFFFFFL)
+                  * ((m[i + 5] + key[i + 5]) & 0xFFFFFFFFL);
+          result += ((m[i + 2] + key[i + 2]) & 0xFFFFFFFFL)
+                  * ((m[i + 6] + key[i + 6]) & 0xFFFFFFFFL);
+          result += ((m[i + 3] + key[i + 3]) & 0xFFFFFFFFL)
+                  * ((m[i + 7] + key[i + 7]) & 0xFFFFFFFFL);
+        }
+      return new byte[] {
+          (byte)(result >>> 56), (byte)(result >>> 48),
+          (byte)(result >>> 40), (byte)(result >>> 32),
+          (byte)(result >>> 24), (byte)(result >>> 16),
+          (byte)(result >>>  8), (byte) result };
+    }
+  }
+
+  /**
+   * Second hash stage of the UHash32 algorithm.
+   * <p>
+   * 5.4 L2-HASH-32: Second-layer hash.
+   * <ul>
+   * <li>Input:<br>
+   * K string of length 24 bytes.<br>
+   * M string of length less than 2^64 bytes.</li>
+   * <li>Returns:<br>
+   * Y, string of length 16 bytes.</li>
+   * </ul>
+   */
+  class L2Hash32
+      implements Cloneable
+  {
+    private BigInteger k64, k128;
+    private BigInteger y;
+    private boolean highBound;
+    private long bytesSoFar;
+    private ByteArrayOutputStream buffer;
+
+    L2Hash32(byte[] K)
+    {
+      super();
+
+      if (K.length != 24)
+        throw new ExceptionInInitializerError("K length is not 24");
+      //  Extract keys and restrict to special key-sets
+      //         Mask64  = uint2str(0x01FFFFFF01FFFFFF, 8);
+      //         Mask128 = uint2str(0x01FFFFFF01FFFFFF01FFFFFF01FFFFFF, 16);
+      //         k64    = str2uint(K[1..8]  and Mask64);
+      //         k128   = str2uint(K[9..24] and Mask128);
+      int i = 0;
+      k64 = new BigInteger(1, new byte[] {
+          (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF) });
+      k128 = new BigInteger(1, new byte[] {
+          (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF),
+          (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF) });
+      y = BigInteger.ONE;
+      highBound = false;
+      bytesSoFar = 0L;
+    }
+
+    private L2Hash32(L2Hash32 that)
+    {
+      super();
+
+      this.k64 = that.k64;
+      this.k128 = that.k128;
+      this.y = that.y;
+      this.highBound = that.highBound;
+      this.bytesSoFar = that.bytesSoFar;
+      if (that.buffer != null)
+        {
+          byte[] thatbuffer = that.buffer.toByteArray();
+          this.buffer = new ByteArrayOutputStream();
+          this.buffer.write(thatbuffer, 0, thatbuffer.length);
+        }
+    }
+
+    public Object clone()
+    {
+      return new L2Hash32(this);
+    }
+
+    // this is called with either 8-bytes or 16-bytes
+    void update(byte[] b, int offset, int len)
+    {
+      if (len == 0)
+        return;
+
+      if (! highBound) // do the first (only?) 8-bytes
+        {
+          poly(64, LOWER_RANGE, k64, b, offset, 8);
+          bytesSoFar += 8L;
+          highBound = (bytesSoFar > BOUNDARY);
+          if (highBound) // if we just crossed the limit then process y
+            {
+              poly(128, UPPER_RANGE, k128, yTo16bytes(), 0, 16);
+              buffer = new ByteArrayOutputStream();
+            }
+          // do the rest if any
+          update(b, offset + 8, len - 8);
+        }
+      else
+        { // we're already beyond the 2**17 bytes size limit
+          // process in chuncks of 16
+          buffer.write(b, offset, len);
+          if (buffer.size() > 16)
+            {
+              byte[] bb = buffer.toByteArray();
+              poly(128, UPPER_RANGE, k128, bb, 0, 16);
+              if (bb.length > 16)
+                buffer.write(bb, 16, bb.length - 16);
+            }
+        }
+    }
+
+    byte[] digest()
+    {
+      // If M no more than 2^17 bytes, hash under 64-bit prime,
+      // otherwise, hash first 2^17 bytes under 64-bit prime and
+      // remainder under 128-bit prime.
+      if (! highBound) // y is up-to-date
+        {
+          // do nothing
+        }
+      else // we may have some bytes in buffer
+        {
+          byte[] bb = buffer.toByteArray();
+          byte[] lastBlock = new byte[16];
+          System.arraycopy(bb, 0, lastBlock, 0, bb.length);
+          lastBlock[bb.length] = (byte) 0x80;
+          poly(128, UPPER_RANGE, k128, lastBlock, 0, 16);
+        }
+      byte[] result = yTo16bytes();
+      reset();
+      return result;
+    }
+
+    void reset()
+    {
+      y = BigInteger.ONE;
+      highBound = false;
+      bytesSoFar = 0L;
+      if (buffer != null)
+        buffer.reset();
+    }
+
+    private byte[] yTo16bytes()
+    {
+      byte[] yy = y.toByteArray();
+      byte[] result = new byte[16];
+      if (yy.length > 16)
+        System.arraycopy(yy, yy.length - 16, result, 0, 16);
+      else
+        System.arraycopy(yy, 0, result, 16 - yy.length, yy.length);
+
+      return result;
+    }
+
+    /**
+     * 5.3 POLY: Polynomial hash Function Name: POLY
+     * 
+     * @param wordbits positive integer divisible by 8: called with 64 or 128.
+     * @param maxwordrange positive integer less than 2**wordbits.
+     * @param k integer in the range 0 .. prime(wordbits) - 1.
+     * @param M string with length divisible by (wordbits / 8) bytes. return y,
+     *          integer in the range 0 .. prime(wordbits) - 1.
+     */
+    private void poly(int wordbits, BigInteger maxwordrange, BigInteger k,
+                      byte[] M, int off, int len)
+    {
+      byte[] mag = new byte[len];
+      System.arraycopy(M, off, mag, 0, len);
+      // Define constants used for fixing out-of-range words
+      BigInteger p = prime(wordbits);
+      BigInteger offset = TWO.pow(wordbits).subtract(p); // 2^wordbits - p;
+      BigInteger marker = p.subtract(BigInteger.ONE);
+      // Break M into chunks of length wordbytes bytes
+      //         long n = M.length / wordbytes;
+      // Let M_1, M_2, ..., M_n be strings of length wordbytes bytes
+      // so that M = M_1 || M_2 || .. || M_n
+
+      // For each input word, compare it with maxwordrange.  If larger
+      // then hash the words 'marker' and (m - offset), both in range.
+      //         for (int i = 0; i < n; i++) {
+      BigInteger m = new BigInteger(1, mag);
+      if (m.compareTo(maxwordrange) >= 0) // m >= maxwordrange
+        {
+          y = y.multiply(k).add(marker).mod(p); // (k * y + marker) % p;
+          y = y.multiply(k).add(m.subtract(offset)).mod(p); // (k * y + (m - offset)) % p;
+        }
+      else
+        y = y.multiply(k).add(m).mod(p); // (k * y + m) % p;
+    }
+  }
+
+  /**
+   * Third hash stage of the UHash32 algorithm.
+   * <ul>
+   * <li>Input:<br/>
+   * K1 string of length 64 bytes.<br/>
+   * K2 string of length 4 bytes.<br/>
+   * M string of length 16 bytes.</li>
+   * <li>Returns:<br/>
+   * Y, string of length 4 bytes.</li>
+   * </ul>
+   */
+  class L3Hash32
+      implements Cloneable
+  {
+    private static final long PRIME_36 = 0x0000000FFFFFFFFBL;
+    private int[] k = new int[9];
+
+    /**
+     * @param K1 string of length 64 bytes.
+     * @param K2 string of length 4 bytes.
+     */
+    L3Hash32(byte[] K1, byte[] K2)
+    {
+      super();
+
+      // pre-conditions
+      if (K1.length != 64)
+        throw new ExceptionInInitializerError("K1 length is not 64");
+      if (K2.length != 4)
+        throw new ExceptionInInitializerError("K2 length is not 4");
+      // Break K1 into 8 chunks and convert to integers
+      for (int i = 0, j = 0; i < 8; i++)
+        {
+          long kk = (K1[j++] & 0xFFL) << 56
+                  | (K1[j++] & 0xFFL) << 48
+                  | (K1[j++] & 0xFFL) << 40
+                  | (K1[j++] & 0xFFL) << 32
+                  | (K1[j++] & 0xFFL) << 24
+                  | (K1[j++] & 0xFFL) << 16
+                  | (K1[j++] & 0xFFL) <<  8
+                  | (K1[j++] & 0xFFL);
+          k[i] = (int)(kk % PRIME_36);
+        }
+      k[8] =  K2[0]         << 24
+           | (K2[1] & 0xFF) << 16
+           | (K2[2] & 0xFF) << 8
+           | (K2[3] & 0xFF);
+    }
+
+    private L3Hash32(int[] k)
+    {
+      super();
+
+      this.k = k;
+    }
+
+    public Object clone()
+    {
+      return new L3Hash32((int[]) k.clone());
+    }
+
+    /**
+     * @param M string of length 16 bytes.
+     * @return Y, string of length 4 bytes.
+     */
+    byte[] digest(byte[] M)
+    {
+      if (M.length != 16)
+        throw new IllegalArgumentException("M length is not 16");
+
+      long m, y = 0L;
+      for (int i = 0, j = 0; i < 8; i++)
+        {
+          // Break M into 8 chunks and convert to integers
+          m = (M[j++] & 0xFFL) << 8 | (M[j++] & 0xFFL);
+          // Inner-product hash, extract last 32 bits and affine-translate
+          //            y = (m_1 * k_1 + ... + m_8 * k_8) mod prime(36);
+          //            y = y mod 2^32;
+          y += (m * (k[i] & 0xFFFFFFFFL)) % PRIME_36;
+        }
+      int Y = ((int) y) ^ k[8];
+      return new byte[] {
+          (byte)(Y >>> 24),
+          (byte)(Y >>> 16),
+          (byte)(Y >>> 8),
+          (byte) Y };
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mac/UMac32.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,418 @@
+/* UMac32.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mac;
+
+import gnu.java.security.Registry;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.prng.UMacGenerator;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The implementation of the <i>UMAC</i> (Universal Message Authentication
+ * Code).
+ * <p>
+ * The <i>UMAC</i> algorithms described are <i>parameterized</i>. This means
+ * that various low-level choices, like the endian convention and the underlying
+ * cryptographic primitive, have not been fixed. One must choose values for
+ * these parameters before the authentication tag generated by <i>UMAC</i> (for
+ * a given message, key, and nonce) becomes fully-defined. In this document we
+ * provide two collections of parameter settings, and have named the sets
+ * <i>UMAC16</i> and <i>UMAC32</i>. The parameter sets have been chosen based
+ * on experimentation and provide good performance on a wide variety of
+ * processors. <i>UMAC16</i> is designed to excel on processors which provide
+ * small-scale SIMD parallelism of the type found in Intel's MMX and Motorola's
+ * AltiVec instruction sets, while <i>UMAC32</i> is designed to do well on
+ * processors with good 32- and 64- bit support. <i>UMAC32</i> may take
+ * advantage of SIMD parallelism in future processors.
+ * <p>
+ * <i>UMAC</i> has been designed to allow implementations which accommodate
+ * <i>on-line</i> authentication. This means that pieces of the message may be
+ * presented to <i>UMAC</i> at different times (but in correct order) and an
+ * on-line implementation will be able to process the message correctly without
+ * the need to buffer more than a few dozen bytes of the message. For
+ * simplicity, the algorithms in this specification are presented as if the
+ * entire message being authenticated were available at once.
+ * <p>
+ * To authenticate a message, <code>Msg</code>, one first applies the
+ * universal hash function, resulting in a string which is typically much
+ * shorter than the original message. The pseudorandom function is applied to a
+ * nonce, and the result is used in the manner of a Vernam cipher: the
+ * authentication tag is the xor of the output from the hash function and the
+ * output from the pseudorandom function. Thus, an authentication tag is
+ * generated as
+ * <pre>
+ *     AuthTag = f(Nonce) xor h(Msg)
+ * </pre>
+ * <p>
+ * Here <code>f</code> is the pseudorandom function shared between the sender
+ * and the receiver, and h is a universal hash function shared by the sender and
+ * the receiver. In <i>UMAC</i>, a shared key is used to key the pseudorandom
+ * function <code>f</code>, and then <code>f</code> is used for both tag
+ * generation and internally to generate all of the bits needed by the universal
+ * hash function.
+ * <p>
+ * The universal hash function that we use is called <code>UHASH</code>. It
+ * combines several software-optimized algorithms into a multi-layered
+ * structure. The algorithm is moderately complex. Some of this complexity comes
+ * from extensive speed optimizations.
+ * <p>
+ * For the pseudorandom function we use the block cipher of the <i>Advanced
+ * Encryption Standard</i> (AES).
+ * <p>
+ * The UMAC32 parameters, considered in this implementation are:
+ * <pre>
+ *                                    UMAC32
+ *                                    ------
+ *         WORD-LEN                        4
+ *         UMAC-OUTPUT-LEN                 8
+ *         L1-KEY-LEN                   1024
+ *         UMAC-KEY-LEN                   16
+ *         ENDIAN-FAVORITE               BIG *
+ *         L1-OPERATIONS-SIGN       UNSIGNED
+ * </pre>
+ * <p>
+ * Please note that this UMAC32 differs from the one described in the paper by
+ * the <i>ENDIAN-FAVORITE</i> value.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
+ * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
+ * </ol>
+ */
+public class UMac32
+    extends BaseMac
+{
+  /**
+   * Property name of the user-supplied <i>Nonce</i>. The value associated to
+   * this property name is taken to be a byte array.
+   */
+  public static final String NONCE_MATERIAL = "gnu.crypto.umac.nonce.material";
+  /** Known test vector. */
+  // private static final String TV1 = "3E5A0E09198B0F94";
+  // private static final String TV1 = "5FD764A6D3A9FD9D";
+  // private static final String TV1 = "48658DE1D9A70304";
+  private static final String TV1 = "455ED214A6909F20";
+  private static final BigInteger MAX_NONCE_ITERATIONS = BigInteger.ONE.shiftLeft(16 * 8);
+  // UMAC32 parameters
+  static final int OUTPUT_LEN = 8;
+  static final int L1_KEY_LEN = 1024;
+  static final int KEY_LEN = 16;
+  /** caches the result of the correctness test, once executed. */
+  private static Boolean valid;
+  private byte[] nonce;
+  private UHash32 uhash32;
+  private BigInteger nonceReuseCount;
+  /** The authentication key for this instance. */
+  private transient byte[] K;
+
+  /** Trivial 0-arguments constructor. */
+  public UMac32()
+  {
+    super("umac32");
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   * 
+   * @param that the instance to clone.
+   */
+  private UMac32(UMac32 that)
+  {
+    this();
+
+    if (that.K != null)
+      this.K = (byte[]) that.K.clone();
+    if (that.nonce != null)
+      this.nonce = (byte[]) that.nonce.clone();
+    if (that.uhash32 != null)
+      this.uhash32 = (UHash32) that.uhash32.clone();
+    this.nonceReuseCount = that.nonceReuseCount;
+  }
+
+  public Object clone()
+  {
+    return new UMac32(this);
+  }
+
+  public int macSize()
+  {
+    return OUTPUT_LEN;
+  }
+
+  /**
+   * Initialising a <i>UMAC</i> instance consists of defining values for the
+   * following parameters:
+   * <ol>
+   * <li>Key Material: as the value of the attribute entry keyed by
+   * {@link #MAC_KEY_MATERIAL}. The value is taken to be a byte array
+   * containing the user-specified key material. The length of this array,
+   * if/when defined SHOULD be exactly equal to {@link #KEY_LEN}.</li>
+   * <li>Nonce Material: as the value of the attribute entry keyed by
+   * {@link #NONCE_MATERIAL}. The value is taken to be a byte array containing
+   * the user-specified nonce material. The length of this array, if/when
+   * defined SHOULD be (a) greater than zero, and (b) less or equal to 16 (the
+   * size of the AES block).</li>
+   * </ol>
+   * <p>
+   * For convenience, this implementation accepts that not both parameters be
+   * always specified.
+   * <ul>
+   * <li>If the <i>Key Material</i> is specified, but the <i>Nonce Material</i>
+   * is not, then this implementation, re-uses the previously set <i>Nonce
+   * Material</i> after (a) converting the bytes to an unsigned integer, (b)
+   * incrementing the number by one, and (c) converting it back to 16 bytes.</li>
+   * <li>If the <i>Nonce Material</i> is specified, but the <i>Key Material</i>
+   * is not, then this implementation re-uses the previously set <i>Key Material</i>.
+   * </li>
+   * </ul>
+   * <p>
+   * This method throws an exception if no <i>Key Material</i> is specified in
+   * the input map, and there is no previously set/defined <i>Key Material</i>
+   * (from an earlier invocation of this method). If a <i>Key Material</i> can
+   * be used, but no <i>Nonce Material</i> is defined or previously
+   * set/defined, then a default value of all-zeroes shall be used.
+   * 
+   * @param attributes one or both of required parameters.
+   * @throws InvalidKeyException the key material specified is not of the
+   *           correct length.
+   */
+  public void init(Map attributes) throws InvalidKeyException,
+      IllegalStateException
+  {
+    byte[] key = (byte[]) attributes.get(MAC_KEY_MATERIAL);
+    byte[] n = (byte[]) attributes.get(NONCE_MATERIAL);
+    boolean newKey = (key != null);
+    boolean newNonce = (n != null);
+    if (newKey)
+      {
+        if (key.length != KEY_LEN)
+          throw new InvalidKeyException("Key length: "
+                                        + String.valueOf(key.length));
+        K = key;
+      }
+    else
+      {
+        if (K == null)
+          throw new InvalidKeyException("Null Key");
+      }
+    if (newNonce)
+      {
+        if (n.length < 1 || n.length > 16)
+          throw new IllegalArgumentException("Invalid Nonce length: "
+                                             + String.valueOf(n.length));
+        if (n.length < 16) // pad with zeroes
+          {
+            byte[] newN = new byte[16];
+            System.arraycopy(n, 0, newN, 0, n.length);
+            nonce = newN;
+          }
+        else
+          nonce = n;
+
+        nonceReuseCount = BigInteger.ZERO;
+      }
+    else if (nonce == null) // use all-0 nonce if 1st time
+      {
+        nonce = new byte[16];
+        nonceReuseCount = BigInteger.ZERO;
+      }
+    else if (! newKey) // increment nonce if still below max count
+      {
+        nonceReuseCount = nonceReuseCount.add(BigInteger.ONE);
+        if (nonceReuseCount.compareTo(MAX_NONCE_ITERATIONS) >= 0)
+          {
+            // limit reached. we SHOULD have a key
+            throw new InvalidKeyException("Null Key and unusable old Nonce");
+          }
+        BigInteger N = new BigInteger(1, nonce);
+        N = N.add(BigInteger.ONE).mod(MAX_NONCE_ITERATIONS);
+        n = N.toByteArray();
+        if (n.length == 16)
+          nonce = n;
+        else if (n.length < 16)
+          {
+            nonce = new byte[16];
+            System.arraycopy(n, 0, nonce, 16 - n.length, n.length);
+          }
+        else
+          {
+            nonce = new byte[16];
+            System.arraycopy(n, n.length - 16, nonce, 0, 16);
+          }
+      }
+    else // do nothing, re-use old nonce value
+      nonceReuseCount = BigInteger.ZERO;
+
+    if (uhash32 == null)
+      uhash32 = new UHash32();
+
+    Map map = new HashMap();
+    map.put(MAC_KEY_MATERIAL, K);
+    uhash32.init(map);
+  }
+
+  public void update(byte b)
+  {
+    uhash32.update(b);
+  }
+
+  public void update(byte[] b, int offset, int len)
+  {
+    uhash32.update(b, offset, len);
+  }
+
+  public byte[] digest()
+  {
+    byte[] result = uhash32.digest();
+    byte[] pad = pdf(); // pdf(K, nonce);
+    for (int i = 0; i < OUTPUT_LEN; i++)
+      result[i] = (byte)(result[i] ^ pad[i]);
+
+    return result;
+  }
+
+  public void reset()
+  {
+    if (uhash32 != null)
+      uhash32.reset();
+  }
+
+  public boolean selfTest()
+  {
+    if (valid == null)
+      {
+        byte[] key;
+        try
+          {
+            key = "abcdefghijklmnop".getBytes("ASCII");
+          }
+        catch (UnsupportedEncodingException x)
+          {
+            throw new RuntimeException("ASCII not supported");
+          }
+        byte[] nonce = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
+        UMac32 mac = new UMac32();
+        Map attributes = new HashMap();
+        attributes.put(MAC_KEY_MATERIAL, key);
+        attributes.put(NONCE_MATERIAL, nonce);
+        try
+          {
+            mac.init(attributes);
+          }
+        catch (InvalidKeyException x)
+          {
+            x.printStackTrace(System.err);
+            return false;
+          }
+        byte[] data = new byte[128];
+        data[0] = (byte) 0x80;
+        mac.update(data, 0, 128);
+        byte[] result = mac.digest();
+        valid = Boolean.valueOf(TV1.equals(Util.toString(result)));
+      }
+    return valid.booleanValue();
+  }
+
+  /**
+   * @return byte array of length 8 (or OUTPUT_LEN) bytes.
+   */
+  private byte[] pdf()
+  {
+    // Make Nonce 16 bytes by prepending zeroes. done (see init())
+    // one AES invocation is enough for more than one PDF invocation
+    // number of index bits needed = 1
+    // Extract index bits and zero low bits of Nonce
+    BigInteger Nonce = new BigInteger(1, nonce);
+    int nlowbitsnum = Nonce.testBit(0) ? 1 : 0;
+    Nonce = Nonce.clearBit(0);
+    // Generate subkey, AES and extract indexed substring
+    IRandom kdf = new UMacGenerator();
+    Map map = new HashMap();
+    map.put(IBlockCipher.KEY_MATERIAL, K);
+    map.put(UMacGenerator.INDEX, Integer.valueOf(128));
+    kdf.init(map);
+    byte[] Kp = new byte[KEY_LEN];
+    try
+      {
+        kdf.nextBytes(Kp, 0, KEY_LEN);
+      }
+    catch (IllegalStateException x)
+      {
+        x.printStackTrace(System.err);
+        throw new RuntimeException(String.valueOf(x));
+      }
+    catch (LimitReachedException x)
+      {
+        x.printStackTrace(System.err);
+        throw new RuntimeException(String.valueOf(x));
+      }
+    IBlockCipher aes = CipherFactory.getInstance(Registry.AES_CIPHER);
+    map.put(IBlockCipher.KEY_MATERIAL, Kp);
+    try
+      {
+        aes.init(map);
+      }
+    catch (InvalidKeyException x)
+      {
+        x.printStackTrace(System.err);
+        throw new RuntimeException(String.valueOf(x));
+      }
+    catch (IllegalStateException x)
+      {
+        x.printStackTrace(System.err);
+        throw new RuntimeException(String.valueOf(x));
+      }
+    byte[] T = new byte[16];
+    aes.encryptBlock(nonce, 0, T, 0);
+    byte[] result = new byte[OUTPUT_LEN];
+    System.arraycopy(T, nlowbitsnum, result, 0, OUTPUT_LEN);
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/BaseMode.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,293 @@
+/* BaseMode.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.security.InvalidKeyException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A basic abstract class to facilitate implementing block cipher modes of
+ * operations.
+ */
+public abstract class BaseMode
+    implements IMode
+{
+  /** The canonical name prefix of this mode. */
+  protected String name;
+  /** The state indicator of this instance. */
+  protected int state;
+  /** The underlying block cipher implementation. */
+  protected IBlockCipher cipher;
+  /** The block size, in bytes, to operate the underlying block cipher in. */
+  protected int cipherBlockSize;
+  /** The block size, in bytes, in which to operate the mode instance. */
+  protected int modeBlockSize;
+  /** The initialisation vector value. */
+  protected byte[] iv;
+  /** The instance lock. */
+  protected Object lock = new Object();
+
+  /**
+   * Trivial constructor for use by concrete subclasses.
+   * 
+   * @param name the canonical name prefix of this mode.
+   * @param underlyingCipher the implementation of the underlying cipher.
+   * @param cipherBlockSize the block size, in bytes, in which to operate the
+   *          underlying cipher.
+   */
+  protected BaseMode(String name, IBlockCipher underlyingCipher,
+                     int cipherBlockSize)
+  {
+    super();
+
+    this.name = name;
+    this.cipher = underlyingCipher;
+    this.cipherBlockSize = cipherBlockSize;
+    state = -1;
+  }
+
+  public void update(byte[] in, int inOffset, byte[] out, int outOffset)
+      throws IllegalStateException
+  {
+    synchronized (lock)
+      {
+        switch (state)
+          {
+          case ENCRYPTION:
+            encryptBlock(in, inOffset, out, outOffset);
+            break;
+          case DECRYPTION:
+            decryptBlock(in, inOffset, out, outOffset);
+            break;
+          default:
+            throw new IllegalStateException();
+          }
+      }
+  }
+
+  public String name()
+  {
+    return new StringBuffer(name).append('(').append(cipher.name()).append(')')
+        .toString();
+  }
+
+  /**
+   * Returns the default value, in bytes, of the mode's block size. This value
+   * is part of the construction arguments passed to the Factory methods in
+   * {@link ModeFactory}. Unless changed by an invocation of any of the
+   * <code>init()</code> methods, a <i>Mode</i> instance would operate with
+   * the same block size as its underlying block cipher. As mentioned earlier,
+   * the block size of the underlying block cipher itself is specified in one of
+   * the method(s) available in the factory class.
+   * 
+   * @return the default value, in bytes, of the mode's block size.
+   * @see ModeFactory
+   */
+  public int defaultBlockSize()
+  {
+    return cipherBlockSize;
+  }
+
+  /**
+   * Returns the default value, in bytes, of the underlying block cipher key
+   * size.
+   * 
+   * @return the default value, in bytes, of the underlying cipher's key size.
+   */
+  public int defaultKeySize()
+  {
+    return cipher.defaultKeySize();
+  }
+
+  /**
+   * Returns an {@link Iterator} over the supported block sizes. Each element
+   * returned by this object is an {@link Integer}.
+   * <p>
+   * The default behaviour is to return an iterator with just one value, which
+   * is that currently configured for the underlying block cipher. Concrete
+   * implementations may override this behaviour to signal their ability to
+   * support other values.
+   * 
+   * @return an {@link Iterator} over the supported block sizes.
+   */
+  public Iterator blockSizes()
+  {
+    ArrayList al = new ArrayList();
+    al.add(Integer.valueOf(cipherBlockSize));
+    return Collections.unmodifiableList(al).iterator();
+  }
+
+  /**
+   * Returns an {@link Iterator} over the supported underlying block cipher key
+   * sizes. Each element returned by this object is an instance of
+   * {@link Integer}.
+   * 
+   * @return an {@link Iterator} over the supported key sizes.
+   */
+  public Iterator keySizes()
+  {
+    return cipher.keySizes();
+  }
+
+  public void init(Map attributes) throws InvalidKeyException,
+      IllegalStateException
+  {
+    synchronized (lock)
+      {
+        if (state != -1)
+          throw new IllegalStateException();
+        Integer want = (Integer) attributes.get(STATE);
+        if (want != null)
+          {
+            switch (want.intValue())
+              {
+              case ENCRYPTION:
+                state = ENCRYPTION;
+                break;
+              case DECRYPTION:
+                state = DECRYPTION;
+                break;
+              default:
+                throw new IllegalArgumentException();
+              }
+          }
+        Integer bs = (Integer) attributes.get(MODE_BLOCK_SIZE);
+        modeBlockSize = (bs == null ? cipherBlockSize : bs.intValue());
+        byte[] iv = (byte[]) attributes.get(IV);
+        if (iv != null)
+          this.iv = (byte[]) iv.clone();
+        else
+          this.iv = new byte[modeBlockSize];
+        cipher.init(attributes);
+        setup();
+      }
+  }
+
+  public int currentBlockSize()
+  {
+    if (state == -1)
+      throw new IllegalStateException();
+    return modeBlockSize;
+  }
+
+  public void reset()
+  {
+    synchronized (lock)
+      {
+        state = -1;
+        iv = null;
+        cipher.reset();
+        teardown();
+      }
+  }
+
+  public boolean selfTest()
+  {
+    int ks;
+    Iterator bit;
+    for (Iterator kit = keySizes(); kit.hasNext();)
+      {
+        ks = ((Integer) kit.next()).intValue();
+        for (bit = blockSizes(); bit.hasNext();)
+          if (! testSymmetry(ks, ((Integer) bit.next()).intValue()))
+            return false;
+      }
+    return true;
+  }
+
+  public abstract Object clone();
+
+  /** The initialisation phase of the concrete mode implementation. */
+  public abstract void setup();
+
+  /** The termination phase of the concrete mode implementation. */
+  public abstract void teardown();
+
+  public abstract void encryptBlock(byte[] in, int i, byte[] out, int o);
+
+  public abstract void decryptBlock(byte[] in, int i, byte[] out, int o);
+
+  private boolean testSymmetry(int ks, int bs)
+  {
+    try
+      {
+        IMode mode = (IMode) this.clone();
+        byte[] iv = new byte[cipherBlockSize]; // all zeroes
+        byte[] k = new byte[ks];
+        int i;
+        for (i = 0; i < ks; i++)
+          k[i] = (byte) i;
+        int blockCount = 5;
+        int limit = blockCount * bs;
+        byte[] pt = new byte[limit];
+        for (i = 0; i < limit; i++)
+          pt[i] = (byte) i;
+        byte[] ct = new byte[limit];
+        byte[] cpt = new byte[limit];
+        Map map = new HashMap();
+        map.put(KEY_MATERIAL, k);
+        map.put(CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize));
+        map.put(STATE, Integer.valueOf(ENCRYPTION));
+        map.put(IV, iv);
+        map.put(MODE_BLOCK_SIZE, Integer.valueOf(bs));
+        mode.reset();
+        mode.init(map);
+        for (i = 0; i < blockCount; i++)
+          mode.update(pt, i * bs, ct, i * bs);
+        mode.reset();
+        map.put(STATE, Integer.valueOf(DECRYPTION));
+        mode.init(map);
+        for (i = 0; i < blockCount; i++)
+          mode.update(ct, i * bs, cpt, i * bs);
+        return Arrays.equals(pt, cpt);
+      }
+    catch (Exception x)
+      {
+        x.printStackTrace(System.err);
+        return false;
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/CBC.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,123 @@
+/* CBC.java -- 
+   Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+/**
+ * The Cipher Block Chaining mode. This mode introduces feedback into the cipher
+ * by XORing the previous ciphertext block with the plaintext block before
+ * encipherment. That is, encrypting looks like this:
+ * 
+ * <pre>
+ *  C<sub>i</sub> = E<sub>K</sub>(P<sub>i</sub>&circ; C<sub>i-1</sub>)
+ * </pre>
+ * <p>
+ * Similarly, decrypting is:
+ * <pre>
+ *  P<sub>i</sub> = C<sub>i-1</sub> &circ; D<sub>K</sub>(C<sub>i</sub>)
+ * </pre>
+ */
+public class CBC
+    extends BaseMode
+    implements Cloneable
+{
+  /** The last (de|en)crypted block */
+  private byte[] lastBlock;
+  /** An intermediate buffer. */
+  private byte[] scratch;
+
+  /**
+   * Package-private constructor for the factory class.
+   * 
+   * @param underlyingCipher The cipher implementation.
+   * @param cipherBlockSize The cipher's block size.
+   */
+  CBC(IBlockCipher underlyingCipher, int cipherBlockSize)
+  {
+    super(Registry.CBC_MODE, underlyingCipher, cipherBlockSize);
+  }
+
+  /** Our constructor for cloning. */
+  private CBC(CBC that)
+  {
+    this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize);
+  }
+
+  public Object clone()
+  {
+    return new CBC(this);
+  }
+
+  public void setup()
+  {
+    if (modeBlockSize != cipherBlockSize)
+      throw new IllegalArgumentException();
+    scratch = new byte[cipherBlockSize];
+    lastBlock = new byte[cipherBlockSize];
+    // lastBlock gets initialized to the initialization vector.
+    for (int i = 0; i < lastBlock.length && i < iv.length; i++)
+      lastBlock[i] = iv[i];
+  }
+
+  public void teardown()
+  {
+    lastBlock = null;
+    scratch = null;
+  }
+
+  public void encryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    for (int k = 0; k < scratch.length; k++)
+      scratch[k] = (byte)(lastBlock[k] ^ in[k + i]);
+    cipher.encryptBlock(scratch, 0, out, o);
+    System.arraycopy(out, o, lastBlock, 0, cipherBlockSize);
+  }
+
+  public void decryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    byte[] buf = new byte[cipherBlockSize];
+    System.arraycopy(in, i, buf, 0, cipherBlockSize);
+    cipher.decryptBlock(in, i, scratch, 0);
+    for (int k = 0; k < scratch.length; k++)
+      out[o + k] = (byte)(lastBlock[k] ^ scratch[k]);
+    System.arraycopy(buf, 0, lastBlock, 0, cipherBlockSize);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/CFB.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,155 @@
+/* CFB.java -- 
+   Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+/**
+ * The cipher feedback mode. CFB mode is a stream mode that operates on <i>s</i>
+ * bit blocks, where 1 &lt;= <i>s</i> &lt;= <i>b</i>, if <i>b</i> is the
+ * underlying cipher's block size. Encryption is:
+ * <pre>
+ *  I[1] = IV
+ *  I[j] = LSB(b-s, I[j-1]) | C[j-1]   for j = 2...n
+ *  O[j] = CIPH(K, I[j])               for j = 1,2...n
+ *  C[j] = P[j] &circ; MSB(s, O[j])         for j = 1,2...n
+ * </pre>
+ * <p>
+ * And decryption is:
+ * <pre>
+ *  I[1] = IV
+ *  I[j] = LSB(b-s, I[j-1]) | C[j-1]   for j = 2...n
+ *  O[j] = CIPH(K, I[j])               for j = 1,2...n
+ *  P[j] = C[j] &circ; MSB(s, O[j])         for j = 1,2...n
+ * </pre>
+ * <p>
+ * CFB mode requires an initialization vector, which need not be kept secret.
+ * <p>
+ * References:
+ * <ol>
+ * <li>Bruce Schneier, <i>Applied Cryptography: Protocols, Algorithms, and
+ * Source Code in C, Second Edition</i>. (1996 John Wiley and Sons) ISBN
+ * 0-471-11709-9.</li>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>,
+ * Morris Dworkin.</li>
+ * </ol>
+ */
+public class CFB
+    extends BaseMode
+{
+  /** The shift register, the input block to the block cipher. */
+  private byte[] shiftRegister;
+  /** The output block from the block cipher. */
+  private byte[] scratch;
+
+  /**
+   * Package-private constructor for the factory class.
+   * 
+   * @param underlyingCipher The cipher implementation.
+   * @param cipherBlockSize The cipher's block size.
+   */
+  CFB(IBlockCipher underlyingCipher, int cipherBlockSize)
+  {
+    super(Registry.CFB_MODE, underlyingCipher, cipherBlockSize);
+  }
+
+  /**
+   * Cloneing constructor.
+   * 
+   * @param that The instance being cloned.
+   */
+  private CFB(CFB that)
+  {
+    this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize);
+  }
+
+  public Object clone()
+  {
+    return new CFB(this);
+  }
+
+  public void setup()
+  {
+    if (modeBlockSize > cipherBlockSize)
+      throw new IllegalArgumentException(
+          "CFB block size cannot be larger than the cipher block size");
+    shiftRegister = new byte[cipherBlockSize];
+    scratch = new byte[cipherBlockSize];
+    System.arraycopy(iv, 0,
+                     shiftRegister, 0,
+                     Math.min(iv.length, cipherBlockSize));
+  }
+
+  public void teardown()
+  {
+    if (shiftRegister != null)
+      for (int i = 0; i < shiftRegister.length; i++)
+        shiftRegister[i] = 0;
+    shiftRegister = null;
+  }
+
+  public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset)
+  {
+    cipher.encryptBlock(shiftRegister, 0, scratch, 0);
+    for (int i = 0; i < modeBlockSize; i++)
+      out[outOffset + i] = (byte)(in[inOffset + i] ^ scratch[i]);
+    System.arraycopy(shiftRegister, modeBlockSize,
+                     shiftRegister, 0,
+                     cipherBlockSize - modeBlockSize);
+    System.arraycopy(out, outOffset,
+                     shiftRegister, cipherBlockSize - modeBlockSize,
+                     modeBlockSize);
+  }
+
+  public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset)
+  {
+    cipher.encryptBlock(shiftRegister, 0, scratch, 0);
+    for (int i = 0; i < modeBlockSize; i++)
+      out[outOffset + i] = (byte)(in[inOffset + i] ^ scratch[i]);
+    System.arraycopy(shiftRegister, modeBlockSize,
+                     shiftRegister, 0,
+                     cipherBlockSize - modeBlockSize);
+    System.arraycopy(in, inOffset,
+                     shiftRegister, cipherBlockSize - modeBlockSize,
+                     modeBlockSize);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/CTR.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,168 @@
+/* CTR.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Sequence;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+/**
+ * The implementation of the Counter Mode.
+ * <p>
+ * The algorithm steps are formally described as follows:
+ * 
+ * <pre>
+ *     CTR Encryption: O[j] = E(K)(T[j]); for j = 1, 2...n;
+ *                     C[j] = P[j] &circ; O[j]; for j = 1, 2...n.
+ *     CTR Decryption: O[j] = E(K)(T[j]); for j = 1, 2...n;
+ *                     P[j] = C[j] &circ; O[j]; for j = 1, 2...n.
+ * </pre>
+ * 
+ * <p>
+ * where <code>P</code> is the plaintext, <code>C</code> is the ciphertext,
+ * <code>E(K)</code> is the underlying block cipher encryption function
+ * parametrised with the session key <code>K</code>, and <code>T</code> is
+ * the <i>Counter</i>.
+ * <p>
+ * This implementation, uses a standard incrementing function with a step of 1,
+ * and an initial value similar to that described in the NIST document.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>,
+ * Morris Dworkin.</li>
+ * </ol>
+ */
+public class CTR
+    extends BaseMode
+    implements Cloneable
+{
+  private int off;
+  private byte[] counter, enc;
+
+  /**
+   * Trivial package-private constructor for use by the Factory class.
+   * 
+   * @param underlyingCipher the underlying cipher implementation.
+   * @param cipherBlockSize the underlying cipher block size to use.
+   */
+  CTR(IBlockCipher underlyingCipher, int cipherBlockSize)
+  {
+    super(Registry.CTR_MODE, underlyingCipher, cipherBlockSize);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   * 
+   * @param that the instance to clone.
+   */
+  private CTR(CTR that)
+  {
+    this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize);
+  }
+
+  public Object clone()
+  {
+    return new CTR(this);
+  }
+
+  public void setup()
+  {
+    if (modeBlockSize > cipherBlockSize)
+      throw new IllegalArgumentException("mode size exceeds cipher block size");
+    off = 0;
+    counter = new byte[cipherBlockSize];
+    int i = cipherBlockSize - 1;
+    int j = iv.length - 1;
+    while (i >= 0 && j >= 0)
+      counter[i--] = iv[j--];
+    enc = new byte[cipherBlockSize];
+    cipher.encryptBlock(counter, 0, enc, 0);
+  }
+
+  public void teardown()
+  {
+    if (counter != null)
+      Arrays.fill(counter, (byte) 0);
+    if (enc != null)
+      Arrays.fill(enc, (byte) 0);
+  }
+
+  public void encryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    ctr(in, i, out, o);
+  }
+
+  public void decryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    ctr(in, i, out, o);
+  }
+
+  public Iterator blockSizes()
+  {
+    return new Sequence(1, cipherBlockSize).iterator();
+  }
+
+  private void ctr(byte[] in, int inOffset, byte[] out, int outOffset)
+  {
+    for (int i = 0; i < modeBlockSize; i++)
+      {
+        out[outOffset++] = (byte)(in[inOffset++] ^ enc[off++]);
+        if (off == cipherBlockSize)
+          {
+            int j;
+            for (j = cipherBlockSize - 1; j >= 0; j--)
+              {
+                counter[j]++;
+                if ((counter[j] & 0xFF) != 0)
+                  break;
+              }
+            if (j == 0)
+              counter[cipherBlockSize - 1]++;
+            off = 0;
+            cipher.encryptBlock(counter, 0, enc, 0);
+          }
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/EAX.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,289 @@
+/* EAX.java -- 
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mac.MacFactory;
+
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A conventional two-pass authenticated-encrypted mode, EAX. EAX is a
+ * <i>Authenticated Encryption with Additional Data</i> (<b>AEAD</b>) scheme,
+ * which provides protection and authentication for the message, and provides
+ * authentication of an (optional) header. EAX is composed of the counter mode
+ * (CTR) and the one-key CBC MAC (OMAC).
+ * <p>
+ * This class makes full use of the {@link IAuthenticatedMode} interface, that
+ * is, all methods of both {@link IMode} and {@link IMac} can be used as
+ * specified in the {@link IAuthenticatedMode} interface.
+ * <p>
+ * References:
+ * <ol>
+ * <li>M. Bellare, P. Rogaway, and D. Wagner; <a
+ * href="http://www.cs.berkeley.edu/~daw/papers/eprint-short-ae.pdf">A
+ * Conventional Authenticated-Encryption Mode</a>.</li>
+ * </ol>
+ */
+public class EAX
+    implements IAuthenticatedMode
+{
+  /** The tag size, in bytes. */
+  private int tagSize;
+  /** The nonce OMAC instance. */
+  private IMac nonceOmac;
+  /** The header OMAC instance. */
+  private IMac headerOmac;
+  /** The message OMAC instance. */
+  private IMac msgOmac;
+  /** The CTR instance. */
+  private IMode ctr;
+  /** The direction state (encrypting or decrypting). */
+  private int state;
+  /** Whether we're initialized or not. */
+  private boolean init;
+  /** The cipher block size. */
+  private int cipherBlockSize;
+  /** The cipher. */
+  private IBlockCipher cipher;
+  /** The [t]_n array. */
+  private byte[] t_n;
+  private static boolean valid = false;
+
+  public EAX(IBlockCipher cipher, int cipherBlockSize)
+  {
+    this.cipher = cipher;
+    this.cipherBlockSize = cipherBlockSize;
+    String name = cipher.name();
+    int i = name.indexOf('-');
+    if (i >= 0)
+      name = name.substring(0, i);
+    String omacname = Registry.OMAC_PREFIX + name;
+    nonceOmac = MacFactory.getInstance(omacname);
+    headerOmac = MacFactory.getInstance(omacname);
+    msgOmac = MacFactory.getInstance(omacname);
+    ctr = ModeFactory.getInstance(Registry.CTR_MODE, cipher, cipherBlockSize);
+    t_n = new byte[cipherBlockSize];
+    init = false;
+  }
+
+  public Object clone()
+  {
+    return new EAX((IBlockCipher) cipher.clone(), cipherBlockSize);
+  }
+
+  public String name()
+  {
+    return Registry.EAX_MODE + "(" + cipher.name() + ")";
+  }
+
+  public int defaultBlockSize()
+  {
+    return ctr.defaultBlockSize();
+  }
+
+  public int defaultKeySize()
+  {
+    return ctr.defaultKeySize();
+  }
+
+  public Iterator blockSizes()
+  {
+    return ctr.blockSizes();
+  }
+
+  public Iterator keySizes()
+  {
+    return ctr.keySizes();
+  }
+
+  public void init(Map attrib) throws InvalidKeyException
+  {
+    byte[] nonce = (byte[]) attrib.get(IV);
+    if (nonce == null)
+      throw new IllegalArgumentException("no nonce provided");
+    byte[] key = (byte[]) attrib.get(KEY_MATERIAL);
+    if (key == null)
+      throw new IllegalArgumentException("no key provided");
+
+    Arrays.fill(t_n, (byte) 0);
+    nonceOmac.reset();
+    nonceOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key));
+    nonceOmac.update(t_n, 0, t_n.length);
+    nonceOmac.update(nonce, 0, nonce.length);
+    byte[] N = nonceOmac.digest();
+    nonceOmac.reset();
+    nonceOmac.update(t_n, 0, t_n.length);
+    nonceOmac.update(nonce, 0, nonce.length);
+    t_n[t_n.length - 1] = 1;
+    headerOmac.reset();
+    headerOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key));
+    headerOmac.update(t_n, 0, t_n.length);
+    t_n[t_n.length - 1] = 2;
+    msgOmac.reset();
+    msgOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key));
+    msgOmac.update(t_n, 0, t_n.length);
+    Integer modeSize = (Integer) attrib.get(MODE_BLOCK_SIZE);
+    if (modeSize == null)
+      modeSize = Integer.valueOf(cipherBlockSize);
+    HashMap ctrAttr = new HashMap();
+    ctrAttr.put(KEY_MATERIAL, key);
+    ctrAttr.put(IV, N);
+    ctrAttr.put(STATE, Integer.valueOf(ENCRYPTION));
+    ctrAttr.put(MODE_BLOCK_SIZE, modeSize);
+    ctr.reset();
+    ctr.init(ctrAttr);
+    Integer st = (Integer) attrib.get(STATE);
+    if (st != null)
+      {
+        state = st.intValue();
+        if (state != ENCRYPTION && state != DECRYPTION)
+          throw new IllegalArgumentException("invalid state");
+      }
+    else
+      state = ENCRYPTION;
+
+    Integer ts = (Integer) attrib.get(TRUNCATED_SIZE);
+    if (ts != null)
+      tagSize = ts.intValue();
+    else
+      tagSize = cipherBlockSize;
+    if (tagSize < 0 || tagSize > cipherBlockSize)
+      throw new IllegalArgumentException("tag size out of range");
+    init = true;
+  }
+
+  public int currentBlockSize()
+  {
+    return ctr.currentBlockSize();
+  }
+
+  public void encryptBlock(byte[] in, int inOff, byte[] out, int outOff)
+  {
+    if (! init)
+      throw new IllegalStateException("not initialized");
+    if (state != ENCRYPTION)
+      throw new IllegalStateException("not encrypting");
+    ctr.update(in, inOff, out, outOff);
+    msgOmac.update(out, outOff, ctr.currentBlockSize());
+  }
+
+  public void decryptBlock(byte[] in, int inOff, byte[] out, int outOff)
+  {
+    if (! init)
+      throw new IllegalStateException("not initialized");
+    if (state != DECRYPTION)
+      throw new IllegalStateException("not decrypting");
+    msgOmac.update(in, inOff, ctr.currentBlockSize());
+    ctr.update(in, inOff, out, outOff);
+  }
+
+  public void update(byte[] in, int inOff, byte[] out, int outOff)
+  {
+    switch (state)
+      {
+      case ENCRYPTION:
+        encryptBlock(in, inOff, out, outOff);
+        break;
+      case DECRYPTION:
+        decryptBlock(in, inOff, out, outOff);
+        break;
+      default:
+        throw new IllegalStateException("impossible state " + state);
+      }
+  }
+
+  public void reset()
+  {
+    nonceOmac.reset();
+    headerOmac.reset();
+    msgOmac.reset();
+    ctr.reset();
+  }
+
+  public boolean selfTest()
+  {
+    return true; // XXX
+  }
+
+  public int macSize()
+  {
+    return tagSize;
+  }
+
+  public byte[] digest()
+  {
+    byte[] tag = new byte[tagSize];
+    digest(tag, 0);
+    return tag;
+  }
+
+  public void digest(byte[] out, int outOffset)
+  {
+    if (outOffset < 0 || outOffset + tagSize > out.length)
+      throw new IndexOutOfBoundsException();
+    byte[] N = nonceOmac.digest();
+    byte[] H = headerOmac.digest();
+    byte[] M = msgOmac.digest();
+    for (int i = 0; i < tagSize; i++)
+      out[outOffset + i] = (byte)(N[i] ^ H[i] ^ M[i]);
+    reset();
+  }
+
+  public void update(byte b)
+  {
+    if (! init)
+      throw new IllegalStateException("not initialized");
+    headerOmac.update(b);
+  }
+
+  public void update(byte[] buf, int off, int len)
+  {
+    if (! init)
+      throw new IllegalStateException("not initialized");
+    headerOmac.update(buf, off, len);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/ECB.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,121 @@
+/* ECB.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+/**
+ * The implementation of the Electronic Codebook mode.
+ * <p>
+ * The Electronic Codebook (ECB) mode is a confidentiality mode that is defined
+ * as follows:
+ * <ul>
+ * <li>ECB Encryption: C<sub>j</sub> = CIPH<sub>K</sub>(P<sub>j</sub>)
+ * for j = 1...n</li>
+ * <li>ECB Decryption: P<sub>j</sub> = CIPH<sup>-1</sup><sub>K</sub>(C<sub>j</sub>)
+ * for j = 1...n</li>
+ * </ul>
+ * <p>
+ * In ECB encryption, the forward cipher function is applied directly, and
+ * independently, to each block of the plaintext. The resulting sequence of
+ * output blocks is the ciphertext.
+ * <p>
+ * In ECB decryption, the inverse cipher function is applied directly, and
+ * independently, to each block of the ciphertext. The resulting sequence of
+ * output blocks is the plaintext.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>,
+ * Morris Dworkin.</li>
+ * </ol>
+ */
+public class ECB
+    extends BaseMode
+    implements Cloneable
+{
+  /**
+   * Trivial package-private constructor for use by the Factory class.
+   * 
+   * @param underlyingCipher the underlying cipher implementation.
+   * @param cipherBlockSize the underlying cipher block size to use.
+   */
+  ECB(IBlockCipher underlyingCipher, int cipherBlockSize)
+  {
+    super(Registry.ECB_MODE, underlyingCipher, cipherBlockSize);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   * 
+   * @param that the mode to clone.
+   */
+  private ECB(ECB that)
+  {
+    this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize);
+  }
+
+  public Object clone()
+  {
+    return new ECB(this);
+  }
+
+  public void setup()
+  {
+    if (modeBlockSize != cipherBlockSize)
+      throw new IllegalArgumentException(IMode.MODE_BLOCK_SIZE);
+  }
+
+  public void teardown()
+  {
+  }
+
+  public void encryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    cipher.encryptBlock(in, i, out, o);
+  }
+
+  public void decryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    cipher.decryptBlock(in, i, out, o);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/IAuthenticatedMode.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,56 @@
+/* IAuthenticatedMode.java -- 
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.javax.crypto.mac.IMac;
+
+/**
+ * The interface for encryption modes that also produce a message authentication
+ * tag.
+ * <p>
+ * This interface is merely the conjuction of the {@link IMode} and {@link IMac}
+ * interfaces. Encryption and decryption is done via the
+ * {@link IMode#update(byte[],int,byte[],int)} method, tag generation is done
+ * via the {@link IMac#digest()} method, and header updating (if supported by
+ * the mode) is done via the {@link IMac#update(byte[],int,int)} method.
+ */
+public interface IAuthenticatedMode
+    extends IMode, IMac
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/ICM.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,181 @@
+/* ICM.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.math.BigInteger;
+
+/**
+ * An implementation of <i>David McGrew</i> Integer Counter Mode (ICM) as an
+ * {@link IMode}.
+ * <p>
+ * ICM is a way to define a pseudorandom keystream generator using a block
+ * cipher. The keystream can be used for additive encryption, key derivation, or
+ * any other application requiring pseudorandom data. In the case of this class,
+ * it is used as additive encryption, XOR-ing the keystream with the input text
+ * --for both encryption and decryption.
+ * <p>
+ * In ICM, the keystream is logically broken into segments. Each segment is
+ * identified with a segment index, and the segments have equal lengths. This
+ * segmentation makes ICM especially appropriate for securing packet-based
+ * protocols. ICM also allows a variety of configurations based, among other
+ * things, on two parameters: the <i>block index length</i> and the <i>segment
+ * index length</i>. A constraint on those two values exists: The sum of
+ * <i>segment index length</i> and <i>block index length</i> <b>must not</b>
+ * half the <i>block size</i> of the underlying cipher. This requirement
+ * protects the ICM keystream generator from potentially failing to be
+ * pseudorandom.
+ * <p>
+ * For simplicity, this implementation, fixes these two values to the following:
+ * <ul>
+ * <li>block index length: is half the underlying cipher block size, and</li>
+ * <li>segment index length: is zero.</li>
+ * </ul>
+ * <p>
+ * For a 128-bit block cipher, the above values imply a maximum keystream length
+ * of 295,147,905,179,352,825,856 octets, since in ICM, each segment must not
+ * exceed the value
+ * <code>(256 ^ <i>block index length</i>) * <i>block length</i></code>
+ * octets.
+ * <p>
+ * Finally, for this implementation of the ICM, the IV placeholder will be used
+ * to pass the value of the <i>Offset</i> in the keystream segment.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-icm-00.txt">
+ * Integer Counter Mode</a>, David A. McGrew.</li>
+ * </ol>
+ */
+public class ICM
+    extends BaseMode
+    implements Cloneable
+{
+  /** The integer value 256 as a BigInteger. */
+  private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256");
+  /** Maximum number of blocks per segment. */
+  private BigInteger maxBlocksPerSegment;
+  /** A work constant. */
+  private BigInteger counterRange;
+  /** The initial counter for a given keystream segment. */
+  private BigInteger C0;
+  /** The index of the next block for a given keystream segment. */
+  private BigInteger blockNdx;
+
+  /**
+   * Trivial package-private constructor for use by the Factory class.
+   * 
+   * @param underlyingCipher the underlying cipher implementation.
+   * @param cipherBlockSize the underlying cipher block size to use.
+   */
+  ICM(IBlockCipher underlyingCipher, int cipherBlockSize)
+  {
+    super(Registry.ICM_MODE, underlyingCipher, cipherBlockSize);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   * 
+   * @param that the instance to clone.
+   */
+  private ICM(ICM that)
+  {
+    this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize);
+  }
+
+  public Object clone()
+  {
+    return new ICM(this);
+  }
+
+  public void setup()
+  {
+    if (modeBlockSize != cipherBlockSize)
+      throw new IllegalArgumentException();
+    counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize);
+    maxBlocksPerSegment = TWO_FIFTY_SIX.pow(cipherBlockSize / 2);
+    BigInteger r = new BigInteger(1, iv);
+    C0 = maxBlocksPerSegment.add(r).modPow(BigInteger.ONE, counterRange);
+    blockNdx = BigInteger.ZERO;
+  }
+
+  public void teardown()
+  {
+    counterRange = null;
+    maxBlocksPerSegment = null;
+    C0 = null;
+    blockNdx = null;
+  }
+
+  public void encryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    icm(in, i, out, o);
+  }
+
+  public void decryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    icm(in, i, out, o);
+  }
+
+  private void icm(byte[] in, int inOffset, byte[] out, int outOffset)
+  {
+    if (blockNdx.compareTo(maxBlocksPerSegment) >= 0)
+      throw new RuntimeException("Maximum blocks for segment reached");
+    BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange);
+    byte[] result = Ci.toByteArray();
+    int limit = result.length;
+    int ndx = 0;
+    if (limit < cipherBlockSize)
+      {
+        byte[] data = new byte[cipherBlockSize];
+        System.arraycopy(result, 0, data, cipherBlockSize - limit, limit);
+        result = data;
+      }
+    else if (limit > cipherBlockSize)
+      ndx = limit - cipherBlockSize;
+
+    cipher.encryptBlock(result, ndx, result, ndx);
+    blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx
+    for (int i = 0; i < modeBlockSize; i++) // xor result with input block
+      out[outOffset++] = (byte)(in[inOffset++] ^ result[ndx++]);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/IMode.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,123 @@
+/* IMode.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+/**
+ * The basic visible methods of any block cipher mode.
+ * <p>
+ * Block ciphers encrypt plaintext in fixed size n-bit blocks. For messages
+ * larger than n bits, the simplest approach is to segment the message into
+ * n-bit blocks and process (encrypt and/or decrypt) each one separately
+ * (Electronic Codebook or ECB mode). But this approach has disadvantages in
+ * most applications. The block cipher modes of operations are one way of
+ * working around those disadvantages.
+ * <p>
+ * A <i>Mode</i> always employs an underlying block cipher for processing its
+ * input. For all intents and purposes, a <i>Mode</i> appears to behave as any
+ * other block cipher with the following differences:
+ * <ul>
+ * <li>Depending on the specifications of the mode, the block size may be
+ * different that that of the underlying cipher.</li>
+ * <li>While some modes of operations allow operations on block sizes that can
+ * be 1-bit long, this library will only deal with sizes that are multiple of 8
+ * bits. This is because the <tt>byte</tt> is the smallest, easy to handle,
+ * primitive type in Java.</li>
+ * <li>Some modes need an <i>Initialisation Vector</i> (IV) to be properly
+ * initialised.</li>
+ * </ul>
+ * <p>
+ * Possible additional initialisation values for an instance of that type are:
+ * <ul>
+ * <li>The block size in which to operate this mode instance. This value is
+ * <b>optional</b>, if unspecified, the underlying block cipher's configured
+ * block size shall be used.</li>
+ * <li>Whether this mode will be used for encryption or decryption. This value
+ * is <b>mandatory</b> and should be included in the initialisation parameters.
+ * If it isn't, a {@link java.lang.IllegalStateException} will be thrown if any
+ * method, other than <code>reset()</code> is invoked on the instance.</li>
+ * <li>The byte array containing the <i>initialisation vector</i>, if required
+ * by this type of mode.</li>
+ * </ul>
+ */
+public interface IMode
+    extends IBlockCipher
+{
+  /**
+   * Property name of the state in which to operate this mode. The value
+   * associated to this property name is taken to be an {@link Integer} which
+   * value is either <code>ENCRYPTION</code> or <code>DECRYPTION</code>.
+   */
+  String STATE = "gnu.crypto.mode.state";
+  /**
+   * Property name of the block size in which to operate this mode. The value
+   * associated with this property name is taken to be an {@link Integer}. If
+   * it is not specified, the value of the block size of the underlying block
+   * cipher, used to construct the mode instance, shall be used.
+   */
+  String MODE_BLOCK_SIZE = "gnu.crypto.mode.block.size";
+  /**
+   * Property name of the initialisation vector to use, if required, with this
+   * instance. The value associated with this property name is taken to be a
+   * byte array. If the concrete instance needs such a parameter, and it has not
+   * been specified as part of the initialissation parameters, an all-zero byte
+   * array of the appropriate size shall be used.
+   */
+  String IV = "gnu.crypto.mode.iv";
+  /** Constant indicating the instance is being used for <i>encryption</i>. */
+  int ENCRYPTION = 1;
+  /** Constant indicating the instance is being used for <i>decryption</i>. */
+  int DECRYPTION = 2;
+
+  /**
+   * A convenience method. Effectively invokes the <code>encryptBlock()</code>
+   * or <code>decryptBlock()</code> method depending on the operational state
+   * of the instance.
+   * 
+   * @param in the plaintext.
+   * @param inOffset index of <code>in</code> from which to start considering
+   *          data.
+   * @param out the ciphertext.
+   * @param outOffset index of <code>out</code> from which to store result.
+   * @exception IllegalStateException if the instance is not initialised.
+   */
+  void update(byte[] in, int inOffset, byte[] out, int outOffset)
+      throws IllegalStateException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/ModeFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,151 @@
+/* ModeFactory.java -- 
+   Copyright (C) 2001, 2002, 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.java.security.Registry;
+
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A <i>Factory</i> to instantiate block cipher modes of operations.
+ */
+public class ModeFactory
+    implements Registry
+{
+  private static Set names;
+
+  /** Trivial constructor to enforce Singleton pattern. */
+  private ModeFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a block cipher mode of operations given its name and
+   * characteristics of the underlying block cipher.
+   * 
+   * @param mode the case-insensitive name of the mode of operations.
+   * @param cipher the case-insensitive name of the block cipher.
+   * @param cipherBlockSize the block size, in bytes, of the underlying cipher.
+   * @return an instance of the block cipher algorithm, operating in a given
+   *         mode of operations, or <code>null</code> if none found.
+   * @exception InternalError if either the mode or the underlying block cipher
+   *              implementation does not pass its self-test.
+   */
+  public static IMode getInstance(String mode, String cipher,
+                                  int cipherBlockSize)
+  {
+    if (mode == null || cipher == null)
+      return null;
+
+    mode = mode.trim();
+    cipher = cipher.trim();
+    IBlockCipher cipherImpl = CipherFactory.getInstance(cipher);
+    if (cipherImpl == null)
+      return null;
+
+    return getInstance(mode, cipherImpl, cipherBlockSize);
+  }
+
+  public static IMode getInstance(String mode, IBlockCipher cipher,
+                                  int cipherBlockSize)
+  {
+    // ensure that cipherBlockSize is valid for the chosen underlying cipher
+    boolean ok = false;
+    for (Iterator it = cipher.blockSizes(); it.hasNext();)
+      {
+        ok = (cipherBlockSize == ((Integer) it.next()).intValue());
+        if (ok)
+          break;
+      }
+    if (! ok)
+      throw new IllegalArgumentException("cipherBlockSize");
+    IMode result = null;
+    if (mode.equalsIgnoreCase(ECB_MODE))
+      result = new ECB(cipher, cipherBlockSize);
+    else if (mode.equalsIgnoreCase(CTR_MODE))
+      result = new CTR(cipher, cipherBlockSize);
+    else if (mode.equalsIgnoreCase(ICM_MODE))
+      result = new ICM(cipher, cipherBlockSize);
+    else if (mode.equalsIgnoreCase(OFB_MODE))
+      result = new OFB(cipher, cipherBlockSize);
+    else if (mode.equalsIgnoreCase(CBC_MODE))
+      result = new CBC(cipher, cipherBlockSize);
+    else if (mode.equalsIgnoreCase(CFB_MODE))
+      result = new CFB(cipher, cipherBlockSize);
+    else if (mode.equalsIgnoreCase(EAX_MODE))
+      result = new EAX(cipher, cipherBlockSize);
+
+    if (result != null && ! result.selfTest())
+      throw new InternalError(result.name());
+
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of names of mode supported by this <i>Factory</i>.
+   * 
+   * @return a {@link Set} of mode names (Strings).
+   */
+  public static final Set getNames()
+  {
+    synchronized (ModeFactory.class)
+      {
+        if (names == null)
+          {
+            HashSet hs = new HashSet();
+            hs.add(ECB_MODE);
+            hs.add(CTR_MODE);
+            hs.add(ICM_MODE);
+            hs.add(OFB_MODE);
+            hs.add(CBC_MODE);
+            hs.add(CFB_MODE);
+            hs.add(EAX_MODE);
+            names = Collections.unmodifiableSet(hs);
+          }
+      }
+    return names;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/mode/OFB.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,174 @@
+/* OFB.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.mode;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+/**
+ * The Output Feedback (OFB) mode is a confidentiality mode that requires a
+ * unique <code>IV</code> for every message that is ever encrypted under the
+ * given key. The OFB mode is defined as follows:
+ * <ul>
+ * <li>OFB Encryption:
+ * <ul>
+ * <li>I<sub>1</sub> = IV;</li>
+ * <li>I<sub>j</sub> = O<sub>j -1</sub> for j = 2...n;</li>
+ * <li>O<sub>j</sub> = CIPH<sub>K</sub>(I<sub>j</sub>) for j = 1, 2...n;</li>
+ * <li>C<sub>j</sub> = P<sub>j</sub> XOR O<sub>j</sub> for j = 1, 2...n.</li>
+ * </ul>
+ * </li>
+ * <li>OFB Decryption:
+ * <ul>
+ * <li>I<sub>1</sub> = IV;</li>
+ * <li>I<sub>j</sub> = O<sub>j -1</sub> for j = 2...n;</li>
+ * <li>O<sub>j</sub> = CIPH<sub>K</sub>(I<sub>j</sub>) for j = 1, 2...n;</li>
+ * <li>P<sub>j</sub> = C<sub>j</sub> XOR O<sub>j</sub> for j = 1, 2...n.</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * <p>
+ * In OFB encryption, the <code>IV</code> is transformed by the forward cipher
+ * function to produce the first output block. The first output block is
+ * exclusive-ORed with the first plaintext block to produce the first ciphertext
+ * block. The first output block is then transformed by the forward cipher
+ * function to produce the second output block. The second output block is
+ * exclusive-ORed with the second plaintext block to produce the second
+ * ciphertext block, and the second output block is transformed by the forward
+ * cipher function to produce the third output block. Thus, the successive
+ * output blocks are produced from enciphering the previous output blocks, and
+ * the output blocks are exclusive-ORed with the corresponding plaintext blocks
+ * to produce the ciphertext blocks.
+ * <p>
+ * In OFB decryption, the <code>IV</code> is transformed by the forward cipher
+ * function to produce the first output block. The first output block is
+ * exclusive-ORed with the first ciphertext block to recover the first plaintext
+ * block. The first output block is then transformed by the forward cipher
+ * function to produce the second output block. The second output block is
+ * exclusive-ORed with the second ciphertext block to produce the second
+ * plaintext block, and the second output block is also transformed by the
+ * forward cipher function to produce the third output block. Thus, the
+ * successive output blocks are produced from enciphering the previous output
+ * blocks, and the output blocks are exclusive-ORed with the corresponding
+ * ciphertext blocks to recover the plaintext blocks.
+ * <p>
+ * In both OFB encryption and OFB decryption, each forward cipher function
+ * (except the first) depends on the results of the previous forward cipher
+ * function; therefore, multiple forward cipher functions cannot be performed in
+ * parallel. However, if the <code>IV</code> is known, the output blocks can
+ * be generated prior to the availability of the plaintext or ciphertext data.
+ * <p>
+ * The OFB mode requires a unique <code>IV</code> for every message that is
+ * ever encrypted under the given key. If, contrary to this requirement, the
+ * same <code>IV</code> is used for the encryption of more than one message,
+ * then the confidentiality of those messages may be compromised. In particular,
+ * if a plaintext block of any of these messages is known, say, the j<sup>th</sup>
+ * plaintext block, then the j<sup>th</sup> output of the forward cipher
+ * function can be determined easily from the j<sup>th</sup> ciphertext block
+ * of the message. This information allows the j<sup>th</sup> plaintext block
+ * of any other message that is encrypted using the same <code>IV</code> to be
+ * easily recovered from the jth ciphertext block of that message.
+ * <p>
+ * Confidentiality may similarly be compromised if any of the input blocks to
+ * the forward cipher function for the encryption of a message is used as the
+ * <code>IV</code> for the encryption of another message under the given key.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>,
+ * Morris Dworkin.</li>
+ * </ol>
+ */
+public class OFB
+    extends BaseMode
+    implements Cloneable
+{
+  private byte[] outputBlock;
+
+  /**
+   * Trivial package-private constructor for use by the Factory class.
+   * 
+   * @param underlyingCipher the underlying cipher implementation.
+   * @param cipherBlockSize the underlying cipher block size to use.
+   */
+  OFB(IBlockCipher underlyingCipher, int cipherBlockSize)
+  {
+    super(Registry.OFB_MODE, underlyingCipher, cipherBlockSize);
+  }
+
+  /**
+   * Private constructor for cloning purposes.
+   * 
+   * @param that the mode to clone.
+   */
+  private OFB(OFB that)
+  {
+    this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize);
+  }
+
+  public Object clone()
+  {
+    return new OFB(this);
+  }
+
+  public void setup()
+  {
+    if (modeBlockSize != cipherBlockSize)
+      throw new IllegalArgumentException(IMode.MODE_BLOCK_SIZE);
+    outputBlock = (byte[]) iv.clone();
+  }
+
+  public void teardown()
+  {
+  }
+
+  public void encryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    cipher.encryptBlock(outputBlock, 0, outputBlock, 0);
+    for (int j = 0; j < cipherBlockSize;)
+      out[o++] = (byte)(in[i++] ^ outputBlock[j++]);
+  }
+
+  public void decryptBlock(byte[] in, int i, byte[] out, int o)
+  {
+    this.encryptBlock(in, i, out, o);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/BasePad.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,191 @@
+/* BasePad.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+import gnu.java.security.Configuration;
+
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * An abstract class to facilitate implementing padding algorithms.
+ */
+public abstract class BasePad
+    implements IPad
+{
+  private static final Logger log = Logger.getLogger(BasePad.class.getName());
+  /** The canonical name prefix of the padding algorithm. */
+  protected String name;
+  /** The block size, in bytes, for this instance. */
+  protected int blockSize;
+
+  /** Trivial constructor for use by concrete subclasses. */
+  protected BasePad(final String name)
+  {
+    super();
+
+    this.name = name;
+    blockSize = -1;
+  }
+
+  public String name()
+  {
+    final StringBuffer sb = new StringBuffer(name);
+    if (blockSize != -1)
+      sb.append('-').append(String.valueOf(8 * blockSize));
+    return sb.toString();
+  }
+
+  public void init(final int bs) throws IllegalStateException
+  {
+    if (blockSize != -1)
+      throw new IllegalStateException();
+    blockSize = bs;
+    setup();
+  }
+
+  /**
+   * Initialises the algorithm with designated attributes. Names, valid and/or
+   * recognisable by all concrete implementations are described in {@link IPad}
+   * class documentation. Other algorithm-specific attributes MUST be documented
+   * in the implementation class of that padding algorithm.
+   * <p>
+   * For compatibility reasons, this method is not declared <i>abstract</i>.
+   * Furthermore, and unless overridden, the default implementation will throw
+   * an {@link UnsupportedOperationException}. Concrete padding algorithms MUST
+   * override this method if they wish to offer an initialisation method that
+   * allows for other than the padding block size parameter to be specified.
+   * 
+   * @param attributes a set of name-value pairs that describes the desired
+   *          future behaviour of this instance.
+   * @exception IllegalStateException if the instance is already initialised.
+   * @exception IllegalArgumentException if the block size value is invalid.
+   */
+  public void init(Map attributes) throws IllegalStateException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public void reset()
+  {
+    blockSize = -1;
+  }
+
+  /**
+   * A default implementation of a correctness test that exercises the padder
+   * implementation, using block sizes varying from 2 to 256 bytes.
+   * 
+   * @return <code>true</code> if the concrete implementation correctly unpads
+   *         what it pads for all tested block sizes. Returns <code>false</code>
+   *         if the test fails for any block size.
+   */
+  public boolean selfTest()
+  {
+    final byte[] in = new byte[1024];
+    for (int bs = 2; bs < 256; bs++)
+      if (! test1BlockSize(bs, in))
+        return false;
+    return true;
+  }
+
+  /**
+   * The basic symmetric test for a padder given a specific block size.
+   * <p>
+   * The code ensures that the implementation is capable of unpadding what it
+   * pads.
+   * 
+   * @param size the block size to test.
+   * @param buffer a work buffer. It is exposed as an argument for this method
+   *          to reduce un-necessary object allocations.
+   * @return <code>true</code> if the test passes; <code>false</code>
+   *         otherwise.
+   */
+  protected boolean test1BlockSize(int size, byte[] buffer)
+  {
+    byte[] padBytes;
+    final int offset = 5;
+    final int limit = buffer.length;
+    this.init(size);
+    for (int i = 0; i < limit - offset - blockSize; i++)
+      {
+        padBytes = pad(buffer, offset, i);
+        if (((i + padBytes.length) % blockSize) != 0)
+          {
+            if (Configuration.DEBUG)
+              log.log(Level.SEVERE,
+                      "Length of padded text MUST be a multiple of "
+                      + blockSize, new RuntimeException(name()));
+            return false;
+          }
+        System.arraycopy(padBytes, 0, buffer, offset + i, padBytes.length);
+        try
+          {
+            if (padBytes.length != unpad(buffer, offset, i + padBytes.length))
+              {
+                if (Configuration.DEBUG)
+                  log.log(Level.SEVERE,
+                          "IPad [" + name() + "] failed symmetric operation",
+                          new RuntimeException(name()));
+                return false;
+              }
+          }
+        catch (WrongPaddingException x)
+          {
+            if (Configuration.DEBUG)
+              log.throwing(this.getClass().getName(), "test1BlockSize", x);
+            return false;
+          }
+      }
+    this.reset();
+    return true;
+  }
+
+  /**
+   * If any additional checks or resource setup must be done by the subclass,
+   * then this is the hook for it. This method will be called before the
+   * {@link #init(int)} method returns.
+   */
+  public abstract void setup();
+
+  public abstract byte[] pad(byte[] in, int off, int len);
+
+  public abstract int unpad(byte[] in, int off, int len)
+      throws WrongPaddingException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/IPad.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,127 @@
+/* IPad.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+import java.util.Map;
+
+/**
+ * The basic visible methods, and attribute names, of every padding algorithm.
+ * <p>
+ * Padding algorithms serve to <i>pad</i> and <i>unpad</i> byte arrays usually
+ * as the last step in an <i>encryption</i> or respectively a <i>decryption</i>
+ * operation. Their input buffers are usually those processed by instances of
+ * {@link gnu.javax.crypto.mode.IMode} and/or
+ * {@link gnu.javax.crypto.cipher.IBlockCipher}.
+ */
+public interface IPad
+{
+  /**
+   * Property name of the block size in which to operate the padding algorithm.
+   * The value associated with this property name is taken to be a positive 
+   * {@link Integer} greater than zero.
+   */
+  String PADDING_BLOCK_SIZE = "gnu.crypto.pad.block.size";
+
+  /** @return the canonical name of this instance. */
+  String name();
+
+  /**
+   * Initialises the padding scheme with a designated block size.
+   * 
+   * @param bs the designated block size.
+   * @exception IllegalStateException if the instance is already initialised.
+   * @exception IllegalArgumentException if the block size value is invalid.
+   */
+  void init(int bs) throws IllegalStateException;
+
+  /**
+   * Initialises the algorithm with designated attributes. Names, valid and/or
+   * recognisable by all concrete implementations are described in the class
+   * documentation above. Other algorithm-specific attributes MUST be documented
+   * in the implementation class of that padding algorithm.
+   * 
+   * @param attributes a set of name-value pairs that describes the desired
+   *          future behaviour of this instance.
+   * @exception IllegalStateException if the instance is already initialised.
+   * @exception IllegalArgumentException if the block size value is invalid.
+   */
+  void init(Map attributes) throws IllegalStateException;
+
+  /**
+   * Returns the byte sequence that should be appended to the designated input.
+   * 
+   * @param in the input buffer containing the bytes to pad.
+   * @param offset the starting index of meaningful data in <i>in</i>.
+   * @param length the number of meaningful bytes in <i>in</i>.
+   * @return the possibly 0-byte long sequence to be appended to the designated
+   *         input.
+   */
+  byte[] pad(byte[] in, int offset, int length);
+
+  /**
+   * Returns the number of bytes to discard from a designated input buffer.
+   * 
+   * @param in the input buffer containing the bytes to unpad.
+   * @param offset the starting index of meaningful data in <i>in</i>.
+   * @param length the number of meaningful bytes in <i>in</i>.
+   * @return the number of bytes to discard, to the left of index position
+   *         <code>offset + length</code> in <i>in</i>. In other words, if
+   *         the return value of a successful invocation of this method is
+   *         <code>result</code>, then the unpadded byte sequence will be
+   *         <code>offset + length - result</code> bytes in <i>in</i>,
+   *         starting from index position <code>offset</code>.
+   * @exception WrongPaddingException if the data is not terminated with the
+   *              expected padding bytes.
+   */
+  int unpad(byte[] in, int offset, int length) throws WrongPaddingException;
+
+  /**
+   * Resets the scheme instance for re-initialisation and use with other
+   * characteristics. This method always succeeds.
+   */
+  void reset();
+
+  /**
+   * A basic symmetric pad/unpad test.
+   * 
+   * @return <code>true</code> if the implementation passes a basic symmetric
+   *         self-test. Returns <code>false</code> otherwise.
+   */
+  boolean selfTest();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/ISO10126.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,109 @@
+/* ISO10126.java -- An implementation of the ISO 10126-2 padding scheme
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.PRNG;
+
+/**
+ * The implementation of the ISO 10126-2 padding algorithm.
+ * <p>
+ * The last byte of the padding block is the number of padding bytes, all other
+ * padding bytes are random.
+ * <p>
+ * References:
+ * <ol>
+ *    <li><a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and
+ *    Processing</a> Section "5.2 Block Encryption Algorithms"; "Padding".</li>
+ * </ol>
+ */
+public final class ISO10126
+    extends BasePad
+{
+  /** Used to generate random numbers for padding bytes. */
+  private PRNG prng;
+
+  ISO10126()
+  {
+    super(Registry.ISO10126_PAD);
+    prng = PRNG.getInstance();
+  }
+
+  public void setup()
+  {
+    // Nothing to do here
+  }
+
+  public byte[] pad(byte[] in, int offset, int length)
+  {
+    int padLength = blockSize - (length % blockSize);
+    final byte[] pad = new byte[padLength];
+
+    // generate random numbers for the padding bytes except for the last byte
+    prng.nextBytes(pad, 0, padLength - 1);
+    // the last byte contains the number of padding bytes
+    pad[padLength - 1] = (byte) padLength;
+
+    return pad;
+  }
+
+  public int unpad(byte[] in, int offset, int length)
+      throws WrongPaddingException
+  {
+    // the last byte contains the number of padding bytes
+    int padLength = in[offset + length - 1] & 0xFF;
+    if (padLength > length)
+      throw new WrongPaddingException();
+
+    return padLength;
+  }
+
+  /**
+   * The default self-test in the super-class would take too long to finish
+   * with this type of padder --due to the large amount of random data needed.
+   * We override the default test and replace it with a simple one for a 16-byte
+   * block-size (default AES block-size). The Mauve test TestOfISO10126 will
+   * exercise all block-sizes that the default self-test uses for the other
+   * padders.
+   */
+  public boolean selfTest()
+  {
+    return test1BlockSize(16, new byte[1024]);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/PKCS1_V1_5.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,156 @@
+/* PKCS1_V1_5.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.sig.rsa.EME_PKCS1_V1_5;
+import gnu.java.security.util.PRNG;
+import gnu.java.security.util.Util;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A padding algorithm implementation of the EME-PKCS1-V1.5 encoding/decoding
+ * algorithm as described in section 7.2 of RFC-3447. This is effectively an
+ * <i>Adapter</i> over an instance of {@link EME_PKCS1_V1_5} initialised with
+ * the RSA public shared modulus length (in bytes).
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ * Standards (PKCS) #1:</a><br>
+ * RSA Cryptography Specifications Version 2.1.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ * 
+ * @see EME_PKCS1_V1_5
+ */
+public class PKCS1_V1_5
+    extends BasePad
+{
+  private static final Logger log = Logger.getLogger(PKCS1_V1_5.class.getName());
+  private EME_PKCS1_V1_5 codec;
+
+  /**
+   * Trivial package-private constructor for use by the <i>Factory</i> class.
+   *
+   * @see PadFactory
+   */
+  PKCS1_V1_5()
+  {
+    super(Registry.EME_PKCS1_V1_5_PAD);
+  }
+
+  public void setup()
+  {
+    codec = EME_PKCS1_V1_5.getInstance(blockSize);
+  }
+
+  public byte[] pad(final byte[] in, final int offset, final int length)
+  {
+    final byte[] M = new byte[length];
+    System.arraycopy(in, offset, M, 0, length);
+    final byte[] EM = codec.encode(M);
+    final byte[] result = new byte[blockSize - length];
+    System.arraycopy(EM, 0, result, 0, result.length);
+    if (Configuration.DEBUG)
+      log.fine("padding: 0x" + Util.toString(result));
+    return result;
+  }
+
+  public int unpad(final byte[] in, final int offset, final int length)
+      throws WrongPaddingException
+  {
+    final byte[] EM = new byte[length];
+    System.arraycopy(in, offset, EM, 0, length);
+    final int result = length - codec.decode(EM).length;
+    if (Configuration.DEBUG)
+      log.fine("padding length: " + String.valueOf(result));
+    return result;
+  }
+
+  public boolean selfTest()
+  {
+    final int[] mLen = new int[] { 16, 20, 32, 48, 64 };
+    final byte[] M = new byte[mLen[mLen.length - 1]];
+    PRNG.getInstance().nextBytes(M);
+    final byte[] EM = new byte[1024];
+    byte[] p;
+    int bs, i, j;
+    for (bs = 256; bs < 1025; bs += 256)
+      {
+        init(bs);
+        for (i = 0; i < mLen.length; i++)
+          {
+            j = mLen[i];
+            p = pad(M, 0, j);
+            if (j + p.length != blockSize)
+              {
+                if (Configuration.DEBUG)
+                  log.log(Level.SEVERE,
+                          "Length of padded text MUST be a multiple of "
+                          + blockSize, new RuntimeException(name()));
+                return false;
+              }
+            System.arraycopy(p, 0, EM, 0, p.length);
+            System.arraycopy(M, 0, EM, p.length, j);
+            try
+              {
+                if (p.length != unpad(EM, 0, blockSize))
+                  {
+                    if (Configuration.DEBUG)
+                      log.log(Level.SEVERE, "Failed symmetric operation",
+                              new RuntimeException(name()));
+                    return false;
+                  }
+              }
+            catch (WrongPaddingException x)
+              {
+                if (Configuration.DEBUG)
+                  log.throwing(this.getClass().getName(), "selfTest", x);
+                return false;
+              }
+          }
+        reset();
+      }
+    return true;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/PKCS7.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,111 @@
+/* PKCS7.java -- 
+ Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+ This file is a part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at
+ your option) any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ USA
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.util.logging.Logger;
+
+/**
+ * The implementation of the PKCS7 padding algorithm.
+ * <p>
+ * This algorithm is described for 8-byte blocks in [RFC-1423] and extended to
+ * block sizes of up to 256 bytes in [PKCS-7].
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc1423.txt">RFC-1423</a>: Privacy
+ * Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and
+ * Identifiers.</li>
+ * <li><a href="http://www.ietf.org/">IETF</a>.</li>
+ * <li><a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-7/">[PKCS-7]</a>
+ * PKCS #7: Cryptographic Message Syntax Standard - An RSA Laboratories
+ * Technical Note.</li>
+ * <li><a href="http://www.rsasecurity.com/">RSA Security</a>.</li>
+ * </ol>
+ */
+public final class PKCS7
+    extends BasePad
+{
+  private static final Logger log = Logger.getLogger(PKCS7.class.getName());
+
+  /**
+   * Trivial package-private constructor for use by the <i>Factory</i> class.
+   * 
+   * @see PadFactory
+   */
+  PKCS7()
+  {
+    super(Registry.PKCS7_PAD);
+  }
+
+  public void setup()
+  {
+    if (blockSize < 2 || blockSize > 256)
+      throw new IllegalArgumentException();
+  }
+
+  public byte[] pad(byte[] in, int offset, int length)
+  {
+    int padLength = blockSize;
+    if (length % blockSize != 0)
+      padLength = blockSize - length % blockSize;
+    byte[] result = new byte[padLength];
+    for (int i = 0; i < padLength;)
+      result[i++] = (byte) padLength;
+    if (Configuration.DEBUG)
+      log.fine("padding: 0x" + Util.toString(result));
+    return result;
+  }
+
+  public int unpad(byte[] in, int offset, int length)
+      throws WrongPaddingException
+  {
+    int limit = offset + length;
+    int result = in[--limit] & 0xFF;
+    for (int i = 0; i < result - 1; i++)
+      if (result != (in[--limit] & 0xFF))
+        throw new WrongPaddingException();
+    if (Configuration.DEBUG)
+      log.fine("padding length: " + result);
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/PadFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,120 @@
+/* PadFactory.java -- 
+   Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+import gnu.java.security.Registry;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A Factory to instantiate padding schemes.
+ */
+public class PadFactory
+    implements Registry
+{
+  /** Collection of padding algorithm names --cached for speed. */
+  private static Set names;
+
+  /** Trivial constructor to enforce Singleton pattern. */
+  private PadFactory()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a padding algorithm given its name.
+   * 
+   * @param pad the case-insensitive name of the padding algorithm.
+   * @return an instance of the padding algorithm, operating with a given block
+   *         size, or <code>null</code> if none found.
+   * @throws InternalError if the implementation does not pass its self-test.
+   */
+  public static final IPad getInstance(String pad)
+  {
+    if (pad == null)
+      return null;
+
+    pad = pad.trim().toLowerCase();
+    if (pad.endsWith("padding"))
+      pad = pad.substring(0, pad.length() - "padding".length());
+    IPad result = null;
+    if (pad.equals(PKCS7_PAD) || pad.equals(PKCS5_PAD))
+      result = new PKCS7();
+    else if (pad.equals(TBC_PAD))
+      result = new TBC();
+    else if (pad.equals(EME_PKCS1_V1_5_PAD))
+      result = new PKCS1_V1_5();
+    else if (pad.equals(SSL3_PAD))
+      result = new SSL3();
+    else if (pad.equals(TLS1_PAD))
+      result = new TLS1();
+    else if (pad.equals(ISO10126_PAD))
+      result = new ISO10126();
+
+    if (result != null && ! result.selfTest())
+      throw new InternalError(result.name());
+
+    return result;
+  }
+
+  /**
+   * Returns a {@link Set} of names of padding algorithms supported by this
+   * <i>Factory</i>.
+   * 
+   * @return a {@link Set} of padding algorithm names (Strings).
+   */
+  public static final Set getNames()
+  {
+    if (names == null)
+      {
+        HashSet hs = new HashSet();
+        hs.add(PKCS5_PAD);
+        hs.add(PKCS7_PAD);
+        hs.add(TBC_PAD);
+        hs.add(EME_PKCS1_V1_5_PAD);
+        hs.add(SSL3_PAD);
+        hs.add(TLS1_PAD);
+        hs.add(ISO10126_PAD);
+        names = Collections.unmodifiableSet(hs);
+      }
+    return names;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/SSL3.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,90 @@
+/* SSL3.java -- SSLv3 padding scheme.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+/**
+ * The padding scheme used by the Secure Sockets Layer, version 3. This padding
+ * scheme is used in the block-ciphered struct, e.g.:
+ * <pre>
+ *  block-ciphered struct {
+ *    opaque content[SSLCompressed.length];
+ *    opaque MAC[CipherSpec.hash_size];
+ *    uint8 padding[GenericBlockCipher.padding_length];
+ *    uint8 padding_length;
+ *  } GenericBlockCipher;
+ * </pre>
+ * <p>
+ * Where <i>padding_length</i> is <i>cipher_block_size</i> -
+ * ((<i>SSLCompressed.length</i> + <i>CipherSpec.hash_size</i>) %
+ * <i>cipher_block_size</i>) - 1. That is, the padding is enough bytes to make
+ * the plaintext a multiple of the block size minus one, plus one additional
+ * byte for the padding length. The padding can be any arbitrary data.
+ */
+public class SSL3
+    extends BasePad
+{
+  public SSL3()
+  {
+    super("ssl3");
+  }
+
+  public void setup()
+  {
+    if (blockSize <= 0 || blockSize > 255)
+      throw new IllegalArgumentException("invalid block size: " + blockSize);
+  }
+
+  public byte[] pad(final byte[] in, final int off, final int len)
+  {
+    int padlen = blockSize - (len % blockSize);
+    byte[] pad = new byte[padlen];
+    for (int i = 0; i < padlen; i++)
+      pad[i] = (byte)(padlen - 1);
+    return pad;
+  }
+
+  public int unpad(final byte[] in, final int off, final int len)
+      throws WrongPaddingException
+  {
+    int padlen = in[off + len - 1] & 0xFF;
+    if (padlen >= blockSize)
+      throw new WrongPaddingException();
+    return padlen + 1;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/TBC.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,118 @@
+/* TBC.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.util.logging.Logger;
+
+/**
+ * The implementation of the Trailing Bit Complement (TBC) padding algorithm.
+ * <p>
+ * In this mode, "...the data string is padded at the trailing end with the
+ * complement of the trailing bit of the unpadded message: if the trailing bit
+ * is <tt>1</tt>, then <tt>0</tt> bits are appended, and if the trailing
+ * bit is <tt>0</tt>, then <tt>1</tt> bits are appended. As few bits are
+ * added as are necessary to meet the formatting size requirement."
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and
+ * Techniques</a>, Morris Dworkin.</li>
+ * </ol>
+ */
+public final class TBC
+    extends BasePad
+{
+  private static final Logger log = Logger.getLogger(TBC.class.getName());
+
+  /**
+   * Trivial package-private constructor for use by the <i>Factory</i> class.
+   * 
+   * @see PadFactory
+   */
+  TBC()
+  {
+    super(Registry.TBC_PAD);
+  }
+
+  public void setup()
+  {
+    if (blockSize < 1 || blockSize > 256)
+      throw new IllegalArgumentException();
+  }
+
+  public byte[] pad(byte[] in, int offset, int length)
+  {
+    int padLength = blockSize;
+    if (length % blockSize != 0)
+      padLength = blockSize - length % blockSize;
+    byte[] result = new byte[padLength];
+    int lastBit = in[offset + length - 1] & 0x01;
+    if (lastBit == 0)
+      for (int i = 0; i < padLength;)
+        result[i++] = 0x01;
+    // else it's already set to zeroes by virtue of initialisation
+    if (Configuration.DEBUG)
+      log.fine("padding: 0x" + Util.toString(result));
+    return result;
+  }
+
+  public int unpad(byte[] in, int offset, int length)
+      throws WrongPaddingException
+  {
+    int limit = offset + length - 1;
+    int lastBit = in[limit] & 0xFF;
+    int result = 0;
+    while (lastBit == (in[limit] & 0xFF))
+      {
+        result++;
+        limit--;
+      }
+    if (result > length)
+      throw new WrongPaddingException();
+    if (Configuration.DEBUG)
+      log.fine("padding length: " + result);
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/TLS1.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,91 @@
+/* TLS1.java -- TLSv1 padding scheme.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+/**
+ * The padding scheme used by the Transport Layer Security protocol, version 1.
+ * This padding scheme is used in the block-ciphered struct, e.g.:
+ * <pre>
+ *  block-ciphered struct {
+ *    opaque content[TLSCompressed.length];
+ *    opaque MAC[CipherSpec.hash_size];
+ *    uint8 padding[GenericBlockCipher.padding_length];
+ *    uint8 padding_length;
+ *  } GenericBlockCipher;
+ * </pre>
+ * <p>
+ * Where <i>padding_length</i> is any multiple of <i>cipher_block_size</i> -
+ * ((<i>SSLCompressed.length</i> + <i>CipherSpec.hash_size</i>) %
+ * <i>cipher_block_size</i>) - 1 that is less than 255. Every byte of the
+ * padding must be equal to <i>padding_length</i>. That is, the end of the
+ * plaintext is <i>n</i> + 1 copies of the unsigned byte <i>n</i>.
+ */
+public class TLS1
+    extends BasePad
+{
+  public TLS1()
+  {
+    super("tls1");
+  }
+
+  public void setup()
+  {
+    if (blockSize <= 0 || blockSize > 255)
+      throw new IllegalArgumentException("invalid block size: " + blockSize);
+  }
+
+  public byte[] pad(final byte[] in, final int off, final int len)
+  {
+    int padlen = blockSize - (len % blockSize);
+    byte[] pad = new byte[padlen];
+    for (int i = 0; i < padlen; i++)
+      pad[i] = (byte)(padlen - 1);
+    return pad;
+  }
+
+  public int unpad(final byte[] in, final int off, final int len)
+      throws WrongPaddingException
+  {
+    int padlen = in[off + len - 1] & 0xFF;
+    for (int i = off + (len - padlen - 1); i < off + len - 1; i++)
+      if ((in[i] & 0xFF) != padlen)
+        throw new WrongPaddingException();
+    return padlen + 1;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/pad/WrongPaddingException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,48 @@
+/* WrongPaddingException.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.pad;
+
+/**
+ * A checked exception that indicates that a padding algorithm did not find the
+ * expected padding bytes when unpadding some data.
+ */
+public class WrongPaddingException
+    extends Exception
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/prng/ARCFour.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,137 @@
+/* ARCFour.java -- 
+   Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.prng;
+
+import gnu.java.security.Registry;
+import gnu.java.security.prng.BasePRNG;
+import gnu.java.security.prng.LimitReachedException;
+
+import java.util.Map;
+
+/**
+ * RC4 is a stream cipher developed by Ron Rivest. Until 1994 RC4 was a trade
+ * secret of RSA Data Security, Inc., when it was released anonymously to a
+ * mailing list. This version is a descendent of that code, and since there is
+ * no proof that the leaked version was in fact RC4 and because "RC4" is a
+ * trademark, it is called "ARCFOUR", short for "Allegedly RC4".
+ * <p>
+ * This class only implements the <i>keystream</i> of ARCFOUR. To use this as a
+ * stream cipher, one would say:
+ * <pre>
+ * out = in &circ; arcfour.nextByte();
+ * </pre>
+ * <p>
+ * This operation works for encryption and decryption.
+ * <p>
+ * References:
+ * <ol>
+ * <li>Schneier, Bruce: <i>Applied Cryptography: Protocols, Algorithms, and
+ * Source Code in C, Second Edition.</i> (1996 John Wiley and Sons), pp.
+ * 397--398. ISBN 0-471-11709-9</li>
+ * <li>K. Kaukonen and R. Thayer, "A Stream Cipher Encryption Algorithm
+ * 'Arcfour'", Internet Draft (expired), <a
+ * href="http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt">draft-kaukonen-cipher-arcfour-03.txt</a></li>
+ * </ol>
+ */
+public class ARCFour
+    extends BasePRNG
+    implements Cloneable
+{
+  /** The attributes property name for the key bytes. */
+  public static final String ARCFOUR_KEY_MATERIAL = "gnu.crypto.prng.arcfour.key-material";
+  /** The size of the internal S-box. */
+  public static final int ARCFOUR_SBOX_SIZE = 256;
+  /** The S-box. */
+  private byte[] s;
+  private byte m, n;
+
+  /** Default 0-arguments constructor. */
+  public ARCFour()
+  {
+    super(Registry.ARCFOUR_PRNG);
+  }
+
+  public void setup(Map attributes)
+  {
+    byte[] kb = (byte[]) attributes.get(ARCFOUR_KEY_MATERIAL);
+    if (kb == null)
+      throw new IllegalArgumentException("ARCFOUR needs a key");
+    s = new byte[ARCFOUR_SBOX_SIZE];
+    m = n = 0;
+    byte[] k = new byte[ARCFOUR_SBOX_SIZE];
+    for (int i = 0; i < ARCFOUR_SBOX_SIZE; i++)
+      s[i] = (byte) i;
+    if (kb.length > 0)
+      for (int i = 0, j = 0; i < ARCFOUR_SBOX_SIZE; i++)
+        {
+          k[i] = kb[j++];
+          if (j >= kb.length)
+            j = 0;
+        }
+    for (int i = 0, j = 0; i < ARCFOUR_SBOX_SIZE; i++)
+      {
+        j = j + s[i] + k[i];
+        byte temp = s[i];
+        s[i] = s[j & 0xff];
+        s[j & 0xff] = temp;
+      }
+    buffer = new byte[ARCFOUR_SBOX_SIZE];
+    try
+      {
+        fillBlock();
+      }
+    catch (LimitReachedException wontHappen)
+      {
+      }
+  }
+
+  public void fillBlock() throws LimitReachedException
+  {
+    for (int i = 0; i < buffer.length; i++)
+      {
+        m++;
+        n = (byte)(n + s[m & 0xff]);
+        byte temp = s[m & 0xff];
+        s[m & 0xff] = s[n & 0xff];
+        s[n & 0xff] = temp;
+        temp = (byte)(s[m & 0xff] + s[n & 0xff]);
+        buffer[i] = s[temp & 0xff];
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/prng/CSPRNG.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,985 @@
+/* CSPRNG.java -- continuously-seeded pseudo-random number generator.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.prng;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Properties;
+import gnu.java.security.Registry;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.prng.BasePRNG;
+import gnu.java.security.prng.EntropySource;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.SimpleList;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.InvalidKeyException;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * An entropy pool-based pseudo-random number generator based on the PRNG in
+ * Peter Gutmann's cryptlib (<a
+ * href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">http://www.cs.auckland.ac.nz/~pgut001/cryptlib/</a>).
+ * <p>
+ * The basic properties of this generator are:
+ * <ol>
+ * <li>The internal state cannot be determined by knowledge of the input.</li>
+ * <li>It is resistant to bias introduced by specific inputs.</li>
+ * <li>The output does not reveal the state of the generator.</li>
+ * </ol>
+ */
+public class CSPRNG
+    extends BasePRNG
+{
+  private static final Logger log = Logger.getLogger(CSPRNG.class.getName());
+  /**
+   * Property name for the list of files to read for random values. The mapped
+   * value is a list with the following values:
+   * <ol>
+   * <li>A {@link Double}, indicating the suggested <i>quality</i> of this
+   * source. This value must be between 0 and 100.</li>
+   * <li>An {@link Integer}, indicating the number of bytes to skip in the
+   * file before reading bytes. This can be any nonnegative value.</li>
+   * <li>An {@link Integer}, indicating the number of bytes to read.</li>
+   * <li>A {@link String}, indicating the path to the file.</li>
+   * </ol>
+   * 
+   * @see gnu.java.security.util.SimpleList
+   */
+  public static final String FILE_SOURCES = "gnu.crypto.prng.pool.files";
+  /**
+   * Property name for the list of URLs to poll for random values. The mapped
+   * value is a list formatted similarly as in {@link #FILE_SOURCES}, but the
+   * fourth member is a {@link URL}.
+   */
+  public static final String URL_SOURCES = "gnu.crypto.prng.pool.urls";
+  /**
+   * Property name for the list of programs to execute, and use the output as
+   * new random bytes. The mapped property is formatted similarly an in
+   * {@link #FILE_SOURCES} and {@link #URL_SOURCES}, except the fourth member
+   * is a {@link String} of the program to execute.
+   */
+  public static final String PROGRAM_SOURCES = "gnu.crypto.prng.pool.programs";
+  /**
+   * Property name for a list of other sources of entropy. The mapped value must
+   * be a list of {@link EntropySource} objects.
+   */
+  public static final String OTHER_SOURCES = "gnu.crypto.prng.pool.other";
+  /**
+   * Property name for whether or not to wait for the slow poll to complete,
+   * passed as a {@link Boolean}. The default value is true.
+   */
+  public static final String BLOCKING = "gnu.crypto.prng.pool.blocking";
+  private static final String FILES = "gnu.crypto.csprng.file.";
+  private static final String URLS = "gnu.crypto.csprng.url.";
+  private static final String PROGS = "gnu.crypto.csprng.program.";
+  private static final String OTHER = "gnu.crypto.csprng.other.";
+  private static final String BLOCK = "gnu.crypto.csprng.blocking";
+  private static final int POOL_SIZE = 256;
+  private static final int ALLOC_SIZE = 260;
+  private static final int OUTPUT_SIZE = POOL_SIZE / 2;
+  private static final int X917_POOL_SIZE = 16;
+  private static final String HASH_FUNCTION = Registry.SHA160_HASH;
+  private static final String CIPHER = Registry.AES_CIPHER;
+  private static final int MIX_COUNT = 10;
+  private static final int X917_LIFETIME = 8192;
+  // FIXME this should be configurable.
+  private static final int SPINNER_COUNT = 8;
+  /**
+   * The spinner group singleton. We use this to add a small amount of
+   * randomness (in addition to the current time and the amount of free memory)
+   * based on the randomness (if any) present due to system load and thread
+   * scheduling.
+   */
+  private static final Spinner[] SPINNERS = new Spinner[SPINNER_COUNT];
+  private static final Thread[] SPINNER_THREADS = new Thread[SPINNER_COUNT];
+  static
+    {
+      for (int i = 0; i < SPINNER_COUNT; i++)
+        {
+          SPINNER_THREADS[i] = new Thread(SPINNERS[i] = new Spinner(),
+                                          "spinner-" + i);
+          SPINNER_THREADS[i].setDaemon(true);
+          SPINNER_THREADS[i].setPriority(Thread.MIN_PRIORITY);
+          SPINNER_THREADS[i].start();
+        }
+    }
+  /** The message digest (SHA-1) used in the mixing function. */
+  private final IMessageDigest hash;
+  /** The cipher (AES) used in the output masking function. */
+  private final IBlockCipher cipher;
+  /** The number of times the pool has been mixed. */
+  private int mixCount;
+  /** The entropy pool. */
+  private final byte[] pool;
+  /** The quality of the random pool (percentage). */
+  private double quality;
+  /** The index of the next byte in the entropy pool. */
+  private int index;
+  /** The pool for the X9.17-like generator. */
+  private byte[] x917pool;
+  /** The number of iterations of the X9.17-like generators. */
+  private int x917count;
+  /** Whether or not the X9.17-like generator is initialized. */
+  private boolean x917init;
+  /** The list of file soures. */
+  private final List files;
+  /** The list of URL sources. */
+  private final List urls;
+  /** The list of program sources. */
+  private final List progs;
+  /** The list of other sources. */
+  private final List other;
+  /** Whether or not to wait for the slow poll to complete. */
+  private boolean blocking;
+  /** The thread that polls for random data. */
+  private Poller poller;
+  private Thread pollerThread;
+
+  public CSPRNG()
+  {
+    super("CSPRNG");
+    pool = new byte[ALLOC_SIZE];
+    x917pool = new byte[X917_POOL_SIZE];
+    x917count = 0;
+    x917init = false;
+    quality = 0.0;
+    hash = HashFactory.getInstance(HASH_FUNCTION);
+    cipher = CipherFactory.getInstance(CIPHER);
+    buffer = new byte[OUTPUT_SIZE];
+    ndx = 0;
+    initialised = false;
+    files = new LinkedList();
+    urls = new LinkedList();
+    progs = new LinkedList();
+    other = new LinkedList();
+  }
+
+  /**
+   * Create and initialize a CSPRNG instance with the "system" parameters; the
+   * files, URLs, programs, and {@link EntropySource} sources used by the
+   * instance are derived from properties set in the system {@link Properties}.
+   * <p>
+   * All properties are of the from <i>name</i>.</i>N</i>, where <i>name</i>
+   * is the name of the source, and <i>N</i> is an integer (staring at 1) that
+   * indicates the preference number for that source.
+   * <p>
+   * The following vales for <i>name</i> are used here:
+   * <dl>
+   * <dt>gnu.crypto.csprng.file</dt>
+   * <dd>
+   * <p>
+   * These properties are file sources, passed as the {@link #FILE_SOURCES}
+   * parameter of the instance. The property value is a 4-tuple formatted as:
+   * </p>
+   * <blockquote><i>quality</i> ; <i>offset</i> ; <i>count</i> ; <i>path</i></blockquote>
+   * <p>
+   * The parameters are mapped to the parameters defined for {@link
+   * #FILE_SOURCES}. Leading or trailing spaces on any item are trimmed off.
+   * </p>
+   * </dd>
+   * <dt>gnu.crypto.csprng.url</dt>
+   * <dd>
+   * <p>
+   * These properties are URL sources, passed as the {@link #URL_SOURCES}
+   * parameter of the instance. The property is formatted the same way as file
+   * sources, but the <i>path</i> argument must be a valid URL.
+   * </p>
+   * </dd>
+   * <dt>gnu.crypto.csprng.program</dt>
+   * <dd>
+   * <p>
+   * These properties are program sources, passed as the {@link
+   * #PROGRAM_SOURCES} parameter of the instance. This property is formatted the
+   * same way as file and URL sources, but the last argument is a program and
+   * its arguments.
+   * </p>
+   * </dd>
+   * <dt>gnu.crypto.cspring.other</dt>
+   * <dd>
+   * <p>
+   * These properties are other sources, passed as the {@link #OTHER_SOURCES}
+   * parameter of the instance. The property value must be the full name of a
+   * class that implements the {@link EntropySource} interface and has a public
+   * no-argument constructor.
+   * </p>
+   * </dd>
+   * </dl>
+   * <p>
+   * Finally, a boolean property "gnu.crypto.csprng.blocking" can be set to the
+   * desired value of {@link #BLOCKING}.
+   * <p>
+   * An example of valid properties would be:
+   * <pre>
+   *  gnu.crypto.csprng.blocking=true
+   * 
+   *  gnu.crypto.csprng.file.1=75.0;0;256;/dev/random
+   *  gnu.crypto.csprng.file.2=10.0;0;100;/home/user/file
+   * 
+   *  gnu.crypto.csprng.url.1=5.0;0;256;http://www.random.org/cgi-bin/randbyte?nbytes=256
+   *  gnu.crypto.csprng.url.2=0;256;256;http://slashdot.org/
+   * 
+   *  gnu.crypto.csprng.program.1=0.5;0;10;last -n 50
+   *  gnu.crypto.csprng.program.2=0.5;0;10;tcpdump -c 5
+   * 
+   *  gnu.crypto.csprng.other.1=foo.bar.MyEntropySource
+   *  gnu.crypto.csprng.other.2=com.company.OtherEntropySource
+   * </pre>
+   */
+  public static IRandom getSystemInstance() throws ClassNotFoundException,
+      MalformedURLException, NumberFormatException
+  {
+    CSPRNG instance = new CSPRNG();
+    HashMap attrib = new HashMap();
+    attrib.put(BLOCKING, Boolean.valueOf(getProperty(BLOCK)));
+    String s = null;
+    // Get each file source "gnu.crypto.csprng.file.N".
+    List l = new LinkedList();
+    for (int i = 0; (s = getProperty(FILES + i)) != null; i++)
+      try
+        {
+          l.add(parseString(s.trim()));
+        }
+      catch (NumberFormatException nfe)
+        {
+        }
+    attrib.put(FILE_SOURCES, l);
+    l = new LinkedList();
+    for (int i = 0; (s = getProperty(URLS + i)) != null; i++)
+      try
+        {
+          l.add(parseURL(s.trim()));
+        }
+      catch (NumberFormatException nfe)
+        {
+        }
+      catch (MalformedURLException mue)
+        {
+        }
+    attrib.put(URL_SOURCES, l);
+    l = new LinkedList();
+    for (int i = 0; (s = getProperty(PROGS + i)) != null; i++)
+      try
+        {
+          l.add(parseString(s.trim()));
+        }
+      catch (NumberFormatException nfe)
+        {
+        }
+    attrib.put(PROGRAM_SOURCES, l);
+    l = new LinkedList();
+    for (int i = 0; (s = getProperty(OTHER + i)) != null; i++)
+      try
+        {
+          Class c = Class.forName(s.trim());
+          l.add(c.newInstance());
+        }
+      catch (ClassNotFoundException cnfe)
+        {
+        }
+      catch (InstantiationException ie)
+        {
+        }
+      catch (IllegalAccessException iae)
+        {
+        }
+    attrib.put(OTHER_SOURCES, l);
+    instance.init(attrib);
+    return instance;
+  }
+
+  private static String getProperty(final String name)
+  {
+    return (String) AccessController.doPrivileged(new PrivilegedAction()
+    {
+      public Object run()
+      {
+        return Properties.getProperty(name);
+      }
+    });
+  }
+
+  private static List parseString(String s) throws NumberFormatException
+  {
+    StringTokenizer tok = new StringTokenizer(s, ";");
+    if (tok.countTokens() != 4)
+      throw new IllegalArgumentException("malformed property");
+    Double quality = new Double(tok.nextToken());
+    Integer offset = new Integer(tok.nextToken());
+    Integer length = new Integer(tok.nextToken());
+    String str = tok.nextToken();
+    return new SimpleList(quality, offset, length, str);
+  }
+
+  private static List parseURL(String s) throws MalformedURLException,
+      NumberFormatException
+  {
+    StringTokenizer tok = new StringTokenizer(s, ";");
+    if (tok.countTokens() != 4)
+      throw new IllegalArgumentException("malformed property");
+    Double quality = new Double(tok.nextToken());
+    Integer offset = new Integer(tok.nextToken());
+    Integer length = new Integer(tok.nextToken());
+    URL url = new URL(tok.nextToken());
+    return new SimpleList(quality, offset, length, url);
+  }
+
+  public Object clone()
+  {
+    return new CSPRNG();
+  }
+
+  public void setup(Map attrib)
+  {
+    List list = null;
+    if (Configuration.DEBUG)
+      log.fine("attrib=" + String.valueOf(attrib));
+    try
+      {
+        list = (List) attrib.get(FILE_SOURCES);
+        if (Configuration.DEBUG)
+          log.fine("list=" + String.valueOf(list));
+        if (list != null)
+          {
+            files.clear();
+            for (Iterator it = list.iterator(); it.hasNext();)
+              {
+                List l = (List) it.next();
+                if (Configuration.DEBUG)
+                  log.fine("l=" + l);
+                if (l.size() != 4)
+                  {
+                    if (Configuration.DEBUG)
+                      log.fine("file list too small: " + l.size());
+                    throw new IllegalArgumentException("invalid file list");
+                  }
+                Double quality = (Double) l.get(0);
+                Integer offset = (Integer) l.get(1);
+                Integer length = (Integer) l.get(2);
+                String source = (String) l.get(3);
+                files.add(new SimpleList(quality, offset, length, source));
+              }
+          }
+      }
+    catch (ClassCastException cce)
+      {
+        if (Configuration.DEBUG)
+          log.log(Level.FINE, "bad file list", cce);
+        throw new IllegalArgumentException("invalid file list");
+      }
+    try
+      {
+        list = (List) attrib.get(URL_SOURCES);
+        if (Configuration.DEBUG)
+          log.fine("list=" + String.valueOf(list));
+        if (list != null)
+          {
+            urls.clear();
+            for (Iterator it = list.iterator(); it.hasNext();)
+              {
+                List l = (List) it.next();
+                if (Configuration.DEBUG)
+                  log.fine("l=" + l);
+                if (l.size() != 4)
+                  {
+                    if (Configuration.DEBUG)
+                      log.fine("URL list too small: " + l.size());
+                    throw new IllegalArgumentException("invalid URL list");
+                  }
+                Double quality = (Double) l.get(0);
+                Integer offset = (Integer) l.get(1);
+                Integer length = (Integer) l.get(2);
+                URL source = (URL) l.get(3);
+                urls.add(new SimpleList(quality, offset, length, source));
+              }
+          }
+      }
+    catch (ClassCastException cce)
+      {
+        if (Configuration.DEBUG)
+          log.log(Level.FINE, "bad URL list", cce);
+        throw new IllegalArgumentException("invalid URL list");
+      }
+    try
+      {
+        list = (List) attrib.get(PROGRAM_SOURCES);
+        if (Configuration.DEBUG)
+          log.fine("list=" + String.valueOf(list));
+        if (list != null)
+          {
+            progs.clear();
+            for (Iterator it = list.iterator(); it.hasNext();)
+              {
+                List l = (List) it.next();
+                if (Configuration.DEBUG)
+                  log.fine("l=" + l);
+                if (l.size() != 4)
+                  {
+                    if (Configuration.DEBUG)
+                      log.fine("program list too small: " + l.size());
+                    throw new IllegalArgumentException("invalid program list");
+                  }
+                Double quality = (Double) l.get(0);
+                Integer offset = (Integer) l.get(1);
+                Integer length = (Integer) l.get(2);
+                String source = (String) l.get(3);
+                progs.add(new SimpleList(quality, offset, length, source));
+              }
+          }
+      }
+    catch (ClassCastException cce)
+      {
+        if (Configuration.DEBUG)
+          log.log(Level.FINE, "bad program list", cce);
+        throw new IllegalArgumentException("invalid program list");
+      }
+    try
+      {
+        list = (List) attrib.get(OTHER_SOURCES);
+        if (Configuration.DEBUG)
+          log.fine("list=" + String.valueOf(list));
+        if (list != null)
+          {
+            other.clear();
+            for (Iterator it = list.iterator(); it.hasNext();)
+              {
+                EntropySource src = (EntropySource) it.next();
+                if (Configuration.DEBUG)
+                  log.fine("src=" + src);
+                if (src == null)
+                  throw new NullPointerException("null source in source list");
+                other.add(src);
+              }
+          }
+      }
+    catch (ClassCastException cce)
+      {
+        throw new IllegalArgumentException("invalid source list");
+      }
+
+    try
+      {
+        Boolean block = (Boolean) attrib.get(BLOCKING);
+        if (block != null)
+          blocking = block.booleanValue();
+        else
+          blocking = true;
+      }
+    catch (ClassCastException cce)
+      {
+        throw new IllegalArgumentException("invalid blocking parameter");
+      }
+    poller = new Poller(files, urls, progs, other, this);
+    try
+      {
+        fillBlock();
+      }
+    catch (LimitReachedException lre)
+      {
+        throw new RuntimeException("bootstrapping CSPRNG failed");
+      }
+  }
+
+  public void fillBlock() throws LimitReachedException
+  {
+    if (Configuration.DEBUG)
+      log.fine("fillBlock");
+    if (getQuality() < 100.0)
+      {
+        if (Configuration.DEBUG)
+          log.fine("doing slow poll");
+        slowPoll();
+      }
+    do
+      {
+        fastPoll();
+        mixRandomPool();
+      }
+    while (mixCount < MIX_COUNT);
+    if (! x917init || x917count >= X917_LIFETIME)
+      {
+        mixRandomPool(pool);
+        Map attr = new HashMap();
+        byte[] key = new byte[32];
+        System.arraycopy(pool, 0, key, 0, 32);
+        cipher.reset();
+        attr.put(IBlockCipher.KEY_MATERIAL, key);
+        try
+          {
+            cipher.init(attr);
+          }
+        catch (InvalidKeyException ike)
+          {
+            throw new Error(ike.toString());
+          }
+        mixRandomPool(pool);
+        generateX917(pool);
+        mixRandomPool(pool);
+        generateX917(pool);
+        if (x917init)
+          quality = 0.0;
+        x917init = true;
+        x917count = 0;
+      }
+    byte[] export = new byte[ALLOC_SIZE];
+    for (int i = 0; i < ALLOC_SIZE; i++)
+      export[i] = (byte)(pool[i] ^ 0xFF);
+    mixRandomPool();
+    mixRandomPool(export);
+    generateX917(export);
+    for (int i = 0; i < OUTPUT_SIZE; i++)
+      buffer[i] = (byte)(export[i] ^ export[i + OUTPUT_SIZE]);
+    Arrays.fill(export, (byte) 0);
+  }
+
+  /**
+   * Add an array of bytes into the randomness pool. Note that this method will
+   * <i>not</i> increment the pool's quality counter (this can only be done via
+   * a source provided to the setup method).
+   * 
+   * @param buf The byte array.
+   * @param off The offset from whence to start reading bytes.
+   * @param len The number of bytes to add.
+   * @throws ArrayIndexOutOfBoundsException If <i>off</i> or <i>len</i> are
+   *           out of the range of <i>buf</i>.
+   */
+  public synchronized void addRandomBytes(byte[] buf, int off, int len)
+  {
+    if (off < 0 || len < 0 || off + len > buf.length)
+      throw new ArrayIndexOutOfBoundsException();
+    if (Configuration.DEBUG)
+      {
+        log.fine("adding random bytes:");
+        log.fine(Util.toString(buf, off, len));
+      }
+    final int count = off + len;
+    for (int i = off; i < count; i++)
+      {
+        pool[index++] ^= buf[i];
+        if (index == pool.length)
+          {
+            mixRandomPool();
+            index = 0;
+          }
+      }
+  }
+
+  /**
+   * Add a single random byte to the randomness pool. Note that this method will
+   * <i>not</i> increment the pool's quality counter (this can only be done via
+   * a source provided to the setup method).
+   * 
+   * @param b The byte to add.
+   */
+  public synchronized void addRandomByte(byte b)
+  {
+    if (Configuration.DEBUG)
+      log.fine("adding byte " + Integer.toHexString(b));
+    pool[index++] ^= b;
+    if (index >= pool.length)
+      {
+        mixRandomPool();
+        index = 0;
+      }
+  }
+
+  synchronized void addQuality(double quality)
+  {
+    if (Configuration.DEBUG)
+      log.fine("adding quality " + quality);
+    if (this.quality < 100)
+      this.quality += quality;
+    if (Configuration.DEBUG)
+      log.fine("quality now " + this.quality);
+  }
+
+  synchronized double getQuality()
+  {
+    return quality;
+  }
+
+  /**
+   * The mix operation. This method will, for every 20-byte block in the random
+   * pool, hash that block, the previous 20 bytes, and the next 44 bytes with
+   * SHA-1, writing the result back into that block.
+   */
+  private void mixRandomPool(byte[] buf)
+  {
+    int hashSize = hash.hashSize();
+    for (int i = 0; i < buf.length; i += hashSize)
+      {
+        // First update the bytes [p-19..p-1].
+        if (i == 0)
+          hash.update(buf, buf.length - hashSize, hashSize);
+        else
+          hash.update(buf, i - hashSize, hashSize);
+        // Now the next 64 bytes.
+        if (i + 64 < buf.length)
+          hash.update(buf, i, 64);
+        else
+          {
+            hash.update(buf, i, buf.length - i);
+            hash.update(buf, 0, 64 - (buf.length - i));
+          }
+        byte[] digest = hash.digest();
+        System.arraycopy(digest, 0, buf, i, hashSize);
+      }
+  }
+
+  private void mixRandomPool()
+  {
+    mixRandomPool(pool);
+    mixCount++;
+  }
+
+  private void generateX917(byte[] buf)
+  {
+    int off = 0;
+    for (int i = 0; i < buf.length; i += X917_POOL_SIZE)
+      {
+        int copy = Math.min(buf.length - i, X917_POOL_SIZE);
+        for (int j = 0; j < copy; j++)
+          x917pool[j] ^= pool[off + j];
+        cipher.encryptBlock(x917pool, 0, x917pool, 0);
+        System.arraycopy(x917pool, 0, buf, off, copy);
+        cipher.encryptBlock(x917pool, 0, x917pool, 0);
+        off += copy;
+        x917count++;
+      }
+  }
+
+  /**
+   * Add random data always immediately available into the random pool, such as
+   * the values of the eight asynchronous counters, the current time, the
+   * current memory usage, the calling thread name, and the current stack trace.
+   * <p>
+   * This method does not alter the quality counter, and is provided more to
+   * maintain randomness, not to seriously improve the current random state.
+   */
+  private void fastPoll()
+  {
+    byte b = 0;
+    for (int i = 0; i < SPINNER_COUNT; i++)
+      b ^= SPINNERS[i].counter;
+    addRandomByte(b);
+    addRandomByte((byte) System.currentTimeMillis());
+    addRandomByte((byte) Runtime.getRuntime().freeMemory());
+    String s = Thread.currentThread().getName();
+    if (s != null)
+      {
+        byte[] buf = s.getBytes();
+        addRandomBytes(buf, 0, buf.length);
+      }
+    ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
+    PrintStream pout = new PrintStream(bout);
+    Throwable t = new Throwable();
+    t.printStackTrace(pout);
+    pout.flush();
+    byte[] buf = bout.toByteArray();
+    addRandomBytes(buf, 0, buf.length);
+  }
+
+  private void slowPoll() throws LimitReachedException
+  {
+    if (Configuration.DEBUG)
+      log.fine("poller is alive? "
+               + (pollerThread == null ? false : pollerThread.isAlive()));
+    if (pollerThread == null || ! pollerThread.isAlive())
+      {
+        boolean interrupted = false;
+        pollerThread = new Thread(poller);
+        pollerThread.setDaemon(true);
+        pollerThread.setPriority(Thread.NORM_PRIORITY - 1);
+        pollerThread.start();
+        if (blocking)
+          try
+            {
+              pollerThread.join();
+            }
+          catch (InterruptedException ie)
+            {
+              interrupted = true;
+            }
+        // If the full slow poll has completed after we waited for it,
+        // and there in insufficient randomness, throw an exception.
+        if (! interrupted && blocking && quality < 100.0)
+          {
+            if (Configuration.DEBUG)
+              log.fine("insufficient quality: " + quality);
+            throw new LimitReachedException("insufficient randomness was polled");
+          }
+      }
+  }
+
+  protected void finalize() throws Throwable
+  {
+    if (poller != null && pollerThread != null && pollerThread.isAlive())
+      {
+        pollerThread.interrupt();
+        poller.stopUpdating();
+        pollerThread.interrupt();
+      }
+    Arrays.fill(pool, (byte) 0);
+    Arrays.fill(x917pool, (byte) 0);
+    Arrays.fill(buffer, (byte) 0);
+  }
+
+  /**
+   * A simple thread that constantly updates a byte counter. This class is used
+   * in a group of lowest-priority threads and the values of their counters
+   * (updated in competition with all other threads) is used as a source of
+   * entropy bits.
+   */
+  private static class Spinner
+      implements Runnable
+  {
+    protected byte counter;
+
+    private Spinner()
+    {
+    }
+
+    public void run()
+    {
+      while (true)
+        {
+          counter++;
+          try
+            {
+              Thread.sleep(100);
+            }
+          catch (InterruptedException ie)
+            {
+            }
+        }
+    }
+  }
+
+  private final class Poller
+      implements Runnable
+  {
+    private final List files;
+    private final List urls;
+    private final List progs;
+    private final List other;
+    private final CSPRNG pool;
+    private boolean running;
+
+    Poller(List files, List urls, List progs, List other, CSPRNG pool)
+    {
+      super();
+      this.files = Collections.unmodifiableList(files);
+      this.urls = Collections.unmodifiableList(urls);
+      this.progs = Collections.unmodifiableList(progs);
+      this.other = Collections.unmodifiableList(other);
+      this.pool = pool;
+    }
+
+    public void run()
+    {
+      running = true;
+      if (Configuration.DEBUG)
+        {
+          log.fine("files: " + files);
+          log.fine("URLs: " + urls);
+          log.fine("progs: " + progs);
+        }
+      Iterator files_it = files.iterator();
+      Iterator urls_it = urls.iterator();
+      Iterator prog_it = progs.iterator();
+      Iterator other_it = other.iterator();
+
+      while (files_it.hasNext() || urls_it.hasNext() || prog_it.hasNext()
+             || other_it.hasNext())
+        {
+          // There is enough random data. Go away.
+          if (pool.getQuality() >= 100.0 || ! running)
+            return;
+          if (files_it.hasNext())
+            try
+              {
+                List l = (List) files_it.next();
+                if (Configuration.DEBUG)
+                  log.fine(l.toString());
+                double qual = ((Double) l.get(0)).doubleValue();
+                int offset = ((Integer) l.get(1)).intValue();
+                int count = ((Integer) l.get(2)).intValue();
+                String src = (String) l.get(3);
+                InputStream in = new FileInputStream(src);
+                byte[] buf = new byte[count];
+                if (offset > 0)
+                  in.skip(offset);
+                int len = in.read(buf);
+                if (len >= 0)
+                  {
+                    pool.addRandomBytes(buf, 0, len);
+                    pool.addQuality(qual * ((double) len / (double) count));
+                  }
+                if (Configuration.DEBUG)
+                  log.fine("got " + len + " bytes from " + src);
+              }
+            catch (Exception x)
+              {
+                if (Configuration.DEBUG)
+                  log.throwing(this.getClass().getName(), "run", x);
+              }
+          if (pool.getQuality() >= 100.0 || ! running)
+            return;
+          if (urls_it.hasNext())
+            try
+              {
+                List l = (List) urls_it.next();
+                if (Configuration.DEBUG)
+                  log.fine(l.toString());
+                double qual = ((Double) l.get(0)).doubleValue();
+                int offset = ((Integer) l.get(1)).intValue();
+                int count = ((Integer) l.get(2)).intValue();
+                URL src = (URL) l.get(3);
+                InputStream in = src.openStream();
+                byte[] buf = new byte[count];
+                if (offset > 0)
+                  in.skip(offset);
+                int len = in.read(buf);
+                if (len >= 0)
+                  {
+                    pool.addRandomBytes(buf, 0, len);
+                    pool.addQuality(qual * ((double) len / (double) count));
+                  }
+                if (Configuration.DEBUG)
+                  log.fine("got " + len + " bytes from " + src);
+              }
+            catch (Exception x)
+              {
+                if (Configuration.DEBUG)
+                  log.throwing(this.getClass().getName(), "run", x);
+              }
+          if (pool.getQuality() >= 100.0 || ! running)
+            return;
+          Process proc = null;
+          if (prog_it.hasNext())
+            try
+              {
+                List l = (List) prog_it.next();
+                if (Configuration.DEBUG)
+                  log.finer(l.toString());
+                double qual = ((Double) l.get(0)).doubleValue();
+                int offset = ((Integer) l.get(1)).intValue();
+                int count = ((Integer) l.get(2)).intValue();
+                String src = (String) l.get(3);
+                proc = null;
+                proc = Runtime.getRuntime().exec(src);
+                InputStream in = proc.getInputStream();
+                byte[] buf = new byte[count];
+                if (offset > 0)
+                  in.skip(offset);
+                int len = in.read(buf);
+                if (len >= 0)
+                  {
+                    pool.addRandomBytes(buf, 0, len);
+                    pool.addQuality(qual * ((double) len / (double) count));
+                  }
+                proc.destroy();
+                proc.waitFor();
+                if (Configuration.DEBUG)
+                  log.fine("got " + len + " bytes from " + src);
+              }
+            catch (Exception x)
+              {
+                if (Configuration.DEBUG)
+                  log.throwing(this.getClass().getName(), "run", x);
+                try
+                  {
+                    if (proc != null)
+                      {
+                        proc.destroy();
+                        proc.waitFor();
+                      }
+                  }
+                catch (Exception ignored)
+                  {
+                  }
+              }
+          if (pool.getQuality() >= 100.0 || ! running)
+            return;
+          if (other_it.hasNext())
+            try
+              {
+                EntropySource src = (EntropySource) other_it.next();
+                byte[] buf = src.nextBytes();
+                if (pool == null)
+                  return;
+                pool.addRandomBytes(buf, 0, buf.length);
+                pool.addQuality(src.quality());
+                if (Configuration.DEBUG)
+                  log.fine("got " + buf.length + " bytes from " + src);
+              }
+            catch (Exception x)
+              {
+                if (Configuration.DEBUG)
+                  log.throwing(this.getClass().getName(), "run", x);
+              }
+        }
+    }
+
+    public void stopUpdating()
+    {
+      running = false;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/prng/Fortuna.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,349 @@
+/* Fortuna.java -- The Fortuna PRNG.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.prng;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.prng.BasePRNG;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.prng.RandomEvent;
+import gnu.java.security.prng.RandomEventListener;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * The Fortuna continuously-seeded pseudo-random number generator. This
+ * generator is composed of two major pieces: the entropy accumulator and the
+ * generator function. The former takes in random bits and incorporates them
+ * into the generator's state. The latter takes this base entropy and generates
+ * pseudo-random bits from it.
+ * <p>
+ * There are some things users of this class <em>must</em> be aware of:
+ * <dl>
+ * <dt>Adding Random Data</dt>
+ * <dd>This class does not do any polling of random sources, but rather
+ * provides an interface for adding random events. Applications that use this
+ * code <em>must</em> provide this mechanism. We use this design because an
+ * application writer who knows the system he is targeting is in a better
+ * position to judge what random data is available.</dd>
+ * <dt>Storing the Seed</dt>
+ * <dd>This class implements {@link Serializable} in such a way that it writes
+ * a 64 byte seed to the stream, and reads it back again when being
+ * deserialized. This is the extent of seed file management, however, and those
+ * using this class are encouraged to think deeply about when, how often, and
+ * where to store the seed.</dd>
+ * </dl>
+ * <p>
+ * <b>References:</b>
+ * <ul>
+ * <li>Niels Ferguson and Bruce Schneier, <i>Practical Cryptography</i>, pp.
+ * 155--184. Wiley Publishing, Indianapolis. (2003 Niels Ferguson and Bruce
+ * Schneier). ISBN 0-471-22357-3.</li>
+ * </ul>
+ */
+public class Fortuna
+    extends BasePRNG
+    implements Serializable, RandomEventListener
+{
+  private static final long serialVersionUID = 0xFACADE;
+  private static final int SEED_FILE_SIZE = 64;
+  private static final int NUM_POOLS = 32;
+  private static final int MIN_POOL_SIZE = 64;
+  private final Generator generator;
+  private final IMessageDigest[] pools;
+  private long lastReseed;
+  private int pool;
+  private int pool0Count;
+  private int reseedCount;
+  public static final String SEED = "gnu.crypto.prng.fortuna.seed";
+
+  public Fortuna()
+  {
+    super(Registry.FORTUNA_PRNG);
+    generator = new Generator(CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER),
+                              HashFactory.getInstance(Registry.SHA256_HASH));
+    pools = new IMessageDigest[NUM_POOLS];
+    for (int i = 0; i < NUM_POOLS; i++)
+      pools[i] = HashFactory.getInstance(Registry.SHA256_HASH);
+    lastReseed = 0;
+    pool = 0;
+    pool0Count = 0;
+    buffer = new byte[256];
+  }
+
+  public void setup(Map attributes)
+  {
+    lastReseed = 0;
+    reseedCount = 0;
+    pool = 0;
+    pool0Count = 0;
+    generator.init(attributes);
+    try
+      {
+        fillBlock();
+      }
+    catch (LimitReachedException shouldNotHappen)
+      {
+        throw new RuntimeException(shouldNotHappen);
+      }
+  }
+
+  public void fillBlock() throws LimitReachedException
+  {
+    if (pool0Count >= MIN_POOL_SIZE
+        && System.currentTimeMillis() - lastReseed > 100)
+      {
+        reseedCount++;
+        byte[] seed = new byte[0];
+        for (int i = 0; i < NUM_POOLS; i++)
+          if (reseedCount % (1 << i) == 0)
+            generator.addRandomBytes(pools[i].digest());
+        lastReseed = System.currentTimeMillis();
+        pool0Count = 0;
+      }
+    generator.nextBytes(buffer);
+  }
+
+  public void addRandomByte(byte b)
+  {
+    pools[pool].update(b);
+    if (pool == 0)
+      pool0Count++;
+    pool = (pool + 1) % NUM_POOLS;
+  }
+
+  public void addRandomBytes(byte[] buf, int offset, int length)
+  {
+    pools[pool].update(buf, offset, length);
+    if (pool == 0)
+      pool0Count += length;
+    pool = (pool + 1) % NUM_POOLS;
+  }
+
+  public void addRandomEvent(RandomEvent event)
+  {
+    if (event.getPoolNumber() < 0 || event.getPoolNumber() >= pools.length)
+      throw new IllegalArgumentException("pool number out of range: "
+                                         + event.getPoolNumber());
+    pools[event.getPoolNumber()].update(event.getSourceNumber());
+    pools[event.getPoolNumber()].update((byte) event.getData().length);
+    pools[event.getPoolNumber()].update(event.getData());
+    if (event.getPoolNumber() == 0)
+      pool0Count += event.getData().length;
+  }
+
+  // Reading and writing this object is equivalent to storing and retrieving
+  // the seed.
+
+  private void writeObject(ObjectOutputStream out) throws IOException
+  {
+    byte[] seed = new byte[SEED_FILE_SIZE];
+    try
+      {
+        generator.nextBytes(seed);
+      }
+    catch (LimitReachedException shouldNeverHappen)
+      {
+        throw new Error(shouldNeverHappen);
+      }
+    out.write(seed);
+  }
+
+  private void readObject(ObjectInputStream in) throws IOException
+  {
+    byte[] seed = new byte[SEED_FILE_SIZE];
+    in.readFully(seed);
+    generator.addRandomBytes(seed);
+  }
+
+  /**
+   * The Fortuna generator function. The generator is a PRNG in its own right;
+   * Fortuna itself is basically a wrapper around this generator that manages
+   * reseeding in a secure way.
+   */
+  public static class Generator
+      extends BasePRNG
+      implements Cloneable
+  {
+    private static final int LIMIT = 1 << 20;
+    private final IBlockCipher cipher;
+    private final IMessageDigest hash;
+    private final byte[] counter;
+    private final byte[] key;
+    private boolean seeded;
+
+    public Generator(final IBlockCipher cipher, final IMessageDigest hash)
+    {
+      super(Registry.FORTUNA_GENERATOR_PRNG);
+      this.cipher = cipher;
+      this.hash = hash;
+      counter = new byte[cipher.defaultBlockSize()];
+      buffer = new byte[cipher.defaultBlockSize()];
+      int keysize = 0;
+      for (Iterator it = cipher.keySizes(); it.hasNext();)
+        {
+          int ks = ((Integer) it.next()).intValue();
+          if (ks > keysize)
+            keysize = ks;
+          if (keysize >= 32)
+            break;
+        }
+      key = new byte[keysize];
+    }
+
+    public byte nextByte()
+    {
+      byte[] b = new byte[1];
+      nextBytes(b, 0, 1);
+      return b[0];
+    }
+
+    public void nextBytes(byte[] out, int offset, int length)
+    {
+      if (! seeded)
+        throw new IllegalStateException("generator not seeded");
+      int count = 0;
+      do
+        {
+          int amount = Math.min(LIMIT, length - count);
+          try
+            {
+              super.nextBytes(out, offset + count, amount);
+            }
+          catch (LimitReachedException shouldNeverHappen)
+            {
+              throw new Error(shouldNeverHappen);
+            }
+          count += amount;
+          for (int i = 0; i < key.length; i += counter.length)
+            {
+              fillBlock();
+              int l = Math.min(key.length - i, cipher.currentBlockSize());
+              System.arraycopy(buffer, 0, key, i, l);
+            }
+          resetKey();
+        }
+      while (count < length);
+      fillBlock();
+      ndx = 0;
+    }
+
+    public void addRandomByte(byte b)
+    {
+      addRandomBytes(new byte[] { b });
+    }
+
+    public void addRandomBytes(byte[] seed, int offset, int length)
+    {
+      hash.update(key);
+      hash.update(seed, offset, length);
+      byte[] newkey = hash.digest();
+      System.arraycopy(newkey, 0, key, 0, Math.min(key.length, newkey.length));
+      resetKey();
+      incrementCounter();
+      seeded = true;
+    }
+
+    public void fillBlock()
+    {
+      if (! seeded)
+        throw new IllegalStateException("generator not seeded");
+      cipher.encryptBlock(counter, 0, buffer, 0);
+      incrementCounter();
+    }
+
+    public void setup(Map attributes)
+    {
+      seeded = false;
+      Arrays.fill(key, (byte) 0);
+      Arrays.fill(counter, (byte) 0);
+      byte[] seed = (byte[]) attributes.get(SEED);
+      if (seed != null)
+        addRandomBytes(seed);
+      fillBlock();
+    }
+
+    /**
+     * Resets the cipher's key. This is done after every reseed, which combines
+     * the old key and the seed, and processes that throigh the hash function.
+     */
+    private void resetKey()
+    {
+      try
+        {
+          cipher.reset();
+          cipher.init(Collections.singletonMap(IBlockCipher.KEY_MATERIAL, key));
+        }
+      // We expect to never get an exception here.
+      catch (InvalidKeyException ike)
+        {
+          throw new Error(ike);
+        }
+      catch (IllegalArgumentException iae)
+        {
+          throw new Error(iae);
+        }
+    }
+
+    /**
+     * Increment `counter' as a sixteen-byte little-endian unsigned integer by
+     * one.
+     */
+    private void incrementCounter()
+    {
+      for (int i = 0; i < counter.length; i++)
+        {
+          counter[i]++;
+          if (counter[i] != 0)
+            break;
+        }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/prng/ICMGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,297 @@
+/* ICMGenerator.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.prng;
+
+import gnu.java.security.Registry;
+import gnu.java.security.prng.BasePRNG;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Counter Mode is a way to define a pseudorandom keystream generator using a
+ * block cipher. The keystream can be used for additive encryption, key
+ * derivation, or any other application requiring pseudorandom data.
+ * <p>
+ * In ICM, the keystream is logically broken into segments. Each segment is
+ * identified with a segment index, and the segments have equal lengths. This
+ * segmentation makes ICM especially appropriate for securing packet-based
+ * protocols.
+ * <p>
+ * This implementation adheres to the definition of the ICM keystream generation
+ * function that allows for any symetric key block cipher algorithm
+ * (initialisation parameter <code>gnu.crypto.prng.icm.cipher.name</code>
+ * taken to be an instance of {@link java.lang.String}) to be used. If such a
+ * parameter is not defined/included in the initialisation <code>Map</code>,
+ * then the "Rijndael" algorithm is used. Furthermore, if the initialisation
+ * parameter <code>gnu.crypto.cipher.block.size</code> (taken to be a instance
+ * of {@link java.lang.Integer}) is missing or undefined in the initialisation
+ * <code>Map</code>, then the cipher's <em>default</em> block size is used.
+ * <p>
+ * The practical limits and constraints of such generator are:
+ * <ul>
+ * <li>The number of blocks in any segment <b>MUST NOT</b> exceed <code>
+ *    256 ** BLOCK_INDEX_LENGTH</code>.
+ * The number of segments <b>MUST NOT</b> exceed
+ * <code>256 ** SEGMENT_INDEX_LENGTH</code>. These restrictions ensure the
+ * uniqueness of each block cipher input.</li>
+ * <li>Each segment contains <code>SEGMENT_LENGTH</code> octets; this value
+ * <b>MUST NOT</b> exceed the value <code>(256 ** BLOCK_INDEX_LENGTH) *
+ *    BLOCK_LENGTH</code>.</li>
+ * <li>The sum of <code>SEGMENT_INDEX_LENGTH</code> and
+ * <code>BLOCK_INDEX_LENGTH</code> <b>MUST NOT</b> exceed <code>BLOCK_LENGTH
+ *    / 2</code>.
+ * This requirement protects the ICM keystream generator from potentially
+ * failing to be pseudorandom.</li>
+ * </ul>
+ * <p>
+ * <b>NOTE</b>: Rijndael is used as the default symmetric key block cipher
+ * algorithm because, with its default block and key sizes, it is the AES. Yet
+ * being Rijndael, the algorithm offers more versatile block and key sizes which
+ * may prove to be useful for generating <em>longer</em> key streams.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-icm-00.txt">
+ * Integer Counter Mode</a>, David A. McGrew.</li>
+ * </ol>
+ */
+public class ICMGenerator
+    extends BasePRNG
+    implements Cloneable
+{
+  /** Property name of underlying block cipher for this ICM generator. */
+  public static final String CIPHER = "gnu.crypto.prng.icm.cipher.name";
+  /** Property name of ICM's block index length. */
+  public static final String BLOCK_INDEX_LENGTH =
+      "gnu.crypto.prng.icm.block.index.length";
+  /** Property name of ICM's segment index length. */
+  public static final String SEGMENT_INDEX_LENGTH =
+      "gnu.crypto.prng.icm.segment.index.length";
+  /** Property name of ICM's offset. */
+  public static final String OFFSET = "gnu.crypto.prng.icm.offset";
+  /** Property name of ICM's segment index. */
+  public static final String SEGMENT_INDEX = "gnu.crypto.prng.icm.segment.index";
+  /** The integer value 256 as a BigInteger. */
+  private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256");
+  /** The underlying cipher implementation. */
+  private IBlockCipher cipher;
+  /** This keystream block index length in bytes. */
+  private int blockNdxLength = -1;
+  /** This keystream segment index length in bytes. */
+  private int segmentNdxLength = -1;
+  /** The index of the next block for a given keystream segment. */
+  private BigInteger blockNdx = BigInteger.ZERO;
+  /** The segment index for this keystream. */
+  private BigInteger segmentNdx;
+  /** The initial counter for a given keystream segment. */
+  private BigInteger C0;
+
+  /** Trivial 0-arguments constructor. */
+  public ICMGenerator()
+  {
+    super(Registry.ICM_PRNG);
+  }
+
+  // Conceptually, ICM is a keystream generator that takes a secret key and a
+  // segment index as an input and then outputs a keystream segment. The
+  // segmentation lends itself to packet encryption, as each keystream segment
+  // can be used to encrypt a distinct packet.
+  //
+  // An ICM key consists of the block cipher key and an Offset. The Offset is
+  // an integer with BLOCK_LENGTH octets...
+  public void setup(Map attributes)
+  {
+    // find out which cipher algorithm to use
+    boolean newCipher = true;
+    String underlyingCipher = (String) attributes.get(CIPHER);
+    if (underlyingCipher == null)
+      if (cipher == null) // happy birthday
+        // ensure we have a reliable implementation of this cipher
+        cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER);
+      else
+        // we already have one. use it as is
+        newCipher = false;
+    else // ensure we have a reliable implementation of this cipher
+      cipher = CipherFactory.getInstance(underlyingCipher);
+
+    // find out what block size we should use it in
+    int cipherBlockSize = 0;
+    Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE);
+    if (bs != null)
+      cipherBlockSize = bs.intValue();
+    else
+      {
+        if (newCipher) // assume we'll use its default block size
+          cipherBlockSize = cipher.defaultBlockSize();
+        // else use as is
+      }
+    // get the key material
+    byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL);
+    if (key == null)
+      throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
+    // now initialise the cipher
+    HashMap map = new HashMap();
+    if (cipherBlockSize != 0) // only needed if new or changed
+      map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize));
+    map.put(IBlockCipher.KEY_MATERIAL, key);
+    try
+      {
+        cipher.init(map);
+      }
+    catch (InvalidKeyException x)
+      {
+        throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
+      }
+    // at this point we have an initialised (new or otherwise) cipher
+    // ensure that remaining params make sense
+    cipherBlockSize = cipher.currentBlockSize();
+    BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize);
+    // offset, like the underlying cipher key is not cloneable
+    // always look for it and throw an exception if it's not there
+    Object obj = attributes.get(OFFSET);
+    // allow either a byte[] or a BigInteger
+    BigInteger r;
+    if (obj instanceof BigInteger)
+      r = (BigInteger) obj;
+    else // assume byte[]. should be same length as cipher block size
+      {
+        byte[] offset = (byte[]) obj;
+        if (offset.length != cipherBlockSize)
+          throw new IllegalArgumentException(OFFSET);
+        r = new BigInteger(1, offset);
+      }
+    int wantBlockNdxLength = -1; // number of octets in the block index
+    Integer i = (Integer) attributes.get(BLOCK_INDEX_LENGTH);
+    if (i != null)
+      {
+        wantBlockNdxLength = i.intValue();
+        if (wantBlockNdxLength < 1)
+          throw new IllegalArgumentException(BLOCK_INDEX_LENGTH);
+      }
+    int wantSegmentNdxLength = -1; // number of octets in the segment index
+    i = (Integer) attributes.get(SEGMENT_INDEX_LENGTH);
+    if (i != null)
+      {
+        wantSegmentNdxLength = i.intValue();
+        if (wantSegmentNdxLength < 1)
+          throw new IllegalArgumentException(SEGMENT_INDEX_LENGTH);
+      }
+    // if both are undefined check if it's a reuse
+    if ((wantBlockNdxLength == -1) && (wantSegmentNdxLength == -1))
+      {
+        if (blockNdxLength == -1) // new instance
+          throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", "
+                                             + SEGMENT_INDEX_LENGTH);
+        // else reuse old values
+      }
+    else // only one is undefined, set it to BLOCK_LENGTH/2 minus the other
+      {
+        int limit = cipherBlockSize / 2;
+        if (wantBlockNdxLength == -1)
+          wantBlockNdxLength = limit - wantSegmentNdxLength;
+        else if (wantSegmentNdxLength == -1)
+          wantSegmentNdxLength = limit - wantBlockNdxLength;
+        else if ((wantSegmentNdxLength + wantBlockNdxLength) > limit)
+          throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", "
+                                             + SEGMENT_INDEX_LENGTH);
+        // save new values
+        blockNdxLength = wantBlockNdxLength;
+        segmentNdxLength = wantSegmentNdxLength;
+      }
+    // get the segment index as a BigInteger
+    BigInteger s = (BigInteger) attributes.get(SEGMENT_INDEX);
+    if (s == null)
+      {
+        if (segmentNdx == null) // segment index was never set
+          throw new IllegalArgumentException(SEGMENT_INDEX);
+        // reuse; check if still valid
+        if (segmentNdx.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0)
+          throw new IllegalArgumentException(SEGMENT_INDEX);
+      }
+    else
+      {
+        if (s.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0)
+          throw new IllegalArgumentException(SEGMENT_INDEX);
+        segmentNdx = s;
+      }
+    // The initial counter of the keystream segment with segment index s is
+    // defined as follows, where r denotes the Offset:
+    //
+    // C[0] = (s * (256^BLOCK_INDEX_LENGTH) + r) modulo (256^BLOCK_LENGTH)
+    C0 = segmentNdx.multiply(TWO_FIFTY_SIX.pow(blockNdxLength))
+                   .add(r).modPow(BigInteger.ONE, counterRange);
+  }
+
+  public void fillBlock() throws LimitReachedException
+  {
+    if (C0 == null)
+      throw new IllegalStateException();
+    if (blockNdx.compareTo(TWO_FIFTY_SIX.pow(blockNdxLength)) >= 0)
+      throw new LimitReachedException();
+    int cipherBlockSize = cipher.currentBlockSize();
+    BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize);
+    // encrypt the counter for the current blockNdx
+    // C[i] = (C[0] + i) modulo (256^BLOCK_LENGTH).
+    BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange);
+    buffer = Ci.toByteArray();
+    int limit = buffer.length;
+    if (limit < cipherBlockSize)
+      {
+        byte[] data = new byte[cipherBlockSize];
+        System.arraycopy(buffer, 0, data, cipherBlockSize - limit, limit);
+        buffer = data;
+      }
+    else if (limit > cipherBlockSize)
+      {
+        byte[] data = new byte[cipherBlockSize];
+        System.arraycopy(buffer, limit - cipherBlockSize, data, 0,
+                         cipherBlockSize);
+        buffer = data;
+      }
+    cipher.encryptBlock(buffer, 0, buffer, 0);
+    blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/prng/IPBE.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,81 @@
+/* IPBE.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.prng;
+
+/**
+ * Trivial interface to group Password-based encryption property names and
+ * constants.
+ */
+public interface IPBE
+{
+  /**
+   * Property name for the iteration count in a PBE algorithm. The property
+   * associated with this is expected to be an {@link Integer}.
+   */
+  String ITERATION_COUNT = "gnu.crypto.pbe.iteration.count";
+
+  /**
+   * Property name for the password in a PBE algorithm. The property associated
+   * with this is expected to be a char array.
+   */
+  String PASSWORD = "gnu.crypto.pbe.password";
+
+  /**
+   * Property name for the password character encoding in a PBE algorithm. The
+   * property associated with this is expected to be a String denoting a valid
+   * character-encoding name. If this property is not set, and a password is
+   * used, then {@link #DEFAULT_PASSWORD_ENCODING} will be used when converting
+   * the password character(s) to bytes.
+   */
+  String PASSWORD_ENCODING = "gnu.crypto.pbe.password.encoding";
+
+  /**
+   * Property name for the salt in a PBE algorithm. The property associated
+   * with this is expected to be a byte array.
+   */
+  String SALT = "gnu.crypto.pbe.salt";
+
+  /**
+   * The default character set encoding name to be used if (a) a password is
+   * to be used as the source for a PBE-based Key Derivation Function (KDF) and
+   * (b) no character set encoding name was specified among the attributes used
+   * to initialize the instance.
+   */
+  String DEFAULT_PASSWORD_ENCODING = "UTF-8";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/prng/PBKDF2.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,184 @@
+/* PBKDF2.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.prng;
+
+import gnu.java.security.prng.BasePRNG;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.mac.HMac;
+import gnu.javax.crypto.mac.IMac;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An implementation of the <i>key derivation function</i> KDF2 from PKCS #5:
+ * Password-Based Cryptography (<b>PBE</b>). This KDF is essentially a way to
+ * transform a password and a salt into a stream of random bytes, which may then
+ * be used to initialize a cipher or a MAC.
+ * <p>
+ * This version uses a MAC as its pseudo-random function, and the password is
+ * used as the key.
+ * <p>
+ * References:
+ * <ol>
+ * <li>B. Kaliski, <a href="http://www.ietf.org/rfc/rfc2898.txt">RFC 2898:
+ * Password-Based Cryptography Specification, Version 2.0</a></li>
+ * </ol>
+ */
+public class PBKDF2
+    extends BasePRNG
+    implements Cloneable
+{
+  /**
+   * The bytes fed into the MAC. This is initially the concatenation of the salt
+   * and the block number.
+   */
+  private byte[] in;
+  /** The iteration count. */
+  private int iterationCount;
+  /** The salt. */
+  private byte[] salt;
+  /** The MAC (the pseudo-random function we use). */
+  private IMac mac;
+  /** The number of hLen-sized blocks generated. */
+  private long count;
+
+  /**
+   * Creates a new PBKDF2 object. The argument is the MAC that will serve as the
+   * pseudo-random function. The MAC does not need to be initialized.
+   * 
+   * @param mac The pseudo-random function.
+   */
+  public PBKDF2(IMac mac)
+  {
+    super("PBKDF2-" + mac.name());
+    this.mac = mac;
+    iterationCount = -1;
+  }
+
+  public void setup(Map attributes)
+  {
+    Map macAttrib = new HashMap();
+    macAttrib.put(HMac.USE_WITH_PKCS5_V2, Boolean.TRUE);
+    byte[] s = (byte[]) attributes.get(IPBE.SALT);
+    if (s == null)
+      {
+        if (salt == null)
+          throw new IllegalArgumentException("no salt specified");
+        // Otherwise re-use.
+      }
+    else
+      salt = s;
+    byte[] macKeyMaterial;
+    char[] password = (char[]) attributes.get(IPBE.PASSWORD);
+    if (password != null)
+      {
+        String encoding = (String) attributes.get(IPBE.PASSWORD_ENCODING);
+        if (encoding == null || encoding.trim().length() == 0)
+          encoding = IPBE.DEFAULT_PASSWORD_ENCODING;
+        else
+          encoding = encoding.trim();
+        try
+          {
+            macKeyMaterial = new String(password).getBytes(encoding);
+          }
+        catch (UnsupportedEncodingException uee)
+          {
+            throw new IllegalArgumentException("Unknown or unsupported encoding: "
+                                               + encoding, uee);
+          }
+      }
+    else
+      macKeyMaterial = (byte[]) attributes.get(IMac.MAC_KEY_MATERIAL);
+
+    if (macKeyMaterial != null)
+      macAttrib.put(IMac.MAC_KEY_MATERIAL, macKeyMaterial);
+    else if (! initialised)
+      throw new IllegalArgumentException(
+          "Neither password nor key-material were specified");
+    // otherwise re-use previous password/key-material
+    try
+      {
+        mac.init(macAttrib);
+      }
+    catch (Exception x)
+      {
+        throw new IllegalArgumentException(x.getMessage());
+      }
+    Integer ic = (Integer) attributes.get(IPBE.ITERATION_COUNT);
+    if (ic != null)
+      iterationCount = ic.intValue();
+    if (iterationCount <= 0)
+      throw new IllegalArgumentException("bad iteration count");
+    count = 0L;
+    buffer = new byte[mac.macSize()];
+    try
+      {
+        fillBlock();
+      }
+    catch (LimitReachedException x)
+      {
+        throw new Error(x.getMessage());
+      }
+  }
+
+  public void fillBlock() throws LimitReachedException
+  {
+    if (++count > ((1L << 32) - 1))
+      throw new LimitReachedException();
+    Arrays.fill(buffer, (byte) 0x00);
+    int limit = salt.length;
+    in = new byte[limit + 4];
+    System.arraycopy(salt, 0, in, 0, salt.length);
+    in[limit++] = (byte)(count >>> 24);
+    in[limit++] = (byte)(count >>> 16);
+    in[limit++] = (byte)(count >>> 8);
+    in[limit  ] = (byte) count;
+    for (int i = 0; i < iterationCount; i++)
+      {
+        mac.reset();
+        mac.update(in, 0, in.length);
+        in = mac.digest();
+        for (int j = 0; j < buffer.length; j++)
+          buffer[j] ^= in[j];
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/prng/PRNGFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,115 @@
+/* PRNGFactory.java -- 
+   Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.prng;
+
+import gnu.java.security.Registry;
+import gnu.java.security.prng.IRandom;
+import gnu.javax.crypto.mac.HMacFactory;
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mac.MacFactory;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A Factory to instantiate pseudo random number generators.
+ */
+public class PRNGFactory
+    implements Registry
+{
+  /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+  private PRNGFactory()
+  {
+  }
+
+  /**
+   * Returns an instance of a padding algorithm given its name.
+   * 
+   * @param prng the case-insensitive name of the PRNG.
+   * @return an instance of the pseudo-random number generator.
+   * @exception InternalError if the implementation does not pass its self-
+   *              test.
+   */
+  public static IRandom getInstance(String prng)
+  {
+    if (prng == null)
+      return null;
+    prng = prng.trim();
+    IRandom result = null;
+    if (prng.equalsIgnoreCase(ARCFOUR_PRNG) || prng.equalsIgnoreCase(RC4_PRNG))
+      result = new ARCFour();
+    else if (prng.equalsIgnoreCase(ICM_PRNG))
+      result = new ICMGenerator();
+    else if (prng.equalsIgnoreCase(UMAC_PRNG))
+      result = new UMacGenerator();
+    else if (prng.toLowerCase().startsWith(PBKDF2_PRNG_PREFIX))
+      {
+        String macName = prng.substring(PBKDF2_PRNG_PREFIX.length());
+        IMac mac = MacFactory.getInstance(macName);
+        if (mac == null)
+          return null;
+        result = new PBKDF2(mac);
+      }
+
+    if (result != null)
+      return result;
+
+    return gnu.java.security.prng.PRNGFactory.getInstance(prng);
+  }
+
+  /**
+   * Returns a {@link Set} of names of padding algorithms supported by this
+   * <i>Factory</i>.
+   * 
+   * @return a {@link Set} of pseudo-random number generator algorithm names
+   *         (Strings).
+   */
+  public static Set getNames()
+  {
+    HashSet hs = new HashSet(gnu.java.security.prng.PRNGFactory.getNames());
+    hs.add(ICM_PRNG);
+    hs.add(UMAC_PRNG);
+    // add all hmac implementations as candidate PBKDF2 ones too
+    for (Iterator it = HMacFactory.getNames().iterator(); it.hasNext();)
+      hs.add(PBKDF2_PRNG_PREFIX + ((String) it.next()));
+    return Collections.unmodifiableSet(hs);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/prng/UMacGenerator.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,186 @@
+/* UMacGenerator.java -- 
+   Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.prng;
+
+import gnu.java.security.Registry;
+import gnu.java.security.prng.BasePRNG;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.security.InvalidKeyException;
+
+/**
+ * <i>KDF</i>s (Key Derivation Functions) are used to stretch user-supplied key
+ * material to specific size(s) required by high level cryptographic primitives.
+ * Described in the <A
+ * HREF="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">UMAC</A>
+ * paper, this function basically operates an underlying <em>symmetric key block
+ * cipher</em> instance in output feedback mode (OFB), as a <b>strong</b>
+ * pseudo-random number generator.
+ * <p>
+ * <code>UMacGenerator</code> requires an <em>index</em> parameter
+ * (initialisation parameter <code>gnu.crypto.prng.umac.kdf.index</code> taken
+ * to be an instance of {@link Integer} with a value between <code>0</code> and
+ * <code>255</code>). Using the same key, but different indices, generates
+ * different pseudorandom outputs.
+ * <p>
+ * This implementation generalises the definition of the
+ * <code>UmacGenerator</code> algorithm to allow for other than the AES
+ * symetric key block cipher algorithm (initialisation parameter
+ * <code>gnu.crypto.prng.umac.cipher.name</code> taken to be an instance of
+ * {@link String}). If such a parameter is not defined/included in the
+ * initialisation <code>Map</code>, then the "Rijndael" algorithm is used.
+ * Furthermore, if the initialisation parameter
+ * <code>gnu.crypto.cipher.block.size</code> (taken to be a instance of
+ * {@link Integer}) is missing or undefined in the initialisation
+ * <code>Map</code>, then the cipher's <em>default</em> block size is used.
+ * <p>
+ * <b>NOTE</b>: Rijndael is used as the default symmetric key block cipher
+ * algorithm because, with its default block and key sizes, it is the AES. Yet
+ * being Rijndael, the algorithm offers more versatile block and key sizes which
+ * may prove to be useful for generating "longer" key streams.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
+ * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
+ * </ol>
+ */
+public class UMacGenerator
+    extends BasePRNG
+    implements Cloneable
+{
+  /**
+   * Property name of the KDF <code>index</code> value to use in this
+   * instance. The value is taken to be an {@link Integer} less than
+   * <code>256</code>.
+   */
+  public static final String INDEX = "gnu.crypto.prng.umac.index";
+  /** The name of the underlying symmetric key block cipher algorithm. */
+  public static final String CIPHER = "gnu.crypto.prng.umac.cipher.name";
+  /** The generator's underlying block cipher. */
+  private IBlockCipher cipher;
+
+  /** Trivial 0-arguments constructor. */
+  public UMacGenerator()
+  {
+    super(Registry.UMAC_PRNG);
+  }
+
+  public void setup(Map attributes)
+  {
+    boolean newCipher = true;
+    String cipherName = (String) attributes.get(CIPHER);
+    if (cipherName == null)
+      if (cipher == null) // happy birthday
+        cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER);
+      else // we already have one. use it as is
+        newCipher = false;
+    else
+      cipher = CipherFactory.getInstance(cipherName);
+    // find out what block size we should use it in
+    int cipherBlockSize = 0;
+    Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE);
+    if (bs != null)
+      cipherBlockSize = bs.intValue();
+    else
+      {
+        if (newCipher) // assume we'll use its default block size
+          cipherBlockSize = cipher.defaultBlockSize();
+        // else use as is
+      }
+    // get the key material
+    byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL);
+    if (key == null)
+      throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
+
+    int keyLength = key.length;
+    // ensure that keyLength is valid for the chosen underlying cipher
+    boolean ok = false;
+    for (Iterator it = cipher.keySizes(); it.hasNext();)
+      {
+        ok = (keyLength == ((Integer) it.next()).intValue());
+        if (ok)
+          break;
+      }
+    if (! ok)
+      throw new IllegalArgumentException("key length");
+    // ensure that remaining params make sense
+    int index = -1;
+    Integer i = (Integer) attributes.get(INDEX);
+    if (i != null)
+      {
+        index = i.intValue();
+        if (index < 0 || index > 255)
+          throw new IllegalArgumentException(INDEX);
+      }
+    // now initialise the underlying cipher
+    Map map = new HashMap();
+    if (cipherBlockSize != 0) // only needed if new or changed
+      map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize));
+    map.put(IBlockCipher.KEY_MATERIAL, key);
+    try
+      {
+        cipher.init(map);
+      }
+    catch (InvalidKeyException x)
+      {
+        throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
+      }
+    buffer = new byte[cipher.currentBlockSize()];
+    buffer[cipher.currentBlockSize() - 1] = (byte) index;
+    try
+      {
+        fillBlock();
+      }
+    catch (LimitReachedException impossible)
+      {
+      }
+  }
+
+  public void fillBlock() throws LimitReachedException
+  {
+    cipher.encryptBlock(buffer, 0, buffer, 0);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/AuthInfo.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,129 @@
+/* AuthInfo.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Registry;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+/**
+ * A static class for creating {@link IAuthInfoProvider} providers. It
+ * transparently locates and uses any provider instances, based on the value
+ * assigned to the System property with the key
+ * <code>gnu.crypto.sasl.auth.info.provider.pkgs</code>. If more than one is
+ * specified they SHOULD be separated with a vertical bar character. Please note
+ * that the GNU provider is always added last to the list, disregarding whether
+ * it was mentioned or not in the value of that property, or if it that property
+ * was not defined.
+ */
+public class AuthInfo
+{
+  private static final ArrayList factories = new ArrayList();
+  static
+    {
+      IAuthInfoProviderFactory ours = new AuthInfoProviderFactory();
+      // if SASL_AUTH_INFO_PROVIDER_PKGS is defined then parse it
+      String clazz;
+      String pkgs = System.getProperty(Registry.SASL_AUTH_INFO_PROVIDER_PKGS,
+                                       null);
+      if (pkgs != null)
+        {
+          for (StringTokenizer st = new StringTokenizer(pkgs, "|"); st.hasMoreTokens();)
+            {
+              clazz = st.nextToken().trim();
+              if (! "gnu.javax.crypto.sasl".equals(clazz))
+                {
+                  clazz += ".AuthInfoProviderFactory";
+                  try
+                    {
+                      IAuthInfoProviderFactory factory =
+                          (IAuthInfoProviderFactory) Class.forName(clazz).newInstance();
+                      factories.add(factory);
+                    }
+                  catch (ClassCastException ignored)
+                    {
+                    }
+                  catch (ClassNotFoundException ignored)
+                    {
+                    }
+                  catch (InstantiationException ignored)
+                    {
+                    }
+                  catch (IllegalAccessException ignored)
+                    {
+                    }
+                }
+            }
+        }
+      // always add ours last; unless it's already there
+      if (!factories.contains(ours))
+        factories.add(ours);
+    }
+
+  /** Trivial constructor to enforce Singleton pattern. */
+  private AuthInfo()
+  {
+    super();
+  }
+
+  /**
+   * A convenience method to return the authentication information provider for
+   * a designated SASL mechnanism. It goes through all the installed provider
+   * factories, one at a time, and attempts to return a new instance of the
+   * provider for the designated mechanism. It stops at the first factory
+   * returning a non-null provider.
+   * 
+   * @param mechanism the name of a SASL mechanism.
+   * @return an implementation that provides {@link IAuthInfoProvider} for that
+   *         mechanism; or <code>null</code> if none found.
+   */
+  public static IAuthInfoProvider getProvider(String mechanism)
+  {
+    for (Iterator it = factories.iterator(); it.hasNext();)
+      {
+        IAuthInfoProviderFactory factory = (IAuthInfoProviderFactory) it.next();
+        IAuthInfoProvider result = factory.getInstance(mechanism);
+        if (result != null)
+          return result;
+      }
+    return null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,67 @@
+/* AuthInfoProviderFactory.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.crammd5.CramMD5AuthInfoProvider;
+import gnu.javax.crypto.sasl.plain.PlainAuthInfoProvider;
+import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider;
+
+/**
+ * The concrete SASL authentication information provider factory.
+ */
+public class AuthInfoProviderFactory
+    implements IAuthInfoProviderFactory
+{
+  // implicit 0-args constructor
+
+  public IAuthInfoProvider getInstance(String mechanism)
+  {
+    if (mechanism == null)
+      return null;
+    mechanism = mechanism.trim().toUpperCase();
+    if (mechanism.startsWith(Registry.SASL_SRP_MECHANISM))
+      return new SRPAuthInfoProvider();
+    if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM))
+      return new CramMD5AuthInfoProvider();
+    if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM))
+      return new PlainAuthInfoProvider();
+    return null;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/ClientFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,168 @@
+/* ClientFactory.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.anonymous.AnonymousClient;
+import gnu.javax.crypto.sasl.crammd5.CramMD5Client;
+import gnu.javax.crypto.sasl.plain.PlainClient;
+import gnu.javax.crypto.sasl.srp.SRPClient;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslClientFactory;
+import javax.security.sasl.SaslException;
+
+/**
+ * The implementation of {@link SaslClientFactory}.
+ */
+public class ClientFactory
+    implements SaslClientFactory
+{
+  // implicit 0-arguments constructor
+
+  public static final Set getNames()
+  {
+    return Collections.unmodifiableSet(new HashSet(Arrays.asList(getNamesInternal(null))));
+  }
+
+  private static final String[] getNamesInternal(Map props)
+  {
+    String[] all = new String[] {
+        Registry.SASL_SRP_MECHANISM,
+        Registry.SASL_CRAM_MD5_MECHANISM,
+        Registry.SASL_PLAIN_MECHANISM,
+        Registry.SASL_ANONYMOUS_MECHANISM };
+    if (props == null)
+      return all;
+    if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props))
+      return new String[0];
+    List result = new ArrayList(all.length);
+    for (int i = 0; i < all.length;)
+      result.add(all[i++]);
+    if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props))
+      result.remove(Registry.SASL_PLAIN_MECHANISM);
+    if (hasPolicy(Sasl.POLICY_NOACTIVE, props))
+      {
+        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
+        result.remove(Registry.SASL_PLAIN_MECHANISM);
+      }
+    if (hasPolicy(Sasl.POLICY_NODICTIONARY, props))
+      {
+        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
+        result.remove(Registry.SASL_PLAIN_MECHANISM);
+      }
+    if (hasPolicy(Sasl.POLICY_NOANONYMOUS, props))
+      {
+        result.remove(Registry.SASL_ANONYMOUS_MECHANISM);
+      }
+    if (hasPolicy(Sasl.POLICY_FORWARD_SECRECY, props))
+      {
+        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
+        result.remove(Registry.SASL_ANONYMOUS_MECHANISM);
+        result.remove(Registry.SASL_PLAIN_MECHANISM);
+      }
+    return (String[]) result.toArray(new String[0]);
+  }
+
+  public static final ClientMechanism getInstance(String mechanism)
+  {
+    if (mechanism == null)
+      return null;
+    mechanism = mechanism.trim().toUpperCase();
+    if (mechanism.equals(Registry.SASL_SRP_MECHANISM))
+      return new SRPClient();
+    if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM))
+      return new CramMD5Client();
+    if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM))
+      return new PlainClient();
+    if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM))
+      return new AnonymousClient();
+    return null;
+  }
+
+  public SaslClient createSaslClient(String[] mechanisms,
+                                     String authorisationID, String protocol,
+                                     String serverName, Map props,
+                                     CallbackHandler cbh) throws SaslException
+  {
+    ClientMechanism result = null;
+    String mechanism;
+    for (int i = 0; i < mechanisms.length; i++)
+      {
+        mechanism = mechanisms[i];
+        result = getInstance(mechanism);
+        if (result != null)
+          break;
+      }
+    if (result != null)
+      {
+        HashMap attributes = new HashMap();
+        if (props != null)
+          attributes.putAll(props);
+        attributes.put(Registry.SASL_AUTHORISATION_ID, authorisationID);
+        attributes.put(Registry.SASL_PROTOCOL, protocol);
+        attributes.put(Registry.SASL_SERVER_NAME, serverName);
+        attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh);
+        result.init(attributes);
+        return result;
+      }
+    throw new SaslException("No supported mechanism found in given mechanism list");
+  }
+
+  public String[] getMechanismNames(Map props)
+  {
+    return getNamesInternal(props);
+  }
+
+  private static boolean hasPolicy(String propertyName, Map props)
+  {
+    return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName)));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/ClientMechanism.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,293 @@
+/* ClientMechanism.java -- 
+   Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Registry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+/**
+ * A base class to facilitate implementing SASL client-side mechanisms.
+ */
+public abstract class ClientMechanism
+    implements SaslClient
+{
+  /** Name of this mechanism. */
+  protected String mechanism;
+  /** The authorisation identity. */
+  protected String authorizationID;
+  /** Name of protocol using this mechanism. */
+  protected String protocol;
+  /** Name of server to authenticate to. */
+  protected String serverName;
+  /** Properties of qualities desired for this mechanism. */
+  protected Map properties;
+  /** Callback handler to use with this mechanism instance. */
+  protected CallbackHandler handler;
+  /** Channel binding data to use with this mechanism instance. */
+  protected byte[] channelBinding;
+  /** Whether authentication phase is completed (true) or not (false). */
+  protected boolean complete = false;
+  /** The state of the authentication automaton. */
+  protected int state = -1;
+
+  protected ClientMechanism(final String mechanism)
+  {
+    super();
+
+    this.mechanism = mechanism;
+    this.state = -1;
+  }
+
+  protected abstract void initMechanism() throws SaslException;
+
+  protected abstract void resetMechanism() throws SaslException;
+
+  public abstract byte[] evaluateChallenge(byte[] challenge)
+      throws SaslException;
+
+  public abstract boolean hasInitialResponse();
+
+  public boolean isComplete()
+  {
+    return complete;
+  }
+
+  public byte[] unwrap(final byte[] incoming, final int offset, final int len)
+      throws SaslException
+  {
+    if (! isComplete())
+      throw new IllegalMechanismStateException();
+    return this.engineUnwrap(incoming, offset, len);
+  }
+
+  public byte[] wrap(final byte[] outgoing, final int offset, final int len)
+      throws SaslException
+  {
+    if (! isComplete())
+      throw new IllegalMechanismStateException();
+    return this.engineWrap(outgoing, offset, len);
+  }
+
+  public String getMechanismName()
+  {
+    return mechanism;
+  }
+
+  public Object getNegotiatedProperty(final String propName)
+  {
+    if (! isComplete())
+      throw new IllegalStateException();
+    if (Sasl.QOP.equals(propName))
+      return getNegotiatedQOP();
+    if (Sasl.STRENGTH.equals(propName))
+      return getNegotiatedStrength();
+    if (Sasl.SERVER_AUTH.equals(propName))
+      return getNegotiatedServerAuth();
+    if (Sasl.MAX_BUFFER.equals(propName))
+      return getNegotiatedMaxBuffer();
+    if (Sasl.RAW_SEND_SIZE.equals(propName))
+      return getNegotiatedRawSendSize();
+    if (Sasl.POLICY_NOPLAINTEXT.equals(propName))
+      return getNegotiatedPolicyNoPlainText();
+    if (Sasl.POLICY_NOACTIVE.equals(propName))
+      return getNegotiatedPolicyNoActive();
+    if (Sasl.POLICY_NODICTIONARY.equals(propName))
+      return getNegotiatedPolicyNoDictionary();
+    if (Sasl.POLICY_NOANONYMOUS.equals(propName))
+      return getNegotiatedPolicyNoAnonymous();
+    if (Sasl.POLICY_FORWARD_SECRECY.equals(propName))
+      return getNegotiatedPolicyForwardSecrecy();
+    if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName))
+      return getNegotiatedPolicyPassCredentials();
+    if (Sasl.REUSE.equals(propName))
+      return getReuse();
+    return null;
+  }
+
+  public void dispose() throws SaslException
+  {
+  }
+
+  public String getAuthorizationID()
+  {
+    return authorizationID;
+  }
+
+  protected String getNegotiatedQOP()
+  {
+    return Registry.QOP_AUTH;
+  }
+
+  protected String getNegotiatedStrength()
+  {
+    return Registry.STRENGTH_LOW;
+  }
+
+  protected String getNegotiatedServerAuth()
+  {
+    return Registry.SERVER_AUTH_FALSE;
+  }
+
+  protected String getNegotiatedMaxBuffer()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedRawSendSize()
+  {
+    return String.valueOf(Registry.SASL_BUFFER_MAX_LIMIT);
+  }
+
+  protected String getNegotiatedPolicyNoPlainText()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyNoActive()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyNoDictionary()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyNoAnonymous()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyForwardSecrecy()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyPassCredentials()
+  {
+    return null;
+  }
+
+  protected String getReuse()
+  {
+    return Registry.REUSE_FALSE;
+  }
+
+  protected byte[] engineUnwrap(final byte[] incoming, final int offset,
+                                final int len) throws SaslException
+  {
+    final byte[] result = new byte[len];
+    System.arraycopy(incoming, offset, result, 0, len);
+    return result;
+  }
+
+  protected byte[] engineWrap(final byte[] outgoing, final int offset,
+                              final int len) throws SaslException
+  {
+    final byte[] result = new byte[len];
+    System.arraycopy(outgoing, offset, result, 0, len);
+    return result;
+  }
+
+  /**
+   * Initialises the mechanism with designated attributes. Permissible names and
+   * values are mechanism specific.
+   * 
+   * @param attributes a set of name-value pairs that describes the desired
+   *          future behaviour of this instance.
+   * @throws IllegalMechanismStateException if the instance is already
+   *           initialised.
+   * @throws SaslException if an exception occurs during the process.
+   */
+  public void init(final Map attributes) throws SaslException
+  {
+    if (state != -1)
+      throw new IllegalMechanismStateException("init()");
+    if (properties == null)
+      properties = new HashMap();
+    else
+      properties.clear();
+    if (attributes != null)
+      {
+        authorizationID = (String) attributes.get(Registry.SASL_AUTHORISATION_ID);
+        protocol = (String) attributes.get(Registry.SASL_PROTOCOL);
+        serverName = (String) attributes.get(Registry.SASL_SERVER_NAME);
+        handler = (CallbackHandler) attributes.get(Registry.SASL_CALLBACK_HANDLER);
+        channelBinding = (byte[]) attributes.get(Registry.SASL_CHANNEL_BINDING);
+        properties.putAll(attributes);
+      }
+    else
+      handler = null;
+
+    if (authorizationID == null)
+      authorizationID = "";
+    if (protocol == null)
+      protocol = "";
+    if (serverName == null)
+      serverName = "";
+    if (channelBinding == null)
+      channelBinding = new byte[0];
+    initMechanism();
+    complete = false;
+    state = 0;
+  }
+
+  /**
+   * Resets the mechanism instance for re-initialisation and use with other
+   * characteristics.
+   * 
+   * @throws SaslException if an exception occurs during the process.
+   */
+  public void reset() throws SaslException
+  {
+    resetMechanism();
+    properties.clear();
+    authorizationID = protocol = serverName = null;
+    channelBinding = null;
+    complete = false;
+    state = -1;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/ConfidentialityException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,82 @@
+/* ConfidentialityException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * Used by mechanisms that offer a security services layer, this checked
+ * exception is thrown to indicate that a violation has occured during the
+ * processing of a <i>confidentiality</i> protection filter.
+ */
+public class ConfidentialityException
+    extends SaslException
+{
+  /**
+   * Constructs a new instance of <code>ConfidentialityException</code> with
+   * no detail message.
+   */
+  public ConfidentialityException()
+  {
+    super();
+  }
+
+  /**
+   * Constructs a new instance of <code>ConfidentialityException</code> with
+   * the specified detail message.
+   * 
+   * @param s the detail message.
+   */
+  public ConfidentialityException(String s)
+  {
+    super(s);
+  }
+
+  /**
+   * Constructs a new instance of <code>ConfidentialityException</code> with a
+   * detailed message and a root exception.
+   * 
+   * @param s possibly null additional detail about the exception.
+   * @param x a possibly null root exception that caused this one.
+   */
+  public ConfidentialityException(String s, Throwable x)
+  {
+    super(s, x);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/IAuthInfoProvider.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,116 @@
+/* IAuthInfoProvider.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import java.util.Map;
+
+import javax.security.sasl.AuthenticationException;
+
+/**
+ * The visible methods of any authentication information provider.
+ */
+public interface IAuthInfoProvider
+{
+  /**
+   * Activates (initialises) this provider instance. SHOULD be the first method
+   * invoked on the provider.
+   * 
+   * @param context a collection of name-value bindings describing the
+   *          activation context.
+   * @throws AuthenticationException if an exception occurs during the
+   *           operation.
+   */
+  void activate(Map context) throws AuthenticationException;
+
+  /**
+   * Passivates (releases) this provider instance. SHOULD be the last method
+   * invoked on the provider. Once it is done, no other method may be invoked on
+   * the same instance before it is <i>activated</i> agains.
+   * 
+   * @throws AuthenticationException if an exception occurs during the
+   *           operation.
+   */
+  void passivate() throws AuthenticationException;
+
+  /**
+   * Checks if a user with a designated name is known to this provider.
+   * 
+   * @param userName the name of a user to check.
+   * @return <code>true</code> if the user with the designated name is known
+   *         to this provider; <code>false</code> otherwise.
+   * @throws AuthenticationException if an exception occurs during the
+   *           operation.
+   */
+  boolean contains(String userName) throws AuthenticationException;
+
+  /**
+   * Returns a collection of information about a designated user. The contents
+   * of the returned map is provider-specific of name-to-value mappings.
+   * 
+   * @param userID a map of name-to-value bindings that fully describe a user.
+   * @return a collection of information about the designated user.
+   * @throws AuthenticationException if an exception occurs during the
+   *           operation.
+   */
+  Map lookup(Map userID) throws AuthenticationException;
+
+  /**
+   * Updates the credentials of a designated user.
+   * 
+   * @param userCredentials a map of name-to-value bindings that fully describe
+   *          a user, including per new credentials.
+   * @throws AuthenticationException if an exception occurs during the
+   *           operation.
+   */
+  void update(Map userCredentials) throws AuthenticationException;
+
+  /**
+   * A provider may operate in more than mode; e.g. SRP-II caters for user
+   * credentials computed in more than one message digest algorithm. This method
+   * returns the set of name-to-value bindings describing the mode of the
+   * provider.
+   * 
+   * @param mode a unique identifier describing the operational mode.
+   * @return a collection of name-to-value bindings describing the designated
+   *         mode.
+   * @throws AuthenticationException if an exception occurs during the
+   *           operation.
+   */
+  Map getConfiguration(String mode) throws AuthenticationException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,55 @@
+/* IAuthInfoProviderFactory.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+/**
+ * The visible method of every authentication information provider factory.
+ */
+public interface IAuthInfoProviderFactory
+{
+  /**
+   * Returns an implementation of a provider for a designated mechanism capable
+   * of honouring {@link IAuthInfoProvider} requests.
+   * 
+   * @param mechanism the unique name of a mechanism.
+   * @return an implementation of {@link IAuthInfoProvider} for that mechanism
+   *         or <code>null</code> if none found.
+   */
+  IAuthInfoProvider getInstance(String mechanism);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/IllegalMechanismStateException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,84 @@
+/* IllegalMechanismStateException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import javax.security.sasl.AuthenticationException;
+
+/**
+ * A checked exception thrown to indicate that an operation that should be
+ * invoked on a completed mechanism was invoked but the authentication phase of
+ * that mechanism was not completed yet, or that an operation that should be
+ * invoked on incomplete mechanisms was invoked but the authentication phase of
+ * that mechanism was already completed.
+ */
+public class IllegalMechanismStateException
+    extends AuthenticationException
+{
+  /**
+   * Constructs a new instance of <code>IllegalMechanismStateException</code>
+   * with no detail message.
+   */
+  public IllegalMechanismStateException()
+  {
+    super();
+  }
+
+  /**
+   * Constructs a new instance of <code>IllegalMechanismStateException</code>
+   * with the specified detail message.
+   * 
+   * @param detail the detail message.
+   */
+  public IllegalMechanismStateException(String detail)
+  {
+    super(detail);
+  }
+
+  /**
+   * Constructs a new instance of <code>IllegalMechanismStateException</code>
+   * with the specified detail message, and cause.
+   * 
+   * @param detail the detail message.
+   * @param ex the original cause.
+   */
+  public IllegalMechanismStateException(String detail, Throwable ex)
+  {
+    super(detail, ex);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/InputBuffer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,272 @@
+/* InputBuffer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Registry;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+/**
+ * The implementation of an incoming SASL buffer.
+ * <p>
+ * The data elements this class caters for are described in [1].
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a>;<br/>
+ * draft-burdis-cat-srp-sasl-09,<br/> <a
+ * href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and <a
+ * href="mailto:raif@forge.com.au">Ra&iuml;f S. Naffah</a>.</li>
+ * </ol>
+ */
+public class InputBuffer
+{
+  /** The internal buffer stream containing the buffer's contents. */
+  protected ByteArrayInputStream in;
+  /** The length of the buffer, according to its header. */
+  protected int length;
+
+  /**
+   * Constructs a SASL buffer given the buffer's encoded form, including its
+   * header bytes.
+   * 
+   * @param frame the encoded form, including the header bytes, of a SASL
+   *          buffer.
+   * @throws SaslEncodingException if the buffer is malformed.
+   */
+  public InputBuffer(byte[] frame) throws SaslEncodingException
+  {
+    this();
+
+    if (frame.length < 4)
+      throw new SaslEncodingException("SASL buffer header too short");
+    length = (frame[0] & 0xFF) << 24
+           | (frame[1] & 0xFF) << 16
+           | (frame[2] & 0xFF) << 8
+           | (frame[3] & 0xFF);
+    if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
+      throw new SaslEncodingException("SASL buffer size limit exceeded");
+    in = new ByteArrayInputStream(frame, 4, length);
+  }
+
+  /** Trivial private constructor for use by the class method. */
+  private InputBuffer()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of a SASL buffer given the buffer's encoded contents,
+   * excluding the buffer's header bytes.
+   * <p>
+   * Calls the method with the same name and three arguments as:
+   * <code>getInstance(raw, 0, raw.length)</code>.
+   * 
+   * @param raw the encoded form, excluding the header bytes, of a SASL buffer.
+   * @return a new instance of {@link InputBuffer}.
+   */
+  public static InputBuffer getInstance(byte[] raw)
+  {
+    return getInstance(raw, 0, raw.length);
+  }
+
+  /**
+   * Returns an instance of a SASL buffer given the buffer's encoded contents,
+   * excluding the buffer's header bytes.
+   * 
+   * @param raw the encoded form, excluding the header bytes, of a SASL buffer.
+   * @param offset offset where to start using raw bytes from.
+   * @param len number of bytes to use.
+   * @return a new instance of {@link InputBuffer}.
+   */
+  public static InputBuffer getInstance(byte[] raw, int offset, int len)
+  {
+    InputBuffer result = new InputBuffer();
+    result.in = new ByteArrayInputStream(raw, offset, len);
+    return result;
+  }
+
+  /**
+   * Converts two octets into the number that they represent.
+   * 
+   * @param b the two octets.
+   * @return the length.
+   */
+  public static int twoBytesToLength(byte[] b) throws SaslEncodingException
+  {
+    final int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF);
+    if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+      throw new SaslEncodingException("SASL MPI/Text size limit exceeded");
+    return result;
+  }
+
+  public boolean hasMoreElements()
+  {
+    return (in.available() > 0);
+  }
+
+  /**
+   * Decodes a SASL scalar quantity, <code>count</code>-octet long, from the
+   * current buffer.
+   * 
+   * @param count the number of octets of this scalar quantity.
+   * @return a native representation of a SASL scalar (unsigned integer)
+   *         quantity.
+   * @throws SaslEncodingException if an encoding exception occurs during the
+   *           operation.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public long getScalar(int count) throws IOException
+  {
+    if (count < 0 || count > 4)
+      throw new SaslEncodingException("Invalid SASL scalar octet count: "
+                                      + String.valueOf(count));
+    if (! hasMoreElements())
+      throw new SaslEncodingException("Not enough bytes for a scalar in buffer");
+    if (in.available() < count)
+      throw new SaslEncodingException("Illegal SASL scalar encoding");
+    byte[] element = new byte[count];
+    in.read(element);
+    long result = 0L;
+    for (int i = 0; i < count; i++)
+      {
+        result <<= 8;
+        result |= element[i] & 0xFFL;
+      }
+    return result;
+  }
+
+  /**
+   * Decodes a SASL OS from the current buffer.
+   * 
+   * @return a native representation of a SASL OS.
+   * @throws SaslEncodingException if an encoding exception occurs during the
+   *           operation.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public byte[] getOS() throws IOException
+  {
+    if (! hasMoreElements())
+      throw new SaslEncodingException(
+          "Not enough bytes for an octet-sequence in buffer");
+    final int elementLength = in.read();
+    if (elementLength > Registry.SASL_ONE_BYTE_MAX_LIMIT)
+      throw new SaslEncodingException("SASL octet-sequence size limit exceeded");
+    if (in.available() < elementLength)
+      throw new SaslEncodingException("Illegal SASL octet-sequence encoding");
+    byte[] result = new byte[elementLength];
+    in.read(result);
+    return result;
+  }
+
+  /**
+   * Decodes a SASL EOS from the current buffer.
+   * 
+   * @return a native representation of a SASL EOS.
+   * @throws SaslEncodingException if an encoding exception occurs during the
+   *           operation.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public byte[] getEOS() throws IOException
+  {
+    if (in.available() < 2)
+      throw new SaslEncodingException(
+          "Not enough bytes for an extended octet-sequence in buffer");
+    byte[] elementLengthBytes = new byte[2];
+    in.read(elementLengthBytes);
+    final int elementLength = twoBytesToLength(elementLengthBytes);
+    if (in.available() < elementLength)
+      throw new SaslEncodingException(
+          "Illegal SASL extended octet-sequence encoding");
+    byte[] result = new byte[elementLength];
+    in.read(result);
+    return result;
+  }
+
+  /**
+   * Decodes a SASL MPI from the current buffer.
+   * 
+   * @return a native representation of a SASL MPI.
+   * @throws SaslEncodingException if an encoding exception occurs during the
+   *           operation.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public BigInteger getMPI() throws IOException
+  {
+    if (in.available() < 2)
+      throw new SaslEncodingException("Not enough bytes for an MPI in buffer");
+    byte[] elementLengthBytes = new byte[2];
+    in.read(elementLengthBytes);
+    final int elementLength = twoBytesToLength(elementLengthBytes);
+    if (in.available() < elementLength)
+      throw new SaslEncodingException(
+          "Illegal SASL multi-precision integer encoding");
+    byte[] element = new byte[elementLength];
+    in.read(element);
+    return new BigInteger(1, element);
+  }
+
+  /**
+   * Decodes a SASL Text from the current buffer.
+   * 
+   * @return a native representation of a SASL Text.
+   * @throws SaslEncodingException if an encoding exception occurs during the
+   *           operation.
+   * @throws SaslEncodingException if the UTF-8 character encoding is not
+   *           supported on this platform.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public String getText() throws IOException
+  {
+    if (in.available() < 2)
+      throw new SaslEncodingException("Not enough bytes for a text in buffer");
+    byte[] elementLengthBytes = new byte[2];
+    in.read(elementLengthBytes);
+    final int elementLength = twoBytesToLength(elementLengthBytes);
+    if (in.available() < elementLength)
+      throw new SaslEncodingException("Illegal SASL text encoding");
+    byte[] element = new byte[elementLength];
+    in.read(element);
+    return new String(element, "UTF8");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/IntegrityException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,83 @@
+/* IntegrityException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * Used by mechanisms that offer a security services layer, this checked
+ * exception is thrown to indicate that a violation has occured during the
+ * processing of an <i>integrity</i> protection filter, including <i>replay
+ * detection</i>.
+ */
+public class IntegrityException
+    extends SaslException
+{
+  /**
+   * Constructs a new instance of <code>IntegrityException</code> with no
+   * detail message.
+   */
+  public IntegrityException()
+  {
+    super();
+  }
+
+  /**
+   * Constructs a new instance of <code>IntegrityException</code> with the
+   * specified detail message.
+   * 
+   * @param s the detail message.
+   */
+  public IntegrityException(String s)
+  {
+    super(s);
+  }
+
+  /**
+   * Constructs a new instance of <code>IntegrityException</code> with a
+   * detailed message and a root exception.
+   * 
+   * @param s possibly null additional detail about the exception.
+   * @param x a possibly null root exception that caused this one.
+   */
+  public IntegrityException(String s, Throwable x)
+  {
+    super(s, x);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/NoSuchMechanismException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,62 @@
+/* NoSuchMechanismException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * A checked exception thrown to indicate that a designated SASL mechanism
+ * implementation was not found.
+ */
+public class NoSuchMechanismException
+    extends SaslException
+{
+  /**
+   * Constructs a <code>NoSuchMechanismException</code> with the specified
+   * detail message. In the case of this exception, the detail message
+   * designates the offending mechanism name.
+   * 
+   * @param arg the detail message, which in this case is the offending
+   *          mechanism name.
+   */
+  public NoSuchMechanismException(String arg)
+  {
+    super(arg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/NoSuchUserException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,67 @@
+/* NoSuchUserException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import javax.security.sasl.AuthenticationException;
+
+/**
+ * A checked exception thrown to indicate that a designated user is unknown to
+ * the authentication layer.
+ */
+public class NoSuchUserException
+    extends AuthenticationException
+{
+  /** Constructs a <code>NoSuchUserException</code> with no detail message. */
+  public NoSuchUserException()
+  {
+    super();
+  }
+
+  /**
+   * Constructs a <code>NoSuchUserException</code> with the specified detail
+   * message. In the case of this exception, the detail message designates the
+   * offending username.
+   * 
+   * @param arg the detail message, which in this case is the username.
+   */
+  public NoSuchUserException(String arg)
+  {
+    super(arg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/OutputBuffer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,198 @@
+/* OutputBuffer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+/**
+ * The implementation of an outgoing SASL buffer.
+ * <p>
+ * The data elements this class caters for are described in [1].
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a>;<br/>
+ * draft-burdis-cat-srp-sasl-09,<br/> <a
+ * href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and <a
+ * href="mailto:raif@forge.com.au">Ra&iuml;f S. Naffah</a>.</li>
+ * </ol>
+ */
+public class OutputBuffer
+{
+  /** The internal output stream. */
+  private ByteArrayOutputStream out;
+
+  public OutputBuffer()
+  {
+    super();
+
+    out = new ByteArrayOutputStream();
+  }
+
+  /**
+   * Encodes a SASL scalar quantity, <code>count</code>-octet long, to the
+   * current buffer.
+   * 
+   * @param count number of octets to encode <code>b</code> with.
+   * @param b the scalar quantity.
+   * @throws SaslEncodingException if an encoding size constraint is violated.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public void setScalar(int count, int b) throws IOException
+  {
+    if (count < 0 || count > 4)
+      throw new SaslEncodingException("Invalid SASL scalar octet count: "
+                                      + String.valueOf(count));
+    byte[] element = new byte[count];
+    for (int i = count; --i >= 0; b >>>= 8)
+      element[i] = (byte) b;
+    out.write(element);
+  }
+
+  /**
+   * Encodes a SASL OS to the current buffer.
+   * 
+   * @param b the OS element.
+   * @throws SaslEncodingException if an encoding size constraint is violated.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public void setOS(byte[] b) throws IOException
+  {
+    final int length = b.length;
+    if (length > Registry.SASL_ONE_BYTE_MAX_LIMIT)
+      throw new SaslEncodingException("SASL octet-sequence too long");
+    out.write(length & 0xFF);
+    out.write(b);
+  }
+
+  /**
+   * Encodes a SASL EOS to the current buffer.
+   * 
+   * @param b the EOS element.
+   * @throws SaslEncodingException if an encoding size constraint is violated.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public void setEOS(byte[] b) throws IOException
+  {
+    final int length = b.length;
+    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+      throw new SaslEncodingException("SASL extended octet-sequence too long");
+    byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
+    out.write(lengthBytes);
+    out.write(b);
+  }
+
+  /**
+   * Encodes a SASL MPI to the current buffer.
+   * 
+   * @param val the MPI element.
+   * @throws SaslEncodingException if an encoding size constraint is violated.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public void setMPI(BigInteger val) throws IOException
+  {
+    byte[] b = Util.trim(val);
+    final int length = b.length;
+    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+      throw new SaslEncodingException("SASL multi-precision integer too long");
+    byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
+    out.write(lengthBytes);
+    out.write(b);
+  }
+
+  /**
+   * Encodes a SASL Text to the current buffer.
+   * 
+   * @param str the Text element.
+   * @throws SaslEncodingException if an encoding size constraint is violated.
+   * @throws SaslEncodingException if the UTF-8 encoding is not supported on
+   *           this platform.
+   * @throws IOException if any other I/O exception occurs during the operation.
+   */
+  public void setText(String str) throws IOException
+  {
+    byte[] b = str.getBytes("UTF8");
+    final int length = b.length;
+    if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+      throw new SaslEncodingException("SASL text too long");
+    byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
+    out.write(lengthBytes);
+    out.write(b);
+  }
+
+  /**
+   * Returns the encoded form of the current buffer including the 4-byte length
+   * header.
+   * 
+   * @throws SaslEncodingException if an encoding size constraint is violated.
+   */
+  public byte[] encode() throws SaslEncodingException
+  {
+    byte[] buffer = wrap();
+    final int length = buffer.length;
+    byte[] result = new byte[length + 4];
+    result[0] = (byte)(length >>> 24);
+    result[1] = (byte)(length >>> 16);
+    result[2] = (byte)(length >>> 8);
+    result[3] = (byte) length;
+    System.arraycopy(buffer, 0, result, 4, length);
+    return result;
+  }
+
+  /**
+   * Returns the encoded form of the current buffer excluding the 4-byte length
+   * header.
+   * 
+   * @throws SaslEncodingException if an encoding size constraint is violated.
+   */
+  public byte[] wrap() throws SaslEncodingException
+  {
+    final int length = out.size();
+    if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
+      throw new SaslEncodingException("SASL buffer too long");
+    return out.toByteArray();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/SaslEncodingException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,66 @@
+/* SaslEncodingException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * A checked exception, thrown when an exception occurs while decoding a SASL
+ * buffer and/or a SASL data element from/to a buffer.
+ */
+public class SaslEncodingException
+    extends SaslException
+{
+  /** Constructs a <code>SaslEncodingException</code> with no detail message. */
+  public SaslEncodingException()
+  {
+    super();
+  }
+
+  /**
+   * Constructs a <code>SaslEncodingException</code> with the specified detail
+   * message.
+   * 
+   * @param s the detail message.
+   */
+  public SaslEncodingException(String s)
+  {
+    super(s);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/SaslInputStream.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,393 @@
+/* SaslInputStream.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.util.Util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.util.logging.Logger;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslServer;
+
+/**
+ * An input stream that uses either a {@link SaslClient} or a {@link SaslServer}
+ * to process the data through these entities' security layer filter(s).
+ */
+public class SaslInputStream
+    extends InputStream
+{
+  private static final Logger log = Logger.getLogger(SaslInputStream.class.getName());
+  private SaslClient client;
+  private SaslServer server;
+  private int maxRawSendSize;
+  private InputStream source;
+  private byte[] internalBuf;
+
+  public SaslInputStream(SaslClient client, InputStream source)
+      throws IOException
+  {
+    super();
+
+    this.client = client;
+    String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
+    maxRawSendSize = Integer.parseInt(size);
+    server = null;
+    this.source = source;
+  }
+
+  public SaslInputStream(SaslServer server, InputStream source)
+      throws IOException
+  {
+    super();
+
+    this.server = server;
+    String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
+    maxRawSendSize = Integer.parseInt(size);
+    client = null;
+    this.source = source;
+  }
+
+  public int available() throws IOException
+  {
+    return (internalBuf == null) ? 0 : internalBuf.length;
+  }
+
+  public void close() throws IOException
+  {
+    source.close();
+  }
+
+  /**
+   * Reads the next byte of data from the input stream. The value byte is
+   * returned as an <code>int</code> in the range <code>0</code> to
+   * <code>255</code>. If no byte is available because the end of the stream
+   * has been reached, the value <code>-1</code> is returned. This method
+   * blocks until input data is available, the end of the stream is detected, or
+   * an exception is thrown.
+   * <p>
+   * From a SASL mechanism provider's perspective, if a security layer has been
+   * negotiated, the underlying <i>source</i> is expected to contain SASL
+   * buffers, as defined in RFC 2222. Four octets in network byte order in the
+   * front of each buffer identify the length of the buffer. The provider is
+   * responsible for performing any integrity checking or other processing on
+   * the buffer before returning the data as a stream of octets. For example,
+   * the protocol driver's request for a single octet from the stream might;
+   * i.e. an invocation of this method, may result in an entire SASL buffer
+   * being read and processed before that single octet can be returned.
+   * 
+   * @return the next byte of data, or <code>-1</code> if the end of the
+   *         stream is reached.
+   * @throws IOException if an I/O error occurs.
+   */
+  public int read() throws IOException
+  {
+    int result = -1;
+    if (internalBuf != null && internalBuf.length > 0)
+      {
+        result = internalBuf[0] & 0xFF;
+        if (internalBuf.length == 1)
+          internalBuf = new byte[0];
+        else
+          {
+            byte[] tmp = new byte[internalBuf.length - 1];
+            System.arraycopy(internalBuf, 1, tmp, 0, tmp.length);
+            internalBuf = tmp;
+          }
+      }
+    else
+      {
+        byte[] buf = new byte[1];
+        int check = read(buf);
+        result = (check > 0) ? (buf[0] & 0xFF) : -1;
+      }
+    return result;
+  }
+
+  /**
+   * Reads up to <code>len</code> bytes of data from the underlying <i>source</i>
+   * input stream into an array of bytes. An attempt is made to read as many as
+   * <code>len</code> bytes, but a smaller number may be read, possibly zero.
+   * The number of bytes actually read is returned as an integer.
+   * <p>
+   * This method blocks until input data is available, end of file is detected,
+   * or an exception is thrown.
+   * <p>
+   * If <code>b</code> is <code>null</code>, a {@link NullPointerException}
+   * is thrown.
+   * <p>
+   * If <code>off</code> is negative, or <code>len</code> is negative, or
+   * <code>off+len</code> is greater than the length of the array
+   * <code>b</code>, then an {@link IndexOutOfBoundsException} is thrown.
+   * <p>
+   * If <code>len</code> is zero, then no bytes are read and <code>0</code>
+   * is returned; otherwise, there is an attempt to read at least one byte. If
+   * no byte is available because the stream is at end of file, the value
+   * <code>-1</code> is returned; otherwise, at least one byte is read and
+   * stored into <code>b</code>.
+   * <p>
+   * The first byte read is stored into element <code>b[off]</code>, the next
+   * one into <code>b[off+1]</code>, and so on. The number of bytes read is,
+   * at most, equal to <code>len</code>. Let <code>k</code> be the number
+   * of bytes actually read; these bytes will be stored in elements
+   * <code>b[off]</code> through <code>b[off+k-1]</code>, leaving elements
+   * <code>b[off+k]</code> through <code>b[off+len-1]</code> unaffected.
+   * <p>
+   * In every case, elements <code>b[0]</code> through <code>b[off]</code>
+   * and elements <code>b[off+len]</code> through <code>b[b.length-1]</code>
+   * are unaffected.
+   * <p>
+   * If the first byte cannot be read for any reason other than end of file,
+   * then an {@link IOException} is thrown. In particular, an
+   * {@link IOException} is thrown if the input stream has been closed.
+   * <p>
+   * From the SASL mechanism provider's perspective, if a security layer has
+   * been negotiated, the underlying <i>source</i> is expected to contain SASL
+   * buffers, as defined in RFC 2222. Four octets in network byte order in the
+   * front of each buffer identify the length of the buffer. The provider is
+   * responsible for performing any integrity checking or other processing on
+   * the buffer before returning the data as a stream of octets. The protocol
+   * driver's request for a single octet from the stream might result in an
+   * entire SASL buffer being read and processed before that single octet can be
+   * returned.
+   * 
+   * @param b the buffer into which the data is read.
+   * @param off the start offset in array <code>b</code> at which the data is
+   *          wricodeen.
+   * @param len the maximum number of bytes to read.
+   * @return the total number of bytes read into the buffer, or <code>-1</code>
+   *         if there is no more data because the end of the stream has been
+   *         reached.
+   * @throws IOException if an I/O error occurs.
+   */
+  public int read(byte[] b, int off, int len) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "read", new Object[] {
+          b, Integer.valueOf(off), Integer.valueOf(len)
+      });
+    if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
+        || ((off + len) < 0))
+      throw new IndexOutOfBoundsException("off=" + off + ", len=" + len
+                                          + ", b.length=" + b.length);
+    if (len == 0)
+      {
+        if (Configuration.DEBUG)
+          log.exiting(this.getClass().getName(), "read", Integer.valueOf(0));
+        return 0;
+      }
+    if (Configuration.DEBUG)
+      log.finer("Available: " + available());
+    int result = 0;
+    if (internalBuf == null || internalBuf.length < 1)
+      try
+        {
+          internalBuf = readSaslBuffer();
+          if (internalBuf == null)
+            {
+              if (Configuration.DEBUG)
+                {
+                  log.finer("Underlying stream empty. Returning -1");
+                  log.exiting(this.getClass().getName(), "read",
+                              Integer.valueOf(-1));
+                }
+              return -1;
+            }
+        }
+      catch (InterruptedIOException x)
+        {
+          if (Configuration.DEBUG)
+            {
+              log.finer("Reading thread was interrupted. Returning -1");
+              log.throwing(this.getClass().getName(), "read", x);
+              log.exiting(this.getClass().getName(), "read",
+                          Integer.valueOf(-1));
+            }
+          return -1;
+        }
+    if (len <= internalBuf.length)
+      {
+        result = len;
+        System.arraycopy(internalBuf, 0, b, off, len);
+        if (len == internalBuf.length)
+          internalBuf = null;
+        else
+          {
+            byte[] tmp = new byte[internalBuf.length - len];
+            System.arraycopy(internalBuf, len, tmp, 0, tmp.length);
+            internalBuf = tmp;
+          }
+      }
+    else
+      {
+        // first copy the available bytes to b
+        result = internalBuf.length;
+        System.arraycopy(internalBuf, 0, b, off, result);
+        internalBuf = null;
+        off += result;
+        len -= result;
+        int remaining; // count of bytes remaining in buffer after an iteration
+        int delta; // count of bytes moved to b after an iteration
+        int datalen;
+        byte[] data;
+        while (len > 0)
+          // we need to read SASL buffers, as long as there are at least
+          // 4 bytes available at the source
+          if (source.available() > 3)
+            {
+              // process a buffer
+              data = readSaslBuffer();
+              if (data == null)
+                {
+                  if (Configuration.DEBUG)
+                    log.finer("Underlying stream exhausted. Breaking...");
+                  break;
+                }
+              datalen = data.length;
+              // copy [part of] the result to b
+              remaining = (datalen <= len) ? 0 : datalen - len;
+              delta = datalen - remaining;
+              System.arraycopy(data, 0, b, off, delta);
+              if (remaining > 0)
+                {
+                  internalBuf = new byte[remaining];
+                  System.arraycopy(data, delta, internalBuf, 0, remaining);
+                }
+              // update off, result and len
+              off += delta;
+              result += delta;
+              len -= delta;
+            }
+          else
+            { // nothing much we can do except return what we have
+              if (Configuration.DEBUG)
+                log.finer("Not enough bytes in source to read a buffer. Breaking...");
+              break;
+            }
+      }
+    if (Configuration.DEBUG)
+      {
+        log.finer("Remaining: "
+                  + (internalBuf == null ? 0 : internalBuf.length));
+        log.exiting(this.getClass().getName(), "read()", String.valueOf(result));
+      }
+    return result;
+  }
+
+  /**
+   * Reads a SASL buffer from the underlying source if at least 4 bytes are
+   * available.
+   * 
+   * @return the byte[] of decoded buffer contents, or null if the underlying
+   *         source was exhausted.
+   * @throws IOException if an I/O exception occurs during the operation.
+   */
+  private byte[] readSaslBuffer() throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "readSaslBuffer()");
+    int realLength; // check if we read as many bytes as we're supposed to
+    byte[] result = new byte[4];
+    try
+      {
+        realLength = source.read(result);
+        if (realLength == -1)
+          {
+            if (Configuration.DEBUG)
+              log.exiting(this.getClass().getName(), "readSaslBuffer");
+            return null;
+          }
+      }
+    catch (IOException x)
+      {
+        if (Configuration.DEBUG)
+          log.throwing(this.getClass().getName(), "readSaslBuffer", x);
+        throw x;
+      }
+    if (realLength != 4)
+      throw new IOException("Was expecting 4 but found " + realLength);
+    int bufferLength =  result[0]         << 24
+                     | (result[1] & 0xFF) << 16
+                     | (result[2] & 0xFF) << 8
+                     | (result[3] & 0xFF);
+    if (Configuration.DEBUG)
+      log.finer("SASL buffer size: " + bufferLength);
+    if (bufferLength > maxRawSendSize || bufferLength < 0)
+      throw new SaslEncodingException("SASL buffer (security layer) too long");
+
+    result = new byte[bufferLength];
+    try
+      {
+        realLength = source.read(result);
+      }
+    catch (IOException x)
+      {
+        if (Configuration.DEBUG)
+          log.throwing(this.getClass().getName(), "readSaslBuffer", x);
+        throw x;
+      }
+    if (realLength != bufferLength)
+      throw new IOException("Was expecting " + bufferLength + " but found "
+                            + realLength);
+    if (Configuration.DEBUG)
+      {
+        log.finer("Incoming buffer (before security) (hex): "
+                  + Util.dumpString(result));
+        log.finer("Incoming buffer (before security) (str): \""
+                  + new String(result) + "\"");
+      }
+    if (client != null)
+      result = client.unwrap(result, 0, realLength);
+    else
+      result = server.unwrap(result, 0, realLength);
+    if (Configuration.DEBUG)
+      {
+        log.finer("Incoming buffer (after security) (hex): "
+                  + Util.dumpString(result));
+        log.finer("Incoming buffer (after security) (str): \""
+                  + new String(result) + "\"");
+        log.exiting(this.getClass().getName(), "readSaslBuffer");
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/SaslOutputStream.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,175 @@
+/* SaslOutputStream.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.util.Util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.logging.Logger;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslServer;
+
+/**
+ * An output stream that uses either a {@link SaslClient} or a {@link SaslServer}
+ * to process the data through these entities' security layer filter(s).
+ */
+public class SaslOutputStream
+    extends OutputStream
+{
+  private static final Logger log = Logger.getLogger(SaslOutputStream.class.getName());
+  private SaslClient client;
+  private SaslServer server;
+  private int maxRawSendSize;
+  private OutputStream dest;
+
+  public SaslOutputStream(SaslClient client, OutputStream dest)
+      throws IOException
+  {
+    super();
+
+    this.client = client;
+    String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
+    maxRawSendSize = Integer.parseInt(size);
+    server = null;
+    this.dest = dest;
+  }
+
+  public SaslOutputStream(SaslServer server, OutputStream dest)
+      throws IOException
+  {
+    super();
+
+    this.server = server;
+    String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
+    maxRawSendSize = Integer.parseInt(size);
+    client = null;
+    this.dest = dest;
+  }
+
+  public void close() throws IOException
+  {
+    dest.flush();
+    dest.close();
+  }
+
+  public void flush() throws IOException
+  {
+    dest.flush();
+  }
+
+  /**
+   * When writing octets to the resulting stream, if a security layer has been
+   * negotiated, each piece of data written (by a single invocation of
+   * <code>write()</code>) will be encapsulated as a SASL buffer, as defined in
+   * RFC 2222, and then written to the underlying <i>dest</i> output stream.
+   */
+  public void write(int b) throws IOException
+  {
+    write(new byte[] { (byte) b });
+  }
+
+  /**
+   * When writing octets to the resulting stream, if a security layer has been
+   * negotiated, each piece of data written (by a single invocation of
+   * <code>write()</code>) will be encapsulated as a SASL buffer, as defined in
+   * RFC 2222, and then written to the underlying <i>dest</i> output stream.
+   */
+  public void write(byte[] b, int off, int len) throws IOException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "write");
+    if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
+        || ((off + len) < 0))
+      throw new IndexOutOfBoundsException("off=" + off + ", len=" + len
+                                          + ", b.length=" + b.length);
+    if (len == 0)
+      {
+        if (Configuration.DEBUG)
+          log.exiting(this.getClass().getName(), "write");
+        return;
+      }
+    int chunckSize, length, chunck = 1;
+    byte[] output = null, result;
+    if (Configuration.DEBUG)
+      log.finer("About to wrap " + len + " byte(s)...");
+    while (len > 0)
+      {
+        chunckSize = (len > maxRawSendSize ? maxRawSendSize : len);
+        if (Configuration.DEBUG)
+          {
+            log.finer("Outgoing buffer (before security) (hex): "
+                      + Util.dumpString(b, off, chunckSize));
+            log.finer("Outgoing buffer (before security) (str): \""
+                      + new String(b, off, chunckSize) + "\"");
+          }
+        if (client != null)
+          output = client.wrap(b, off, chunckSize);
+        else
+          output = server.wrap(b, off, chunckSize);
+
+        if (Configuration.DEBUG)
+          {
+            log.finer("Outgoing buffer (after security) (hex): "
+                      + Util.dumpString(output));
+            log.finer("Outgoing buffer (after security) (str): \""
+                      + new String(output) + "\"");
+          }
+        length = output.length;
+        result = new byte[length + 4];
+        result[0] = (byte)(length >>> 24);
+        result[1] = (byte)(length >>> 16);
+        result[2] = (byte)(length >>> 8);
+        result[3] = (byte) length;
+        System.arraycopy(output, 0, result, 4, length);
+        dest.write(result);
+        off += chunckSize;
+        len -= chunckSize;
+        if (Configuration.DEBUG)
+          log.finer("Wrapped chunck #" + chunck);
+        chunck++;
+      }
+    dest.flush();
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "write");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/SaslUtil.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,75 @@
+/* SaslUtil.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.util.Util;
+
+import java.security.MessageDigest;
+
+/**
+ * Utility methods for SASL-related classes.
+ */
+public class SaslUtil
+{
+  private SaslUtil()
+  {
+    super();
+  }
+
+  public static final boolean validEmailAddress(String address)
+  {
+    // need to do better than this
+    return (address.indexOf("@") != -1);
+  }
+
+  /** Returns the context of the designated hash as a string. */
+  public static final String dump(MessageDigest md)
+  {
+    String result;
+    try
+      {
+        result = Util.dumpString(((MessageDigest) md.clone()).digest());
+      }
+    catch (Exception ignored)
+      {
+        result = "...";
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/ServerFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,158 @@
+/* ServerFactory.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.anonymous.AnonymousServer;
+import gnu.javax.crypto.sasl.crammd5.CramMD5Server;
+import gnu.javax.crypto.sasl.plain.PlainServer;
+import gnu.javax.crypto.sasl.srp.SRPServer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+import javax.security.sasl.SaslServerFactory;
+
+/**
+ * The implementation of the {@link SaslServerFactory}.
+ */
+public class ServerFactory
+    implements SaslServerFactory
+{
+  // implicit 0-arguments constructor
+
+  public static final Set getNames()
+  {
+    return Collections.unmodifiableSet(new HashSet(Arrays.asList(getNamesInternal(null))));
+  }
+
+  private static final String[] getNamesInternal(Map props)
+  {
+    String[] all = new String[] {
+        Registry.SASL_SRP_MECHANISM,
+        Registry.SASL_CRAM_MD5_MECHANISM,
+        Registry.SASL_PLAIN_MECHANISM,
+        Registry.SASL_ANONYMOUS_MECHANISM };
+    List result = new ArrayList(4);
+    int i;
+    for (i = 0; i < all.length;)
+      result.add(all[i++]);
+    if (props == null)
+      return (String[]) result.toArray(new String[0]); // all
+    if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props)) // none
+      return new String[0];
+    if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props))
+      result.remove(Registry.SASL_PLAIN_MECHANISM);
+    if (hasPolicy(Sasl.POLICY_NOACTIVE, props))
+      {
+        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
+        result.remove(Registry.SASL_PLAIN_MECHANISM);
+      }
+    if (hasPolicy(Sasl.POLICY_NODICTIONARY, props))
+      {
+        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
+        result.remove(Registry.SASL_PLAIN_MECHANISM);
+      }
+    if (hasPolicy(Sasl.POLICY_NOANONYMOUS, props))
+      {
+        result.remove(Registry.SASL_ANONYMOUS_MECHANISM);
+      }
+    if (hasPolicy(Sasl.POLICY_FORWARD_SECRECY, props))
+      {
+        result.remove(Registry.SASL_CRAM_MD5_MECHANISM);
+        result.remove(Registry.SASL_ANONYMOUS_MECHANISM);
+        result.remove(Registry.SASL_PLAIN_MECHANISM);
+      }
+    return (String[]) result.toArray(new String[0]);
+  }
+
+  public static final ServerMechanism getInstance(String mechanism)
+  {
+    if (mechanism == null)
+      return null;
+    mechanism = mechanism.trim().toUpperCase();
+    if (mechanism.equals(Registry.SASL_SRP_MECHANISM))
+      return new SRPServer();
+    if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM))
+      return new CramMD5Server();
+    if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM))
+      return new PlainServer();
+    if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM))
+      return new AnonymousServer();
+    return null;
+  }
+
+  public SaslServer createSaslServer(String mechanism, String protocol,
+                                     String serverName, Map props,
+                                     CallbackHandler cbh) throws SaslException
+  {
+    ServerMechanism result = getInstance(mechanism);
+    if (result != null)
+      {
+        HashMap attributes = new HashMap();
+        if (props != null)
+          attributes.putAll(props);
+        attributes.put(Registry.SASL_PROTOCOL, protocol);
+        attributes.put(Registry.SASL_SERVER_NAME, serverName);
+        attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh);
+        result.init(attributes);
+      }
+    return result;
+  }
+
+  public String[] getMechanismNames(Map props)
+  {
+    return getNamesInternal(props);
+  }
+
+  private static boolean hasPolicy(String propertyName, Map props)
+  {
+    return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName)));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/ServerMechanism.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,294 @@
+/* ServerMechanism.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import gnu.java.security.Registry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+/**
+ * A base class to facilitate implementing SASL server-side mechanisms.
+ */
+public abstract class ServerMechanism
+    implements SaslServer
+{
+  /** Name of this mechanism. */
+  protected String mechanism;
+  /** Name of protocol using this mechanism. */
+  protected String protocol;
+  /** Name of server to authenticate to. */
+  protected String serverName;
+  /** Properties of qualities desired for this mechanism. */
+  protected Map properties;
+  /** Callback handler to use with this mechanism instance. */
+  protected CallbackHandler handler;
+  /** Whether authentication phase is completed (true) or not (false). */
+  protected boolean complete = false;
+  /** The authorisation identity. */
+  protected String authorizationID;
+  /** Channel binding data to use with this mechanism instance. */
+  protected byte[] channelBinding;
+  /** The state of the authentication automaton. -1 means uninitialised. */
+  protected int state = -1;
+  /** The provider for authentication information. */
+  protected IAuthInfoProvider authenticator;
+
+  protected ServerMechanism(final String mechanism)
+  {
+    super();
+
+    this.mechanism = mechanism;
+    this.authenticator = AuthInfo.getProvider(mechanism);
+    this.state = -1;
+  }
+
+  protected abstract void initMechanism() throws SaslException;
+
+  protected abstract void resetMechanism() throws SaslException;
+
+  public abstract byte[] evaluateResponse(byte[] response) throws SaslException;
+
+  public boolean isComplete()
+  {
+    return complete;
+  }
+
+  public byte[] unwrap(final byte[] incoming, final int offset, final int len)
+      throws SaslException
+  {
+    if (! isComplete())
+      throw new IllegalMechanismStateException();
+    return this.engineUnwrap(incoming, offset, len);
+  }
+
+  public byte[] wrap(final byte[] outgoing, final int offset, final int len)
+      throws SaslException
+  {
+    if (! isComplete())
+      throw new IllegalMechanismStateException();
+    return this.engineWrap(outgoing, offset, len);
+  }
+
+  public String getMechanismName()
+  {
+    return this.mechanism;
+  }
+
+  public String getAuthorizationID()
+  {
+    return this.authorizationID;
+  }
+
+  public Object getNegotiatedProperty(final String propName)
+  {
+    if (! isComplete())
+      throw new IllegalStateException();
+    if (Sasl.QOP.equals(propName))
+      return getNegotiatedQOP();
+    if (Sasl.STRENGTH.equals(propName))
+      return getNegotiatedStrength();
+    if (Sasl.SERVER_AUTH.equals(propName))
+      return getNegotiatedServerAuth();
+    if (Sasl.MAX_BUFFER.equals(propName))
+      return getNegotiatedMaxBuffer();
+    if (Sasl.RAW_SEND_SIZE.equals(propName))
+      return getNegotiatedRawSendSize();
+    if (Sasl.POLICY_NOPLAINTEXT.equals(propName))
+      return getNegotiatedPolicyNoPlainText();
+    if (Sasl.POLICY_NOACTIVE.equals(propName))
+      return getNegotiatedPolicyNoActive();
+    if (Sasl.POLICY_NODICTIONARY.equals(propName))
+      return getNegotiatedPolicyNoDictionary();
+    if (Sasl.POLICY_NOANONYMOUS.equals(propName))
+      return getNegotiatedPolicyNoAnonymous();
+    if (Sasl.POLICY_FORWARD_SECRECY.equals(propName))
+      return getNegotiatedPolicyForwardSecrecy();
+    if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName))
+      return getNegotiatedPolicyPassCredentials();
+    if (Sasl.REUSE.equals(propName))
+      return getReuse();
+    return null;
+  }
+
+  public void dispose() throws SaslException
+  {
+    reset();
+  }
+
+  protected String getNegotiatedQOP()
+  {
+    return Registry.QOP_AUTH;
+  }
+
+  protected String getNegotiatedStrength()
+  {
+    return Registry.STRENGTH_LOW;
+  }
+
+  protected String getNegotiatedServerAuth()
+  {
+    return Registry.SERVER_AUTH_FALSE;
+  }
+
+  protected String getNegotiatedMaxBuffer()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyNoPlainText()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyNoActive()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyNoDictionary()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyNoAnonymous()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyForwardSecrecy()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedPolicyPassCredentials()
+  {
+    return null;
+  }
+
+  protected String getNegotiatedRawSendSize()
+  {
+    return String.valueOf(Registry.SASL_BUFFER_MAX_LIMIT);
+  }
+
+  protected String getReuse()
+  {
+    return Registry.REUSE_FALSE;
+  }
+
+  protected byte[] engineUnwrap(final byte[] incoming, final int offset,
+                                final int len) throws SaslException
+  {
+    final byte[] result = new byte[len];
+    System.arraycopy(incoming, offset, result, 0, len);
+    return result;
+  }
+
+  protected byte[] engineWrap(final byte[] outgoing, final int offset,
+                              final int len) throws SaslException
+  {
+    final byte[] result = new byte[len];
+    System.arraycopy(outgoing, offset, result, 0, len);
+    return result;
+  }
+
+  /**
+   * Initialises the mechanism with designated attributes. Permissible names and
+   * values are mechanism specific.
+   * 
+   * @param attributes a set of name-value pairs that describes the desired
+   *          future behaviour of this instance.
+   * @throws IllegalMechanismStateException if the instance is already
+   *           initialised.
+   * @throws SaslException if an exception occurs during the process.
+   */
+  public void init(final Map attributes) throws SaslException
+  {
+    if (state != -1)
+      throw new IllegalMechanismStateException("init()");
+    if (properties == null)
+      properties = new HashMap();
+    else
+      properties.clear();
+    if (attributes != null)
+      {
+        protocol = (String) attributes.get(Registry.SASL_PROTOCOL);
+        serverName = (String) attributes.get(Registry.SASL_SERVER_NAME);
+        handler = (CallbackHandler) attributes.get(Registry.SASL_CALLBACK_HANDLER);
+        channelBinding = (byte[]) attributes.get(Registry.SASL_CHANNEL_BINDING);
+        properties.putAll(attributes);
+      }
+    else
+      handler = null;
+    if (protocol == null)
+      protocol = "";
+    if (serverName == null)
+      serverName = "";
+    if (authenticator != null)
+      authenticator.activate(properties);
+    if (channelBinding == null)
+      channelBinding = new byte[0];
+    initMechanism();
+    complete = false;
+    state = 0;
+  }
+
+  /**
+   * Resets the mechanism instance for re-initialisation and use with other
+   * characteristics.
+   * 
+   * @throws SaslException if an exception occurs during the process.
+   */
+  public void reset() throws SaslException
+  {
+    resetMechanism();
+    properties.clear();
+    if (authenticator != null)
+      authenticator.passivate();
+    protocol = serverName = null;
+    channelBinding = null;
+    complete = false;
+    state = -1;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/UserAlreadyExistsException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,70 @@
+/* UserAlreadyExistsException.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * A checked exception thrown to indicate that a designated user is already
+ * known to the the authentication layer.
+ */
+public class UserAlreadyExistsException
+    extends SaslException
+{
+  /**
+   * Constructs a <code>UserAlreadyExistsException</code> with no detail
+   * message.
+   */
+  public UserAlreadyExistsException()
+  {
+    super();
+  }
+
+  /**
+   * Constructs a <code>UserAlreadyExistsException</code> with the specified
+   * detail message. In the case of this exception, the detail message
+   * designates the offending username.
+   * 
+   * @param userName the detail message, which in this case is the username.
+   */
+  public UserAlreadyExistsException(String userName)
+  {
+    super(userName);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,102 @@
+/* AnonymousClient.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.anonymous;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.ClientMechanism;
+import gnu.javax.crypto.sasl.IllegalMechanismStateException;
+
+import java.io.UnsupportedEncodingException;
+
+import javax.security.sasl.AuthenticationException;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+/**
+ * The ANONYMOUS client-side mechanism.
+ */
+public class AnonymousClient
+    extends ClientMechanism
+    implements SaslClient
+{
+  public AnonymousClient()
+  {
+    super(Registry.SASL_ANONYMOUS_MECHANISM);
+  }
+
+  protected void initMechanism() throws SaslException
+  {
+  }
+
+  protected void resetMechanism() throws SaslException
+  {
+  }
+
+  public boolean hasInitialResponse()
+  {
+    return true;
+  }
+
+  public byte[] evaluateChallenge(final byte[] challenge) throws SaslException
+  {
+    if (complete)
+      {
+        throw new IllegalMechanismStateException("evaluateChallenge()");
+      }
+    return response();
+  }
+
+  private byte[] response() throws SaslException
+  {
+    if (! AnonymousUtil.isValidTraceInformation(authorizationID))
+      throw new AuthenticationException(
+          "Authorisation ID is not a valid email address");
+    complete = true;
+    final byte[] result;
+    try
+      {
+        result = authorizationID.getBytes("UTF-8");
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new AuthenticationException("response()", x);
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,90 @@
+/* AnonymousServer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.anonymous;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.ServerMechanism;
+
+import java.io.UnsupportedEncodingException;
+
+import javax.security.sasl.AuthenticationException;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+/**
+ * The ANONYMOUS server-side mechanism.
+ */
+public class AnonymousServer
+    extends ServerMechanism
+    implements SaslServer
+{
+  public AnonymousServer()
+  {
+    super(Registry.SASL_ANONYMOUS_MECHANISM);
+  }
+
+  protected void initMechanism() throws SaslException
+  {
+  }
+
+  protected void resetMechanism() throws SaslException
+  {
+  }
+
+  public byte[] evaluateResponse(final byte[] response) throws SaslException
+  {
+    if (response == null)
+      return null;
+    try
+      {
+        authorizationID = new String(response, "UTF-8");
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new AuthenticationException("evaluateResponse()", x);
+      }
+    if (AnonymousUtil.isValidTraceInformation(authorizationID))
+      {
+        this.complete = true;
+        return null;
+      }
+    authorizationID = null;
+    throw new AuthenticationException("Invalid email address");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,83 @@
+/* AnonymousUtil.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.anonymous;
+
+import gnu.javax.crypto.sasl.SaslUtil;
+
+/**
+ * An ANONYMOUS-specific utility class.
+ */
+public class AnonymousUtil
+{
+  /** Trivial private constructor to enforce Singleton pattern. */
+  private AnonymousUtil()
+  {
+    super();
+  }
+
+  static boolean isValidTraceInformation(String traceInformation)
+  {
+    if (traceInformation == null)
+      return false;
+    if (traceInformation.length() == 0)
+      return true;
+    if (SaslUtil.validEmailAddress(traceInformation))
+      return true;
+    return isValidToken(traceInformation);
+  }
+
+  static boolean isValidToken(String token)
+  {
+    if (token == null)
+      return false;
+    if (token.length() == 0)
+      return false;
+    if (token.length() > 255)
+      return false;
+    if (token.indexOf('@') != -1)
+      return false;
+    for (int i = 0; i < token.length(); i++)
+      {
+        char c = token.charAt(i);
+        if (c < 0x20 || c > 0x7E)
+          return false;
+      }
+    return true;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,166 @@
+/* CramMD5AuthInfoProvider.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.crammd5;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.IAuthInfoProvider;
+import gnu.javax.crypto.sasl.NoSuchUserException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.sasl.AuthenticationException;
+
+/**
+ * The CRAM-MD5 mechanism authentication information provider implementation.
+ */
+public class CramMD5AuthInfoProvider
+    implements IAuthInfoProvider
+{
+  private PasswordFile passwordFile = null;
+
+  // implicit 0-args constrcutor
+
+  public void activate(Map context) throws AuthenticationException
+  {
+    try
+      {
+        if (context == null)
+          passwordFile = new PasswordFile();
+        else
+          {
+            String pfn = (String) context.get(CramMD5Registry.PASSWORD_FILE);
+            if (pfn == null)
+              passwordFile = new PasswordFile();
+            else
+              passwordFile = new PasswordFile(pfn);
+          }
+      }
+    catch (IOException x)
+      {
+        throw new AuthenticationException("activate()", x);
+      }
+  }
+
+  public void passivate() throws AuthenticationException
+  {
+    passwordFile = null;
+  }
+
+  public boolean contains(String userName) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("contains()",
+                                        new IllegalStateException());
+    boolean result = false;
+    try
+      {
+        result = passwordFile.contains(userName);
+      }
+    catch (IOException x)
+      {
+        throw new AuthenticationException("contains()", x);
+      }
+    return result;
+  }
+
+  public Map lookup(Map userID) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("lookup()", new IllegalStateException());
+    Map result = new HashMap();
+    try
+      {
+        String userName = (String) userID.get(Registry.SASL_USERNAME);
+        if (userName == null)
+          throw new NoSuchUserException("");
+        String[] data = passwordFile.lookup(userName);
+        result.put(Registry.SASL_USERNAME, data[0]);
+        result.put(Registry.SASL_PASSWORD, data[1]);
+        result.put(CramMD5Registry.UID_FIELD, data[2]);
+        result.put(CramMD5Registry.GID_FIELD, data[3]);
+        result.put(CramMD5Registry.GECOS_FIELD, data[4]);
+        result.put(CramMD5Registry.DIR_FIELD, data[5]);
+        result.put(CramMD5Registry.SHELL_FIELD, data[6]);
+      }
+    catch (Exception x)
+      {
+        if (x instanceof AuthenticationException)
+          throw (AuthenticationException) x;
+        throw new AuthenticationException("lookup()", x);
+      }
+    return result;
+  }
+
+  public void update(Map userCredentials) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("update()", new IllegalStateException());
+    try
+      {
+        String userName = (String) userCredentials.get(Registry.SASL_USERNAME);
+        String password = (String) userCredentials.get(Registry.SASL_PASSWORD);
+        String uid = (String) userCredentials.get(CramMD5Registry.UID_FIELD);
+        String gid = (String) userCredentials.get(CramMD5Registry.GID_FIELD);
+        String gecos = (String) userCredentials.get(CramMD5Registry.GECOS_FIELD);
+        String dir = (String) userCredentials.get(CramMD5Registry.DIR_FIELD);
+        String shell = (String) userCredentials.get(CramMD5Registry.SHELL_FIELD);
+        if (uid == null || gid == null || gecos == null || dir == null
+            || shell == null)
+          passwordFile.changePasswd(userName, password);
+        else
+          {
+            String[] attributes = new String[] { uid, gid, gecos, dir, shell };
+            passwordFile.add(userName, password, attributes);
+          }
+      }
+    catch (Exception x)
+      {
+        if (x instanceof AuthenticationException)
+          throw (AuthenticationException) x;
+        throw new AuthenticationException("update()", x);
+      }
+  }
+
+  public Map getConfiguration(String mode) throws AuthenticationException
+  {
+    throw new AuthenticationException("", new UnsupportedOperationException());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,168 @@
+/* CramMD5Client.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.crammd5;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.sasl.ClientMechanism;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthenticationException;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+/**
+ * The CRAM-MD5 SASL client-side mechanism.
+ */
+public class CramMD5Client
+    extends ClientMechanism
+    implements SaslClient
+{
+  public CramMD5Client()
+  {
+    super(Registry.SASL_CRAM_MD5_MECHANISM);
+  }
+
+  protected void initMechanism() throws SaslException
+  {
+  }
+
+  protected void resetMechanism() throws SaslException
+  {
+  }
+
+  public boolean hasInitialResponse()
+  {
+    return false;
+  }
+
+  public byte[] evaluateChallenge(final byte[] challenge) throws SaslException
+  {
+    if (challenge == null)
+      throw new SaslException("null challenge");
+    try
+      {
+        final String username;
+        final char[] password;
+        Callback[] callbacks;
+        if ((! properties.containsKey(Registry.SASL_USERNAME))
+            && (! properties.containsKey(Registry.SASL_PASSWORD)))
+          {
+            callbacks = new Callback[2];
+            final NameCallback nameCB;
+            final String defaultName = System.getProperty("user.name");
+            if (defaultName == null)
+              nameCB = new NameCallback("username: ");
+            else
+              nameCB = new NameCallback("username: ", defaultName);
+            final PasswordCallback pwdCB = new PasswordCallback("password: ",
+                                                                false);
+            callbacks[0] = nameCB;
+            callbacks[1] = pwdCB;
+            this.handler.handle(callbacks);
+            username = nameCB.getName();
+            password = pwdCB.getPassword();
+          }
+        else
+          {
+            if (properties.containsKey(Registry.SASL_USERNAME))
+              username = (String) properties.get(Registry.SASL_USERNAME);
+            else
+              {
+                callbacks = new Callback[1];
+                final NameCallback nameCB;
+                final String defaultName = System.getProperty("user.name");
+                if (defaultName == null)
+                  nameCB = new NameCallback("username: ");
+                else
+                  nameCB = new NameCallback("username: ", defaultName);
+                callbacks[0] = nameCB;
+                this.handler.handle(callbacks);
+                username = nameCB.getName();
+              }
+
+            if (properties.containsKey(Registry.SASL_PASSWORD))
+              password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray();
+            else
+              {
+                callbacks = new Callback[1];
+                final PasswordCallback pwdCB = new PasswordCallback("password: ",
+                                                                    false);
+                callbacks[0] = pwdCB;
+                this.handler.handle(callbacks);
+                password = pwdCB.getPassword();
+              }
+          }
+        if (password == null)
+          throw new SaslException("null password supplied");
+        final byte[] digest;
+        try
+          {
+            digest = CramMD5Util.createHMac(password, challenge);
+          }
+        catch (InvalidKeyException x)
+          {
+            throw new AuthenticationException("evaluateChallenge()", x);
+          }
+        final String response = username + " "
+                                + Util.toString(digest).toLowerCase();
+        this.complete = true;
+        return response.getBytes("UTF-8");
+      }
+    catch (UnsupportedCallbackException x)
+      {
+        throw new AuthenticationException("evaluateChallenge()", x);
+      }
+    catch (IOException x)
+      {
+        throw new AuthenticationException("evaluateChallenge()", x);
+      }
+  }
+
+  protected String getNegotiatedQOP()
+  {
+    return Registry.QOP_AUTH;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,60 @@
+/* CramMD5Registry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.crammd5;
+
+/**
+ * A list of properties common to CRAM-MD5 classes.
+ */
+public interface CramMD5Registry
+{
+  /** Name of the password file (used by the server) property. */
+  String PASSWORD_FILE = "gnu.crypto.sasl.crammd5.password.file";
+  /** Default password file (used by the server) pathname. */
+  String DEFAULT_PASSWORD_FILE = "/etc/passwd";
+  /** Name of the UID field in the plain password file. */
+  String UID_FIELD = "crammd5.uid";
+  /** Name of the GID field in the plain password file. */
+  String GID_FIELD = "crammd5.gid";
+  /** Name of the GECOS field in the plain password file. */
+  String GECOS_FIELD = "crammd5.gecos";
+  /** Name of the DIR field in the plain password file. */
+  String DIR_FIELD = "crammd5.dir";
+  /** Name of the SHELL field in the plain password file. */
+  String SHELL_FIELD = "crammd5.shell";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,158 @@
+/* CramMD5Server.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.crammd5;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.sasl.NoSuchUserException;
+import gnu.javax.crypto.sasl.ServerMechanism;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.sasl.AuthenticationException;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+/**
+ * The CRAM-MD5 SASL server-side mechanism.
+ */
+public class CramMD5Server
+    extends ServerMechanism
+    implements SaslServer
+{
+  private byte[] msgID;
+
+  public CramMD5Server()
+  {
+    super(Registry.SASL_CRAM_MD5_MECHANISM);
+  }
+
+  protected void initMechanism() throws SaslException
+  {
+  }
+
+  protected void resetMechanism() throws SaslException
+  {
+  }
+
+  public byte[] evaluateResponse(final byte[] response) throws SaslException
+  {
+    if (state == 0)
+      {
+        msgID = CramMD5Util.createMsgID();
+        state++;
+        return msgID;
+      }
+    final String responseStr = new String(response);
+    final int index = responseStr.lastIndexOf(" ");
+    final String username = responseStr.substring(0, index);
+    final byte[] responseDigest;
+    try
+      {
+        responseDigest = responseStr.substring(index + 1).getBytes("UTF-8");
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new AuthenticationException("evaluateResponse()", x);
+      }
+    // Look up the password
+    final char[] password = lookupPassword(username);
+    // Compute the digest
+    byte[] digest;
+    try
+      {
+        digest = CramMD5Util.createHMac(password, msgID);
+      }
+    catch (InvalidKeyException x)
+      {
+        throw new AuthenticationException("evaluateResponse()", x);
+      }
+    try
+      {
+        digest = Util.toString(digest).toLowerCase().getBytes("UTF-8");
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new AuthenticationException("evaluateResponse()", x);
+      }
+    // Compare the received and computed digests
+    if (! Arrays.equals(digest, responseDigest))
+      throw new AuthenticationException("Digest mismatch");
+    state++;
+    return null;
+  }
+
+  public boolean isComplete()
+  {
+    return (state == 2);
+  }
+
+  protected String getNegotiatedQOP()
+  {
+    return Registry.QOP_AUTH;
+  }
+
+  private char[] lookupPassword(final String userName) throws SaslException
+  {
+    try
+      {
+        if (! authenticator.contains(userName))
+          throw new NoSuchUserException(userName);
+        final Map userID = new HashMap();
+        userID.put(Registry.SASL_USERNAME, userName);
+        final Map credentials = authenticator.lookup(userID);
+        final String password = (String) credentials.get(Registry.SASL_PASSWORD);
+        if (password == null)
+          throw new AuthenticationException("lookupPassword()",
+                                            new InternalError());
+        return password.toCharArray();
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new AuthenticationException("lookupPassword()", x);
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,120 @@
+/* CramMD5Util.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.crammd5;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.mac.HMacFactory;
+import gnu.javax.crypto.mac.IMac;
+
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.util.HashMap;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * A package-private CRAM-MD5-specific utility class.
+ */
+class CramMD5Util
+{
+  private CramMD5Util()
+  {
+    super();
+  }
+
+  static byte[] createMsgID() throws SaslException
+  {
+    final String encoded;
+    try
+      {
+        encoded = Util.toBase64(Thread.currentThread().getName().getBytes("UTF-8"));
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new SaslException("createMsgID()", x);
+      }
+    String hostname = "localhost";
+    try
+      {
+        hostname = InetAddress.getLocalHost().getHostAddress();
+      }
+    catch (UnknownHostException ignored)
+      {
+      }
+    final byte[] result;
+    try
+      {
+        result = new StringBuffer("<")
+            .append(encoded.substring(0,encoded.length()))
+            .append(".").append(String.valueOf(System.currentTimeMillis()))
+            .append("@").append(hostname).append(">")
+            .toString()
+            .getBytes("UTF-8");
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new SaslException("createMsgID()", x);
+      }
+    return result;
+  }
+
+  static byte[] createHMac(final char[] passwd, final byte[] data)
+      throws InvalidKeyException, SaslException
+  {
+    final IMac mac = HMacFactory.getInstance(Registry.HMAC_NAME_PREFIX
+                                             + Registry.MD5_HASH);
+    final HashMap map = new HashMap();
+    final byte[] km;
+    try
+      {
+        km = new String(passwd).getBytes("UTF-8");
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new SaslException("createHMac()", x);
+      }
+    map.put(IMac.MAC_KEY_MATERIAL, km);
+    mac.init(map);
+    mac.update(data, 0, data.length);
+    return mac.digest();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/crammd5/PasswordFile.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,238 @@
+/* PasswordFile.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.crammd5;
+
+import gnu.javax.crypto.sasl.NoSuchUserException;
+import gnu.javax.crypto.sasl.UserAlreadyExistsException;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+/**
+ * The CRAM-MD5 password file representation.
+ */
+public class PasswordFile
+{
+  private static String DEFAULT_FILE;
+  static
+    {
+      DEFAULT_FILE = System.getProperty(CramMD5Registry.PASSWORD_FILE,
+                                        CramMD5Registry.DEFAULT_PASSWORD_FILE);
+    }
+  private HashMap entries;
+  private File passwdFile;
+  private long lastmod;
+
+  public PasswordFile() throws IOException
+  {
+    this(DEFAULT_FILE);
+  }
+
+  public PasswordFile(final File pwFile) throws IOException
+  {
+    this(pwFile.getAbsolutePath());
+  }
+
+  public PasswordFile(final String fileName) throws IOException
+  {
+    passwdFile = new File(fileName);
+    update();
+  }
+
+  public synchronized void add(final String user, final String passwd,
+                               final String[] attributes) throws IOException
+  {
+    checkCurrent(); // check if the entry exists
+    if (entries.containsKey(user))
+      throw new UserAlreadyExistsException(user);
+    if (attributes.length != 5)
+      throw new IllegalArgumentException("Wrong number of attributes");
+    final String[] fields = new String[7]; // create the new entry
+    fields[0] = user;
+    fields[1] = passwd;
+    System.arraycopy(attributes, 0, fields, 2, 5);
+    entries.put(user, fields);
+    savePasswd();
+  }
+
+  public synchronized void changePasswd(final String user, final String passwd)
+      throws IOException
+  {
+    checkCurrent();
+    if (! entries.containsKey(user))
+      throw new NoSuchUserException(user);
+    final String[] fields = (String[]) entries.get(user); // get existing entry
+    fields[1] = passwd; // modify the password field
+    entries.remove(user); // delete the existing entry
+    entries.put(user, fields); // add the new entry
+    savePasswd();
+  }
+
+  public synchronized String[] lookup(final String user) throws IOException
+  {
+    checkCurrent();
+    if (! entries.containsKey(user))
+      throw new NoSuchUserException(user);
+    return (String[]) entries.get(user);
+  }
+
+  public synchronized boolean contains(final String s) throws IOException
+  {
+    checkCurrent();
+    return entries.containsKey(s);
+  }
+
+  private synchronized void update() throws IOException
+  {
+    lastmod = passwdFile.lastModified();
+    readPasswd(new FileInputStream(passwdFile));
+  }
+
+  private void checkCurrent() throws IOException
+  {
+    if (passwdFile.lastModified() > lastmod)
+      update();
+  }
+
+  private synchronized void readPasswd(final InputStream in) throws IOException
+  {
+    final BufferedReader din = new BufferedReader(new InputStreamReader(in));
+    String line;
+    entries = new HashMap();
+    while ((line = din.readLine()) != null)
+      {
+        final String[] fields = new String[7];
+        final StringTokenizer st = new StringTokenizer(line, ":", true);
+        try
+          {
+            fields[0] = st.nextToken(); // username
+            st.nextToken();
+            fields[1] = st.nextToken(); // passwd
+            if (fields[1].equals(":"))
+              fields[1] = "";
+            else
+              st.nextToken();
+            fields[2] = st.nextToken(); // uid
+            if (fields[2].equals(":"))
+              fields[2] = "";
+            else
+              st.nextToken();
+            fields[3] = st.nextToken(); // gid
+            if (fields[3].equals(":"))
+              fields[3] = "";
+            else
+              st.nextToken();
+            fields[4] = st.nextToken(); // gecos
+            if (fields[4].equals(":"))
+              fields[4] = "";
+            else
+              st.nextToken();
+            fields[5] = st.nextToken(); // dir
+            if (fields[5].equals(":"))
+              fields[5] = "";
+            else
+              st.nextToken();
+            fields[6] = st.nextToken(); // shell
+            if (fields[6].equals(":"))
+              fields[6] = "";
+          }
+        catch (NoSuchElementException x)
+          {
+            continue;
+          }
+        entries.put(fields[0], fields);
+      }
+  }
+
+  private synchronized void savePasswd() throws IOException
+  {
+    if (passwdFile != null)
+      {
+        final FileOutputStream fos = new FileOutputStream(passwdFile);
+        PrintWriter pw = null;
+        try
+          {
+            pw = new PrintWriter(fos);
+            String key;
+            String[] fields;
+            StringBuffer sb;
+            int i;
+            for (Iterator it = entries.keySet().iterator(); it.hasNext();)
+              {
+                key = (String) it.next();
+                fields = (String[]) entries.get(key);
+                sb = new StringBuffer(fields[0]);
+                for (i = 1; i < fields.length; i++)
+                  sb.append(":").append(fields[i]);
+                pw.println(sb.toString());
+              }
+          }
+        finally
+          {
+            if (pw != null)
+              try
+                {
+                  pw.flush();
+                }
+              finally
+                {
+                  pw.close();
+                }
+            try
+              {
+                fos.close();
+              }
+            catch (IOException ignored)
+              {
+              }
+            lastmod = passwdFile.lastModified();
+          }
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/plain/PasswordFile.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,243 @@
+/* PasswordFile.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.plain;
+
+import gnu.java.security.action.GetPropertyAction;
+import gnu.javax.crypto.sasl.NoSuchUserException;
+import gnu.javax.crypto.sasl.UserAlreadyExistsException;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.security.AccessController;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+/**
+ * A representation of a Plain password file.
+ */
+public class PasswordFile
+{
+  private static String DEFAULT_FILE;
+  static
+    {
+      DEFAULT_FILE = (String) AccessController.doPrivileged
+          (new GetPropertyAction(PlainRegistry.PASSWORD_FILE,
+          PlainRegistry.DEFAULT_PASSWORD_FILE));
+    }
+  private Hashtable entries;
+  private File passwdFile;
+  private long lastmod;
+
+  public PasswordFile() throws IOException
+  {
+    this(DEFAULT_FILE);
+  }
+
+  public PasswordFile(File pwFile) throws IOException
+  {
+    this(pwFile.getAbsolutePath());
+  }
+
+  public PasswordFile(String fileName) throws IOException
+  {
+    passwdFile = new File(fileName);
+    update();
+  }
+
+  public synchronized void add(String user, String passwd, String[] attributes)
+      throws IOException
+  {
+    checkCurrent();
+    if (entries.containsKey(user))
+      throw new UserAlreadyExistsException(user);
+    if (attributes.length != 5)
+      throw new IllegalArgumentException("Wrong number of attributes");
+    // create the new entry
+    String[] fields = new String[7];
+    fields[0] = user;
+    fields[1] = passwd;
+    System.arraycopy(attributes, 0, fields, 2, 5);
+    entries.put(user, fields);
+    savePasswd();
+  }
+
+  public synchronized void changePasswd(String user, String passwd)
+      throws IOException
+  {
+    checkCurrent();
+    if (! entries.containsKey(user))
+      throw new NoSuchUserException(user);
+    String[] fields = (String[]) entries.get(user); // get the existing entry
+    fields[1] = passwd; // modify the password field
+    entries.remove(user); // delete the existing entry
+    entries.put(user, fields); // add the new entry
+    savePasswd();
+  }
+
+  public synchronized String[] lookup(String user) throws IOException
+  {
+    checkCurrent();
+    if (! entries.containsKey(user))
+      throw new NoSuchUserException(user);
+    return (String[]) entries.get(user);
+  }
+
+  public synchronized boolean contains(String s) throws IOException
+  {
+    checkCurrent();
+    return entries.containsKey(s);
+  }
+
+  private synchronized void update() throws IOException
+  {
+    lastmod = passwdFile.lastModified();
+    readPasswd(new FileInputStream(passwdFile));
+  }
+
+  private void checkCurrent() throws IOException
+  {
+    if (passwdFile.lastModified() > lastmod)
+      update();
+  }
+
+  private synchronized void readPasswd(InputStream in) throws IOException
+  {
+    BufferedReader din = new BufferedReader(new InputStreamReader(in));
+    String line;
+    entries = new Hashtable();
+    String[] fields = new String[7];
+    while ((line = din.readLine()) != null)
+      {
+        StringTokenizer st = new StringTokenizer(line, ":", true);
+        try
+          {
+            fields[0] = st.nextToken(); // username
+            st.nextToken();
+            fields[1] = st.nextToken(); // passwd
+            if (fields[1].equals(":"))
+              fields[1] = "";
+            else
+              st.nextToken();
+            fields[2] = st.nextToken(); // uid
+            if (fields[2].equals(":"))
+              fields[2] = "";
+            else
+              st.nextToken();
+            fields[3] = st.nextToken(); // gid
+            if (fields[3].equals(":"))
+              fields[3] = "";
+            else
+              st.nextToken();
+            fields[4] = st.nextToken(); // gecos
+            if (fields[4].equals(":"))
+              fields[4] = "";
+            else
+              st.nextToken();
+            fields[5] = st.nextToken(); // dir
+            if (fields[5].equals(":"))
+              fields[5] = "";
+            else
+              st.nextToken();
+            fields[6] = st.nextToken(); // shell
+            if (fields[6].equals(":"))
+              fields[6] = "";
+          }
+        catch (NoSuchElementException ignored)
+          {
+            continue;
+          }
+        entries.put(fields[0], fields);
+      }
+  }
+
+  private synchronized void savePasswd() throws IOException
+  {
+    if (passwdFile != null)
+      {
+        FileOutputStream fos = new FileOutputStream(passwdFile);
+        PrintWriter pw = null;
+        try
+          {
+            pw = new PrintWriter(fos);
+            String key;
+            String[] fields;
+            StringBuffer sb;
+            Enumeration keys = entries.keys();
+            while (keys.hasMoreElements())
+              {
+                key = (String) keys.nextElement();
+                fields = (String[]) entries.get(key);
+                sb = new StringBuffer(fields[0]);
+                for (int i = 1; i < fields.length; i++)
+                  sb.append(":" + fields[i]);
+                pw.println(sb.toString());
+              }
+          }
+        finally
+          {
+            if (pw != null)
+              try
+                {
+                  pw.flush();
+                }
+              finally
+                {
+                  pw.close();
+                }
+            if (fos != null)
+              try
+                {
+                  fos.close();
+                }
+              catch (IOException ignored)
+                {
+                }
+            lastmod = passwdFile.lastModified();
+          }
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,166 @@
+/* PlainAuthInfoProvider.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.plain;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.IAuthInfoProvider;
+import gnu.javax.crypto.sasl.NoSuchUserException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.sasl.AuthenticationException;
+
+/**
+ * The PLAIN mechanism authentication information provider implementation.
+ */
+public class PlainAuthInfoProvider
+    implements IAuthInfoProvider, PlainRegistry
+{
+  private PasswordFile passwordFile = null;
+
+  // implicit 0-args constrcutor
+
+  public void activate(Map context) throws AuthenticationException
+  {
+    try
+      {
+        if (context == null)
+          passwordFile = new PasswordFile();
+        else
+          {
+            String pfn = (String) context.get(PASSWORD_FILE);
+            if (pfn == null)
+              passwordFile = new PasswordFile();
+            else
+              passwordFile = new PasswordFile(pfn);
+          }
+      }
+    catch (IOException x)
+      {
+        throw new AuthenticationException("activate()", x);
+      }
+  }
+
+  public void passivate() throws AuthenticationException
+  {
+    passwordFile = null;
+  }
+
+  public boolean contains(String userName) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("contains()",
+                                        new IllegalStateException());
+    boolean result = false;
+    try
+      {
+        result = passwordFile.contains(userName);
+      }
+    catch (IOException x)
+      {
+        throw new AuthenticationException("contains()", x);
+      }
+    return result;
+  }
+
+  public Map lookup(Map userID) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("lookup()", new IllegalStateException());
+    Map result = new HashMap();
+    try
+      {
+        String userName = (String) userID.get(Registry.SASL_USERNAME);
+        if (userName == null)
+          throw new NoSuchUserException("");
+        String[] data = passwordFile.lookup(userName);
+        result.put(Registry.SASL_USERNAME, data[0]);
+        result.put(Registry.SASL_PASSWORD, data[1]);
+        result.put(UID_FIELD, data[2]);
+        result.put(GID_FIELD, data[3]);
+        result.put(GECOS_FIELD, data[4]);
+        result.put(DIR_FIELD, data[5]);
+        result.put(SHELL_FIELD, data[6]);
+      }
+    catch (Exception x)
+      {
+        if (x instanceof AuthenticationException)
+          throw (AuthenticationException) x;
+        throw new AuthenticationException("lookup()", x);
+      }
+    return result;
+  }
+
+  public void update(Map userCredentials) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("update()", new IllegalStateException());
+    try
+      {
+        String userName = (String) userCredentials.get(Registry.SASL_USERNAME);
+        String password = (String) userCredentials.get(Registry.SASL_PASSWORD);
+        String uid = (String) userCredentials.get(UID_FIELD);
+        String gid = (String) userCredentials.get(GID_FIELD);
+        String gecos = (String) userCredentials.get(GECOS_FIELD);
+        String dir = (String) userCredentials.get(DIR_FIELD);
+        String shell = (String) userCredentials.get(SHELL_FIELD);
+        if (uid == null || gid == null || gecos == null || dir == null
+            || shell == null)
+          passwordFile.changePasswd(userName, password);
+        else
+          {
+            String[] attributes = new String[] { uid, gid, gecos, dir, shell };
+            passwordFile.add(userName, password, attributes);
+          }
+      }
+    catch (Exception x)
+      {
+        if (x instanceof AuthenticationException)
+          throw (AuthenticationException) x;
+        throw new AuthenticationException("update()", x);
+      }
+  }
+
+  public Map getConfiguration(String mode) throws AuthenticationException
+  {
+    throw new AuthenticationException("", new UnsupportedOperationException());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/plain/PlainClient.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,154 @@
+/* PlainClient.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.plain;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.ClientMechanism;
+
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+
+/**
+ * The PLAIN SASL client-side mechanism.
+ */
+public class PlainClient
+    extends ClientMechanism
+    implements SaslClient
+{
+  public PlainClient()
+  {
+    super(Registry.SASL_PLAIN_MECHANISM);
+  }
+
+  protected void initMechanism() throws SaslException
+  {
+  }
+
+  protected void resetMechanism() throws SaslException
+  {
+  }
+
+  public boolean hasInitialResponse()
+  {
+    return true;
+  }
+
+  public byte[] evaluateChallenge(final byte[] challenge) throws SaslException
+  {
+    try
+      {
+        final String username;
+        final char[] password;
+        Callback[] callbacks;
+        if ((! properties.containsKey(Registry.SASL_USERNAME))
+            && (! properties.containsKey(Registry.SASL_PASSWORD)))
+          {
+            callbacks = new Callback[2];
+            final NameCallback nameCB;
+            final String defaultName = System.getProperty("user.name");
+            if (defaultName == null)
+              nameCB = new NameCallback("username: ");
+            else
+              nameCB = new NameCallback("username: ", defaultName);
+            final PasswordCallback pwdCB = new PasswordCallback("password: ",
+                                                                false);
+            callbacks[0] = nameCB;
+            callbacks[1] = pwdCB;
+            this.handler.handle(callbacks);
+            username = nameCB.getName();
+            password = pwdCB.getPassword();
+          }
+        else
+          {
+            if (properties.containsKey(Registry.SASL_USERNAME))
+              username = (String) properties.get(Registry.SASL_USERNAME);
+            else
+              {
+                callbacks = new Callback[1];
+                final NameCallback nameCB;
+                final String defaultName = System.getProperty("user.name");
+                if (defaultName == null)
+                  nameCB = new NameCallback("username: ");
+                else
+                  nameCB = new NameCallback("username: ", defaultName);
+                callbacks[0] = nameCB;
+                this.handler.handle(callbacks);
+                username = nameCB.getName();
+              }
+            if (properties.containsKey(Registry.SASL_PASSWORD))
+              password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray();
+            else
+              {
+                callbacks = new Callback[1];
+                final PasswordCallback pwdCB = new PasswordCallback("password: ",
+                                                                    false);
+                callbacks[0] = pwdCB;
+                this.handler.handle(callbacks);
+                password = pwdCB.getPassword();
+              }
+          }
+        if (password == null)
+          throw new SaslException("null password supplied");
+        final StringBuffer sb = new StringBuffer();
+        if (authorizationID != null)
+          sb.append(authorizationID);
+        sb.append('\0');
+        sb.append(username);
+        sb.append('\0');
+        sb.append(password);
+        this.complete = true;
+        final byte[] response = sb.toString().getBytes("UTF-8");
+        return response;
+      }
+    catch (Exception x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new SaslException("evaluateChallenge()", x);
+      }
+  }
+
+  protected String getNegotiatedQOP()
+  {
+    return Registry.QOP_AUTH;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/plain/PlainRegistry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,57 @@
+/* PlainRegistry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.plain;
+
+public interface PlainRegistry
+{
+  /** Name of PLAIN password file property. */
+  String PASSWORD_FILE = "gnu.crypto.sasl.plain.password.file";
+  /** Default fully qualified pathname of the PLAIN password file. */
+  String DEFAULT_PASSWORD_FILE = "/etc/tpasswd";
+  /** Name of the UID field in the plain password file. */
+  String UID_FIELD = "plain.uid";
+  /** Name of the GID field in the plain password file. */
+  String GID_FIELD = "plain.gid";
+  /** Name of the GECOS field in the plain password file. */
+  String GECOS_FIELD = "plain.gecos";
+  /** Name of the DIR field in the plain password file. */
+  String DIR_FIELD = "plain.dir";
+  /** Name of the SHELL field in the plain password file. */
+  String SHELL_FIELD = "plain.shell";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/plain/PlainServer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,155 @@
+/* PlainServer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.plain;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.sasl.NoSuchUserException;
+import gnu.javax.crypto.sasl.ServerMechanism;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+/**
+ * The PLAIN SASL server-side mechanism.
+ */
+public class PlainServer
+    extends ServerMechanism
+    implements SaslServer
+{
+  public PlainServer()
+  {
+    super(Registry.SASL_PLAIN_MECHANISM);
+  }
+
+  protected void initMechanism() throws SaslException
+  {
+  }
+
+  protected void resetMechanism() throws SaslException
+  {
+  }
+
+  public byte[] evaluateResponse(final byte[] response) throws SaslException
+  {
+    if (response == null)
+      return null;
+    try
+      {
+        final String nullStr = new String("\0");
+        final StringTokenizer strtok = new StringTokenizer(new String(response),
+                                                           nullStr, true);
+        authorizationID = strtok.nextToken();
+        if (! authorizationID.equals(nullStr))
+          strtok.nextToken();
+        else
+          authorizationID = null;
+        final String id = strtok.nextToken();
+        if (id.equals(nullStr))
+          throw new SaslException("No identity given");
+        if (authorizationID == null)
+          authorizationID = id;
+        if ((! authorizationID.equals(nullStr)) && (! authorizationID.equals(id)))
+          throw new SaslException("Delegation not supported");
+        strtok.nextToken();
+        final byte[] pwd;
+        try
+          {
+            pwd = strtok.nextToken().getBytes("UTF-8");
+          }
+        catch (UnsupportedEncodingException x)
+          {
+            throw new SaslException("evaluateResponse()", x);
+          }
+        if (pwd == null)
+          throw new SaslException("No password given");
+        final byte[] password;
+        try
+          {
+            password = new String(lookupPassword(id)).getBytes("UTF-8");
+          }
+        catch (UnsupportedEncodingException x)
+          {
+            throw new SaslException("evaluateResponse()", x);
+          }
+        if (! Arrays.equals(pwd, password))
+          throw new SaslException("Password incorrect");
+        this.complete = true;
+        return null;
+      }
+    catch (NoSuchElementException x)
+      {
+        throw new SaslException("evaluateResponse()", x);
+      }
+  }
+
+  protected String getNegotiatedQOP()
+  {
+    return Registry.QOP_AUTH;
+  }
+
+  private char[] lookupPassword(final String userName) throws SaslException
+  {
+    try
+      {
+        if (! authenticator.contains(userName))
+          throw new NoSuchUserException(userName);
+        final Map userID = new HashMap();
+        userID.put(Registry.SASL_USERNAME, userName);
+        final Map credentials = authenticator.lookup(userID);
+        final String password = (String) credentials.get(Registry.SASL_PASSWORD);
+        if (password == null)
+          throw new SaslException("lookupPassword()", new InternalError());
+        return password.toCharArray();
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new SaslException("lookupPassword()", x);
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/CALG.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,221 @@
+/* CALG.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.assembly.Assembly;
+import gnu.javax.crypto.assembly.Cascade;
+import gnu.javax.crypto.assembly.Direction;
+import gnu.javax.crypto.assembly.Stage;
+import gnu.javax.crypto.assembly.Transformer;
+import gnu.javax.crypto.assembly.TransformerException;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.mode.IMode;
+import gnu.javax.crypto.mode.ModeFactory;
+import gnu.javax.crypto.pad.IPad;
+import gnu.javax.crypto.pad.PadFactory;
+import gnu.javax.crypto.sasl.ConfidentialityException;
+
+import java.util.HashMap;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * A Factory class that returns CALG (Confidentiality Algorithm) instances that
+ * operate as described in the draft-burdis-cat-sasl-srp-08.
+ * <p>
+ * The designated CALG block cipher should be used in OFB (Output Feedback
+ * Block) mode in the ISO variant, as described in <i>The Handbook of Applied
+ * Cryptography</i>, algorithm 7.20.
+ * <p>
+ * Let <code>k</code> be the block size of the chosen symmetric key block
+ * cipher algorithm; e.g. for AES this is <code>128</code> bits or
+ * <code>16</code> octets. The OFB mode used shall be of length/size
+ * <code>k</code>.
+ * <p>
+ * It is recommended that block ciphers operating in OFB mode be used with an
+ * Initial Vector (the mode's IV). In such a mode of operation - OFB with key
+ * re-use - the IV need not be secret. For the mechanism in question the IVs
+ * shall be a random octet sequence of <code>k</code> bytes.
+ * <p>
+ * The input data to the confidentiality protection algorithm shall be a
+ * multiple of the symmetric cipher block size <code>k</code>. When the input
+ * length is not a multiple of <code>k</code> octets, the data shall be padded
+ * according to the following scheme:
+ * <p>
+ * Assuming the length of the input is <code>l</code> octets,
+ * <code>(k - (l mod k))</code> octets, all having the value
+ * <code>(k - (l mod k))</code>, shall be appended to the original data. In
+ * other words, the input is padded at the trailing end with one of the
+ * following sequences:
+ * <pre>
+ * 
+ *                     01 -- if l mod k = k-1
+ *                    02 02 -- if l mod k = k-2
+ *                              ...
+ *                              ...
+ *                              ...
+ *                  k k ... k k -- if l mod k = 0
+ * </pre>
+ * <p>
+ * The padding can be removed unambiguously since all input is padded and no
+ * padding sequence is a suffix of another. This padding method is well-defined
+ * if and only if <code>k &lt; 256</code> octets, which is the case with
+ * symmetric key block ciphers today, and in the forseeable future.
+ */
+public final class CALG
+{
+  private Assembly assembly;
+  private Object modeNdx; // initialisation key of the cascade's attributes
+  private int blockSize; // the underlying cipher's blocksize == IV length
+  private int keySize; // the underlying cipher's key size (in bytes).
+
+  /** Private constructor to enforce instantiation through Factory method. */
+  private CALG(final int blockSize, final int keySize, final Object modeNdx,
+               final Assembly assembly)
+  {
+    super();
+
+    this.blockSize = blockSize;
+    this.keySize = keySize;
+    this.modeNdx = modeNdx;
+    this.assembly = assembly;
+  }
+
+  /**
+   * Returns an instance of a SASL-SRP CALG implementation.
+   * 
+   * @param algorithm the name of the symmetric cipher algorithm.
+   * @return an instance of this object.
+   */
+  static synchronized CALG getInstance(final String algorithm)
+  {
+    final IBlockCipher cipher = CipherFactory.getInstance(algorithm);
+    final int blockSize = cipher.defaultBlockSize();
+    final int keySize = cipher.defaultKeySize();
+    final Cascade ofbCipher = new Cascade();
+    IMode ofbMode = ModeFactory.getInstance(Registry.OFB_MODE,
+                                            cipher,
+                                            blockSize);
+    Stage modeStage = Stage.getInstance(ofbMode, Direction.FORWARD);
+    final Object modeNdx = ofbCipher.append(modeStage);
+    final IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD);
+    final Assembly asm = new Assembly();
+    asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher));
+    asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7));
+    return new CALG(blockSize, keySize, modeNdx, asm);
+  }
+
+  /**
+   * Initialises a SASL-SRP CALG implementation.
+   * 
+   * @param kdf the key derivation function.
+   * @param iv the initial vector value to use.
+   * @param dir whether this CALG is used for encryption or decryption.
+   */
+  public void init(final KDF kdf, final byte[] iv, final Direction dir)
+      throws SaslException
+  {
+    final byte[] realIV;
+    if (iv.length == blockSize)
+      realIV = iv;
+    else
+      {
+        realIV = new byte[blockSize];
+        if (iv.length > blockSize)
+          System.arraycopy(iv, 0, realIV, 0, blockSize);
+        else // shouldnt happen
+          System.arraycopy(iv, 0, realIV, 0, iv.length);
+      }
+    final HashMap modeAttributes = new HashMap();
+    final byte[] sk = kdf.derive(keySize);
+    modeAttributes.put(IBlockCipher.KEY_MATERIAL, sk);
+    modeAttributes.put(IMode.IV, realIV);
+    final HashMap attributes = new HashMap();
+    attributes.put(Assembly.DIRECTION, dir);
+    attributes.put(modeNdx, modeAttributes);
+    try
+      {
+        assembly.init(attributes);
+      }
+    catch (TransformerException x)
+      {
+        throw new SaslException("getInstance()", x);
+      }
+  }
+
+  /**
+   * Encrypts or decrypts, depending on the mode already set, a designated array
+   * of bytes and returns the result.
+   * 
+   * @param data the data to encrypt/decrypt.
+   * @return the decrypted/encrypted result.
+   * @throws ConfidentialityException if an exception occurs duirng the process.
+   */
+  public byte[] doFinal(final byte[] data) throws ConfidentialityException
+  {
+    return doFinal(data, 0, data.length);
+  }
+
+  /**
+   * Encrypts or decrypts, depending on the mode already set, a designated array
+   * of bytes and returns the result.
+   * 
+   * @param data the data to encrypt/decrypt.
+   * @param offset where to start in <code>data</code>.
+   * @param length how many bytes to consider in <code>data</code>.
+   * @return the decrypted/encrypted result.
+   * @throws ConfidentialityException if an exception occurs duirng the process.
+   */
+  public byte[] doFinal(final byte[] data, final int offset, final int length)
+      throws ConfidentialityException
+  {
+    final byte[] result;
+    try
+      {
+        result = assembly.lastUpdate(data, offset, length);
+      }
+    catch (TransformerException x)
+      {
+        throw new ConfidentialityException("doFinal()", x);
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/ClientStore.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,155 @@
+/* ClientStore.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import java.util.HashMap;
+
+/**
+ * The client-side implementation of the SRP security context store.
+ */
+public class ClientStore
+{
+  /** The underlying singleton. */
+  private static ClientStore singleton = null;
+  /** The map of uid --> SASL Security Context record. */
+  private static final HashMap uid2ssc = new HashMap();
+  /** The map of sid --> Session timing record. */
+  private static final HashMap uid2ttl = new HashMap();
+  /** A synchronisation lock. */
+  private static final Object lock = new Object();
+
+  /** Private constructor to enforce Singleton pattern. */
+  private ClientStore()
+  {
+    super();
+
+    // TODO: add a cleaning timer thread
+  }
+
+  /**
+   * Returns the classloader Singleton.
+   * 
+   * @return the classloader Singleton instance.
+   */
+  static synchronized final ClientStore instance()
+  {
+    if (singleton == null)
+      singleton = new ClientStore();
+    return singleton;
+  }
+
+  /**
+   * Returns a boolean flag indicating if the designated client's session is
+   * still alive or not.
+   * 
+   * @param uid the identifier of the client whose session to check.
+   * @return <code>true</code> if the designated client's session is still
+   *         alive. <code>false</code> otherwise.
+   */
+  boolean isAlive(final String uid)
+  {
+    final boolean result;
+    synchronized (lock)
+      {
+        final Object obj = uid2ssc.get(uid);
+        result = (obj != null);
+        if (result) // is it still alive?
+          {
+            final StoreEntry sto = (StoreEntry) uid2ttl.get(uid);
+            if (! sto.isAlive()) // invalidate it
+              {
+                uid2ssc.remove(uid);
+                uid2ttl.remove(uid);
+              }
+          }
+      }
+    return result;
+  }
+
+  /**
+   * Records a mapping between a client's unique identifier and its security
+   * context.
+   * 
+   * @param uid the unique identifier of the SRP client for which the session is
+   *          to be cached.
+   * @param ttl the session's Time-To-Live indicator (in seconds).
+   * @param ctx the client's security context.
+   */
+  void cacheSession(final String uid, final int ttl, final SecurityContext ctx)
+  {
+    synchronized (lock)
+      {
+        uid2ssc.put(uid, ctx);
+        uid2ttl.put(uid, new StoreEntry(ttl));
+      }
+  }
+
+  /**
+   * Removes the mapping between the designated SRP client unique identifier and
+   * the its session security context (and other timing information).
+   * 
+   * @param uid the identifier of the client whose session is to invalidate.
+   */
+  void invalidateSession(final String uid)
+  {
+    synchronized (lock)
+      {
+        uid2ssc.remove(uid);
+        uid2ttl.remove(uid);
+      }
+  }
+
+  /**
+   * Returns an SRP client's security context record mapped by that client's
+   * unique identifier.
+   * 
+   * @param uid the identifier of the client whose session is to restore.
+   * @return the SRP client's security context.
+   */
+  SecurityContext restoreSession(final String uid)
+  {
+    final SecurityContext result;
+    synchronized (lock)
+      {
+        result = (SecurityContext) uid2ssc.remove(uid);
+        uid2ttl.remove(uid);
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/IALG.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,128 @@
+/* IALG.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mac.MacFactory;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * A Factory class that returns IALG (Integrity Algorithm) instances that
+ * operate as described in the draft-burdis-cat-sasl-srp-04 and later.
+ */
+public final class IALG
+    implements Cloneable
+{
+  private IMac hmac;
+
+  /** Private constructor to enforce instantiation through Factory method. */
+  private IALG(final IMac hmac)
+  {
+    super();
+
+    this.hmac = hmac;
+  }
+
+  /**
+   * Returns an instance of a SASL-SRP IALG implementation.
+   * 
+   * @param algorithm the name of the HMAC algorithm.
+   * @return an instance of this object.
+   */
+  static synchronized IALG getInstance(final String algorithm)
+      throws SaslException
+  {
+    final IMac hmac;
+    hmac = MacFactory.getInstance(algorithm);
+    if (hmac == null)
+      throw new SaslException("getInstance()",
+                              new NoSuchAlgorithmException(algorithm));
+    return new IALG(hmac);
+  }
+
+  public Object clone() throws CloneNotSupportedException
+  {
+    return new IALG((IMac) hmac.clone());
+  }
+
+  public void init(final KDF kdf) throws SaslException
+  {
+    try
+      {
+        final byte[] sk = kdf.derive(hmac.macSize());
+        final HashMap map = new HashMap();
+        map.put(IMac.MAC_KEY_MATERIAL, sk);
+        hmac.init(map);
+      }
+    catch (InvalidKeyException x)
+      {
+        throw new SaslException("getInstance()", x);
+      }
+  }
+
+  public void update(final byte[] data)
+  {
+    hmac.update(data, 0, data.length);
+  }
+
+  public void update(final byte[] data, final int offset, final int length)
+  {
+    hmac.update(data, offset, length);
+  }
+
+  public byte[] doFinal()
+  {
+    return hmac.digest();
+  }
+
+  /**
+   * Returns the length (in bytes) of this SASL SRP Integrity Algorithm.
+   * 
+   * @return the length, in bytes, of this integrity protection algorithm.
+   */
+  public int length()
+  {
+    return hmac.macSize();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/KDF.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,140 @@
+/* KDF.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.java.security.Registry;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.PRNG;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.prng.UMacGenerator;
+
+import java.util.HashMap;
+
+/**
+ * The SASL-SRP KDF implementation, which is also used, depending on how it was
+ * instantiated, as a secure Pseudo Random Number Generator.
+ */
+public class KDF
+{
+  private static final int AES_BLOCK_SIZE = 16; // default block size for AES
+  private static final int AES_KEY_SIZE = 16; // default key size for the AES
+  private static final byte[] buffer = new byte[1];
+  /** Our default source of randomness. */
+  private static final PRNG prng = PRNG.getInstance();
+  /** The underlying UMAC Generator instance. */
+  private UMacGenerator umac = null;
+
+  /**
+   * Constructs an instance of the <code>KDF</code> initialised with the
+   * designated shared secret bytes.
+   * 
+   * @param keyMaterial the SASL SRP shared secret (K) bytes.
+   */
+  private KDF(final byte[] keyMaterial, final int ndx)
+  {
+    super();
+
+    final HashMap map = new HashMap();
+    map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER);
+    map.put(UMacGenerator.INDEX, Integer.valueOf(ndx));
+    map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(AES_BLOCK_SIZE));
+    final byte[] key = new byte[AES_KEY_SIZE];
+    System.arraycopy(keyMaterial, 0, key, 0, AES_KEY_SIZE);
+    map.put(IBlockCipher.KEY_MATERIAL, key);
+    umac = new UMacGenerator();
+    umac.init(map);
+  }
+
+  /**
+   * A Factory mehod that returns an instance of a <code>KDF</code> based on
+   * supplied seed data.
+   * 
+   * @param K the SASL SRP shared secret for a <code>KDF</code> to be used for
+   *          <i>CALG</i> and <i>IALG</i> setup. <code>null</code> otherwise.
+   * @return an instance of a <code>KDF</code>.
+   */
+  static final KDF getInstance(final byte[] K)
+  {
+    int ndx = -1;
+    final byte[] keyMaterial;
+    if (K != null)
+      {
+        keyMaterial = K;
+        ndx = 0;
+      }
+    else
+      {
+        keyMaterial = new byte[AES_BLOCK_SIZE];
+        while (ndx < 1 || ndx > 255)
+          ndx = (byte) nextByte();
+      }
+    return new KDF(keyMaterial, ndx);
+  }
+
+  private static synchronized final int nextByte()
+  {
+    prng.nextBytes(buffer);
+    return (buffer[0] & 0xFF);
+  }
+
+  /**
+   * Returns a designated number of bytes suitable for use in the SASL SRP
+   * mechanism.
+   * 
+   * @param length the number of bytes needed.
+   * @return a byte array containing the generated/selected bytes.
+   */
+  public synchronized byte[] derive(final int length)
+  {
+    final byte[] result = new byte[length];
+    try
+      {
+        umac.nextBytes(result, 0, length);
+      }
+    catch (IllegalStateException x) // should not happen
+      {
+        x.printStackTrace(System.err);
+      }
+    catch (LimitReachedException x) // idem
+      {
+        x.printStackTrace(System.err);
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/PasswordFile.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,625 @@
+/* PasswordFile.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.key.srp6.SRPAlgorithm;
+import gnu.javax.crypto.sasl.NoSuchUserException;
+import gnu.javax.crypto.sasl.UserAlreadyExistsException;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+/**
+ * The implementation of SRP password files.
+ * <p>
+ * For SRP, there are three (3) files:
+ * <ol>
+ * <li>The password configuration file: tpasswd.conf. It contains the pairs
+ * &lt;N,g> indexed by a number for each pair used for a user. By default, this
+ * file's pathname is constructed from the base password file pathname by
+ * prepending it with the ".conf" suffix.</li>
+ * <li>The base password file: tpasswd. It contains the related password
+ * entries for all the users with values computed using SRP's default message
+ * digest algorithm: SHA-1 (with 160-bit output block size).</li>
+ * <li>The extended password file: tpasswd2. Its name, by default, is
+ * constructed by adding the suffix "2" to the fully qualified pathname of the
+ * base password file. It contains, in addition to the same fields as the base
+ * password file, albeit with a different verifier value, an extra field
+ * identifying the message digest algorithm used to compute this (verifier)
+ * value.</li>
+ * </ol>
+ * <p>
+ * This implementation assumes the following message digest algorithm codes:
+ * <ul>
+ * <li>0: the default hash algorithm, which is SHA-1 (or its alias SHA-160).</li>
+ * <li>1: MD5.</li>
+ * <li>2: RIPEMD-128.</li>
+ * <li>3: RIPEMD-160.</li>
+ * <li>4: SHA-256.</li>
+ * <li>5: SHA-384.</li>
+ * <li>6: SHA-512.</li>
+ * </ul>
+ * <p>
+ * <b>IMPORTANT:</b> This method computes the verifiers as described in
+ * RFC-2945, which differs from the description given on the web page for SRP-6.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class PasswordFile
+{
+  // names of property keys used in this class
+  private static final String USER_FIELD = "user";
+  private static final String VERIFIERS_FIELD = "verifier";
+  private static final String SALT_FIELD = "salt";
+  private static final String CONFIG_FIELD = "config";
+  private static String DEFAULT_FILE;
+  static
+    {
+      DEFAULT_FILE = System.getProperty(SRPRegistry.PASSWORD_FILE,
+                                        SRPRegistry.DEFAULT_PASSWORD_FILE);
+    }
+  /** The SRP algorithm instances used by this object. */
+  private static final HashMap srps;
+  static
+    {
+      final HashMap map = new HashMap(SRPRegistry.SRP_ALGORITHMS.length);
+      // The first entry MUST exist. The others are optional.
+      map.put("0", SRP.instance(SRPRegistry.SRP_ALGORITHMS[0]));
+      for (int i = 1; i < SRPRegistry.SRP_ALGORITHMS.length; i++)
+        {
+          try
+            {
+              map.put(String.valueOf(i),
+                      SRP.instance(SRPRegistry.SRP_ALGORITHMS[i]));
+            }
+          catch (Exception x)
+            {
+              System.err.println("Ignored: " + x);
+              x.printStackTrace(System.err);
+            }
+        }
+      srps = map;
+    }
+
+  private String confName, pwName, pw2Name;
+  private File configFile, passwdFile, passwd2File;
+  private long lastmodPasswdFile, lastmodPasswd2File;
+  private HashMap entries = new HashMap();
+  private HashMap configurations = new HashMap();
+  // default N values to use when creating a new password.conf file
+  private static final BigInteger[] Nsrp = new BigInteger[] {
+      SRPAlgorithm.N_2048,
+      SRPAlgorithm.N_1536,
+      SRPAlgorithm.N_1280,
+      SRPAlgorithm.N_1024,
+      SRPAlgorithm.N_768,
+      SRPAlgorithm.N_640,
+      SRPAlgorithm.N_512 };
+
+  public PasswordFile() throws IOException
+  {
+    this(DEFAULT_FILE);
+  }
+
+  public PasswordFile(final File pwFile) throws IOException
+  {
+    this(pwFile.getAbsolutePath());
+  }
+
+  public PasswordFile(final String pwName) throws IOException
+  {
+    this(pwName, pwName + "2", pwName + ".conf");
+  }
+
+  public PasswordFile(final String pwName, final String confName)
+      throws IOException
+  {
+    this(pwName, pwName + "2", confName);
+  }
+
+  public PasswordFile(final String pwName, final String pw2Name,
+                      final String confName) throws IOException
+  {
+    super();
+
+    this.pwName = pwName;
+    this.pw2Name = pw2Name;
+    this.confName = confName;
+
+    readOrCreateConf();
+    update();
+  }
+
+  /**
+   * Returns a string representing the decimal value of an integer identifying
+   * the message digest algorithm to use for the SRP computations.
+   * 
+   * @param mdName the canonical name of a message digest algorithm.
+   * @return a string representing the decimal value of an ID for that
+   *         algorithm.
+   */
+  private static final String nameToID(final String mdName)
+  {
+    if (Registry.SHA_HASH.equalsIgnoreCase(mdName)
+        || Registry.SHA1_HASH.equalsIgnoreCase(mdName)
+        || Registry.SHA160_HASH.equalsIgnoreCase(mdName))
+      return "0";
+    else if (Registry.MD5_HASH.equalsIgnoreCase(mdName))
+      return "1";
+    else if (Registry.RIPEMD128_HASH.equalsIgnoreCase(mdName))
+      return "2";
+    else if (Registry.RIPEMD160_HASH.equalsIgnoreCase(mdName))
+      return "3";
+    else if (Registry.SHA256_HASH.equalsIgnoreCase(mdName))
+      return "4";
+    else if (Registry.SHA384_HASH.equalsIgnoreCase(mdName))
+      return "5";
+    else if (Registry.SHA512_HASH.equalsIgnoreCase(mdName))
+      return "6";
+    return "0";
+  }
+
+  /**
+   * Checks if the current configuration file contains the &lt;N, g> pair for
+   * the designated <code>index</code>.
+   * 
+   * @param index a string representing 1-digit identification of an &lt;N, g>
+   *          pair used.
+   * @return <code>true</code> if the designated <code>index</code> is that
+   *         of a known &lt;N, g> pair, and <code>false</code> otherwise.
+   * @throws IOException if an exception occurs during the process.
+   * @see SRPRegistry#N_2048_BITS
+   * @see SRPRegistry#N_1536_BITS
+   * @see SRPRegistry#N_1280_BITS
+   * @see SRPRegistry#N_1024_BITS
+   * @see SRPRegistry#N_768_BITS
+   * @see SRPRegistry#N_640_BITS
+   * @see SRPRegistry#N_512_BITS
+   */
+  public synchronized boolean containsConfig(final String index)
+      throws IOException
+  {
+    checkCurrent();
+    return configurations.containsKey(index);
+  }
+
+  /**
+   * Returns a pair of strings representing the pair of <code>N</code> and
+   * <code>g</code> MPIs for the designated <code>index</code>.
+   * 
+   * @param index a string representing 1-digit identification of an &lt;N, g>
+   *          pair to look up.
+   * @return a pair of strings, arranged in an array, where the first (at index
+   *         position #0) is the repesentation of the MPI <code>N</code>, and
+   *         the second (at index position #1) is the representation of the MPI
+   *         <code>g</code>. If the <code>index</code> refers to an unknown
+   *         pair, then an empty string array is returned.
+   * @throws IOException if an exception occurs during the process.
+   */
+  public synchronized String[] lookupConfig(final String index)
+      throws IOException
+  {
+    checkCurrent();
+    String[] result = null;
+    if (configurations.containsKey(index))
+      result = (String[]) configurations.get(index);
+    return result;
+  }
+
+  public synchronized boolean contains(final String user) throws IOException
+  {
+    checkCurrent();
+    return entries.containsKey(user);
+  }
+
+  public synchronized void add(final String user, final String passwd,
+                               final byte[] salt, final String index)
+      throws IOException
+  {
+    checkCurrent();
+    if (entries.containsKey(user))
+      throw new UserAlreadyExistsException(user);
+    final HashMap fields = new HashMap(4);
+    fields.put(USER_FIELD, user); // 0
+    fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index)); // 1
+    fields.put(SALT_FIELD, Util.toBase64(salt)); // 2
+    fields.put(CONFIG_FIELD, index); // 3
+    entries.put(user, fields);
+    savePasswd();
+  }
+
+  public synchronized void changePasswd(final String user, final String passwd)
+      throws IOException
+  {
+    checkCurrent();
+    if (! entries.containsKey(user))
+      throw new NoSuchUserException(user);
+    final HashMap fields = (HashMap) entries.get(user);
+    final byte[] salt;
+    try
+      {
+        salt = Util.fromBase64((String) fields.get(SALT_FIELD));
+      }
+    catch (NumberFormatException x)
+      {
+        throw new IOException("Password file corrupt");
+      }
+    final String index = (String) fields.get(CONFIG_FIELD);
+    fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index));
+    entries.put(user, fields);
+    savePasswd();
+  }
+
+  public synchronized void savePasswd() throws IOException
+  {
+    final FileOutputStream f1 = new FileOutputStream(passwdFile);
+    final FileOutputStream f2 = new FileOutputStream(passwd2File);
+    PrintWriter pw1 = null;
+    PrintWriter pw2 = null;
+    try
+      {
+        pw1 = new PrintWriter(f1, true);
+        pw2 = new PrintWriter(f2, true);
+        this.writePasswd(pw1, pw2);
+      }
+    finally
+      {
+        if (pw1 != null)
+          try
+            {
+              pw1.flush();
+            }
+          finally
+            {
+              pw1.close();
+            }
+        if (pw2 != null)
+          try
+            {
+              pw2.flush();
+            }
+          finally
+            {
+              pw2.close();
+            }
+        try
+          {
+            f1.close();
+          }
+        catch (IOException ignored)
+          {
+          }
+        try
+          {
+            f2.close();
+          }
+        catch (IOException ignored)
+          {
+          }
+      }
+    lastmodPasswdFile = passwdFile.lastModified();
+    lastmodPasswd2File = passwd2File.lastModified();
+  }
+
+  /**
+   * Returns the triplet: verifier, salt and configuration file index, of a
+   * designated user, and a designated message digest algorithm name, as an
+   * array of strings.
+   * 
+   * @param user the username.
+   * @param mdName the canonical name of the SRP's message digest algorithm.
+   * @return a string array containing, in this order, the BASE-64 encodings of
+   *         the verifier, the salt and the index in the password configuration
+   *         file of the MPIs N and g of the designated user.
+   */
+  public synchronized String[] lookup(final String user, final String mdName)
+      throws IOException
+  {
+    checkCurrent();
+    if (! entries.containsKey(user))
+      throw new NoSuchUserException(user);
+    final HashMap fields = (HashMap) entries.get(user);
+    final HashMap verifiers = (HashMap) fields.get(VERIFIERS_FIELD);
+    final String salt = (String) fields.get(SALT_FIELD);
+    final String index = (String) fields.get(CONFIG_FIELD);
+    final String verifier = (String) verifiers.get(nameToID(mdName));
+    return new String[] { verifier, salt, index };
+  }
+
+  private synchronized void readOrCreateConf() throws IOException
+  {
+    configurations.clear();
+    final FileInputStream fis;
+    configFile = new File(confName);
+    try
+      {
+        fis = new FileInputStream(configFile);
+        readConf(fis);
+      }
+    catch (FileNotFoundException x)
+      { // create a default one
+        final String g = Util.toBase64(Util.trim(new BigInteger("2")));
+        String index, N;
+        for (int i = 0; i < Nsrp.length; i++)
+          {
+            index = String.valueOf(i + 1);
+            N = Util.toBase64(Util.trim(Nsrp[i]));
+            configurations.put(index, new String[] { N, g });
+          }
+        FileOutputStream f0 = null;
+        PrintWriter pw0 = null;
+        try
+          {
+            f0 = new FileOutputStream(configFile);
+            pw0 = new PrintWriter(f0, true);
+            this.writeConf(pw0);
+          }
+        finally
+          {
+            if (pw0 != null)
+              pw0.close();
+            else if (f0 != null)
+              f0.close();
+          }
+      }
+  }
+
+  private void readConf(final InputStream in) throws IOException
+  {
+    final BufferedReader din = new BufferedReader(new InputStreamReader(in));
+    String line, index, N, g;
+    StringTokenizer st;
+    while ((line = din.readLine()) != null)
+      {
+        st = new StringTokenizer(line, ":");
+        try
+          {
+            index = st.nextToken();
+            N = st.nextToken();
+            g = st.nextToken();
+          }
+        catch (NoSuchElementException x)
+          {
+            throw new IOException("SRP password configuration file corrupt");
+          }
+        configurations.put(index, new String[] { N, g });
+      }
+  }
+
+  private void writeConf(final PrintWriter pw)
+  {
+    String ndx;
+    String[] mpi;
+    StringBuffer sb;
+    for (Iterator it = configurations.keySet().iterator(); it.hasNext();)
+      {
+        ndx = (String) it.next();
+        mpi = (String[]) configurations.get(ndx);
+        sb = new StringBuffer(ndx)
+            .append(":").append(mpi[0])
+            .append(":").append(mpi[1]);
+        pw.println(sb.toString());
+      }
+  }
+
+  /**
+   * Compute the new verifiers for the designated username and password.
+   * <p>
+   * <b>IMPORTANT:</b> This method computes the verifiers as described in
+   * RFC-2945, which differs from the description given on the web page for
+   * SRP-6.
+   * 
+   * @param user the user's name.
+   * @param s the user's salt.
+   * @param password the user's password
+   * @param index the index of the &lt;N, g> pair to use for this user.
+   * @return a {@link java.util.Map} of user verifiers.
+   * @throws UnsupportedEncodingException if the US-ASCII decoder is not
+   *           available on this platform.
+   */
+  private HashMap newVerifiers(final String user, final byte[] s,
+                               final String password, final String index)
+      throws UnsupportedEncodingException
+  {
+    // to ensure inter-operability with non-java tools
+    final String[] mpi = (String[]) configurations.get(index);
+    final BigInteger N = new BigInteger(1, Util.fromBase64(mpi[0]));
+    final BigInteger g = new BigInteger(1, Util.fromBase64(mpi[1]));
+    final HashMap result = new HashMap(srps.size());
+    BigInteger x, v;
+    SRP srp;
+    for (int i = 0; i < srps.size(); i++)
+      {
+        final String digestID = String.valueOf(i);
+        srp = (SRP) srps.get(digestID);
+        x = new BigInteger(1, srp.computeX(s, user, password));
+        v = g.modPow(x, N);
+        final String verifier = Util.toBase64(v.toByteArray());
+        result.put(digestID, verifier);
+      }
+    return result;
+  }
+
+  private synchronized void update() throws IOException
+  {
+    entries.clear();
+    FileInputStream fis;
+    passwdFile = new File(pwName);
+    lastmodPasswdFile = passwdFile.lastModified();
+    try
+      {
+        fis = new FileInputStream(passwdFile);
+        readPasswd(fis);
+      }
+    catch (FileNotFoundException ignored)
+      {
+      }
+    passwd2File = new File(pw2Name);
+    lastmodPasswd2File = passwd2File.lastModified();
+    try
+      {
+        fis = new FileInputStream(passwd2File);
+        readPasswd2(fis);
+      }
+    catch (FileNotFoundException ignored)
+      {
+      }
+  }
+
+  private void checkCurrent() throws IOException
+  {
+    if (passwdFile.lastModified() > lastmodPasswdFile
+        || passwd2File.lastModified() > lastmodPasswd2File)
+      update();
+  }
+
+  private void readPasswd(final InputStream in) throws IOException
+  {
+    final BufferedReader din = new BufferedReader(new InputStreamReader(in));
+    String line, user, verifier, salt, index;
+    StringTokenizer st;
+    while ((line = din.readLine()) != null)
+      {
+        st = new StringTokenizer(line, ":");
+        try
+          {
+            user = st.nextToken();
+            verifier = st.nextToken();
+            salt = st.nextToken();
+            index = st.nextToken();
+          }
+        catch (NoSuchElementException x)
+          {
+            throw new IOException("SRP base password file corrupt");
+          }
+        final HashMap verifiers = new HashMap(6);
+        verifiers.put("0", verifier);
+        final HashMap fields = new HashMap(4);
+        fields.put(USER_FIELD, user);
+        fields.put(VERIFIERS_FIELD, verifiers);
+        fields.put(SALT_FIELD, salt);
+        fields.put(CONFIG_FIELD, index);
+        entries.put(user, fields);
+      }
+  }
+
+  private void readPasswd2(final InputStream in) throws IOException
+  {
+    final BufferedReader din = new BufferedReader(new InputStreamReader(in));
+    String line, digestID, user, verifier;
+    StringTokenizer st;
+    HashMap fields, verifiers;
+    while ((line = din.readLine()) != null)
+      {
+        st = new StringTokenizer(line, ":");
+        try
+          {
+            digestID = st.nextToken();
+            user = st.nextToken();
+            verifier = st.nextToken();
+          }
+        catch (NoSuchElementException x)
+          {
+            throw new IOException("SRP extended password file corrupt");
+          }
+        fields = (HashMap) entries.get(user);
+        if (fields != null)
+          {
+            verifiers = (HashMap) fields.get(VERIFIERS_FIELD);
+            verifiers.put(digestID, verifier);
+          }
+      }
+  }
+
+  private void writePasswd(final PrintWriter pw1, final PrintWriter pw2)
+      throws IOException
+  {
+    String user, digestID;
+    HashMap fields, verifiers;
+    StringBuffer sb1, sb2;
+    Iterator j;
+    final Iterator i = entries.keySet().iterator();
+    while (i.hasNext())
+      {
+        user = (String) i.next();
+        fields = (HashMap) entries.get(user);
+        if (! user.equals(fields.get(USER_FIELD)))
+          throw new IOException("Inconsistent SRP password data");
+        verifiers = (HashMap) fields.get(VERIFIERS_FIELD);
+        sb1 = new StringBuffer(user)
+            .append(":").append((String) verifiers.get("0"))
+            .append(":").append((String) fields.get(SALT_FIELD))
+            .append(":").append((String) fields.get(CONFIG_FIELD));
+        pw1.println(sb1.toString());
+        // write extended information
+        j = verifiers.keySet().iterator();
+        while (j.hasNext())
+          {
+            digestID = (String) j.next();
+            if (! "0".equals(digestID))
+              {
+                // #0 is the default digest, already present in tpasswd!
+                sb2 = new StringBuffer(digestID)
+                    .append(":").append(user)
+                    .append(":").append((String) verifiers.get(digestID));
+                pw2.println(sb2.toString());
+              }
+          }
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/SRP.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,255 @@
+/* SRP.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.HashMap;
+
+/**
+ * A Factory class that returns SRP Singletons that know all SRP-related
+ * mathematical computations and protocol-related operations for both the
+ * client- and server-sides.
+ */
+public final class SRP
+{
+  /** The map of already instantiated SRP algorithm instances. */
+  private static final HashMap algorithms = new HashMap();
+  private static final byte COLON = (byte) 0x3A;
+  /** The underlying message digest algorithm used for all SRP calculations. */
+  private IMessageDigest mda;
+
+  /** Trivial private constructor to enforce Singleton pattern. */
+  private SRP(final IMessageDigest mda)
+  {
+    super();
+
+    this.mda = mda;
+  }
+
+  /**
+   * Returns an instance of this object that uses the designated message digest
+   * algorithm as its digest function.
+   * 
+   * @return an instance of this object for the designated digest name.
+   */
+  public static synchronized SRP instance(String mdName)
+  {
+    if (mdName != null)
+      mdName = mdName.trim().toLowerCase();
+    if (mdName == null || mdName.equals(""))
+      mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME;
+    SRP result = (SRP) algorithms.get(mdName);
+    if (result == null)
+      {
+        final IMessageDigest mda = HashFactory.getInstance(mdName);
+        result = new SRP(mda);
+        algorithms.put(mdName, result);
+      }
+    return result;
+  }
+
+  private static final byte[] xor(final byte[] b1, final byte[] b2,
+                                  final int length)
+  {
+    final byte[] result = new byte[length];
+    for (int i = 0; i < length; ++i)
+      result[i] = (byte)(b1[i] ^ b2[i]);
+    return result;
+  }
+
+  /** @return the message digest algorithm name used by this instance. */
+  public String getAlgorithm()
+  {
+    return mda.name();
+  }
+
+  /**
+   * Returns a new instance of the SRP message digest algorithm --which is
+   * SHA-160 by default, but could be anything else provided the proper
+   * conditions as specified in the SRP specifications.
+   * 
+   * @return a new instance of the underlying SRP message digest algorithm.
+   * @throws RuntimeException if the implementation of the message digest
+   *           algorithm does not support cloning.
+   */
+  public IMessageDigest newDigest()
+  {
+    return (IMessageDigest) mda.clone();
+  }
+
+  /**
+   * Convenience method to return the result of digesting the designated input
+   * with a new instance of the SRP message digest algorithm.
+   * 
+   * @param src some bytes to digest.
+   * @return the bytes constituting the result of digesting the designated input
+   *         with a new instance of the SRP message digest algorithm.
+   */
+  public byte[] digest(final byte[] src)
+  {
+    final IMessageDigest hash = (IMessageDigest) mda.clone();
+    hash.update(src, 0, src.length);
+    return hash.digest();
+  }
+
+  /**
+   * Convenience method to return the result of digesting the designated input
+   * with a new instance of the SRP message digest algorithm.
+   * 
+   * @param src a String whose bytes (using US-ASCII encoding) are to be
+   *          digested.
+   * @return the bytes constituting the result of digesting the designated input
+   *         with a new instance of the SRP message digest algorithm.
+   * @throws UnsupportedEncodingException if US-ASCII charset is not found.
+   */
+  public byte[] digest(final String src) throws UnsupportedEncodingException
+  {
+    return digest(src.getBytes("US-ASCII"));
+  }
+
+  /**
+   * Convenience method to XOR N bytes from two arrays; N being the output size
+   * of the SRP message digest algorithm.
+   * 
+   * @param a the first byte array.
+   * @param b the second one.
+   * @return N bytes which are the result of the XOR operations on the first N
+   *         bytes from the designated arrays. N is the size of the SRP message
+   *         digest algorithm; eg. 20 for SHA-160.
+   */
+  public byte[] xor(final byte[] a, final byte[] b)
+  {
+    return xor(a, b, mda.hashSize());
+  }
+
+  public byte[] generateM1(final BigInteger N, final BigInteger g,
+                           final String U, final byte[] s, final BigInteger A,
+                           final BigInteger B, final byte[] K, final String I,
+                           final String L, final byte[] cn, final byte[] cCB)
+      throws UnsupportedEncodingException
+  {
+    final IMessageDigest hash = (IMessageDigest) mda.clone();
+    byte[] b;
+    b = xor(digest(Util.trim(N)), digest(Util.trim(g)));
+    hash.update(b, 0, b.length);
+    b = digest(U);
+    hash.update(b, 0, b.length);
+    hash.update(s, 0, s.length);
+    b = Util.trim(A);
+    hash.update(b, 0, b.length);
+    b = Util.trim(B);
+    hash.update(b, 0, b.length);
+    hash.update(K, 0, K.length);
+    b = digest(I);
+    hash.update(b, 0, b.length);
+    b = digest(L);
+    hash.update(b, 0, b.length);
+    hash.update(cn, 0, cn.length);
+    hash.update(cCB, 0, cCB.length);
+    return hash.digest();
+  }
+
+  public byte[] generateM2(final BigInteger A, final byte[] M1, final byte[] K,
+                           final String U, final String I, final String o,
+                           final byte[] sid, final int ttl, final byte[] cIV,
+                           final byte[] sIV, final byte[] sCB)
+      throws UnsupportedEncodingException
+  {
+    final IMessageDigest hash = (IMessageDigest) mda.clone();
+    byte[] b;
+    b = Util.trim(A);
+    hash.update(b, 0, b.length);
+    hash.update(M1, 0, M1.length);
+    hash.update(K, 0, K.length);
+    b = digest(U);
+    hash.update(b, 0, b.length);
+    b = digest(I);
+    hash.update(b, 0, b.length);
+    b = digest(o);
+    hash.update(b, 0, b.length);
+    hash.update(sid, 0, sid.length);
+    hash.update((byte)(ttl >>> 24));
+    hash.update((byte)(ttl >>> 16));
+    hash.update((byte)(ttl >>> 8));
+    hash.update((byte) ttl);
+    hash.update(cIV, 0, cIV.length);
+    hash.update(sIV, 0, sIV.length);
+    hash.update(sCB, 0, sCB.length);
+    return hash.digest();
+  }
+
+  public byte[] generateKn(final byte[] K, final byte[] cn, final byte[] sn)
+  {
+    final IMessageDigest hash = (IMessageDigest) mda.clone();
+    hash.update(K, 0, K.length);
+    hash.update(cn, 0, cn.length);
+    hash.update(sn, 0, sn.length);
+    return hash.digest();
+  }
+
+  public byte[] computeX(final byte[] s, final String user,
+                         final String password)
+      throws UnsupportedEncodingException
+  {
+    return computeX(s, user.getBytes("US-ASCII"), password.getBytes("US-ASCII"));
+  }
+
+  public byte[] computeX(final byte[] s, final String user, final byte[] p)
+      throws UnsupportedEncodingException
+  {
+    return computeX(s, user.getBytes("US-ASCII"), p);
+  }
+
+  private byte[] computeX(final byte[] s, final byte[] user, final byte[] p)
+  {
+    final IMessageDigest hash = (IMessageDigest) mda.clone();
+    hash.update(user, 0, user.length);
+    hash.update(COLON);
+    hash.update(p, 0, p.length);
+    final byte[] up = hash.digest();
+    hash.update(s, 0, s.length);
+    hash.update(up, 0, up.length);
+    return hash.digest();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,177 @@
+/* SRPAuthInfoProvider.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.sasl.IAuthInfoProvider;
+import gnu.javax.crypto.sasl.NoSuchUserException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.sasl.AuthenticationException;
+
+/**
+ * The SRP mechanism authentication information provider implementation.
+ */
+public class SRPAuthInfoProvider
+    implements IAuthInfoProvider
+{
+  private PasswordFile passwordFile = null;
+
+  // implicit 0-args constrcutor
+
+  public void activate(Map context) throws AuthenticationException
+  {
+    try
+      {
+        if (context == null)
+          passwordFile = new PasswordFile();
+        else
+          {
+            passwordFile = (PasswordFile) context.get(SRPRegistry.PASSWORD_DB);
+            if (passwordFile == null)
+              {
+                String pfn = (String) context.get(SRPRegistry.PASSWORD_FILE);
+                if (pfn == null)
+                  passwordFile = new PasswordFile();
+                else
+                  passwordFile = new PasswordFile(pfn);
+              }
+          }
+      }
+    catch (IOException x)
+      {
+        throw new AuthenticationException("activate()", x);
+      }
+  }
+
+  public void passivate() throws AuthenticationException
+  {
+    passwordFile = null;
+  }
+
+  public boolean contains(String userName) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("contains()",
+                                        new IllegalStateException());
+    boolean result = false;
+    try
+      {
+        result = passwordFile.contains(userName);
+      }
+    catch (IOException x)
+      {
+        throw new AuthenticationException("contains()", x);
+      }
+    return result;
+  }
+
+  public Map lookup(Map userID) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("lookup()", new IllegalStateException());
+    Map result = new HashMap();
+    try
+      {
+        String userName = (String) userID.get(Registry.SASL_USERNAME);
+        if (userName == null)
+          throw new NoSuchUserException("");
+        String mdName = (String) userID.get(SRPRegistry.MD_NAME_FIELD);
+        String[] data = passwordFile.lookup(userName, mdName);
+        result.put(SRPRegistry.USER_VERIFIER_FIELD, data[0]);
+        result.put(SRPRegistry.SALT_FIELD, data[1]);
+        result.put(SRPRegistry.CONFIG_NDX_FIELD, data[2]);
+      }
+    catch (Exception x)
+      {
+        if (x instanceof AuthenticationException)
+          throw (AuthenticationException) x;
+        throw new AuthenticationException("lookup()", x);
+      }
+    return result;
+  }
+
+  public void update(Map userCredentials) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("update()", new IllegalStateException());
+    try
+      {
+        String userName = (String) userCredentials.get(Registry.SASL_USERNAME);
+        String password = (String) userCredentials.get(Registry.SASL_PASSWORD);
+        String salt = (String) userCredentials.get(SRPRegistry.SALT_FIELD);
+        String config = (String) userCredentials.get(SRPRegistry.CONFIG_NDX_FIELD);
+        if (salt == null || config == null)
+          passwordFile.changePasswd(userName, password);
+        else
+          passwordFile.add(userName, password, Util.fromBase64(salt), config);
+      }
+    catch (Exception x)
+      {
+        if (x instanceof AuthenticationException)
+          throw (AuthenticationException) x;
+        throw new AuthenticationException("update()", x);
+      }
+  }
+
+  public Map getConfiguration(String mode) throws AuthenticationException
+  {
+    if (passwordFile == null)
+      throw new AuthenticationException("getConfiguration()",
+                                        new IllegalStateException());
+    Map result = new HashMap();
+    try
+      {
+        String[] data = passwordFile.lookupConfig(mode);
+        result.put(SRPRegistry.SHARED_MODULUS, data[0]);
+        result.put(SRPRegistry.FIELD_GENERATOR, data[1]);
+      }
+    catch (Exception x)
+      {
+        if (x instanceof AuthenticationException)
+          throw (AuthenticationException) x;
+        throw new AuthenticationException("getConfiguration()", x);
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/SRPClient.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,952 @@
+/* SRPClient.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.hash.MD5;
+import gnu.java.security.util.PRNG;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.assembly.Direction;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.key.IKeyAgreementParty;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.KeyAgreementFactory;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.key.srp6.SRP6KeyAgreement;
+import gnu.javax.crypto.sasl.ClientMechanism;
+import gnu.javax.crypto.sasl.IllegalMechanismStateException;
+import gnu.javax.crypto.sasl.InputBuffer;
+import gnu.javax.crypto.sasl.IntegrityException;
+import gnu.javax.crypto.sasl.OutputBuffer;
+import gnu.javax.security.auth.Password;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+import java.util.logging.Logger;
+
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthenticationException;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+/**
+ * The SASL-SRP client-side mechanism.
+ */
+public class SRPClient
+    extends ClientMechanism
+    implements SaslClient
+{
+  private static final Logger log = Logger.getLogger(SRPClient.class.getName());
+  private String uid; // the unique key for this type of client
+  private String U; // the authentication identity
+  BigInteger N, g, A, B;
+  private Password password; // the authentication credentials
+  private byte[] s; // the user's salt
+  private byte[] cIV, sIV; // client+server IVs, when confidentiality is on
+  private byte[] M1, M2; // client+server evidences
+  private byte[] cn, sn; // client's and server's nonce
+  private SRP srp; // SRP algorithm instance used by this client
+  private byte[] sid; // session ID when re-used
+  private int ttl; // session time-to-live in seconds
+  private byte[] sCB; // the peer's channel binding data
+  private String L; // available options
+  private String o;
+  private String chosenIntegrityAlgorithm;
+  private String chosenConfidentialityAlgorithm;
+  private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT;
+  private byte[] K; // shared session key
+  private boolean replayDetection = true; // whether Replay Detection is on
+  private int inCounter = 0; // messages sequence numbers
+  private int outCounter = 0;
+  private IALG inMac, outMac; // if !null, use for integrity
+  private CALG inCipher, outCipher; // if !null, use for confidentiality
+  private IKeyAgreementParty clientHandler =
+      KeyAgreementFactory.getPartyAInstance(Registry.SRP_SASL_KA);
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+
+  public SRPClient()
+  {
+    super(Registry.SASL_SRP_MECHANISM);
+  }
+
+  protected void initMechanism() throws SaslException
+  {
+    // we shall keep track of the sid (and the security context of this SRP
+    // client) based on the initialisation parameters of an SRP session.
+    // we shall compute a unique key for those parameters and key the sid
+    // (and the security context) accordingly.
+    // 1. compute the mapping key. use MD5 (the fastest) for this purpose
+    final MD5 md = new MD5();
+    byte[] b;
+    b = authorizationID.getBytes();
+    md.update(b, 0, b.length);
+    b = serverName.getBytes();
+    md.update(b, 0, b.length);
+    b = protocol.getBytes();
+    md.update(b, 0, b.length);
+    if (channelBinding.length > 0)
+      md.update(channelBinding, 0, channelBinding.length);
+
+    uid = Util.toBase64(md.digest());
+    if (ClientStore.instance().isAlive(uid))
+      {
+        final SecurityContext ctx = ClientStore.instance().restoreSession(uid);
+        srp = SRP.instance(ctx.getMdName());
+        sid = ctx.getSID();
+        K = ctx.getK();
+        cIV = ctx.getClientIV();
+        sIV = ctx.getServerIV();
+        replayDetection = ctx.hasReplayDetection();
+        inCounter = ctx.getInCounter();
+        outCounter = ctx.getOutCounter();
+        inMac = ctx.getInMac();
+        outMac = ctx.getOutMac();
+        inCipher = ctx.getInCipher();
+        outCipher = ctx.getOutCipher();
+      }
+    else
+      {
+        sid = new byte[0];
+        ttl = 0;
+        K = null;
+        cIV = null;
+        sIV = null;
+        cn = null;
+        sn = null;
+      }
+  }
+
+  protected void resetMechanism() throws SaslException
+  {
+    try
+      {
+        password.destroy();
+      }
+    catch (DestroyFailedException dfe)
+      {
+        SaslException se = new SaslException("resetMechanism()");
+        se.initCause(dfe);
+        throw se;
+      }
+    password = null;
+    M1 = null;
+    K = null;
+    cIV = null;
+    sIV = null;
+    inMac = outMac = null;
+    inCipher = outCipher = null;
+    sid = null;
+    ttl = 0;
+    cn = null;
+    sn = null;
+  }
+
+  public boolean hasInitialResponse()
+  {
+    return true;
+  }
+
+  public byte[] evaluateChallenge(final byte[] challenge) throws SaslException
+  {
+    switch (state)
+      {
+      case 0:
+        state++;
+        return sendIdentities();
+      case 1:
+        state++;
+        final byte[] result = sendPublicKey(challenge);
+        try
+          {
+            password.destroy(); //don't need further this session
+          }
+        catch (DestroyFailedException x)
+          {
+            SaslException se = new SaslException("sendPublicKey()");
+            se.initCause(se);
+            throw se;
+          }
+        return result;
+      case 2: // should only occur if session re-use was rejected
+        if (! complete)
+          {
+            state++;
+            return receiveEvidence(challenge);
+          }
+      // else fall through
+      default:
+        throw new IllegalMechanismStateException("evaluateChallenge()");
+      }
+  }
+
+  protected byte[] engineUnwrap(final byte[] incoming, final int offset,
+                                final int len) throws SaslException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineUnwrap");
+    if (inMac == null && inCipher == null)
+      throw new IllegalStateException("connection is not protected");
+    // at this point one, or both, of confidentiality and integrity protection
+    // services are active.
+    final byte[] result;
+    try
+      {
+        if (inMac != null)
+          { // integrity bytes are at the end of the stream
+            final int macBytesCount = inMac.length();
+            final int payloadLength = len - macBytesCount;
+            final byte[] received_mac = new byte[macBytesCount];
+            System.arraycopy(incoming, offset + payloadLength, received_mac, 0,
+                             macBytesCount);
+            if (Configuration.DEBUG)
+              log.fine("Got C (received MAC): " + Util.dumpString(received_mac));
+            inMac.update(incoming, offset, payloadLength);
+            if (replayDetection)
+              {
+                inCounter++;
+                if (Configuration.DEBUG)
+                  log.fine("inCounter=" + inCounter);
+                inMac.update(new byte[] {
+                    (byte)(inCounter >>> 24),
+                    (byte)(inCounter >>> 16),
+                    (byte)(inCounter >>> 8),
+                    (byte) inCounter });
+              }
+            final byte[] computed_mac = inMac.doFinal();
+            if (Configuration.DEBUG)
+              log.fine("Computed MAC: " + Util.dumpString(computed_mac));
+            if (! Arrays.equals(received_mac, computed_mac))
+              throw new IntegrityException("engineUnwrap()");
+            // deal with the payload, which can be either plain or encrypted
+            if (inCipher != null)
+              result = inCipher.doFinal(incoming, offset, payloadLength);
+            else
+              {
+                result = new byte[len - macBytesCount];
+                System.arraycopy(incoming, offset, result, 0, result.length);
+              }
+          }
+        else // no integrity protection; just confidentiality
+          result = inCipher.doFinal(incoming, offset, len);
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new SaslException("engineUnwrap()", x);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineUnwrap");
+    return result;
+  }
+
+  protected byte[] engineWrap(final byte[] outgoing, final int offset,
+                              final int len) throws SaslException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineWrap");
+    if (outMac == null && outCipher == null)
+      throw new IllegalStateException("connection is not protected");
+    // at this point one, or both, of confidentiality and integrity protection
+    // services are active.
+    byte[] result;
+    try
+      {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        // Process the data
+        if (outCipher != null)
+          {
+            result = outCipher.doFinal(outgoing, offset, len);
+            if (Configuration.DEBUG)
+              log.fine("Encoding c (encrypted plaintext): "
+                       + Util.dumpString(result));
+            out.write(result);
+            if (outMac != null)
+              {
+                outMac.update(result);
+                if (replayDetection)
+                  {
+                    outCounter++;
+                    if (Configuration.DEBUG)
+                      log.fine("outCounter=" + outCounter);
+                    outMac.update(new byte[] {
+                        (byte)(outCounter >>> 24),
+                        (byte)(outCounter >>> 16),
+                        (byte)(outCounter >>> 8),
+                        (byte) outCounter });
+                  }
+                final byte[] C = outMac.doFinal();
+                out.write(C);
+                if (Configuration.DEBUG)
+                  log.fine("Encoding C (integrity checksum): " + Util.dumpString(C));
+              }
+            // else confidentiality only; do nothing
+          }
+        else // no confidentiality; just integrity [+ replay detection]
+          {
+            if (Configuration.DEBUG)
+              log.fine("Encoding p (plaintext): "
+                       + Util.dumpString(outgoing, offset, len));
+            out.write(outgoing, offset, len);
+            outMac.update(outgoing, offset, len);
+            if (replayDetection)
+              {
+                outCounter++;
+                if (Configuration.DEBUG)
+                  log.fine("outCounter=" + outCounter);
+                outMac.update(new byte[] {
+                    (byte)(outCounter >>> 24),
+                    (byte)(outCounter >>> 16),
+                    (byte)(outCounter >>> 8),
+                    (byte) outCounter });
+              }
+            final byte[] C = outMac.doFinal();
+            out.write(C);
+            if (Configuration.DEBUG)
+              log.fine("Encoding C (integrity checksum): " + Util.dumpString(C));
+          }
+        result = out.toByteArray();
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new SaslException("engineWrap()", x);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineWrap");
+    return result;
+  }
+
+  protected String getNegotiatedQOP()
+  {
+    if (inMac != null)
+      {
+        if (inCipher != null)
+          return Registry.QOP_AUTH_CONF;
+        return Registry.QOP_AUTH_INT;
+      }
+    return Registry.QOP_AUTH;
+  }
+
+  protected String getNegotiatedStrength()
+  {
+    if (inMac != null)
+      {
+        if (inCipher != null)
+          return Registry.STRENGTH_HIGH;
+        return Registry.STRENGTH_MEDIUM;
+      }
+    return Registry.STRENGTH_LOW;
+  }
+
+  protected String getNegotiatedRawSendSize()
+  {
+    return String.valueOf(rawSendSize);
+  }
+
+  protected String getReuse()
+  {
+    return Registry.REUSE_TRUE;
+  }
+
+  private byte[] sendIdentities() throws SaslException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "sendIdentities");
+    // If necessary, prompt the client for the username and password
+    getUsernameAndPassword();
+    if (Configuration.DEBUG)
+      {
+        log.fine("Password: \"" + new String(password.getPassword()) + "\"");
+        log.fine("Encoding U (username): \"" + U + "\"");
+        log.fine("Encoding I (userid): \"" + authorizationID + "\"");
+      }
+    // if session re-use generate new 16-byte nonce
+    if (sid.length != 0)
+      {
+        cn = new byte[16];
+        getDefaultPRNG().nextBytes(cn);
+      }
+    else
+      cn = new byte[0];
+    final OutputBuffer frameOut = new OutputBuffer();
+    try
+      {
+        frameOut.setText(U);
+        frameOut.setText(authorizationID);
+        frameOut.setEOS(sid); // session ID to re-use
+        frameOut.setOS(cn); // client nonce
+        frameOut.setEOS(channelBinding);
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new AuthenticationException("sendIdentities()", x);
+      }
+    final byte[] result = frameOut.encode();
+    if (Configuration.DEBUG)
+      {
+        log.fine("C: " + Util.dumpString(result));
+        log.fine("  U = " + U);
+        log.fine("  I = " + authorizationID);
+        log.fine("sid = " + new String(sid));
+        log.fine(" cn = " + Util.dumpString(cn));
+        log.fine("cCB = " + Util.dumpString(channelBinding));
+        log.exiting(this.getClass().getName(), "sendIdentities");
+      }
+    return result;
+  }
+
+  private byte[] sendPublicKey(final byte[] input) throws SaslException
+  {
+    if (Configuration.DEBUG)
+      {
+        log.entering(this.getClass().getName(), "sendPublicKey");
+        log.fine("S: " + Util.dumpString(input));
+      }
+    // Server sends [00], N, g, s, B, L
+    // or [FF], sn, sCB
+    final InputBuffer frameIn = new InputBuffer(input);
+    final int ack;
+    try
+      {
+        ack = (int) frameIn.getScalar(1);
+        if (ack == 0x00) // new session
+          {
+            N = frameIn.getMPI();
+            if (Configuration.DEBUG)
+              log.fine("Got N (modulus): " + Util.dump(N));
+            g = frameIn.getMPI();
+            if (Configuration.DEBUG)
+              log.fine("Got g (generator): " + Util.dump(g));
+            s = frameIn.getOS();
+            if (Configuration.DEBUG)
+              log.fine("Got s (salt): " + Util.dumpString(s));
+            B = frameIn.getMPI();
+            if (Configuration.DEBUG)
+              log.fine("Got B (server ephermeral public key): " + Util.dump(B));
+            L = frameIn.getText();
+            if (Configuration.DEBUG)
+              log.fine("Got L (available options): \"" + L + "\"");
+          }
+        else if (ack == 0xFF) // session re-use
+          {
+            sn = frameIn.getOS();
+            if (Configuration.DEBUG)
+              log.fine("Got sn (server nonce): " + Util.dumpString(sn));
+            sCB = frameIn.getEOS();
+            if (Configuration.DEBUG)
+              log.fine("Got sCB (server channel binding): " + Util.dumpString(sCB));
+          }
+        else // unexpected scalar
+          throw new SaslException("sendPublicKey(): Invalid scalar (" + ack
+                                  + ") in server's request");
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new SaslException("sendPublicKey()", x);
+      }
+    if (ack == 0x00)
+      { // new session ---------------------------------------
+        o = createO(L.toLowerCase()); // do this first to initialise the SRP hash
+        final byte[] pBytes; // use ASCII encoding to inter-operate w/ non-java
+        pBytes = password.getBytes();
+        // ----------------------------------------------------------------------
+        final HashMap mapA = new HashMap();
+        mapA.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm());
+        mapA.put(SRP6KeyAgreement.USER_IDENTITY, U);
+        mapA.put(SRP6KeyAgreement.USER_PASSWORD, pBytes);
+        try
+          {
+            clientHandler.init(mapA);
+            clientHandler.processMessage(null);
+          }
+        catch (KeyAgreementException x)
+          {
+            throw new SaslException("sendPublicKey()", x);
+          }
+        // -------------------------------------------------------------------
+        try
+          {
+            OutgoingMessage out = new OutgoingMessage();
+            out.writeMPI(N);
+            out.writeMPI(g);
+            out.writeMPI(new BigInteger(1, s));
+            out.writeMPI(B);
+            IncomingMessage in = new IncomingMessage(out.toByteArray());
+            out = clientHandler.processMessage(in);
+            in = new IncomingMessage(out.toByteArray());
+            A = in.readMPI();
+            K = clientHandler.getSharedSecret();
+          }
+        catch (KeyAgreementException x)
+          {
+            throw new SaslException("sendPublicKey()", x);
+          }
+        // -------------------------------------------------------------------
+        if (Configuration.DEBUG)
+          {
+            log.fine("K: " + Util.dumpString(K));
+            log.fine("Encoding A (client ephemeral public key): " + Util.dump(A));
+          }
+        try
+          {
+            M1 = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn,
+                                channelBinding);
+          }
+        catch (UnsupportedEncodingException x)
+          {
+            throw new AuthenticationException("sendPublicKey()", x);
+          }
+        if (Configuration.DEBUG)
+          {
+            log.fine("Encoding o (client chosen options): \"" + o + "\"");
+            log.fine("Encoding cIV (client IV): \"" + Util.dumpString(cIV) + "\"");
+          }
+        final OutputBuffer frameOut = new OutputBuffer();
+        try
+          {
+            frameOut.setMPI(A);
+            frameOut.setOS(M1);
+            frameOut.setText(o);
+            frameOut.setOS(cIV);
+          }
+        catch (IOException x)
+          {
+            if (x instanceof SaslException)
+              throw (SaslException) x;
+            throw new AuthenticationException("sendPublicKey()", x);
+          }
+        final byte[] result = frameOut.encode();
+        if (Configuration.DEBUG)
+          {
+            log.fine("New session, or session re-use rejected...");
+            log.fine("C: " + Util.dumpString(result));
+            log.fine("  A = 0x" + A.toString(16));
+            log.fine(" M1 = " + Util.dumpString(M1));
+            log.fine("  o = " + o);
+            log.fine("cIV = " + Util.dumpString(cIV));
+            log.exiting(this.getClass().getName(), "sendPublicKey");
+          }
+        return result;
+      }
+    else // session re-use accepted -------------------------------------------
+      {
+        setupSecurityServices(true);
+        if (Configuration.DEBUG)
+          {
+            log.fine("Session re-use accepted...");
+            log.exiting(this.getClass().getName(), "sendPublicKey");
+          }
+        return null;
+      }
+  }
+
+  private byte[] receiveEvidence(byte[] input) throws SaslException
+  {
+    if (Configuration.DEBUG)
+      {
+        log.entering(this.getClass().getName(), "receiveEvidence");
+        log.fine("S: " + Util.dumpString(input));
+      }
+    // Server send M2, sIV, sCB, sid, ttl
+    final InputBuffer frameIn = new InputBuffer(input);
+    try
+      {
+        M2 = frameIn.getOS();
+        if (Configuration.DEBUG)
+          log.fine("Got M2 (server evidence): " + Util.dumpString(M2));
+        sIV = frameIn.getOS();
+        if (Configuration.DEBUG)
+          log.fine("Got sIV (server IV): " + Util.dumpString(sIV));
+        sid = frameIn.getEOS();
+        if (Configuration.DEBUG)
+          log.fine("Got sid (session ID): " + new String(sid));
+        ttl = (int) frameIn.getScalar(4);
+        if (Configuration.DEBUG)
+          log.fine("Got ttl (session time-to-live): " + ttl + "sec.");
+        sCB = frameIn.getEOS();
+        if (Configuration.DEBUG)
+          log.fine("Got sCB (server channel binding): " + Util.dumpString(sCB));
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new AuthenticationException("receiveEvidence()", x);
+      }
+
+    final byte[] expected;
+    try
+      {
+        expected = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl,
+                                  cIV, sIV, sCB);
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new AuthenticationException("receiveEvidence()", x);
+      }
+    if (Configuration.DEBUG)
+      log.fine("Expected: " + Util.dumpString(expected));
+    if (! Arrays.equals(M2, expected))
+      throw new AuthenticationException("M2 mismatch");
+    setupSecurityServices(false);
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "receiveEvidence");
+    return null;
+  }
+
+  private void getUsernameAndPassword() throws AuthenticationException
+  {
+    try
+      {
+        if ((! properties.containsKey(Registry.SASL_USERNAME))
+            && (! properties.containsKey(Registry.SASL_PASSWORD)))
+          {
+            final NameCallback nameCB;
+            final String defaultName = System.getProperty("user.name");
+            if (defaultName == null)
+              nameCB = new NameCallback("username: ");
+            else
+              nameCB = new NameCallback("username: ", defaultName);
+            final PasswordCallback pwdCB = new PasswordCallback("password: ",
+                                                                false);
+            handler.handle(new Callback[] { nameCB, pwdCB });
+            U = nameCB.getName();
+            password = new Password(pwdCB.getPassword());
+          }
+        else
+          {
+            if (properties.containsKey(Registry.SASL_USERNAME))
+              this.U = (String) properties.get(Registry.SASL_USERNAME);
+            else
+              {
+                final NameCallback nameCB;
+                final String defaultName = System.getProperty("user.name");
+                if (defaultName == null)
+                  nameCB = new NameCallback("username: ");
+                else
+                  nameCB = new NameCallback("username: ", defaultName);
+                this.handler.handle(new Callback[] { nameCB });
+                this.U = nameCB.getName();
+              }
+
+            if (properties.containsKey(Registry.SASL_PASSWORD))
+              {
+                Object pw = properties.get(Registry.SASL_PASSWORD);
+                if (pw instanceof char[])
+                  password = new Password((char[]) pw);
+                else if (pw instanceof Password)
+                  password = (Password) pw;
+                else if (pw instanceof String)
+                  password = new Password(((String) pw).toCharArray());
+                else
+                  throw new IllegalArgumentException(pw.getClass().getName()
+                                                     + "is not a valid password class");
+              }
+            else
+              {
+                final PasswordCallback pwdCB = new PasswordCallback("password: ",
+                                                                    false);
+                this.handler.handle(new Callback[] { pwdCB });
+                password = new Password(pwdCB.getPassword());
+              }
+          }
+
+        if (U == null)
+          throw new AuthenticationException("null username supplied");
+        if (password == null)
+          throw new AuthenticationException("null password supplied");
+      }
+    catch (UnsupportedCallbackException x)
+      {
+        throw new AuthenticationException("getUsernameAndPassword()", x);
+      }
+    catch (IOException x)
+      {
+        throw new AuthenticationException("getUsernameAndPassword()", x);
+      }
+  }
+
+  // We go through the list of available services and for each available one
+  // we decide whether or not we want it enabled, based on properties passed
+  // to us by the client.
+  private String createO(final String aol) throws AuthenticationException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "createO", aol);
+    boolean replaydetectionAvailable = false;
+    boolean integrityAvailable = false;
+    boolean confidentialityAvailable = false;
+    String option, mandatory = SRPRegistry.DEFAULT_MANDATORY;
+    int i;
+
+    String mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME;
+    final StringTokenizer st = new StringTokenizer(aol, ",");
+    while (st.hasMoreTokens())
+      {
+        option = st.nextToken();
+        if (option.startsWith(SRPRegistry.OPTION_SRP_DIGEST + "="))
+          {
+            option = option.substring(option.indexOf('=') + 1);
+            if (Configuration.DEBUG)
+              log.fine("mda: <" + option + ">");
+            for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
+              if (SRPRegistry.SRP_ALGORITHMS[i].equals(option))
+                {
+                  mdName = option;
+                  break;
+                }
+          }
+        else if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION))
+          replaydetectionAvailable = true;
+        else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "="))
+          {
+            option = option.substring(option.indexOf('=') + 1);
+            if (Configuration.DEBUG)
+              log.fine("ialg: <" + option + ">");
+            for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
+              if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option))
+                {
+                  chosenIntegrityAlgorithm = option;
+                  integrityAvailable = true;
+                  break;
+                }
+          }
+        else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "="))
+          {
+            option = option.substring(option.indexOf('=') + 1);
+            if (Configuration.DEBUG)
+              log.fine("calg: <" + option + ">");
+            for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++)
+              if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option))
+                {
+                  chosenConfidentialityAlgorithm = option;
+                  confidentialityAvailable = true;
+                  break;
+                }
+          }
+        else if (option.startsWith(SRPRegistry.OPTION_MANDATORY + "="))
+          mandatory = option.substring(option.indexOf('=') + 1);
+        else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "="))
+          {
+            final String maxBufferSize = option.substring(option.indexOf('=') + 1);
+            try
+              {
+                rawSendSize = Integer.parseInt(maxBufferSize);
+                if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT
+                    || rawSendSize < 1)
+                  throw new AuthenticationException(
+                      "Illegal value for 'maxbuffersize' option");
+              }
+            catch (NumberFormatException x)
+              {
+                throw new AuthenticationException(
+                    SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=" + maxBufferSize, x);
+              }
+          }
+      }
+    String s;
+    Boolean flag;
+    s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION);
+    flag = Boolean.valueOf(s);
+    replayDetection = replaydetectionAvailable && flag.booleanValue();
+    s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION);
+    flag = Boolean.valueOf(s);
+    boolean integrity = integrityAvailable && flag.booleanValue();
+    s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY);
+    flag = Boolean.valueOf(s);
+    boolean confidentiality = confidentialityAvailable && flag.booleanValue();
+    // make sure we do the right thing
+    if (SRPRegistry.OPTION_REPLAY_DETECTION.equals(mandatory))
+      {
+        replayDetection = true;
+        integrity = true;
+      }
+    else if (SRPRegistry.OPTION_INTEGRITY.equals(mandatory))
+      integrity = true;
+    else if (SRPRegistry.OPTION_CONFIDENTIALITY.equals(mandatory))
+      confidentiality = true;
+
+    if (replayDetection)
+      {
+        if (chosenIntegrityAlgorithm == null)
+          throw new AuthenticationException(
+              "Replay detection is required but no integrity protection "
+              + "algorithm was chosen");
+      }
+    if (integrity)
+      {
+        if (chosenIntegrityAlgorithm == null)
+          throw new AuthenticationException(
+              "Integrity protection is required but no algorithm was chosen");
+      }
+    if (confidentiality)
+      {
+        if (chosenConfidentialityAlgorithm == null)
+          throw new AuthenticationException(
+              "Confidentiality protection is required but no algorithm was chosen");
+      }
+    // 1. check if we'll be using confidentiality; if not set IV to 0-byte
+    if (chosenConfidentialityAlgorithm == null)
+      cIV = new byte[0];
+    else
+      {
+        // 2. get the block size of the cipher
+        final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm);
+        if (cipher == null)
+          throw new AuthenticationException("createO()",
+                                            new NoSuchAlgorithmException());
+        final int blockSize = cipher.defaultBlockSize();
+        // 3. generate random iv
+        cIV = new byte[blockSize];
+        getDefaultPRNG().nextBytes(cIV);
+      }
+    srp = SRP.instance(mdName);
+    // Now create the options list specifying which of the available options
+    // we have chosen.
+
+    // For now we just select the defaults. Later we need to add support for
+    // properties (perhaps in a file) where a user can specify the list of
+    // algorithms they would prefer to use.
+    final StringBuffer sb = new StringBuffer();
+    sb.append(SRPRegistry.OPTION_SRP_DIGEST)
+      .append("=").append(mdName).append(",");
+    if (replayDetection)
+      sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(",");
+    if (integrity)
+      sb.append(SRPRegistry.OPTION_INTEGRITY)
+        .append("=").append(chosenIntegrityAlgorithm).append(",");
+    if (confidentiality)
+      sb.append(SRPRegistry.OPTION_CONFIDENTIALITY)
+        .append("=").append(chosenConfidentialityAlgorithm).append(",");
+
+    final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE)
+                            .append("=").append(Registry.SASL_BUFFER_MAX_LIMIT)
+                            .toString();
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "createO", result);
+    return result;
+  }
+
+  private void setupSecurityServices(final boolean sessionReUse)
+      throws SaslException
+  {
+    complete = true; // signal end of authentication phase
+    if (! sessionReUse)
+      {
+        outCounter = inCounter = 0;
+        // instantiate cipher if confidentiality protection filter is active
+        if (chosenConfidentialityAlgorithm != null)
+          {
+            if (Configuration.DEBUG)
+              log.fine("Activating confidentiality protection filter");
+            inCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
+            outCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
+          }
+        // instantiate hmacs if integrity protection filter is active
+        if (chosenIntegrityAlgorithm != null)
+          {
+            if (Configuration.DEBUG)
+              log.fine("Activating integrity protection filter");
+            inMac = IALG.getInstance(chosenIntegrityAlgorithm);
+            outMac = IALG.getInstance(chosenIntegrityAlgorithm);
+          }
+      }
+    else // same session new Keys
+      K = srp.generateKn(K, cn, sn);
+
+    final KDF kdf = KDF.getInstance(K);
+    // initialise in/out ciphers if confidentiality protection is used
+    if (inCipher != null)
+      {
+        inCipher.init(kdf, sIV, Direction.REVERSED);
+        outCipher.init(kdf, cIV, Direction.FORWARD);
+      }
+    // initialise in/out macs if integrity protection is used
+    if (inMac != null)
+      {
+        inMac.init(kdf);
+        outMac.init(kdf);
+      }
+    if (sid != null && sid.length != 0)
+      { // update the security context and save in map
+        if (Configuration.DEBUG)
+          log.fine("Updating security context for UID = " + uid);
+        ClientStore.instance().cacheSession(uid,
+                                            ttl,
+                                            new SecurityContext(srp.getAlgorithm(),
+                                                                sid,
+                                                                K,
+                                                                cIV,
+                                                                sIV,
+                                                                replayDetection,
+                                                                inCounter,
+                                                                outCounter,
+                                                                inMac, outMac,
+                                                                inCipher,
+                                                                outCipher));
+      }
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/SRPRegistry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,165 @@
+/* SRPRegistry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.java.security.Registry;
+
+/**
+ * A list of key names designating the values exchanged between the server
+ * and client in an SRP communication authentication phase.
+ */
+public interface SRPRegistry
+{
+  /** Indices of (N, g) parameter values for SRP (.conf) password database. */
+  String N_2048_BITS = "1";
+  String N_1536_BITS = "2";
+  String N_1280_BITS = "3";
+  String N_1024_BITS = "4";
+  String N_768_BITS = "5";
+  String N_640_BITS = "6";
+  String N_512_BITS = "7";
+  /** Available hash algorithms for all SRP calculations. */
+  String[] SRP_ALGORITHMS = {
+      Registry.SHA160_HASH, // the default one
+      Registry.MD5_HASH,
+      Registry.RIPEMD128_HASH,
+      Registry.RIPEMD160_HASH,
+
+      Registry.SHA256_HASH,
+      Registry.SHA384_HASH,
+      Registry.SHA512_HASH };
+  /**
+   * The name of the default message digest algorithm to use when no name is
+   * explicitely given. In this implementation it is the <b>first</b> among
+   * those supported; i.e. the algorithm at index position #0: SHA with
+   * 160-bit output.
+   */
+  String SRP_DEFAULT_DIGEST_NAME = SRP_ALGORITHMS[0];
+  /**
+   * The property name of the message digest algorithm name to use in a given
+   * SRP incarnation.
+   */
+  String SRP_DIGEST_NAME = "srp.digest.name";
+  /** The public shared modulus: n. */
+  String SHARED_MODULUS = "srp.N";
+  /** The GF generator used: g. */
+  String FIELD_GENERATOR = "srp.g";
+  /** The list of server's available security options. */
+  String AVAILABLE_OPTIONS = "srp.L";
+  /** The client's chosen security options. */
+  String CHOSEN_OPTIONS = "srp.o";
+  /** The client's username. */
+  String USER_NAME = "srp.U";
+  /** The client's authorization ID. */
+  String USER_ROLE = "srp.I";
+  /** The user's salt. */
+  String USER_SALT = "srp.s";
+  /** The user's password verifier. */
+  String PASSWORD_VERIFIER = "srp.v";
+  /** The client's public ephemeral exponent: A. */
+  String CLIENT_PUBLIC_KEY = "srp.A";
+  /** The server's public ephemeral exponent: B. */
+  String SERVER_PUBLIC_KEY = "srp.B";
+  /** The client's evidence: M1. */
+  String CLIENT_EVIDENCE = "srp.M1";
+  /** The server's evidence: M2. */
+  String SERVER_EVIDENCE = "srp.M2";
+  /** Name of underlying hash algorithm for use with all SRP calculations. */
+  String SRP_HASH = "gnu.crypto.sasl.srp.hash";
+  /** Name of SRP mandatory service property. */
+  String SRP_MANDATORY = "gnu.crypto.sasl.srp.mandatory";
+  /** Name of SRP replay detection property. */
+  String SRP_REPLAY_DETECTION = "gnu.crypto.sasl.srp.replay.detection";
+  /** Name of SRP integrity protection property. */
+  String SRP_INTEGRITY_PROTECTION = "gnu.crypto.sasl.srp.integrity";
+  /** Name of SRP confidentiality protection property. */
+  String SRP_CONFIDENTIALITY = "gnu.crypto.sasl.srp.confidentiality";
+  /** Name of the main SRP password file pathname property. */
+  String PASSWORD_FILE = "gnu.crypto.sasl.srp.password.file";
+  /**
+   * Name of the SRP password database property --a reference to
+   * {@link PasswordFile} object.
+   */
+  String PASSWORD_DB = "gnu.crypto.sasl.srp.password.db";
+  /** Default fully qualified pathname of the SRP password file. */
+  String DEFAULT_PASSWORD_FILE = "/etc/tpasswd";
+  /** Default value for replay detection security service. */
+  boolean DEFAULT_REPLAY_DETECTION = true;
+  /** Default value for integrity protection security service. */
+  boolean DEFAULT_INTEGRITY = true; // implied by the previous option
+  /** Default value for confidentiality protection security service. */
+  boolean DEFAULT_CONFIDENTIALITY = false;
+  // constants defining HMAC names
+  String HMAC_SHA1 = "hmac-sha1";
+  String HMAC_MD5 = "hmac-md5";
+  String HMAC_RIPEMD_160 = "hmac-ripemd-160";
+  /** Available HMAC algorithms for integrity protection. */
+  String[] INTEGRITY_ALGORITHMS = { HMAC_SHA1, HMAC_MD5, HMAC_RIPEMD_160 };
+  // constants defining Cipher names
+  String AES = "aes";
+  String BLOWFISH = "blowfish";
+  /** Available Cipher algorithms for confidentiality protection. */
+  String[] CONFIDENTIALITY_ALGORITHMS = { AES, BLOWFISH };
+  /** String for mandatory replay detection. */
+  String OPTION_MANDATORY = "mandatory";
+  /** String for mda: the SRP digest algorithm name. */
+  String OPTION_SRP_DIGEST = "mda";
+  /** String for mandatory replay detection. */
+  String OPTION_REPLAY_DETECTION = "replay_detection";
+  /** String for mandatory integrity protection. */
+  String OPTION_INTEGRITY = "integrity";
+  /** String for mandatory confidentiality protection. */
+  String OPTION_CONFIDENTIALITY = "confidentiality";
+  /** String for mandatory replay detection. */
+  String OPTION_MAX_BUFFER_SIZE = "maxbuffersize";
+  /** String for no mandatory security service. */
+  String MANDATORY_NONE = "none";
+  /** Default mandatory security service required. */
+  String DEFAULT_MANDATORY = OPTION_REPLAY_DETECTION;
+  /** Name of the UID field in the plain password file. */
+  String MD_NAME_FIELD = "srp.md.name";
+  /** Name of the GID field in the plain password file. */
+  String USER_VERIFIER_FIELD = "srp.user.verifier";
+  /** Name of the GECOS field in the plain password file. */
+  String SALT_FIELD = "srp.salt";
+  /** Name of the SHELL field in the plain password file. */
+  String CONFIG_NDX_FIELD = "srp.config.ndx";
+  /** Minimum bitlength of the SRP public modulus. */
+  int MINIMUM_MODULUS_BITLENGTH = 512;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/SRPServer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,840 @@
+/* SRPServer.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.PRNG;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.assembly.Direction;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.key.IKeyAgreementParty;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.KeyAgreementFactory;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.key.srp6.SRP6KeyAgreement;
+import gnu.javax.crypto.sasl.IllegalMechanismStateException;
+import gnu.javax.crypto.sasl.InputBuffer;
+import gnu.javax.crypto.sasl.IntegrityException;
+import gnu.javax.crypto.sasl.OutputBuffer;
+import gnu.javax.crypto.sasl.ServerMechanism;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+import java.util.logging.Logger;
+
+import javax.security.sasl.AuthenticationException;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+/**
+ * The SASL-SRP server-side mechanism.
+ */
+public class SRPServer
+    extends ServerMechanism
+    implements SaslServer
+{
+  private static final Logger log = Logger.getLogger(SRPServer.class.getName());
+  private String U = null; // client's username
+  private BigInteger N, g, A, B;
+  private byte[] s; // salt
+  private byte[] cIV, sIV; // client+server IVs, when confidentiality is on
+  private byte[] cn, sn; // client's and server's nonce
+  private SRP srp; // SRP algorithm instance used by this server
+  private byte[] sid; // session ID when re-used
+  private int ttl = 360; // session time-to-live in seconds
+  private byte[] cCB; // peer's channel binding'
+  private String mandatory; // List of available options
+  private String L = null;
+  private String o;
+  private String chosenIntegrityAlgorithm;
+  private String chosenConfidentialityAlgorithm;
+  private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT;
+  private byte[] K; // shared session key
+  private boolean replayDetection = true; // whether Replay Detection is on
+  private int inCounter = 0; // messages sequence numbers
+  private int outCounter = 0;
+  private IALG inMac, outMac; // if !null, use for integrity
+  private CALG inCipher, outCipher; // if !null, use for confidentiality
+  private IKeyAgreementParty serverHandler =
+      KeyAgreementFactory.getPartyBInstance(Registry.SRP_SASL_KA);
+  /** Our default source of randomness. */
+  private PRNG prng = null;
+
+  public SRPServer()
+  {
+    super(Registry.SASL_SRP_MECHANISM);
+  }
+
+  protected void initMechanism() throws SaslException
+  {
+    // TODO:
+    // we must have a means to map a given username to a preferred
+    // SRP hash algorithm; otherwise we end up using _always_ SHA.
+    // for the time being get it from the mechanism properties map
+    // and apply it for all users.
+    final String mda = (String) properties.get(SRPRegistry.SRP_HASH);
+    srp = SRP.instance(mda == null ? SRPRegistry.SRP_DEFAULT_DIGEST_NAME : mda);
+  }
+
+  protected void resetMechanism() throws SaslException
+  {
+    s = null;
+    A = B = null;
+    K = null;
+    inMac = outMac = null;
+    inCipher = outCipher = null;
+    sid = null;
+  }
+
+  public byte[] evaluateResponse(final byte[] response) throws SaslException
+  {
+    switch (state)
+      {
+      case 0:
+        if (response == null)
+          return null;
+        state++;
+        return sendProtocolElements(response);
+      case 1:
+        if (! complete)
+          {
+            state++;
+            return sendEvidence(response);
+          }
+      // else fall through
+      default:
+        throw new IllegalMechanismStateException("evaluateResponse()");
+      }
+  }
+
+  protected byte[] engineUnwrap(final byte[] incoming, final int offset,
+                                final int len) throws SaslException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineUnwrap");
+    if (inMac == null && inCipher == null)
+      throw new IllegalStateException("connection is not protected");
+    if (Configuration.DEBUG)
+      log.fine("Incoming buffer (before security): "
+               + Util.dumpString(incoming, offset, len));
+    // at this point one, or both, of confidentiality and integrity protection
+    // services are active.
+    final byte[] result;
+    try
+      {
+        if (inMac != null)
+          { // integrity bytes are at the end of the stream
+            final int macBytesCount = inMac.length();
+            final int payloadLength = len - macBytesCount;
+            final byte[] received_mac = new byte[macBytesCount];
+            System.arraycopy(incoming, offset + payloadLength, received_mac, 0,
+                             macBytesCount);
+            if (Configuration.DEBUG)
+              log.fine("Got C (received MAC): " + Util.dumpString(received_mac));
+            inMac.update(incoming, offset, payloadLength);
+            if (replayDetection)
+              {
+                inCounter++;
+                if (Configuration.DEBUG)
+                  log.fine("inCounter=" + String.valueOf(inCounter));
+                inMac.update(new byte[] {
+                    (byte)(inCounter >>> 24),
+                    (byte)(inCounter >>> 16),
+                    (byte)(inCounter >>> 8),
+                    (byte) inCounter });
+              }
+            final byte[] computed_mac = inMac.doFinal();
+            if (Configuration.DEBUG)
+              log.fine("Computed MAC: " + Util.dumpString(computed_mac));
+            if (! Arrays.equals(received_mac, computed_mac))
+              throw new IntegrityException("engineUnwrap()");
+            // deal with the payload, which can be either plain or encrypted
+            if (inCipher != null)
+              result = inCipher.doFinal(incoming, offset, payloadLength);
+            else
+              {
+                result = new byte[payloadLength];
+                System.arraycopy(incoming, offset, result, 0, result.length);
+              }
+          }
+        else // no integrity protection; just confidentiality
+          result = inCipher.doFinal(incoming, offset, len);
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new SaslException("engineUnwrap()", x);
+      }
+    if (Configuration.DEBUG)
+      {
+        log.fine("Incoming buffer (after security): " + Util.dumpString(result));
+        log.exiting(this.getClass().getName(), "engineUnwrap");
+      }
+    return result;
+  }
+
+  protected byte[] engineWrap(final byte[] outgoing, final int offset,
+                              final int len) throws SaslException
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "engineWrap");
+    if (outMac == null && outCipher == null)
+      throw new IllegalStateException("connection is not protected");
+    if (Configuration.DEBUG)
+      {
+        log.fine("Outgoing buffer (before security) (hex): "
+                 + Util.dumpString(outgoing, offset, len));
+        log.fine("Outgoing buffer (before security) (str): \""
+                 + new String(outgoing, offset, len) + "\"");
+      }
+    // at this point one, or both, of confidentiality and integrity protection
+    // services are active.
+    byte[] result;
+    try
+      {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        if (outCipher != null)
+          {
+            result = outCipher.doFinal(outgoing, offset, len);
+            if (Configuration.DEBUG)
+              log.fine("Encoding c (encrypted plaintext): "
+                       + Util.dumpString(result));
+            out.write(result);
+            if (outMac != null)
+              {
+                outMac.update(result);
+                if (replayDetection)
+                  {
+                    outCounter++;
+                    if (Configuration.DEBUG)
+                      log.fine("outCounter=" + outCounter);
+                    outMac.update(new byte[] {
+                        (byte)(outCounter >>> 24),
+                        (byte)(outCounter >>> 16),
+                        (byte)(outCounter >>> 8),
+                        (byte) outCounter });
+                  }
+                final byte[] C = outMac.doFinal();
+                out.write(C);
+                if (Configuration.DEBUG)
+                  log.fine("Encoding C (integrity checksum): " + Util.dumpString(C));
+              }
+            // else ciphertext only; do nothing
+          }
+        else // no confidentiality; just integrity [+ replay detection]
+          {
+            if (Configuration.DEBUG)
+              log.fine("Encoding p (plaintext): "
+                       + Util.dumpString(outgoing, offset, len));
+            out.write(outgoing, offset, len);
+            outMac.update(outgoing, offset, len);
+            if (replayDetection)
+              {
+                outCounter++;
+                if (Configuration.DEBUG)
+                  log.fine("outCounter=" + outCounter);
+                outMac.update(new byte[] {
+                    (byte)(outCounter >>> 24),
+                    (byte)(outCounter >>> 16),
+                    (byte)(outCounter >>> 8),
+                    (byte) outCounter });
+              }
+            final byte[] C = outMac.doFinal();
+            out.write(C);
+            if (Configuration.DEBUG)
+              log.fine("Encoding C (integrity checksum): " + Util.dumpString(C));
+          }
+        result = out.toByteArray();
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new SaslException("engineWrap()", x);
+      }
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "engineWrap");
+    return result;
+  }
+
+  protected String getNegotiatedQOP()
+  {
+    if (inMac != null)
+      {
+        if (inCipher != null)
+          return Registry.QOP_AUTH_CONF;
+        return Registry.QOP_AUTH_INT;
+      }
+    return Registry.QOP_AUTH;
+  }
+
+  protected String getNegotiatedStrength()
+  {
+    if (inMac != null)
+      {
+        if (inCipher != null)
+          return Registry.STRENGTH_HIGH;
+        return Registry.STRENGTH_MEDIUM;
+      }
+    return Registry.STRENGTH_LOW;
+  }
+
+  protected String getNegotiatedRawSendSize()
+  {
+    return String.valueOf(rawSendSize);
+  }
+
+  protected String getReuse()
+  {
+    return Registry.REUSE_TRUE;
+  }
+
+  private byte[] sendProtocolElements(final byte[] input) throws SaslException
+  {
+    if (Configuration.DEBUG)
+      {
+        log.entering(this.getClass().getName(), "sendProtocolElements");
+        log.fine("C: " + Util.dumpString(input));
+      }
+    // Client send U, I, sid, cn
+    final InputBuffer frameIn = new InputBuffer(input);
+    try
+      {
+        U = frameIn.getText(); // Extract username
+        if (Configuration.DEBUG)
+          log.fine("Got U (username): \"" + U + "\"");
+        authorizationID = frameIn.getText(); // Extract authorisation ID
+        if (Configuration.DEBUG)
+          log.fine("Got I (userid): \"" + authorizationID + "\"");
+        sid = frameIn.getEOS();
+        if (Configuration.DEBUG)
+          log.fine("Got sid (session ID): " + new String(sid));
+        cn = frameIn.getOS();
+        if (Configuration.DEBUG)
+          log.fine("Got cn (client nonce): " + Util.dumpString(cn));
+        cCB = frameIn.getEOS();
+        if (Configuration.DEBUG)
+          log.fine("Got cCB (client channel binding): " + Util.dumpString(cCB));
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new AuthenticationException("sendProtocolElements()", x);
+      }
+    // do/can we re-use?
+    if (ServerStore.instance().isAlive(sid))
+      {
+        final SecurityContext ctx = ServerStore.instance().restoreSession(sid);
+        srp = SRP.instance(ctx.getMdName());
+        K = ctx.getK();
+        cIV = ctx.getClientIV();
+        sIV = ctx.getServerIV();
+        replayDetection = ctx.hasReplayDetection();
+        inCounter = ctx.getInCounter();
+        outCounter = ctx.getOutCounter();
+        inMac = ctx.getInMac();
+        outMac = ctx.getOutMac();
+        inCipher = ctx.getInCipher();
+        outCipher = ctx.getOutCipher();
+        if (sn == null || sn.length != 16)
+          sn = new byte[16];
+        getDefaultPRNG().nextBytes(sn);
+        setupSecurityServices(false);
+        final OutputBuffer frameOut = new OutputBuffer();
+        try
+          {
+            frameOut.setScalar(1, 0xFF);
+            frameOut.setOS(sn);
+            frameOut.setEOS(channelBinding);
+          }
+        catch (IOException x)
+          {
+            if (x instanceof SaslException)
+              throw (SaslException) x;
+            throw new AuthenticationException("sendProtocolElements()", x);
+          }
+        final byte[] result = frameOut.encode();
+        if (Configuration.DEBUG)
+          {
+            log.fine("Old session...");
+            log.fine("S: " + Util.dumpString(result));
+            log.fine("  sn = " + Util.dumpString(sn));
+            log.fine(" sCB = " + Util.dumpString(channelBinding));
+            log.exiting(this.getClass().getName(), "sendProtocolElements");
+          }
+        return result;
+      }
+    else
+      { // new session
+        authenticator.activate(properties);
+        // -------------------------------------------------------------------
+        final HashMap mapB = new HashMap();
+        mapB.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm());
+        mapB.put(SRP6KeyAgreement.HOST_PASSWORD_DB, authenticator);
+        try
+          {
+            serverHandler.init(mapB);
+            OutgoingMessage out = new OutgoingMessage();
+            out.writeString(U);
+            IncomingMessage in = new IncomingMessage(out.toByteArray());
+            out = serverHandler.processMessage(in);
+            in = new IncomingMessage(out.toByteArray());
+            N = in.readMPI();
+            g = in.readMPI();
+            s = in.readMPI().toByteArray();
+            B = in.readMPI();
+          }
+        catch (KeyAgreementException x)
+          {
+            throw new SaslException("sendProtocolElements()", x);
+          }
+        // -------------------------------------------------------------------
+        if (Configuration.DEBUG)
+          {
+            log.fine("Encoding N (modulus): " + Util.dump(N));
+            log.fine("Encoding g (generator): " + Util.dump(g));
+            log.fine("Encoding s (client's salt): " + Util.dumpString(s));
+            log.fine("Encoding B (server ephemeral public key): " + Util.dump(B));
+          }
+        // The server creates an options list (L), which consists of a
+        // comma-separated list of option strings that specify the security
+        // service options the server supports.
+        L = createL();
+        if (Configuration.DEBUG)
+          {
+            log.fine("Encoding L (available options): \"" + L + "\"");
+            log.fine("Encoding sIV (server IV): " + Util.dumpString(sIV));
+          }
+        final OutputBuffer frameOut = new OutputBuffer();
+        try
+          {
+            frameOut.setScalar(1, 0x00);
+            frameOut.setMPI(N);
+            frameOut.setMPI(g);
+            frameOut.setOS(s);
+            frameOut.setMPI(B);
+            frameOut.setText(L);
+          }
+        catch (IOException x)
+          {
+            if (x instanceof SaslException)
+              throw (SaslException) x;
+            throw new AuthenticationException("sendProtocolElements()", x);
+          }
+        final byte[] result = frameOut.encode();
+        if (Configuration.DEBUG)
+          {
+            log.fine("New session...");
+            log.fine("S: " + Util.dumpString(result));
+            log.fine("   N = 0x" + N.toString(16));
+            log.fine("   g = 0x" + g.toString(16));
+            log.fine("   s = " + Util.dumpString(s));
+            log.fine("   B = 0x" + B.toString(16));
+            log.fine("   L = " + L);
+            log.exiting(this.getClass().getName(), "sendProtocolElements");
+          }
+        return result;
+      }
+  }
+
+  private byte[] sendEvidence(final byte[] input) throws SaslException
+  {
+    if (Configuration.DEBUG)
+      {
+        log.entering(this.getClass().getName(), "sendEvidence");
+        log.fine("C: " + Util.dumpString(input));
+      }
+    // Client send A, M1, o, cIV
+    final InputBuffer frameIn = new InputBuffer(input);
+    final byte[] M1;
+    try
+      {
+        A = frameIn.getMPI(); // Extract client's ephemeral public key
+        if (Configuration.DEBUG)
+          log.fine("Got A (client ephemeral public key): " + Util.dump(A));
+        M1 = frameIn.getOS(); // Extract evidence
+        if (Configuration.DEBUG)
+          log.fine("Got M1 (client evidence): " + Util.dumpString(M1));
+        o = frameIn.getText(); // Extract client's options list
+        if (Configuration.DEBUG)
+          log.fine("Got o (client chosen options): \"" + o + "\"");
+        cIV = frameIn.getOS(); // Extract client's IV
+        if (Configuration.DEBUG)
+          log.fine("Got cIV (client IV): " + Util.dumpString(cIV));
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new AuthenticationException("sendEvidence()", x);
+      }
+    // Parse client's options and set security layer variables
+    parseO(o);
+    // ----------------------------------------------------------------------
+    try
+      {
+        final OutgoingMessage out = new OutgoingMessage();
+        out.writeMPI(A);
+        final IncomingMessage in = new IncomingMessage(out.toByteArray());
+        serverHandler.processMessage(in);
+        K = serverHandler.getSharedSecret();
+      }
+    catch (KeyAgreementException x)
+      {
+        throw new SaslException("sendEvidence()", x);
+      }
+    // ----------------------------------------------------------------------
+    if (Configuration.DEBUG)
+      log.fine("K: " + Util.dumpString(K));
+    final byte[] expected;
+    try
+      {
+        expected = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn,
+                                  cCB);
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new AuthenticationException("sendEvidence()", x);
+      }
+    // Verify client evidence
+    if (! Arrays.equals(M1, expected))
+      throw new AuthenticationException("M1 mismatch");
+    setupSecurityServices(true);
+    final byte[] M2;
+    try
+      {
+        M2 = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl, cIV,
+                            sIV, channelBinding);
+      }
+    catch (UnsupportedEncodingException x)
+      {
+        throw new AuthenticationException("sendEvidence()", x);
+      }
+    final OutputBuffer frameOut = new OutputBuffer();
+    try
+      {
+        frameOut.setOS(M2);
+        frameOut.setOS(sIV);
+        frameOut.setEOS(sid);
+        frameOut.setScalar(4, ttl);
+        frameOut.setEOS(channelBinding);
+      }
+    catch (IOException x)
+      {
+        if (x instanceof SaslException)
+          throw (SaslException) x;
+        throw new AuthenticationException("sendEvidence()", x);
+      }
+    final byte[] result = frameOut.encode();
+    if (Configuration.DEBUG)
+      {
+        log.fine("S: " + Util.dumpString(result));
+        log.fine("  M2 = " + Util.dumpString(M2));
+        log.fine(" sIV = " + Util.dumpString(sIV));
+        log.fine(" sid = " + new String(sid));
+        log.fine(" ttl = " + ttl);
+        log.fine(" sCB = " + Util.dumpString(channelBinding));
+        log.exiting(this.getClass().getName(), "sendEvidence");
+      }
+    return result;
+  }
+
+  private String createL()
+  {
+    if (Configuration.DEBUG)
+      log.entering(this.getClass().getName(), "createL()");
+    String s = (String) properties.get(SRPRegistry.SRP_MANDATORY);
+    if (s == null)
+      s = SRPRegistry.DEFAULT_MANDATORY;
+
+    if (! SRPRegistry.MANDATORY_NONE.equals(s)
+        && ! SRPRegistry.OPTION_REPLAY_DETECTION.equals(s)
+        && ! SRPRegistry.OPTION_INTEGRITY.equals(s)
+        && ! SRPRegistry.OPTION_CONFIDENTIALITY.equals(s))
+      {
+        if (Configuration.DEBUG)
+          log.fine("Unrecognised mandatory option (" + s + "). Using default...");
+        s = SRPRegistry.DEFAULT_MANDATORY;
+      }
+    mandatory = s;
+    s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY);
+    final boolean confidentiality = (s == null ? SRPRegistry.DEFAULT_CONFIDENTIALITY
+                                               : Boolean.valueOf(s).booleanValue());
+    s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION);
+    boolean integrity = (s == null ? SRPRegistry.DEFAULT_INTEGRITY
+                                   : Boolean.valueOf(s).booleanValue());
+    s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION);
+    final boolean replayDetection = (s == null ? SRPRegistry.DEFAULT_REPLAY_DETECTION
+                                               : Boolean.valueOf(s).booleanValue());
+    final StringBuffer sb = new StringBuffer();
+    sb.append(SRPRegistry.OPTION_SRP_DIGEST).append("=")
+      .append(srp.getAlgorithm()).append(",");
+
+    if (! SRPRegistry.MANDATORY_NONE.equals(mandatory))
+      sb.append(SRPRegistry.OPTION_MANDATORY)
+        .append("=").append(mandatory).append(",");
+
+    if (replayDetection)
+      {
+        sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(",");
+        // if replay detection is on then force integrity protection
+        integrity = true;
+      }
+    int i;
+    if (integrity)
+      {
+        for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
+          sb.append(SRPRegistry.OPTION_INTEGRITY).append("=")
+            .append(SRPRegistry.INTEGRITY_ALGORITHMS[i]).append(",");
+      }
+    if (confidentiality)
+      {
+        IBlockCipher cipher;
+        for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++)
+          {
+            cipher = CipherFactory.getInstance(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]);
+            if (cipher != null)
+              sb.append(SRPRegistry.OPTION_CONFIDENTIALITY).append("=")
+                .append(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]).append(",");
+          }
+      }
+    final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE)
+                            .append("=").append(Registry.SASL_BUFFER_MAX_LIMIT)
+                            .toString();
+    if (Configuration.DEBUG)
+      log.exiting(this.getClass().getName(), "createL");
+    return result;
+  }
+
+  // Parse client's options and set security layer variables
+  private void parseO(final String o) throws AuthenticationException
+  {
+    this.replayDetection = false;
+    boolean integrity = false;
+    boolean confidentiality = false;
+    String option;
+    int i;
+
+    final StringTokenizer st = new StringTokenizer(o.toLowerCase(), ",");
+    while (st.hasMoreTokens())
+      {
+        option = st.nextToken();
+        if (Configuration.DEBUG)
+          log.fine("option: <" + option + ">");
+        if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION))
+          replayDetection = true;
+        else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "="))
+          {
+            if (integrity)
+              throw new AuthenticationException(
+                  "Only one integrity algorithm may be chosen");
+            option = option.substring(option.indexOf('=') + 1);
+            if (Configuration.DEBUG)
+              log.fine("algorithm: <" + option + ">");
+            for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
+              {
+                if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option))
+                  {
+                    chosenIntegrityAlgorithm = option;
+                    integrity = true;
+                    break;
+                  }
+              }
+            if (! integrity)
+              throw new AuthenticationException("Unknown integrity algorithm: "
+                                                + option);
+          }
+        else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "="))
+          {
+            if (confidentiality)
+              throw new AuthenticationException(
+                  "Only one confidentiality algorithm may be chosen");
+            option = option.substring(option.indexOf('=') + 1);
+            if (Configuration.DEBUG)
+              log.fine("algorithm: <" + option + ">");
+            for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++)
+              {
+                if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option))
+                  {
+                    chosenConfidentialityAlgorithm = option;
+                    confidentiality = true;
+                    break;
+                  }
+              }
+            if (! confidentiality)
+              throw new AuthenticationException("Unknown confidentiality algorithm: "
+                                                + option);
+          }
+        else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "="))
+          {
+            final String maxBufferSize = option.substring(option.indexOf('=') + 1);
+            try
+              {
+                rawSendSize = Integer.parseInt(maxBufferSize);
+                if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT
+                    || rawSendSize < 1)
+                  throw new AuthenticationException(
+                      "Illegal value for 'maxbuffersize' option");
+              }
+            catch (NumberFormatException x)
+              {
+                throw new AuthenticationException(
+                    SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=" + maxBufferSize, x);
+              }
+          }
+      }
+    // check if client did the right thing
+    if (replayDetection)
+      {
+        if (! integrity)
+          throw new AuthenticationException(
+              "Missing integrity protection algorithm but replay detection is chosen");
+      }
+    if (mandatory.equals(SRPRegistry.OPTION_REPLAY_DETECTION))
+      {
+        if (! replayDetection)
+          throw new AuthenticationException(
+              "Replay detection is mandatory but was not chosen");
+      }
+    if (mandatory.equals(SRPRegistry.OPTION_INTEGRITY))
+      {
+        if (! integrity)
+          throw new AuthenticationException(
+              "Integrity protection is mandatory but was not chosen");
+      }
+    if (mandatory.equals(SRPRegistry.OPTION_CONFIDENTIALITY))
+      {
+        if (! confidentiality)
+          throw new AuthenticationException(
+              "Confidentiality is mandatory but was not chosen");
+      }
+    int blockSize = 0;
+    if (chosenConfidentialityAlgorithm != null)
+      {
+        final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm);
+        if (cipher != null)
+          blockSize = cipher.defaultBlockSize();
+        else // should not happen
+          throw new AuthenticationException("Confidentiality algorithm ("
+                                            + chosenConfidentialityAlgorithm
+                                            + ") not available");
+      }
+    sIV = new byte[blockSize];
+    if (blockSize > 0)
+      getDefaultPRNG().nextBytes(sIV);
+  }
+
+  private void setupSecurityServices(final boolean newSession)
+      throws SaslException
+  {
+    complete = true; // signal end of authentication phase
+    if (newSession)
+      {
+        outCounter = inCounter = 0;
+        // instantiate cipher if confidentiality protection filter is active
+        if (chosenConfidentialityAlgorithm != null)
+          {
+            if (Configuration.DEBUG)
+              log.fine("Activating confidentiality protection filter");
+            inCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
+            outCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
+          }
+        // instantiate hmacs if integrity protection filter is active
+        if (chosenIntegrityAlgorithm != null)
+          {
+            if (Configuration.DEBUG)
+              log.fine("Activating integrity protection filter");
+            inMac = IALG.getInstance(chosenIntegrityAlgorithm);
+            outMac = IALG.getInstance(chosenIntegrityAlgorithm);
+          }
+        // generate a new sid if at least integrity is used
+        sid = (inMac != null ? ServerStore.getNewSessionID() : new byte[0]);
+      }
+    else // same session new keys
+      K = srp.generateKn(K, cn, sn);
+
+    final KDF kdf = KDF.getInstance(K);
+    // initialise in/out ciphers if confidentaility protection is used
+    if (inCipher != null)
+      {
+        outCipher.init(kdf, sIV, Direction.FORWARD);
+        inCipher.init(kdf, cIV, Direction.REVERSED);
+      }
+    // initialise in/out macs if integrity protection is used
+    if (inMac != null)
+      {
+        outMac.init(kdf);
+        inMac.init(kdf);
+      }
+    if (sid != null && sid.length != 0)
+      { // update the security context and save in map
+        if (Configuration.DEBUG)
+          log.fine("Updating security context for sid = " + new String(sid));
+        ServerStore.instance().cacheSession(ttl,
+                                            new SecurityContext(srp.getAlgorithm(),
+                                                                sid,
+                                                                K,
+                                                                cIV,
+                                                                sIV,
+                                                                replayDetection,
+                                                                inCounter,
+                                                                outCounter,
+                                                                inMac, outMac,
+                                                                inCipher,
+                                                                outCipher));
+      }
+  }
+
+  private PRNG getDefaultPRNG()
+  {
+    if (prng == null)
+      prng = PRNG.getInstance();
+    return prng;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/SecurityContext.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,140 @@
+/* SecurityContext.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+/**
+ * A package-private placeholder for an SRP security context.
+ */
+class SecurityContext
+{
+  private String mdName;
+  private byte[] sid;
+  private byte[] K;
+  private byte[] cIV;
+  private byte[] sIV;
+  private boolean replayDetection;
+  private int inCounter;
+  private int outCounter;
+  private IALG inMac;
+  private IALG outMac;
+  private CALG inCipher;
+  private CALG outCipher;
+
+  SecurityContext(final String mdName, final byte[] sid, final byte[] K,
+                  final byte[] cIV, final byte[] sIV,
+                  final boolean replayDetection, final int inCounter,
+                  final int outCounter, final IALG inMac, final IALG outMac,
+                  final CALG inCipher, final CALG outCipher)
+  {
+    super();
+
+    this.mdName = mdName;
+    this.sid = sid;
+    this.K = K;
+    this.cIV = cIV;
+    this.sIV = sIV;
+    this.replayDetection = replayDetection;
+    this.inCounter = inCounter;
+    this.outCounter = outCounter;
+    this.inMac = inMac;
+    this.outMac = outMac;
+    this.inCipher = inCipher;
+    this.outCipher = outCipher;
+  }
+
+  String getMdName()
+  {
+    return mdName;
+  }
+
+  byte[] getSID()
+  {
+    return sid;
+  }
+
+  byte[] getK()
+  {
+    return K;
+  }
+
+  byte[] getClientIV()
+  {
+    return cIV;
+  }
+
+  byte[] getServerIV()
+  {
+    return sIV;
+  }
+
+  boolean hasReplayDetection()
+  {
+    return replayDetection;
+  }
+
+  int getInCounter()
+  {
+    return inCounter;
+  }
+
+  int getOutCounter()
+  {
+    return outCounter;
+  }
+
+  IALG getInMac()
+  {
+    return inMac;
+  }
+
+  IALG getOutMac()
+  {
+    return outMac;
+  }
+
+  CALG getInCipher()
+  {
+    return inCipher;
+  }
+
+  CALG getOutCipher()
+  {
+    return outCipher;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/ServerStore.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,175 @@
+/* ServerStore.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import java.util.HashMap;
+
+/**
+ * The server-side implementation of the SRP security context store.
+ */
+public class ServerStore
+{
+  /** The underlying singleton. */
+  private static ServerStore singleton = null;
+  /** The map of sid --> Security Context record. */
+  private static final HashMap sid2ssc = new HashMap();
+  /** The map of sid --> Session timing record. */
+  private static final HashMap sid2ttl = new HashMap();
+  /** A synchronisation lock. */
+  private static final Object lock = new Object();
+  /** A counter to generate legible SIDs. */
+  private static int counter = 0;
+
+  /** Private constructor to enforce Singleton pattern. */
+  private ServerStore()
+  {
+    super();
+
+    // TODO: add a cleaning timer thread
+  }
+
+  /**
+   * Returns the classloader Singleton.
+   * 
+   * @return the classloader Singleton instance.
+   */
+  static synchronized final ServerStore instance()
+  {
+    if (singleton == null)
+      singleton = new ServerStore();
+    return singleton;
+  }
+
+  /**
+   * Returns a legible new session identifier.
+   * 
+   * @return a new session identifier.
+   */
+  static synchronized final byte[] getNewSessionID()
+  {
+    final String sid = String.valueOf(++counter);
+    return new StringBuffer("SID-")
+        .append("0000000000".substring(0, 10 - sid.length())).append(sid)
+        .toString().getBytes();
+  }
+
+  /**
+   * Returns a boolean flag indicating if the designated session is still alive
+   * or not.
+   * 
+   * @param sid the identifier of the session to check.
+   * @return <code>true</code> if the designated session is still alive.
+   *         <code>false</code> otherwise.
+   */
+  boolean isAlive(final byte[] sid)
+  {
+    boolean result = false;
+    if (sid != null && sid.length != 0)
+      {
+        synchronized (lock)
+          {
+            final String key = new String(sid);
+            final StoreEntry ctx = (StoreEntry) sid2ttl.get(key);
+            if (ctx != null)
+              {
+                result = ctx.isAlive();
+                if (! result) // invalidate it en-passant
+                  {
+                    sid2ssc.remove(key);
+                    sid2ttl.remove(key);
+                  }
+              }
+          }
+      }
+    return result;
+  }
+
+  /**
+   * Records a mapping between a session identifier and the Security Context of
+   * the designated SRP server mechanism instance.
+   * 
+   * @param ttl the session's Time-To-Live indicator (in seconds).
+   * @param ctx the server's security context.
+   */
+  void cacheSession(final int ttl, final SecurityContext ctx)
+  {
+    synchronized (lock)
+      {
+        final String key = new String(ctx.getSID());
+        sid2ssc.put(key, ctx);
+        sid2ttl.put(key, new StoreEntry(ttl));
+      }
+  }
+
+  /**
+   * Updates the mapping between the designated session identifier and the
+   * designated server's SASL Security Context. In the process, computes and
+   * return the underlying mechanism server's evidence that shall be returned to
+   * the client in a session re-use exchange.
+   * 
+   * @param sid the identifier of the session to restore.
+   * @return an SRP server's security context.
+   */
+  SecurityContext restoreSession(final byte[] sid)
+  {
+    final String key = new String(sid);
+    final SecurityContext result;
+    synchronized (lock)
+      {
+        result = (SecurityContext) sid2ssc.remove(key);
+        sid2ttl.remove(key);
+      }
+    return result;
+  }
+
+  /**
+   * Removes all information related to the designated session ID.
+   * 
+   * @param sid the identifier of the seesion to invalidate.
+   */
+  void invalidateSession(final byte[] sid)
+  {
+    final String key = new String(sid);
+    synchronized (lock)
+      {
+        sid2ssc.remove(key);
+        sid2ttl.remove(key);
+      }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/crypto/sasl/srp/StoreEntry.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,75 @@
+/* StoreEntry.java -- 
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+/**
+ * A simple timing-related object for use by SRP re-use code.
+ */
+class StoreEntry
+{
+  private boolean perenial;
+  private long timeToDie;
+
+  StoreEntry(int ttl)
+  {
+    super();
+
+    if (ttl == 0)
+      {
+        perenial = true;
+        timeToDie = 0L;
+      }
+    else
+      {
+        perenial = false;
+        timeToDie = System.currentTimeMillis() + (ttl & 0xFFFFFFFFL) * 1000L;
+      }
+  }
+
+  /**
+   * Returns <code>true</code> if the Time-To_live period has not elapsed.
+   * 
+   * @return <code>true</code> if the Time-To-Live period (in seconds) has not
+   *         elapsed yet; <code>false</code> otherwise.
+   */
+  boolean isAlive()
+  {
+    return (perenial ? true : (System.currentTimeMillis() < timeToDie));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/security/auth/Password.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,285 @@
+/* Password.java -- opaque wrapper around a password.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth;
+
+import gnu.java.security.util.ExpirableObject;
+
+import javax.security.auth.DestroyFailedException;
+
+/**
+ * Immutible, though destroyable, password class.
+ *
+ * <p>Extends {@link ExpirableObject}, implementing {@link doDestroy()}
+ * in which encapsulated {@link char[]}, and {@link byte[]} password fields
+ * are cleared (elements set to zero) in order to thwart memory heap
+ * snooping.
+ */
+public final class Password extends ExpirableObject
+{
+
+  // Constants and variables
+  // -------------------------------------------------------------------------
+
+  /**
+   * Password stored in {@link char[]} format.
+   */
+  private final char[] password;
+
+  /**
+   * Password stored in {@link byte[]} format.
+   */
+  private final byte[] bPassword;
+
+  /**
+   * Indicates whether this Password object's {@link doDestroy()} method has
+   * been called.  See also, {@link ExpirableObject#Destroy()}.
+   */
+  private boolean mIsDestroyed = false;
+
+  // Constructor(s)
+  // -------------------------------------------------------------------------
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}.
+   *
+   * @param password The character array password to associate with this
+   * Password object.
+   */
+  public Password (char[] password)
+  {
+    this (password, 0, password.length, DEFAULT_TIMEOUT);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * timeout denoted by constructor parameter, <i>delay</i>.
+   *
+   * @param password The character array password to associate with this
+   * Password object.
+   * @param delay The number of miliseconds before this Password object
+   * will be automatically destroyed.
+   */
+  public Password (char[] password, long delay)
+  {
+    this (password, 0, password.length, delay);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}.
+   *
+   * @param password The character array password to associate with this
+   * Password object.
+   * @param offset The <i>password</i> character array parameter element
+   * marking the beginning of the contained password string.
+   * @param length The number of characters, beginning at <i>offset</i>,
+   * to be copied into this object's {@link password} field.
+   */
+  public Password (char[] password, int offset, int length)
+  {
+    this (password, offset, length, DEFAULT_TIMEOUT);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * timeout denoted by constructor parameter, <i>delay</i>.
+   *
+   * @param password The character array password to associate with this
+   * Password object.
+   * @param offset The <i>password</i> character array parameter element
+   * marking the beginning of the contained password string.
+   * @param length The number of characters, beginning at <i>offset</i>,
+   * to be copied into this object's {@link password} field.
+   * @param delay The number of miliseconds before this Password object
+   * will be automatically destroyed.
+   */
+  public Password (char[] password, int offset, int length, long delay)
+  {
+    super (delay);
+
+    if (offset < 0 || length < 0 || offset + length > password.length)
+      throw new ArrayIndexOutOfBoundsException ("off=" + offset + " length=" +
+                                                length + " array.length=" +
+                                                password.length);
+
+    int i, j;
+    this.password = new char[length];
+    bPassword = new byte[length];
+
+    for(i = 0, j = offset; i < length; i++, j++)
+      {
+        this.password[i] = (char) password[j];
+        // XXX this should use character encodings, other than ASCII.
+        bPassword[i] = (byte) (password[j] & 0x7F);
+      }
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}.
+   *
+   * @param password The byte array password to associate with this
+   * Password object.
+   */
+  public Password (byte[] password)
+  {
+    this (password, 0, password.length, DEFAULT_TIMEOUT);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * timeout denoted by constructor parameter, <i>delay</i>.
+   *
+   * @param password The byte array password to associate with this
+   * Password object.
+   * @param delay The number of miliseconds before this Password object
+   * will be automatically destroyed.
+   */
+  public Password (byte[] password, long delay)
+  {
+    this (password, 0, password.length, delay);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}.
+   *
+   * @param password The byte array password to associate with this
+   * Password object.
+   * @param offset The <i>password</i> byte array parameter element
+   * marking the beginning of the contained password string.
+   * @param length The number of bytes, beginning at <i>offset</i>,
+   * to be copied into this object's {@link password} field.
+   */
+  public Password (byte[] password, int offset, int length)
+  {
+    this (password, offset, length, DEFAULT_TIMEOUT);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * timeout denoted by constructor parameter, <i>delay</i>.
+   *
+   * @param password The byte array password to associate with this
+   * Password object.
+   * @param offset The <i>password</i> byte array parameter element
+   * marking the beginning of the contained password string.
+   * @param length The number of bytes, beginning at <i>offset</i>,
+   * to be copied into this object's {@link bPassword} field.
+   * @param delay The number of miliseconds before this Password object
+   * will be automatically destroyed.
+   */
+  public Password (byte[] password, int offset, int length, long delay)
+  {
+    super (delay);
+
+    if (offset < 0 || length < 0 || offset + length > password.length)
+      throw new ArrayIndexOutOfBoundsException ("off=" + offset + " length=" +
+                                                length + " array.length=" +
+                                                password.length);
+
+    int i, j;
+    this.password = new char[length];
+    bPassword = new byte[length];
+
+    for (i = 0, j = offset; i < length; i++, j++)
+      {
+        this.password[i] = (char) password[j];
+        bPassword[i] = password[j];
+      }
+  }
+
+  // Instance methods
+  // -------------------------------------------------------------------------
+
+  /**
+   * Returns a reference to the {@link char[]} password storage field,
+   * {@link password}.
+   */
+  public synchronized char[] getPassword()
+  {
+    if (mIsDestroyed)
+      throw new IllegalStateException ("Attempted destroyed password access.");
+
+    return password;
+  }
+
+  /**
+   * Returns a reference to the {@link byte[]} password storage field,
+   * {@link bPassword}.
+   */
+  public synchronized byte[] getBytes()
+  {
+    if (mIsDestroyed)
+      throw new IllegalStateException ("Attempted destroyed password access.");
+
+    return bPassword;
+  }
+
+  /**
+   * Sets password field char[], and byte[] array elements to zero.
+   * This method implements base class {@link ExpirableObject} abstract
+   * method, {@link ExpirableObject#doDestroy()}.  See also,
+   * {@link ExpirableObject#destroy()}.
+   */
+  protected synchronized void doDestroy()
+  {
+    if (isDestroyed())
+      return;
+    else
+      {
+        for (int i = 0; i < password.length; i++)
+          password[i] = 0;
+        for (int i = 0; i < bPassword.length; i++)
+          bPassword[i] = 0;
+        mIsDestroyed = true;
+      }
+  }
+
+  /**
+   * Returns true, or false relative to whether, or not this object's
+   * {@link doDestroy()} method has been called.  See also,
+   * {@ExpirableObject#destroy()}.
+   */
+  public synchronized boolean isDestroyed()
+  {
+    return (mIsDestroyed);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/security/auth/callback/AbstractCallbackHandler.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,295 @@
+/* AbstractCallbackHandler.java -- 
+   Copyright (C) 2005, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import gnu.java.security.Engine;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public abstract class AbstractCallbackHandler implements CallbackHandler
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private static final String SERVICE = "CallbackHandler";
+
+  protected final ResourceBundle messages;
+
+  private final String name;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  protected AbstractCallbackHandler (final String name)
+  {
+    super();
+    messages = PropertyResourceBundle.getBundle("gnu/javax/security/auth/callback/MessagesBundle");
+    this.name = name;
+  }
+
+  /**
+   * Create an instance of <code>CallbackHandler</code> of the designated
+   * <code>type</code> from the first Security Provider which offers it.
+   * 
+   * @param type the type of callback handler to create.
+   * @return a newly created instance of <code>ClassbackHandler</code>.
+   * @throws NoSuchAlgorithmException if no security provider is found to offer
+   *           an implementation of <code>CallbackHandler</code> of the
+   *           designated <code>type</code>.
+   */
+  public static CallbackHandler getInstance(String type)
+      throws NoSuchAlgorithmException
+  {
+    Provider[] p = Security.getProviders();
+    NoSuchAlgorithmException lastException = null;
+    for (int i = 0; i < p.length; i++)
+      try
+        {
+          return getInstance(type, p[i]);
+        }
+      catch (NoSuchAlgorithmException x)
+        {
+          lastException = x;
+        }
+    if (lastException != null)
+      throw lastException;
+    throw new NoSuchAlgorithmException(type);
+  }
+
+  /**
+   * Create an instance of <code>CallbackHandler</code> of the designated
+   * <code>type</code> from the named security <code>provider</code>.
+   * 
+   * @param type the type of callback handler to create.
+   * @param provider a named security provider to use.
+   * @return a newly created instance of <code>ClassbackHandler</code>.
+   * @throws NoSuchAlgorithmException if no security provider is found to offer
+   *           an implementation of <code>CallbackHandler</code> of the
+   *           designated <code>type</code>.
+   * @throws IllegalArgumentException if either <code>type</code> or
+   *           <code>provider</code> is <code>null</code>, or if
+   *           <code>type</code> is an empty string.
+   */
+  public static CallbackHandler getInstance(String type, String provider)
+      throws NoSuchAlgorithmException, NoSuchProviderException
+  {
+    if (provider == null)
+      throw new IllegalArgumentException("provider MUST NOT be null");
+    Provider p = Security.getProvider(provider);
+    if (p == null)
+      throw new NoSuchProviderException(provider);
+    return getInstance(type, p);
+  }
+
+  /**
+   * Create an instance of <code>CallbackHandler</code> of the designated
+   * <code>type</code> from the designated security <code>provider</code>.
+   * 
+   * @param type the type of callback handler to create.
+   * @param provider a security provider to use.
+   * @return a newly created instance of <code>ClassbackHandler</code>.
+   * @throws NoSuchAlgorithmException if no security provider is found to offer
+   *           an implementation of <code>CallbackHandler</code> of the
+   *           designated <code>type</code>.
+   * @throws IllegalArgumentException if either <code>type</code> or
+   *           <code>provider</code> is <code>null</code>, or if
+   *           <code>type</code> is an empty string.
+   */
+  public static CallbackHandler getInstance(String type, Provider provider)
+    throws NoSuchAlgorithmException
+  {
+    StringBuilder sb = new StringBuilder("CallbackHandler of type [")
+        .append(type).append("] from provider[")
+        .append(provider).append("] could not be created");
+    Throwable cause;
+    try
+      {
+        return (CallbackHandler) Engine.getInstance(SERVICE, type, provider);
+      }
+    catch (InvocationTargetException x)
+      {
+        cause = x.getCause();
+        if (cause instanceof NoSuchAlgorithmException)
+          throw (NoSuchAlgorithmException) cause;
+        if (cause == null)
+          cause = x;
+      }
+    catch (ClassCastException x)
+      {
+        cause = x;
+      }
+    NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+    x.initCause(cause);
+    throw x;
+  }
+
+  public void handle(Callback[] callbacks)
+    throws IOException, UnsupportedCallbackException
+  {
+    if (callbacks == null)
+      throw new NullPointerException();
+    for (int i = 0; i < callbacks.length; i++)
+      {
+        if (callbacks[i] == null)
+          continue;
+        if (callbacks[i] instanceof ChoiceCallback)
+          handleChoice((ChoiceCallback) callbacks[i]);
+        else if (callbacks[i] instanceof ConfirmationCallback)
+          handleConfirmation((ConfirmationCallback) callbacks[i]);
+        else if (callbacks[i] instanceof LanguageCallback)
+          handleLanguage((LanguageCallback) callbacks[i]);
+        else if (callbacks[i] instanceof NameCallback)
+          handleName((NameCallback) callbacks[i]);
+        else if (callbacks[i] instanceof PasswordCallback)
+          handlePassword((PasswordCallback) callbacks[i]);
+        else if (callbacks[i] instanceof TextInputCallback)
+          handleTextInput((TextInputCallback) callbacks[i]);
+        else if (callbacks[i] instanceof TextOutputCallback)
+          handleTextOutput((TextOutputCallback) callbacks[i]);
+        else
+          handleOther(callbacks[i]);
+      }
+  }
+
+  public final String getName ()
+  {
+    return name;
+  }
+
+  // Abstract methods.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Handles a {@link ChoiceCallback}.
+   *
+   * @param callback The choice callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleChoice(ChoiceCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link ConfirmationCallback}.
+   *
+   * @param callback The confirmation callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleConfirmation(ConfirmationCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link LanguageCallback}.
+   *
+   * @param callback The language callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleLanguage(LanguageCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link NameCallback}.
+   *
+   * @param callback The name callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleName(NameCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link PasswordCallback}.
+   *
+   * @param callback The password callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handlePassword(PasswordCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link TextInputCallback}.
+   *
+   * @param callback The text input callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleTextInput(TextInputCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link TextOutputCallback}.
+   *
+   * @param callback The text output callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleTextOutput(TextOutputCallback callback)
+    throws IOException;
+
+  /**
+   * Handles an unknown callback. The default implementation simply throws
+   * an {@link UnsupportedCallbackException}.
+   *
+   * @param callback The callback to handle.
+   * @throws IOException If an I/O error occurs.
+   * @throws UnsupportedCallbackException If the specified callback is not
+   *   supported.
+   */
+  protected void handleOther(Callback callback)
+    throws IOException, UnsupportedCallbackException
+  {
+    throw new UnsupportedCallbackException(callback);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/security/auth/callback/CertificateCallback.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,64 @@
+/* CertificateCallback.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.security.auth.callback;
+
+import java.security.cert.Certificate;
+
+import javax.security.auth.callback.ConfirmationCallback;
+
+/**
+ * A {@link javax.security.auth.callback.Callback} for confirming whether or
+ * not a certificate may be used. This works similarly to
+ * {@link ConfirmationCallback}, but additionally contains the certificate
+ * being verified. Thus, handlers may present the certificate to the user, when
+ * handling this callback.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateCallback extends ConfirmationCallback
+{
+  static final long serialVersionUID = 8343869651419225634L;
+  public final Certificate certificate;
+  
+  public CertificateCallback(Certificate cert, String prompt)
+  {
+    super(prompt, ERROR, YES_NO_OPTION, NO);
+    this.certificate = cert;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,299 @@
+/* ConsoleCallbackHandler.java -- 
+   Copyright (C) 2005, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+
+/**
+ * An implementation of {@link CallbackHandler} that reads and writes
+ * information to and from <code>System.in</code> and <code>System.out</code>.
+ */
+public class ConsoleCallbackHandler extends AbstractCallbackHandler
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private final PrintStream out;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public ConsoleCallbackHandler()
+  {
+    this (System.out);
+  }
+
+  public ConsoleCallbackHandler (final PrintStream out)
+  {
+    super ("CONSOLE");
+    this.out = out;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  protected void handleChoice(ChoiceCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    out.println(c.getPrompt());
+    out.print('(');
+    String[] choices = c.getChoices();
+    for (int i = 0; i < choices.length; i++)
+      {
+        out.print(choices[i]);
+        if (i != choices.length - 1)
+          out.print(", ");
+      }
+    out.print(") ");
+    if (c.getDefaultChoice() >= 0 && c.getDefaultChoice() < choices.length)
+      {
+        out.print('[');
+        out.print(choices[c.getDefaultChoice()]);
+        out.print("] ");
+      }
+    String reply = in.readLine();
+    if (reply == null || reply.length() == 0)
+      {
+        c.setSelectedIndex(c.getDefaultChoice());
+        return;
+      }
+    if (!c.allowMultipleSelections())
+      {
+        for (int i = 0; i < choices.length; i++)
+          {
+            if (reply.trim().equals(choices[i]))
+              {
+                c.setSelectedIndex(i);
+                return;
+              }
+          }
+        c.setSelectedIndex(c.getDefaultChoice());
+      }
+    else
+      {
+        TreeSet indices = new TreeSet();
+        StringTokenizer tok = new StringTokenizer(reply, ",");
+        String[] replies = new String[tok.countTokens()];
+        int idx = 0;
+        while (tok.hasMoreTokens())
+          {
+            replies[idx++] = tok.nextToken().trim();
+          }
+        for (int i = 0; i < choices.length; i++)
+          for (int j = 0; j < replies.length; i++)
+            {
+              if (choices[i].equals(replies[j]))
+                {
+                  indices.add(Integer.valueOf(i));
+                }
+            }
+        if (indices.size() == 0)
+          c.setSelectedIndex(c.getDefaultChoice());
+        else
+          {
+            int[] ii = new int[indices.size()];
+            int i = 0;
+            for (Iterator it = indices.iterator(); it.hasNext(); )
+              ii[i++] = ((Integer) it.next()).intValue();
+            c.setSelectedIndexes(ii);
+          }
+      }
+  }
+
+  protected void handleConfirmation(ConfirmationCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    if (c.getPrompt() != null)
+      out.print(c.getPrompt());
+
+    String[] choices = null;
+    int[] values = null;
+    switch (c.getOptionType())
+      {
+      case ConfirmationCallback.OK_CANCEL_OPTION:
+        out.print(messages.getString("callback.okCancel"));
+        choices = new String[] {
+          messages.getString("callback.ok"),
+          messages.getString("callback.cancel"),
+          messages.getString("callback.shortOk"),
+          messages.getString("callback.shortCancel")
+        };
+        values = new int[] {
+          ConfirmationCallback.OK, ConfirmationCallback.CANCEL,
+          ConfirmationCallback.OK, ConfirmationCallback.CANCEL
+        };
+        break;
+
+      case ConfirmationCallback.YES_NO_CANCEL_OPTION:
+        out.print(messages.getString("callback.yesNoCancel"));
+        choices = new String[] {
+          messages.getString("callback.yes"),
+          messages.getString("callback.no"),
+          messages.getString("callback.cancel"),
+          messages.getString("callback.shortYes"),
+          messages.getString("callback.shortNo"),
+          messages.getString("callback.shortCancel")
+        };
+        values = new int[] {
+          ConfirmationCallback.YES, ConfirmationCallback.NO,
+          ConfirmationCallback.CANCEL, ConfirmationCallback.YES,
+          ConfirmationCallback.NO, ConfirmationCallback.CANCEL
+        };
+        break;
+
+      case ConfirmationCallback.YES_NO_OPTION:
+        out.print(messages.getString("callback.yesNo"));
+        choices = new String[] { messages.getString("callback.yes"),
+                                 messages.getString("callback.no"),
+                                 messages.getString("callback.shortYes"),
+                                 messages.getString("callback.shortNo") };
+        values = new int[] { ConfirmationCallback.YES,
+                             ConfirmationCallback.NO,
+                             ConfirmationCallback.YES,
+                             ConfirmationCallback.NO };
+        int defaultOption = c.getDefaultOption();
+        if (defaultOption > -1 && defaultOption < choices.length)
+          {
+            out.print("[");
+            out.print(choices[defaultOption]);
+            out.print("] ");
+          }
+        break;
+
+      case ConfirmationCallback.UNSPECIFIED_OPTION:
+        choices = c.getOptions();
+        values = new int[choices.length];
+        for (int i = 0; i < values.length; i++)
+          values[i] = i;
+        out.print('(');
+        for (int i = 0; i < choices.length; i++)
+          {
+            out.print(choices[i]);
+            if (i != choices.length - 1)
+              out.print(", ");
+          }
+        out.print(") [");
+        out.print(choices[c.getDefaultOption()]);
+        out.print("] ");
+        break;
+
+      default:
+        throw new IllegalArgumentException();
+      }
+    String reply = in.readLine();
+    if (reply == null)
+      {
+        c.setSelectedIndex(c.getDefaultOption());
+        return;
+      }
+    reply = reply.trim();
+    for (int i = 0; i < choices.length; i++)
+      if (reply.equalsIgnoreCase(choices[i]))
+        {
+          c.setSelectedIndex(values[i]);
+          return;
+        }
+    c.setSelectedIndex(c.getDefaultOption());
+  }
+
+  protected void handleLanguage(LanguageCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    out.print(messages.getString("callback.language"));
+    String reply = null;
+    reply = in.readLine();
+    if (reply == null)
+      {
+        c.setLocale(Locale.getDefault());
+      }
+    else
+      {
+        c.setLocale(new Locale(reply.trim()));
+      }
+  }
+
+  protected void handleName(NameCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    out.print(c.getPrompt());
+    String name = in.readLine();
+    if (name != null)
+      c.setName(name.trim());
+  }
+
+  protected void handlePassword(PasswordCallback c) throws IOException
+  {
+    out.print(c.getPrompt());
+    BufferedReader in =
+      new BufferedReader(new InputStreamReader(System.in));
+    String pass = in.readLine();
+    c.setPassword(pass.toCharArray());
+  }
+
+  protected void handleTextInput(TextInputCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    out.print(c.getPrompt());
+    String text = in.readLine();
+    if (text != null)
+      c.setText(text);
+  }
+
+  protected void handleTextOutput(TextOutputCallback c)
+  {
+    out.print(c.getMessage());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/security/auth/callback/DefaultCallbackHandler.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,109 @@
+/* DefaultCallbackHandler.java -- 
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import java.util.Locale;
+
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+
+/**
+ * This trivial implementation of {@link CallbackHandler} sets its
+ * {@link Callback} arguments to default values, with no user interaction.
+ */
+public class DefaultCallbackHandler extends AbstractCallbackHandler
+{
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public DefaultCallbackHandler()
+  {
+    super("DEFAULT");
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  protected void handleChoice(ChoiceCallback c)
+  {
+    c.setSelectedIndex(c.getDefaultChoice());
+  }
+
+  protected void handleConfirmation(ConfirmationCallback c)
+  {
+    if (c.getOptionType() == ConfirmationCallback.YES_NO_OPTION)
+      c.setSelectedIndex(ConfirmationCallback.NO);
+    else if (c.getOptionType() == ConfirmationCallback.YES_NO_CANCEL_OPTION)
+      c.setSelectedIndex(ConfirmationCallback.NO);
+    else if (c.getOptionType() == ConfirmationCallback.OK_CANCEL_OPTION)
+      c.setSelectedIndex(ConfirmationCallback.OK);
+    else
+      c.setSelectedIndex(c.getDefaultOption());
+  }
+
+  protected void handleLanguage(LanguageCallback c)
+  {
+    c.setLocale(Locale.getDefault());
+  }
+
+  protected void handleName(NameCallback c)
+  {
+    c.setName(System.getProperty("user.name"));
+  }
+
+  protected void handlePassword(PasswordCallback c)
+  {
+    c.setPassword(new char[0]);
+  }
+
+  protected void handleTextInput(TextInputCallback c)
+  {
+    c.setText("");
+  }
+
+  protected void handleTextOutput(TextOutputCallback c)
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/security/auth/callback/GnuCallbacks.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,65 @@
+/* GnuCallbacks.java -- Provider for callback implementations.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+
+public final class GnuCallbacks extends Provider
+{
+  public GnuCallbacks()
+  {
+    super("GNU-CALLBACKS", 2.1, "Implementations of various callback handlers.");
+
+    AccessController.doPrivileged(new PrivilegedAction()
+      {
+        public Object run()
+        {
+          put("CallbackHandler.Default", DefaultCallbackHandler.class.getName());
+          put("CallbackHandler.Console", ConsoleCallbackHandler.class.getName());
+	  /* ICEDTEA  Removed callbacks
+          put("CallbackHandler.AWT", AWTCallbackHandler.class.getName());
+          put("CallbackHandler.Swing", SwingCallbackHandler.class.getName());
+	  */
+          return null;
+        }
+      });
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/security/auth/login/ConfigFileParser.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,346 @@
+/* ConfigFileParser.java -- JAAS Login Configuration default syntax parser
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.security.auth.login;
+
+import gnu.java.security.Configuration;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+/**
+ * A parser that knows how to interpret JAAS Login Module Configuration files
+ * written in the <i>default syntax</i> which is interpreted as adhering to
+ * the following grammar:
+ *
+ * <pre>
+ *   CONFIG              ::= APP_OR_OTHER_ENTRY+
+ *   APP_OR_OTHER_ENTRY  ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK
+ *   APP_NAME_OR_OTHER   ::= APP_NAME
+ *                         | 'other'
+ *   JAAS_CONFIG_BLOCK   ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';'
+ *   LOGIN_MODULE_ENTRY  ::= MODULE_CLASS FLAG MODULE_OPTION* ';'
+ *   FLAG                ::= 'required'
+ *                         | 'requisite'
+ *                         | 'sufficient'
+ *                         | 'optional'
+ *   MODULE_OPTION       ::= PARAM_NAME '=' PARAM_VALUE
+ *
+ *   APP_NAME     ::= JAVA_IDENTIFIER
+ *   MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)*
+ *   PARAM_NAME   ::= STRING
+ *   PARAM_VALUE  ::= '"' STRING '"' | ''' STRING ''' | STRING
+ * </pre>
+ *
+ * <p>This parser handles UTF-8 entities when used as APP_NAME and PARAM_VALUE.
+ * It also checks for the use of Java identifiers used in MODULE_CLASS, thus
+ * minimizing the risks of having {@link java.lang.ClassCastException}s thrown
+ * at runtime due to syntactically invalid names.</p>
+ *
+ * <p>In the above context, a JAVA_IDENTIFIER is a sequence of tokens,
+ * separated by the character '.'. Each of these tokens obeys the following:</p>
+ * 
+ * <ol>
+ *   <li>its first character yields <code>true</code> when used as an input to
+ *   the {@link java.lang.Character#isJavaIdentifierStart(char)}, and</li>
+ *   <li>all remaining characters, yield <code>true</code> when used as an
+ *   input to {@link java.lang.Character#isJavaIdentifierPart(char)}.</li>
+ * </ol>
+ */
+public final class ConfigFileParser
+{
+  private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName());
+  private ConfigFileTokenizer cft;
+  private Map map = new HashMap();
+
+  // default 0-arguments constructor
+
+  /**
+   * Returns the parse result as a {@link Map} where the keys are application
+   * names, and the entries are {@link List}s of {@link AppConfigurationEntry}
+   * entries, one for each login module entry, in the order they were
+   * encountered, for that application name in the just parsed configuration
+   * file.
+   */
+  public Map getLoginModulesMap()
+  {
+    return map;
+  }
+
+  /**
+   * Parses the {@link Reader}'s contents assuming it is in the <i>default
+   * syntax</i>.
+   *
+   * @param r the {@link Reader} whose contents are assumed to be a JAAS Login
+   * Configuration Module file written in the <i>default syntax</i>.
+   * @throws IOException if an exception occurs while parsing the input.
+   */
+  public void parse(Reader r) throws IOException
+  {
+    initParser(r);
+
+    while (parseAppOrOtherEntry())
+      {
+        /* do nothing */
+      }
+  }
+
+  private void initParser(Reader r) throws IOException
+  {
+    map.clear();
+
+    cft = new ConfigFileTokenizer(r);
+  }
+
+  /**
+   * @return <code>true</code> if an APP_OR_OTHER_ENTRY was correctly parsed.
+   * Returns <code>false</code> otherwise.
+   * @throws IOException if an exception occurs while parsing the input.
+   */
+  private boolean parseAppOrOtherEntry() throws IOException
+  {
+    int c = cft.nextToken();
+    if (c == ConfigFileTokenizer.TT_EOF)
+      return false;
+
+    if (c != ConfigFileTokenizer.TT_WORD)
+      {
+        cft.pushBack();
+        return false;
+      }
+
+    String appName = cft.sval;
+    if (Configuration.DEBUG)
+      log.fine("APP_NAME_OR_OTHER = " + appName);
+    if (cft.nextToken() != '{')
+      abort("Missing '{' after APP_NAME_OR_OTHER");
+
+    List lmis = new ArrayList();
+    while (parseACE(lmis))
+      {
+        /* do nothing */
+      }
+
+    c = cft.nextToken();
+    if (c != '}')
+      abort("Was expecting '}' but found " + (char) c);
+
+    c = cft.nextToken();
+    if (c != ';')
+      abort("Was expecting ';' but found " + (char) c);
+
+    List listOfACEs = (List) map.get(appName);
+    if (listOfACEs == null)
+      {
+        listOfACEs = new ArrayList();
+        map.put(appName, listOfACEs);
+      }
+    listOfACEs.addAll(lmis);
+    return !appName.equalsIgnoreCase("other");
+  }
+
+  /**
+   * @return <code>true</code> if a LOGIN_MODULE_ENTRY was correctly parsed.
+   * Returns <code>false</code> otherwise. 
+   * @throws IOException if an exception occurs while parsing the input.
+   */
+  private boolean parseACE(List listOfACEs) throws IOException
+  {
+    int c = cft.nextToken();
+    if (c != ConfigFileTokenizer.TT_WORD)
+      {
+        cft.pushBack();
+        return false;
+      }
+
+    String clazz = validateClassName(cft.sval);
+    if (Configuration.DEBUG)
+      log.fine("MODULE_CLASS = " + clazz);
+
+    if (cft.nextToken() != ConfigFileTokenizer.TT_WORD)
+      abort("Was expecting FLAG but found none");
+
+    String flag = cft.sval;
+    if (Configuration.DEBUG)
+      log.fine("DEBUG: FLAG = " + flag);
+    AppConfigurationEntry.LoginModuleControlFlag f = null;
+    if (flag.equalsIgnoreCase("required"))
+      f = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
+    else if (flag.equalsIgnoreCase("requisite"))
+      f = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
+    else if (flag.equalsIgnoreCase("sufficient"))
+      f = AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
+    else if (flag.equalsIgnoreCase("optional"))
+      f = AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
+    else
+      abort("Unknown Flag: " + flag);
+
+    Map options = new HashMap();
+    String paramName, paramValue;
+    c = cft.nextToken();
+    while (c != ';')
+      {
+        if (c != ConfigFileTokenizer.TT_WORD)
+          abort("Was expecting PARAM_NAME but got '" + ((char) c) + "'");
+
+        paramName = cft.sval;
+        if (Configuration.DEBUG)
+          log.fine("PARAM_NAME = " + paramName);
+        if (cft.nextToken() != '=')
+          abort("Missing '=' after PARAM_NAME");
+
+        c = cft.nextToken();
+        if (c != '"' && c != '\'')
+          {
+          if (Configuration.DEBUG)
+            log.fine("Was expecting a quoted string but got no quote character."
+                     + " Assume unquoted string");
+          }
+        paramValue = expandParamValue(cft.sval);
+        if (Configuration.DEBUG)
+          log.fine("PARAM_VALUE = " + paramValue);
+        options.put(paramName, paramValue);
+
+        c = cft.nextToken();
+      }
+    AppConfigurationEntry ace = new AppConfigurationEntry(clazz, f, options);
+    if (Configuration.DEBUG)
+      log.fine("LOGIN_MODULE_ENTRY = " + ace);
+    listOfACEs.add(ace);
+    return true;
+  }
+
+  private void abort(String m) throws IOException
+  {
+    if (Configuration.DEBUG)
+      {
+        log.fine(m);
+        log.fine("Map (so far) = " + String.valueOf(map));
+      }
+    throw new IOException(m);
+  }
+
+  private String validateClassName(String cn) throws IOException
+  {
+    if (cn.startsWith(".") || cn.endsWith("."))
+      abort("MODULE_CLASS MUST NOT start or end with a '.'");
+
+    String[] tokens = cn.split("\\.");
+    for (int i = 0; i < tokens.length; i++)
+      {
+        String t = tokens[i];
+        if (! Character.isJavaIdentifierStart(t.charAt(0)))
+          abort("Class name [" + cn
+                + "] contains an invalid sub-package identifier: " + t);
+
+        // we dont check the rest of the characters for isJavaIdentifierPart()
+        // because that's what the tokenizer does.
+      }
+    
+    return cn;
+  }
+
+  /**
+   * The documentation of the {@link javax.security.auth.login.Configuration}
+   * states that: <i>"...If a String in the form, ${system.property}, occurs in
+   * the value, it will be expanded to the value of the system property."</i>.
+   * This method ensures this is the case. If such a string can not be expanded
+   * then it is left AS IS, assuming the LoginModule knows what to do with it.
+   *
+   * <p><b>IMPORTANT</b>: This implementation DOES NOT handle embedded ${}
+   * constructs.
+   *
+   * @param s the raw parameter value, incl. eventually strings of the form
+   * <code>${system.property}</code>.
+   * @return the input string with every occurence of
+   * <code>${system.property}</code> replaced with the value of the
+   * corresponding System property at the time of this method invocation. If
+   * the string is not a known System property name, then the complete sequence
+   * (incl. the ${} characters are passed AS IS.
+   */
+  private String expandParamValue(String s)
+  {
+    String result = s;
+    try
+      {
+        int searchNdx = 0;
+        while (searchNdx < result.length())
+          {
+            int i = s.indexOf("${", searchNdx);
+            if (i == -1)
+              break;
+
+            int j = s.indexOf("}", i + 2);
+            if (j == -1)
+              {
+                if (Configuration.DEBUG)
+                  log.fine("Found a ${ prefix with no } suffix. Ignore");
+                break;
+              }
+
+            String sysPropName = s.substring(i + 2, j);
+            if (Configuration.DEBUG)
+              log.fine("Found a reference to System property " + sysPropName);
+            String sysPropValue = System.getProperty(sysPropName);
+            if (Configuration.DEBUG)
+              log.fine("Resolved " + sysPropName + " to '" + sysPropValue + "'");
+            if (sysPropValue != null)
+              {
+                result = s.substring(0, i) + sysPropValue + s.substring(j + 1);
+                searchNdx = i + sysPropValue.length();
+              }
+            else
+              searchNdx = j + 1;
+          }
+      }
+    catch (Exception x)
+      {
+        if (Configuration.DEBUG)
+          log.fine("Exception (ignored) while expanding " + s + ": " + x);
+      }
+
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/security/auth/login/ConfigFileTokenizer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,244 @@
+/* ConfigFileTokenizer.java -- JAAS Login Configuration default syntax tokenizer
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.security.auth.login;
+
+import gnu.java.security.Configuration;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.logging.Logger;
+
+/**
+ * A UTF-8 friendly, JAAS Login Module Configuration file tokenizer written in
+ * the deault syntax. This class emulates, to a certain extent, the behavior of
+ * a {@link java.io.StreamTokenizer} instance <code>st</code>, when set as
+ * follows:
+ * 
+ *  <pre>
+ *  st.resetSyntax();
+ *  st.lowerCaseMode(false);
+ *  st.slashSlashComments(true);
+ *  st.slashStarComments(true);
+ *  st.eolIsSignificant(false);
+ *  st.wordChars('_', '_');
+ *  st.wordChars('$', '$');
+ *  st.wordChars('A', 'Z');
+ *  st.wordChars('a', 'z');
+ *  st.wordChars('0', '9');
+ *  st.wordChars('.', '.');
+ *  st.whitespaceChars(' ', ' ');
+ *  st.whitespaceChars('\t', '\t');
+ *  st.whitespaceChars('\f', '\f');
+ *  st.whitespaceChars('\r', '\r');
+ *  st.whitespaceChars('\n', '\n');
+ *  st.quoteChar('"');
+ *  st.quoteChar('\'');
+ *  </pre>
+ *
+ * <p>The most important (negative) difference with a
+ * {@link java.io.StreamTokenizer} is that this tokenizer does not properly
+ * handle C++ and Java // style comments in the middle of the line. It only
+ * ignores them if/when found at the start of the line.</p>  
+ */
+public class ConfigFileTokenizer
+{
+  private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName());
+  /** A constant indicating that the end of the stream has been read. */
+  public static final int TT_EOF = -1;
+  /** A constant indicating that a word token has been read. */
+  public static final int TT_WORD = -3;
+  /** A constant indicating that no tokens have been read yet. */
+  private static final int TT_NONE = -4;
+
+  public String sval;
+  public int ttype;
+
+  private BufferedReader br;
+  boolean initialised;
+  private StringBuffer sb;
+  private int sbNdx;
+
+  // Constructor(s)
+  // --------------------------------------------------------------------------
+
+  /** Trivial constructor. */
+  ConfigFileTokenizer(Reader r)
+  {
+    super();
+
+    br = r instanceof BufferedReader ? (BufferedReader) r : new BufferedReader(r);
+    initialised = false;
+  }
+
+  // Class methods
+  // --------------------------------------------------------------------------
+
+  // Instance methods
+  // --------------------------------------------------------------------------
+
+  public int nextToken() throws IOException
+  {
+    if (!initialised)
+      init();
+
+    if (sbNdx >= sb.length())
+      return TT_EOF;
+
+    skipWhitespace();
+
+    if (sbNdx >= sb.length())
+      return TT_EOF;
+
+    int endNdx;
+    if (Character.isJavaIdentifierPart(sb.charAt(sbNdx)))
+      {
+        endNdx = sbNdx + 1;
+        while (Character.isJavaIdentifierPart(sb.charAt(endNdx))
+            || sb.charAt(endNdx) == '.')
+          endNdx++;
+
+        ttype = TT_WORD;
+        sval = sb.substring(sbNdx, endNdx);
+        sbNdx = endNdx;
+        return ttype;
+      }
+
+    int c = sb.charAt(sbNdx);
+    if (c == '{' || c == '}' || c == ';' || c == '=')
+      {
+        ttype = c;
+        sbNdx++;
+        return ttype;
+      }
+
+    if (c == '"' || c == '\'')
+      {
+        ttype = c;
+        String quote = sb.substring(sbNdx, sbNdx + 1);
+        int i = sbNdx + 1;
+        while (true)
+          {
+            // find a candidate
+            endNdx = sb.indexOf(quote, i);
+            if (endNdx == -1)
+              abort("Missing closing quote: " + quote);
+
+            // found one; is it escaped?
+            if (sb.charAt(endNdx - 1) != '\\')
+              break;
+
+            i++;
+            continue;
+          }
+
+        endNdx++;
+        sval = sb.substring(sbNdx, endNdx);
+        sbNdx = endNdx;
+        return ttype;
+      }
+
+    abort("Unknown character: " + sb.charAt(sbNdx));
+    return Integer.MIN_VALUE;
+  }
+
+  public void pushBack()
+  {
+    sbNdx -= ttype != TT_WORD ? 1 : sval.length();
+  }
+
+  private void init() throws IOException
+  {
+    sb = new StringBuffer();
+    String line;
+    while ((line = br.readLine()) != null)
+      {
+        line = line.trim();
+        if (line.length() == 0)
+          continue;
+
+        if (line.startsWith("#") || line.startsWith("//"))
+          continue;
+
+        sb.append(line).append(" ");
+      }
+
+    sbNdx = 0;
+    sval = null;
+    ttype = TT_NONE;
+
+    initialised = true;
+  }
+
+  private void skipWhitespace() throws IOException
+  {
+    int endNdx;
+    while (sbNdx < sb.length())
+      if (Character.isWhitespace(sb.charAt(sbNdx)))
+        {
+          sbNdx++;
+          while (sbNdx < sb.length() && Character.isWhitespace(sb.charAt(sbNdx)))
+            sbNdx++;
+
+          continue;
+        }
+      else if (sb.charAt(sbNdx) == '/' && sb.charAt(sbNdx + 1) == '*')
+        {
+          endNdx = sb.indexOf("*/", sbNdx + 2);
+          if (endNdx == -1)
+            abort("Missing closing */ sequence");
+
+          sbNdx = endNdx + 2;
+          continue;
+        }
+      else
+        break;
+  }
+
+  private void abort(String m) throws IOException
+  {
+    if (Configuration.DEBUG)
+      {
+        log.fine(m);
+        log.fine("sb = " + sb);
+        log.fine("sbNdx = " + sbNdx);
+      }
+    throw new IOException(m);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jce/gnu/javax/security/auth/login/GnuConfiguration.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,466 @@
+/* GnuConfiguration.java -- GNU Classpath implementation of JAAS Configuration
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.security.auth.login;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.Security;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.security.auth.AuthPermission;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+/**
+ * An implementation of the {@link Configuration} class which interprets JAAS
+ * Login Configuration files written in the <i>default</i> syntax described in
+ * the publicly available documentation of that class. A more formal definition
+ * of this syntax is as follows:
+ * 
+ * <pre>
+ *   CONFIG              ::= APP_OR_OTHER_ENTRY+
+ *   APP_OR_OTHER_ENTRY  ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK
+ *   APP_NAME_OR_OTHER   ::= APP_NAME
+ *                         | 'other'
+ *   JAAS_CONFIG_BLOCK   ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';'
+ *   LOGIN_MODULE_ENTRY  ::= MODULE_CLASS FLAG MODULE_OPTION* ';'
+ *   FLAG                ::= 'required'
+ *                         | 'requisite'
+ *                         | 'sufficient'
+ *                         | 'optional'
+ *   MODULE_OPTION       ::= PARAM_NAME '=' PARAM_VALUE
+ *
+ *   APP_NAME     ::= JAVA_IDENTIFIER
+ *   MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)*
+ *   PARAM_NAME   ::= STRING
+ *   PARAM_VALUE  ::= '"' STRING '"' | ''' STRING ''' | STRING
+ * </pre>
+ * 
+ * <p>This implementation will specifically attempt to process one or more
+ * Login Configuration files in the following locations, and when found parse
+ * them and merge their contents. The locations, and the order in which they are
+ * investigated, follows:</p>
+ * 
+ * <ol>
+ *   <li>If the following Security properties:
+ *   <i>java.security.auth.login.config.url.<b>N</b></i>, where <i><b>N</b></i>
+ *   is a digit, from <code>1</code> to an arbitrary number, are defined, then
+ *   the value of each of those properties will be considered as a JAAS Login
+ *   Configuration file written in the default syntax. This implementation will
+ *   attempt parsing all such files.
+ *
+ *   <p>It is worth noting the following:
+ *     <ul>
+ *       <li>The GNU Classpath security file, named <i>classpath.security</i>,
+ *       where all Security properties are encoded, is usually located in
+ *       <i>/usr/local/classpath/lib/security</i> folder.</li>
+ *       
+ *       <li>The numbers used in the properties
+ *       <i>java.security.auth.login.config.url.<b>N</b></i> MUST be sequential,
+ *       with no breaks in-between.</li>
+ *     </ul>
+ *   </p>
+ *
+ *   <p>If at least one of the designated Configuration files was found, and
+ *   was parsed correctly, then no other location will be inspected.</p></li>
+ *
+ *   <li>If the System property named <i>java.security.auth.login.config</i>
+ *   is not null or empty, its contents are then interpreted as a URL to a
+ *   JAAS Login Configuration file written in the default syntax.
+ *
+ *   <p>If this System property is defined, and the file it refers to was
+ *   parsed correctly, then no other location will be inspected.</p></li>
+ *
+ *   <li>If a file named <i>.java.login.config</i> or <i>java.login.config</i>
+ *   (in that order) is found in the location referenced by the value of the
+ *   System property <i>user.home</i>, then that file is parsed as a JAAS Login
+ *   Configuration written in the default syntax.</li>
+ *   
+ *   <li>If none of the above resulted in a correctly parsed JAAS Login
+ *   Configuration file, then this implementation will install a <i>Null
+ *   Configuration</i> which basically does not recognize any Application.</li>
+ * </ol>
+ */
+public final class GnuConfiguration extends Configuration
+{
+  private static final Logger log = Logger.getLogger(GnuConfiguration.class.getName());
+  /**
+   * The internal map of login modules keyed by application name. Each entry in
+   * this map is a {@link List} of {@link AppConfigurationEntry}s for that
+   * application name.
+   */
+  private Map loginModulesMap;
+  /** Our reference to our default syntax parser. */
+  private ConfigFileParser cp;
+
+  // Constructor(s)
+  // --------------------------------------------------------------------------
+
+  /** Trivial 0-arguments Constructor. */
+  public GnuConfiguration()
+  {
+    super();
+
+    loginModulesMap = new HashMap();
+    cp = new ConfigFileParser();
+    init();
+  }
+
+  // Class methods
+  // --------------------------------------------------------------------------
+
+  // Instance methods
+  // --------------------------------------------------------------------------
+
+  // Configuration abstract methods implementation ----------------------------
+
+  /* (non-Javadoc)
+   * @see javax.security.auth.login.Configuration#getAppConfigurationEntry(java.lang.String)
+   */
+  public AppConfigurationEntry[] getAppConfigurationEntry(String appName)
+  {
+    if (appName == null)
+      return null;
+
+    appName = appName.trim();
+    if (appName.length() == 0)
+      return null;
+
+    List loginModules = (List) loginModulesMap.get(appName);
+    if (loginModules == null || loginModules.size() == 0)
+      return null;
+
+    if (gnu.java.security.Configuration.DEBUG)
+      log.fine(appName + " -> " + loginModules.size() + " entry(ies)");
+    return (AppConfigurationEntry[]) loginModules.toArray(new AppConfigurationEntry[0]);
+  }
+
+  /**
+   * Refreshes and reloads this <code>Configuration</code>.
+   * 
+   * <p>This method causes this <code>Configuration</code> object to refresh /
+   * reload its contents following the locations and logic described above in
+   * the class documentation section.</p>
+   * 
+   * @throws SecurityException if the caller does not have an
+   * {@link AuthPermission} for the action named
+   * <code>refreshLoginConfiguration</code>.
+   * @see AuthPermission
+   */
+  public void refresh()
+  {
+    SecurityManager sm = System.getSecurityManager();
+    if (sm != null)
+      sm.checkPermission(new AuthPermission("refreshLoginConfiguration"));
+
+    loginModulesMap.clear();
+    init();
+  }
+
+  // helper methods -----------------------------------------------------------
+
+  /**
+   * Attempts to find and parse JAAS Login Configuration file(s) written in
+   * the default syntax. The locations searched are as descibed in the class
+   * documentation.
+   */
+  private void init()
+  {
+    if (processSecurityProperties())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Using login configuration defined by Security property(ies)");
+      }
+    else if (processSystemProperty())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Using login configuration defined by System property");
+      }
+    else if (processUserHome())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Using login configuration defined in ${user.home}");
+      }
+    else
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("No login configuration file found");
+      }
+  }
+
+  /**
+   * Attempts to locate and parse one or more JAAS Login Configuration files
+   * defined as the values of the Security properties
+   * <i>java.security.auth.login.config.url.N</i>.
+   * 
+   * @return <code>true</code> if it succeeds, and <code>false</code>
+   *         otherwsie.
+   */
+  private boolean processSecurityProperties()
+  {
+    boolean result = false;
+    int counter = 0;
+    String s;
+    while (true)
+      try
+        {
+          counter++;
+          s = Security.getProperty("java.security.auth.login.config.url."
+                                   + counter);
+          if (s == null)
+            break;
+
+          s = s.trim();
+          if (s.length() != 0)
+            {
+              if (gnu.java.security.Configuration.DEBUG)
+                log.fine("java.security.auth.login.config.url." + counter
+                         + " = " + s);
+              parseConfig(getInputStreamFromURL(s));
+              result = true;
+            }
+        }
+      catch (Throwable t)
+        {
+          if (gnu.java.security.Configuration.DEBUG)
+            log.fine("Exception while handling Security property at #"
+                     + counter + ". Continue: " + t);
+        }
+    return result;
+  }
+
+  /**
+   * Attempts to open a designated string as a well-formed {@link URL}. If a
+   * {@link MalformedURLException} occurs, this method then tries to open that
+   * string as a {@link File} (with the same name). If it succeeds, an
+   * {@link InputStream} is constructed and returned.
+   * 
+   * @param s
+   *          the designated name of either a {@link URL} or a {@link File}
+   *          assumed to contain a JAAS Login Configuration in the default
+   *          syntax.
+   * @return an {@link InputStream} around the data source.
+   * @throws IOException
+   *           if an exception occurs during the operation.
+   */
+  private InputStream getInputStreamFromURL(String s) throws IOException
+  {
+    InputStream result = null;
+    try
+      {
+        URL url = new URL(s);
+        result = url.openStream();
+      }
+    catch (MalformedURLException x)
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Failed opening as URL: " + s + ". Will try as File");
+        result = new FileInputStream(s);
+      }
+    return result;
+  }
+
+  /**
+   * Attempts to locate and parse a JAAS Login Configuration file defined as the
+   * value of the System property <i>java.security.auth.login.config</i>.
+   * 
+   * @return <code>true</code> if it succeeds, and <code>false</code>
+   *         otherwsie.
+   */
+  private boolean processSystemProperty()
+  {
+    boolean result = false;
+    try
+      {
+        String s = System.getProperty("java.security.auth.login.config");
+        if (s != null)
+          {
+            s = s.trim();
+            if (s.length() != 0)
+              {
+                if (gnu.java.security.Configuration.DEBUG)
+                  log.fine("java.security.auth.login.config = " + s);
+                parseConfig(getInputStreamFromURL(s));
+                result = true;
+              }
+          }
+      }
+    catch (Throwable t)
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Exception while handling System property. Continue: " + t);
+      }
+    return result;
+  }
+
+  /**
+   * Attempts to locate and parse a JAAS Login Configuration file named either
+   * as <i>.java.login.config</i> or <i>java.login.config</i> (without the
+   * leading dot) in the folder referenced by the System property
+   * <code>user.home</code>.
+   * 
+   * @return <code>true</code> if it succeeds, and <code>false</code>
+   *         otherwsie.
+   */
+  private boolean processUserHome()
+  {
+    boolean result = false;
+    try
+      {
+        File userHome = getUserHome();
+        if (userHome == null)
+          return result;
+
+        File jaasFile;
+        jaasFile = getConfigFromUserHome(userHome, ".java.login.config");
+        if (jaasFile == null)
+          jaasFile = getConfigFromUserHome(userHome, "java.login.config");
+
+        if (jaasFile == null)
+          {
+            if (gnu.java.security.Configuration.DEBUG)
+              log.fine("Login Configuration file, in " + userHome
+                       + ", does not exist or is inaccessible");
+            return result;
+          }
+
+        FileInputStream fis = new FileInputStream(jaasFile);
+        parseConfig(fis);
+        result = true;
+      }
+    catch (Throwable t)
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Exception (ignored) while handling ${user.home}: " + t);
+      }
+    return result;
+  }
+
+  private void parseConfig(InputStream configStream) throws IOException
+  {
+    cp.parse(new InputStreamReader(configStream, "UTF-8"));
+    Map loginModulesMap = cp.getLoginModulesMap();
+    mergeLoginModules(loginModulesMap);
+  }
+
+  private void mergeLoginModules(Map otherLoginModules)
+  {
+    if (otherLoginModules == null || otherLoginModules.size() < 1)
+      return;
+
+    for (Iterator it = otherLoginModules.keySet().iterator(); it.hasNext();)
+      {
+        String appName = (String) it.next();
+        List thatListOfACEs = (List) otherLoginModules.get(appName);
+        if (thatListOfACEs == null || thatListOfACEs.size() < 1)
+          continue;
+
+        List thisListsOfACEs = (List) loginModulesMap.get(appName);
+        if (thisListsOfACEs == null)
+          loginModulesMap.put(appName, thatListOfACEs);
+        else
+          thisListsOfACEs.addAll(thatListOfACEs);
+      }
+  }
+
+  private File getUserHome()
+  {
+    String uh = System.getProperty("user.home");
+    if (uh == null || uh.trim().length() == 0)
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("User home path is not set or is empty");
+        return null;
+      }
+    uh = uh.trim();
+    File result = new File(uh);
+    if (! result.exists())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("User home '" + uh + "' does not exist");
+        return null;
+      }
+    if (! result.isDirectory())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("User home '" + uh + "' is not a directory");
+        return null;
+      }
+    if (! result.canRead())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("User home '" + uh + "' is not readable");
+        return null;
+      }
+    return result;
+  }
+
+  private File getConfigFromUserHome(File userHome, String fileName)
+  {
+    File result = new File(userHome, fileName);
+    if (! result.exists())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("File '" + fileName + "' does not exist in user's home");
+        return null;
+      }
+    if (! result.isFile())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("File '" + fileName + "' in user's home is not a file");
+        return null;
+      }
+    if (! result.canRead())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("File '" + fileName + "' in user's home is not readable");
+        return null;
+      }
+    return result;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/gnu/java/io/Base64InputStream.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,220 @@
+/* Base64InputStream.java -- base-64 input stream.
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.io;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A filter input stream that decodes data encoded in the Base-64
+ * encoding scheme.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class Base64InputStream extends FilterInputStream
+{
+
+  // Constants and fields.
+  // ------------------------------------------------------------------------
+
+  /** Base-64 digits. */
+  private static final String BASE_64 = 
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  /** Base-64 padding character. */
+  private static final char BASE_64_PAD = '=';
+
+  /** Decoding state. */
+  private int state;
+
+  /** Intermediate decoded value. */
+  private int temp;
+
+  /** EOF flag. */
+  private boolean eof;
+
+  private final byte[] one = new byte[1];
+
+  // Constructors.
+  // ------------------------------------------------------------------------
+
+  /**
+   * Create a new Base-64 input stream. The input bytes must be the
+   * ASCII characters A-Z, a-z, 0-9, + and /, with optional whitespace,
+   * and will be decoded into a byte stream.
+   *
+   * @param in The source of Base-64 input.
+   */
+  public Base64InputStream(InputStream in)
+  {
+    super(in);
+    state = 0;
+    temp = 0;
+    eof = false;
+  }
+
+  // Class method.
+  // ------------------------------------------------------------------------
+
+  /**
+   * Decode a single Base-64 string to a byte array.
+   *
+   * @param base64 The Base-64 encoded data.
+   * @return The decoded bytes.
+   * @throws IOException If the given data do not compose a valid Base-64
+   *  sequence.
+   */
+  public static byte[] decode(String base64) throws IOException
+  {
+    Base64InputStream in =
+      new Base64InputStream(new ByteArrayInputStream(base64.getBytes()));
+    ByteArrayOutputStream out =
+      new ByteArrayOutputStream((int) (base64.length() / 0.666));
+    byte[] buf = new byte[1024];
+    int len;
+    while ((len = in.read(buf)) != -1)
+      out.write(buf, 0, len);
+    return out.toByteArray();
+  }
+
+  // Instance methods.
+  // ------------------------------------------------------------------------
+
+  public int available()
+  {
+    return 0;
+  }
+
+  public int read() throws IOException
+  {
+    if (read(one) == 1)
+      return one[0];
+    return -1;
+  }
+
+  public int read(byte[] buf, int off, int len) throws IOException
+  {
+    if (eof)
+      return -1;
+    int count = 0;
+    while (count < len)
+      {
+        int i;
+        while (Character.isWhitespace((char) (i = in.read())))
+          ;
+
+        int pos = BASE_64.indexOf((char) i);
+        if (pos >= 0)
+          {
+            switch (state)
+              {
+                case 0:
+                  temp = pos << 2;
+                  state = 1;
+                  break;
+                case 1:
+                  buf[count++] = (byte) (temp | (pos >>> 4));
+                  temp = (pos & 0x0F) << 4;
+                  state = 2;
+                  break;
+                case 2:
+                  buf[count++] = (byte) (temp | (pos >>> 2));
+                  temp = (pos & 0x03) << 6;
+                  state = 3;
+                  break;
+                case 3:
+                  buf[count++] = (byte) (temp | pos);
+                  state = 0;
+                  break;
+              }
+          }
+        else if (i == BASE_64_PAD)
+          {
+            switch (state)
+              {
+                case 0:
+                case 1:
+                  throw new IOException("malformed Base-64 input");
+                case 2:
+                  while (Character.isWhitespace((char) (i = in.read())))
+                    ;
+                  if (i != BASE_64_PAD)
+                    throw new IOException("malformed Base-64 input");
+                case 3:
+                  while (Character.isWhitespace((char) (i = in.read())))
+                    ;
+              }
+            eof = true;
+            break;
+          }
+        else  // First non-Base-64 character, consider it end-of-stream.
+          {
+            if (state != 0)
+              throw new IOException("malformed Base-64 input");
+            eof = true;
+            break;
+          }
+      }
+      return count;
+  }
+
+  public boolean markSupported()
+  {
+    return false;
+  }
+
+  public void mark(int markLimit) { }
+
+  public void reset() throws IOException
+  {
+    throw new IOException("reset not supported");
+  }
+
+  public long skip(long n) throws IOException
+  {
+    long skipped;
+    for (skipped = 0; skipped < n; skipped++)
+      if (read() == -1)
+        break;
+    return skipped;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/gnu/java/security/provider/Gnu.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,306 @@
+/* Gnu.java --- Gnu provider main class
+   Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.provider;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+
+public final class Gnu
+    extends Provider
+{
+  public Gnu()
+  {
+    super("GNU", 1.0,
+          "GNU provider v1.0 implementing SHA-1, MD5, DSA, RSA, X.509 "
+          + "Certificates and CRLs, PKIX certificate path validators, "
+          + "Collection cert stores, Diffie-Hellman key agreement and "
+          + "key pair generator");
+    AccessController.doPrivileged (new PrivilegedAction()
+    {
+      public Object run()
+      {
+        // Note that all implementation class names are referenced by using
+        // Class.getName(). That way when we staticly link the Gnu provider
+        // we automatically get all the implementation classes.
+
+        // Signature
+        put("Signature.SHA160withDSS",
+            gnu.java.security.jce.sig.SHA160withDSS.class.getName());
+        put("Alg.Alias.Signature.SHA1withDSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.DSS", "SHA160withDSS");
+        put("Alg.Alias.Signature.DSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.SHAwithDSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.DSAwithSHA", "SHA160withDSS");
+        put("Alg.Alias.Signature.DSAwithSHA1", "SHA160withDSS");
+        put("Alg.Alias.Signature.SHA/DSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.SHA-1/DSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.SHA1/DSA", "SHA160withDSS");
+        put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", "SHA160withDSS");
+        put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA160withDSS");
+        put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA160withDSS");
+        put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA160withDSS");
+
+        put("Signature.MD2withRSA",
+            gnu.java.security.jce.sig.MD2withRSA.class.getName());
+        put("Signature.MD2withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.md2WithRSAEncryption", "MD2withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", "MD2withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA");
+
+        put("Signature.MD5withRSA",
+            gnu.java.security.jce.sig.MD5withRSA.class.getName());
+        put("Signature.MD5withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.md5WithRSAEncryption", "MD5withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA");
+        put("Alg.Alias.Signature.RSA", "MD5withRSA");
+
+        put("Signature.SHA160withRSA",
+            gnu.java.security.jce.sig.SHA160withRSA.class.getName());
+        put("Signature.SHA160withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.sha-1WithRSAEncryption", "SHA160withRSA");
+        put("Alg.Alias.Signature.sha-160WithRSAEncryption", "SHA160withRSA");
+        put("Alg.Alias.Signature.sha1WithRSAEncryption", "SHA160withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA160withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA160withRSA");
+        put("Alg.Alias.Signature.SHA1withRSA", "SHA160withRSA");
+
+        put("Signature.SHA256withRSA",
+            gnu.java.security.jce.sig.SHA256withRSA.class.getName());
+        put("Signature.SHA160withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.sha256WithRSAEncryption", "SHA256withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA");
+
+        put("Signature.SHA384withRSA",
+            gnu.java.security.jce.sig.SHA384withRSA.class.getName());
+        put("Signature.SHA160withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.sha384WithRSAEncryption", "SHA384withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA");
+
+        put("Signature.SHA512withRSA",
+            gnu.java.security.jce.sig.SHA512withRSA.class.getName());
+        put("Signature.SHA160withRSA ImplementedIn", "Software");
+        put("Alg.Alias.Signature.sha512WithRSAEncryption", "SHA512withRSA");
+        put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA");
+        put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA");
+
+        put("Signature.DSS/RAW",
+            gnu.java.security.jce.sig.DSSRawSignatureSpi.class.getName());
+        put("Signature.DSS/RAW KeySize", "1024");
+        put("Signature.DSS/RAW ImplementedIn", "Software");
+
+        put("Signature.RSA-PSS/RAW",
+            gnu.java.security.jce.sig.RSAPSSRawSignatureSpi.class.getName());
+        put("Signature.RSA-PSS/RAW KeySize", "1024");
+        put("Signature.RSA-PSS/RAW ImplementedIn", "Software");
+
+        // Key Pair Generator
+        put("KeyPairGenerator.DSS",
+            gnu.java.security.jce.sig.DSSKeyPairGeneratorSpi.class.getName());
+        put("KeyPairGenerator.DSS KeySize", "1024");
+        put("KeyPairGenerator.DSS ImplementedIn", "Software");
+        put("Alg.Alias.KeyPairGenerator.DSA", "DSS");
+        put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSS");
+        put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSS");
+        put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSS");
+
+        put("KeyPairGenerator.RSA",
+            gnu.java.security.jce.sig.RSAKeyPairGeneratorSpi.class.getName());
+        put("KeyPairGenerator.RSA KeySize", "1024");
+        put("KeyPairGenerator.RSA ImplementedIn", "Software");
+
+        // Key Factory
+        put("KeyFactory.DSS",
+            gnu.java.security.jce.sig.DSSKeyFactory.class.getName());
+        put("Alg.Alias.KeyFactory.DSA", "DSS");
+        put("Alg.Alias.KeyFactory.OID.1.2.840.10040.4.1", "DSS");
+        put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSS");
+        put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSS");
+
+        put("KeyFactory.RSA",
+            gnu.java.security.jce.sig.RSAKeyFactory.class.getName());
+
+        put("KeyFactory.Encoded",
+            gnu.java.security.jce.sig.EncodedKeyFactory.class.getName());
+        put("KeyFactory.Encoded ImplementedIn", "Software");
+        put("Alg.Alias.KeyFactory.X.509", "Encoded");
+        put("Alg.Alias.KeyFactory.X509", "Encoded");
+        put("Alg.Alias.KeyFactory.PKCS#8", "Encoded");
+        put("Alg.Alias.KeyFactory.PKCS8", "Encoded");
+
+        put("MessageDigest.HAVAL",
+            gnu.java.security.jce.hash.HavalSpi.class.getName());
+        put("MessageDigest.HAVAL ImplementedIn", "Software");
+        put("MessageDigest.MD2",
+            gnu.java.security.jce.hash.MD2Spi.class.getName());
+        put("MessageDigest.MD2 ImplementedIn", "Software");
+        put("MessageDigest.MD4",
+            gnu.java.security.jce.hash.MD4Spi.class.getName());
+        put("MessageDigest.MD4 ImplementedIn", "Software");
+        put("MessageDigest.MD5",
+            gnu.java.security.jce.hash.MD5Spi.class.getName());
+        put("MessageDigest.MD5 ImplementedIn", "Software");
+        put("MessageDigest.RIPEMD128",
+            gnu.java.security.jce.hash.RipeMD128Spi.class.getName());
+        put("MessageDigest.RIPEMD128 ImplementedIn", "Software");
+        put("MessageDigest.RIPEMD160",
+            gnu.java.security.jce.hash.RipeMD160Spi.class.getName());
+        put("MessageDigest.RIPEMD160 ImplementedIn", "Software");
+        put("MessageDigest.SHA-160",
+            gnu.java.security.jce.hash.Sha160Spi.class.getName());
+        put("MessageDigest.SHA-160 ImplementedIn", "Software");
+        put("MessageDigest.SHA-256",
+            gnu.java.security.jce.hash.Sha256Spi.class.getName());
+        put("MessageDigest.SHA-256 ImplementedIn", "Software");
+        put("MessageDigest.SHA-384",
+            gnu.java.security.jce.hash.Sha384Spi.class.getName());
+        put("MessageDigest.SHA-384 ImplementedIn", "Software");
+        put("MessageDigest.SHA-512",
+            gnu.java.security.jce.hash.Sha512Spi.class.getName());
+        put("MessageDigest.SHA-512 ImplementedIn", "Software");
+        put("MessageDigest.TIGER",
+            gnu.java.security.jce.hash.TigerSpi.class.getName());
+        put("MessageDigest.TIGER ImplementedIn", "Software");
+        put("MessageDigest.WHIRLPOOL",
+            gnu.java.security.jce.hash.WhirlpoolSpi.class.getName());
+        put("MessageDigest.WHIRLPOOL ImplementedIn", "Software");
+
+        put("Alg.Alias.MessageDigest.SHS", "SHA-160");
+        put("Alg.Alias.MessageDigest.SHA", "SHA-160");
+        put("Alg.Alias.MessageDigest.SHA1", "SHA-160");
+        put("Alg.Alias.MessageDigest.SHA-1", "SHA-160");
+        put("Alg.Alias.MessageDigest.SHA2-256", "SHA-256");
+        put("Alg.Alias.MessageDigest.SHA2-384", "SHA-384");
+        put("Alg.Alias.MessageDigest.SHA2-512", "SHA-512");
+        put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
+        put("Alg.Alias.MessageDigest.SHA384", "SHA-384");
+        put("Alg.Alias.MessageDigest.SHA512", "SHA-512");
+        put("Alg.Alias.MessageDigest.RIPEMD-160", "RIPEMD160");
+        put("Alg.Alias.MessageDigest.RIPEMD-128", "RIPEMD128");
+        put("Alg.Alias.MessageDigest.OID.1.2.840.11359.2.2", "MD2");
+        put("Alg.Alias.MessageDigest.1.2.840.11359.2.2", "MD2");
+        put("Alg.Alias.MessageDigest.OID.1.2.840.11359.2.5", "MD5");
+        put("Alg.Alias.MessageDigest.1.2.840.11359.2.5", "MD5");
+        put("Alg.Alias.MessageDigest.OID.1.3.14.3.2.26", "SHA1");
+        put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA1");
+
+        // Algorithm Parameters
+        put("AlgorithmParameters.DSS",
+            gnu.java.security.jce.sig.DSSParameters.class.getName());
+        put("Alg.Alias.AlgorithmParameters.DSA", "DSS");
+        put("Alg.Alias.AlgorithmParameters.SHAwithDSA", "DSS");
+        put("Alg.Alias.AlgorithmParameters.OID.1.2.840.10040.4.3", "DSS");
+        put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.3", "DSS");
+
+        // Algorithm Parameter Generator
+        put("AlgorithmParameterGenerator.DSA",
+            gnu.java.security.jce.sig.DSSParametersGenerator.class.getName());
+        put("Alg.Alias.AlgorithmParameterGenerator.DSA", "DSS");
+
+        // SecureRandom
+        put("SecureRandom.SHA1PRNG",
+            gnu.java.security.jce.prng.Sha160RandomSpi.class.getName());
+
+        put("SecureRandom.MD2PRNG",
+            gnu.java.security.jce.prng.MD2RandomSpi.class.getName());
+        put("SecureRandom.MD2PRNG ImplementedIn", "Software");
+        put("SecureRandom.MD4PRNG",
+            gnu.java.security.jce.prng.MD4RandomSpi.class.getName());
+        put("SecureRandom.MD4PRNG ImplementedIn", "Software");
+        put("SecureRandom.MD5PRNG",
+            gnu.java.security.jce.prng.MD5RandomSpi.class.getName());
+        put("SecureRandom.MD5PRNG ImplementedIn", "Software");
+        put("SecureRandom.RIPEMD128PRNG",
+            gnu.java.security.jce.prng.RipeMD128RandomSpi.class.getName());
+        put("SecureRandom.RIPEMD128PRNG ImplementedIn", "Software");
+        put("SecureRandom.RIPEMD160PRNG",
+            gnu.java.security.jce.prng.RipeMD160RandomSpi.class.getName());
+        put("SecureRandom.RIPEMD160PRNG ImplementedIn", "Software");
+        put("SecureRandom.SHA-160PRNG",
+            gnu.java.security.jce.prng.Sha160RandomSpi.class.getName());
+        put("SecureRandom.SHA-160PRNG ImplementedIn", "Software");
+        put("SecureRandom.SHA-256PRNG",
+            gnu.java.security.jce.prng.Sha256RandomSpi.class.getName());
+        put("SecureRandom.SHA-256PRNG ImplementedIn", "Software");
+        put("SecureRandom.SHA-384PRNG",
+            gnu.java.security.jce.prng.Sha384RandomSpi.class.getName());
+        put("SecureRandom.SHA-384PRNG ImplementedIn", "Software");
+        put("SecureRandom.SHA-512PRNG",
+            gnu.java.security.jce.prng.Sha512RandomSpi.class.getName());
+        put("SecureRandom.SHA-512PRNG ImplementedIn", "Software");
+        put("SecureRandom.TIGERPRNG",
+            gnu.java.security.jce.prng.TigerRandomSpi.class.getName());
+        put("SecureRandom.TIGERPRNG ImplementedIn", "Software");
+        put("SecureRandom.HAVALPRNG",
+            gnu.java.security.jce.prng.HavalRandomSpi.class.getName());
+        put("SecureRandom.HAVALPRNG ImplementedIn", "Software");
+        put("SecureRandom.WHIRLPOOLPRNG",
+            gnu.java.security.jce.prng.WhirlpoolRandomSpi.class.getName());
+        put("SecureRandom.WHIRLPOOLPRNG ImplementedIn", "Software");
+
+        put("Alg.Alias.SecureRandom.SHA-1PRNG", "SHA-160PRNG");
+        put("Alg.Alias.SecureRandom.SHA1PRNG", "SHA-160PRNG");
+        put("Alg.Alias.SecureRandom.SHAPRNG", "SHA-160PRNG");
+        put("Alg.Alias.SecureRandom.SHA-256PRNG", "SHA-256PRNG");
+        put("Alg.Alias.SecureRandom.SHA-2-1PRNG", "SHA-256PRNG");
+        put("Alg.Alias.SecureRandom.SHA-384PRNG", "SHA-384PRNG");
+        put("Alg.Alias.SecureRandom.SHA-2-2PRNG", "SHA-384PRNG");
+        put("Alg.Alias.SecureRandom.SHA-512PRNG", "SHA-512PRNG");
+        put("Alg.Alias.SecureRandom.SHA-2-3PRNG", "SHA-512PRNG");
+
+        // CertificateFactory
+        put("CertificateFactory.X509", X509CertificateFactory.class.getName());
+        put("CertificateFactory.X509 ImplementedIn", "Software");
+        put("Alg.Alias.CertificateFactory.X.509", "X509");
+
+        // CertPathValidator
+        put("CertPathValidator.PKIX", PKIXCertPathValidatorImpl.class.getName());
+        put("CertPathValidator.PKIX ImplementedIn", "Software");
+
+        // CertStore
+        put("CertStore.Collection", CollectionCertStoreImpl.class.getName());
+
+        return null;
+      }
+    });
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/java/util/Timer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,700 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.util;
+import java.util.Date;
+
+/**
+ * A facility for threads to schedule tasks for future execution in a
+ * background thread.  Tasks may be scheduled for one-time execution, or for
+ * repeated execution at regular intervals.
+ *
+ * <p>Corresponding to each <tt>Timer</tt> object is a single background
+ * thread that is used to execute all of the timer's tasks, sequentially.
+ * Timer tasks should complete quickly.  If a timer task takes excessive time
+ * to complete, it "hogs" the timer's task execution thread.  This can, in
+ * turn, delay the execution of subsequent tasks, which may "bunch up" and
+ * execute in rapid succession when (and if) the offending task finally
+ * completes.
+ *
+ * <p>After the last live reference to a <tt>Timer</tt> object goes away
+ * <i>and</i> all outstanding tasks have completed execution, the timer's task
+ * execution thread terminates gracefully (and becomes subject to garbage
+ * collection).  However, this can take arbitrarily long to occur.  By
+ * default, the task execution thread does not run as a <i>daemon thread</i>,
+ * so it is capable of keeping an application from terminating.  If a caller
+ * wants to terminate a timer's task execution thread rapidly, the caller
+ * should invoke the timer's <tt>cancel</tt> method.
+ *
+ * <p>If the timer's task execution thread terminates unexpectedly, for
+ * example, because its <tt>stop</tt> method is invoked, any further
+ * attempt to schedule a task on the timer will result in an
+ * <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
+ * method had been invoked.
+ *
+ * <p>This class is thread-safe: multiple threads can share a single
+ * <tt>Timer</tt> object without the need for external synchronization.
+ *
+ * <p>This class does <i>not</i> offer real-time guarantees: it schedules
+ * tasks using the <tt>Object.wait(long)</tt> method.
+ *
+ * <p>Java 5.0 introduced the {@code java.util.concurrent} package and
+ * one of the concurrency utilities therein is the {@link
+ * java.util.concurrent.ScheduledThreadPoolExecutor
+ * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
+ * executing tasks at a given rate or delay.  It is effectively a more
+ * versatile replacement for the {@code Timer}/{@code TimerTask}
+ * combination, as it allows multiple service threads, accepts various
+ * time units, and doesn't require subclassing {@code TimerTask} (just
+ * implement {@code Runnable}).  Configuring {@code
+ * ScheduledThreadPoolExecutor} with one thread makes it equivalent to
+ * {@code Timer}.
+ *
+ * <p>Implementation note: This class scales to large numbers of concurrently
+ * scheduled tasks (thousands should present no problem).  Internally,
+ * it uses a binary heap to represent its task queue, so the cost to schedule
+ * a task is O(log n), where n is the number of concurrently scheduled tasks.
+ *
+ * <p>Implementation note: All constructors start a timer thread.
+ *
+ * @author  Josh Bloch
+ * @version 1.27, 05/05/07
+ * @see     TimerTask
+ * @see     Object#wait(long)
+ * @since   1.3
+ */
+
+public class Timer {
+    /**
+     * The timer task queue.  This data structure is shared with the timer
+     * thread.  The timer produces tasks, via its various schedule calls,
+     * and the timer thread consumes, executing timer tasks as appropriate,
+     * and removing them from the queue when they're obsolete.
+     */
+    private TaskQueue queue = new TaskQueue();
+
+    /**
+     * The timer thread.
+     */
+    private TimerThread thread = new TimerThread(queue);
+
+    /**
+     * This object causes the timer's task execution thread to exit
+     * gracefully when there are no live references to the Timer object and no
+     * tasks in the timer queue.  It is used in preference to a finalizer on
+     * Timer as such a finalizer would be susceptible to a subclass's
+     * finalizer forgetting to call it.
+     */
+    private Object threadReaper = new Object() {
+        protected void finalize() throws Throwable {
+            synchronized(queue) {
+                thread.newTasksMayBeScheduled = false;
+                queue.notify(); // In case queue is empty.
+            }
+        }
+    };
+
+    /**
+     * This ID is used to generate thread names.  (It could be replaced
+     * by an AtomicInteger as soon as they become available.)
+     */
+    private static int nextSerialNumber = 0;
+    private static synchronized int serialNumber() {
+        return nextSerialNumber++;
+    }
+
+    /**
+     * Creates a new timer.  The associated thread does <i>not</i>
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     */
+    public Timer() {
+        this("Timer-" + serialNumber());
+    }
+
+    /**
+     * Creates a new timer whose associated thread may be specified to
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     * A daemon thread is called for if the timer will be used to
+     * schedule repeating "maintenance activities", which must be
+     * performed as long as the application is running, but should not
+     * prolong the lifetime of the application.
+     *
+     * @param isDaemon true if the associated thread should run as a daemon.
+     */
+    public Timer(boolean isDaemon) {
+        this("Timer-" + serialNumber(), isDaemon);
+    }
+
+    /**
+     * Creates a new timer whose associated thread has the specified name.
+     * The associated thread does <i>not</i>
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     *
+     * @param name the name of the associated thread
+     * @throws NullPointerException if name is null
+     * @since 1.5
+     */
+    public Timer(String name) {
+        thread.setName(name);
+        thread.start();
+    }
+
+    /**
+     * Creates a new timer whose associated thread has the specified name,
+     * and may be specified to
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     *
+     * @param name the name of the associated thread
+     * @param isDaemon true if the associated thread should run as a daemon
+     * @throws NullPointerException if name is null
+     * @since 1.5
+     */
+    public Timer(String name, boolean isDaemon) {
+        thread.setName(name);
+        thread.setDaemon(isDaemon);
+        thread.start();
+    }
+
+    /**
+     * Schedules the specified task for execution after the specified delay.
+     *
+     * @param task  task to be scheduled.
+     * @param delay delay in milliseconds before task is to be executed.
+     * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
+     *         <tt>delay + System.currentTimeMillis()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, or timer was cancelled.
+     */
+    public void schedule(TimerTask task, long delay) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        sched(task, System.currentTimeMillis()+delay, 0);
+    }
+
+    /**
+     * Schedules the specified task for execution at the specified time.  If
+     * the time is in the past, the task is scheduled for immediate execution.
+     *
+     * @param task task to be scheduled.
+     * @param time time at which task is to be executed.
+     * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     */
+    public void schedule(TimerTask task, Date time) {
+        sched(task, time.getTime(), 0);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
+     * beginning after the specified delay.  Subsequent executions take place
+     * at approximately regular intervals separated by the specified period.
+     *
+     * <p>In fixed-delay execution, each execution is scheduled relative to
+     * the actual execution time of the previous execution.  If an execution
+     * is delayed for any reason (such as garbage collection or other
+     * background activity), subsequent executions will be delayed as well.
+     * In the long run, the frequency of execution will generally be slightly
+     * lower than the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).
+     *
+     * <p>Fixed-delay execution is appropriate for recurring activities
+     * that require "smoothness."  In other words, it is appropriate for
+     * activities where it is more important to keep the frequency accurate
+     * in the short run than in the long run.  This includes most animation
+     * tasks, such as blinking a cursor at regular intervals.  It also includes
+     * tasks wherein regular activity is performed in response to human
+     * input, such as automatically repeating a character as long as a key
+     * is held down.
+     *
+     * @param task   task to be scheduled.
+     * @param delay  delay in milliseconds before task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
+     *         <tt>delay + System.currentTimeMillis()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     */
+    public void schedule(TimerTask task, long delay, long period) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, System.currentTimeMillis()+delay, -period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
+     * beginning at the specified time. Subsequent executions take place at
+     * approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-delay execution, each execution is scheduled relative to
+     * the actual execution time of the previous execution.  If an execution
+     * is delayed for any reason (such as garbage collection or other
+     * background activity), subsequent executions will be delayed as well.
+     * In the long run, the frequency of execution will generally be slightly
+     * lower than the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).
+     *
+     * <p>Fixed-delay execution is appropriate for recurring activities
+     * that require "smoothness."  In other words, it is appropriate for
+     * activities where it is more important to keep the frequency accurate
+     * in the short run than in the long run.  This includes most animation
+     * tasks, such as blinking a cursor at regular intervals.  It also includes
+     * tasks wherein regular activity is performed in response to human
+     * input, such as automatically repeating a character as long as a key
+     * is held down.
+     *
+     * @param task   task to be scheduled.
+     * @param firstTime First time at which task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     */
+    public void schedule(TimerTask task, Date firstTime, long period) {
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, firstTime.getTime(), -period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
+     * beginning after the specified delay.  Subsequent executions take place
+     * at approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-rate execution, each execution is scheduled relative to the
+     * scheduled execution time of the initial execution.  If an execution is
+     * delayed for any reason (such as garbage collection or other background
+     * activity), two or more executions will occur in rapid succession to
+     * "catch up."  In the long run, the frequency of execution will be
+     * exactly the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).
+     *
+     * <p>Fixed-rate execution is appropriate for recurring activities that
+     * are sensitive to <i>absolute</i> time, such as ringing a chime every
+     * hour on the hour, or running scheduled maintenance every day at a
+     * particular time.  It is also appropriate for recurring activities
+     * where the total time to perform a fixed number of executions is
+     * important, such as a countdown timer that ticks once every second for
+     * ten seconds.  Finally, fixed-rate execution is appropriate for
+     * scheduling multiple repeating timer tasks that must remain synchronized
+     * with respect to one another.
+     *
+     * @param task   task to be scheduled.
+     * @param delay  delay in milliseconds before task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
+     *         <tt>delay + System.currentTimeMillis()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     */
+    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, System.currentTimeMillis()+delay, period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
+     * beginning at the specified time. Subsequent executions take place at
+     * approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-rate execution, each execution is scheduled relative to the
+     * scheduled execution time of the initial execution.  If an execution is
+     * delayed for any reason (such as garbage collection or other background
+     * activity), two or more executions will occur in rapid succession to
+     * "catch up."  In the long run, the frequency of execution will be
+     * exactly the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).
+     *
+     * <p>Fixed-rate execution is appropriate for recurring activities that
+     * are sensitive to <i>absolute</i> time, such as ringing a chime every
+     * hour on the hour, or running scheduled maintenance every day at a
+     * particular time.  It is also appropriate for recurring activities
+     * where the total time to perform a fixed number of executions is
+     * important, such as a countdown timer that ticks once every second for
+     * ten seconds.  Finally, fixed-rate execution is appropriate for
+     * scheduling multiple repeating timer tasks that must remain synchronized
+     * with respect to one another.
+     *
+     * @param task   task to be scheduled.
+     * @param firstTime First time at which task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     */
+    public void scheduleAtFixedRate(TimerTask task, Date firstTime,
+                                    long period) {
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, firstTime.getTime(), period);
+    }
+
+    /**
+     * Schedule the specified timer task for execution at the specified
+     * time with the specified period, in milliseconds.  If period is
+     * positive, the task is scheduled for repeated execution; if period is
+     * zero, the task is scheduled for one-time execution. Time is specified
+     * in Date.getTime() format.  This method checks timer state, task state,
+     * and initial execution time, but not period.
+     *
+     * @throws IllegalArgumentException if <tt>time()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     */
+    private void sched(TimerTask task, long time, long period) {
+        if (time < 0)
+            throw new IllegalArgumentException("Illegal execution time.");
+
+        synchronized(queue) {
+            if (!thread.newTasksMayBeScheduled)
+                throw new IllegalStateException("Timer already cancelled.");
+
+            synchronized(task.lock) {
+                if (task.state != TimerTask.VIRGIN)
+                    throw new IllegalStateException(
+                        "Task already scheduled or cancelled");
+                task.nextExecutionTime = time;
+                task.period = period;
+                task.state = TimerTask.SCHEDULED;
+            }
+
+            queue.add(task);
+            if (queue.getMin() == task)
+                queue.notify();
+        }
+    }
+
+    /**
+     * Terminates this timer, discarding any currently scheduled tasks.
+     * Does not interfere with a currently executing task (if it exists).
+     * Once a timer has been terminated, its execution thread terminates
+     * gracefully, and no more tasks may be scheduled on it.
+     *
+     * <p>Note that calling this method from within the run method of a
+     * timer task that was invoked by this timer absolutely guarantees that
+     * the ongoing task execution is the last task execution that will ever
+     * be performed by this timer.
+     *
+     * <p>This method may be called repeatedly; the second and subsequent
+     * calls have no effect.
+     */
+    public void cancel() {
+        synchronized(queue) {
+            thread.newTasksMayBeScheduled = false;
+            queue.clear();
+            queue.notify();  // In case queue was already empty.
+        }
+    }
+
+    /**
+     * Removes all cancelled tasks from this timer's task queue.  <i>Calling
+     * this method has no effect on the behavior of the timer</i>, but
+     * eliminates the references to the cancelled tasks from the queue.
+     * If there are no external references to these tasks, they become
+     * eligible for garbage collection.
+     *
+     * <p>Most programs will have no need to call this method.
+     * It is designed for use by the rare application that cancels a large
+     * number of tasks.  Calling this method trades time for space: the
+     * runtime of the method may be proportional to n + c log n, where n
+     * is the number of tasks in the queue and c is the number of cancelled
+     * tasks.
+     *
+     * <p>Note that it is permissible to call this method from within a
+     * a task scheduled on this timer.
+     *
+     * @return the number of tasks removed from the queue.
+     * @since 1.5
+     */
+     public int purge() {
+         int result = 0;
+
+         synchronized(queue) {
+             for (int i = queue.size(); i > 0; i--) {
+                 if (queue.get(i).state == TimerTask.CANCELLED) {
+                     queue.quickRemove(i);
+                     result++;
+                 }
+             }
+
+             if (result != 0)
+                 queue.heapify();
+         }
+
+         return result;
+     }
+}
+
+/**
+ * This "helper class" implements the timer's task execution thread, which
+ * waits for tasks on the timer queue, executions them when they fire,
+ * reschedules repeating tasks, and removes cancelled tasks and spent
+ * non-repeating tasks from the queue.
+ */
+class TimerThread extends Thread {
+    /**
+     * This flag is set to false by the reaper to inform us that there
+     * are no more live references to our Timer object.  Once this flag
+     * is true and there are no more tasks in our queue, there is no
+     * work left for us to do, so we terminate gracefully.  Note that
+     * this field is protected by queue's monitor!
+     */
+    boolean newTasksMayBeScheduled = true;
+
+    /**
+     * Our Timer's queue.  We store this reference in preference to
+     * a reference to the Timer so the reference graph remains acyclic.
+     * Otherwise, the Timer would never be garbage-collected and this
+     * thread would never go away.
+     */
+    private TaskQueue queue;
+
+    TimerThread(TaskQueue queue) {
+        this.queue = queue;
+    }
+
+    public void run() {
+        try {
+            mainLoop();
+        } finally {
+            // Someone killed this Thread, behave as if Timer cancelled
+            synchronized(queue) {
+                newTasksMayBeScheduled = false;
+                queue.clear();  // Eliminate obsolete references
+            }
+        }
+    }
+
+    /**
+     * The main timer loop.  (See class comment.)
+     */
+    private void mainLoop() {
+        while (true) {
+            try {
+                TimerTask task;
+                boolean taskFired;
+                synchronized(queue) {
+                    // Wait for queue to become non-empty
+                    while (queue.isEmpty() && newTasksMayBeScheduled)
+                        queue.wait();
+                    if (queue.isEmpty())
+                        break; // Queue is empty and will forever remain; die
+
+                    // Queue nonempty; look at first evt and do the right thing
+                    long currentTime, executionTime;
+                    task = queue.getMin();
+                    synchronized(task.lock) {
+                        if (task.state == TimerTask.CANCELLED) {
+                            queue.removeMin();
+                            continue;  // No action required, poll queue again
+                        }
+                        currentTime = System.currentTimeMillis();
+                        executionTime = task.nextExecutionTime;
+                        if (taskFired = (executionTime<=currentTime)) {
+                            if (task.period == 0) { // Non-repeating, remove
+                                queue.removeMin();
+                                task.state = TimerTask.EXECUTED;
+                            } else { // Repeating task, reschedule
+                                queue.rescheduleMin(
+                                  task.period<0 ? currentTime   - task.period
+                                                : executionTime + task.period);
+                            }
+                        }
+                    }
+                    if (!taskFired) // Task hasn't yet fired; wait
+                        queue.wait(executionTime - currentTime);
+                }
+                if (taskFired)  // Task fired; run it, holding no locks
+                    task.run();
+            } catch(InterruptedException e) {
+            }
+        }
+    }
+}
+
+/**
+ * This class represents a timer task queue: a priority queue of TimerTasks,
+ * ordered on nextExecutionTime.  Each Timer object has one of these, which it
+ * shares with its TimerThread.  Internally this class uses a heap, which
+ * offers log(n) performance for the add, removeMin and rescheduleMin
+ * operations, and constant time performance for the getMin operation.
+ */
+class TaskQueue {
+    /**
+     * Priority queue represented as a balanced binary heap: the two children
+     * of queue[n] are queue[2*n] and queue[2*n+1].  The priority queue is
+     * ordered on the nextExecutionTime field: The TimerTask with the lowest
+     * nextExecutionTime is in queue[1] (assuming the queue is nonempty).  For
+     * each node n in the heap, and each descendant of n, d,
+     * n.nextExecutionTime <= d.nextExecutionTime.
+     */
+    private TimerTask[] queue = new TimerTask[128];
+
+    /**
+     * The number of tasks in the priority queue.  (The tasks are stored in
+     * queue[1] up to queue[size]).
+     */
+    private int size = 0;
+
+    /**
+     * Returns the number of tasks currently on the queue.
+     */
+    int size() {
+        return size;
+    }
+
+    /**
+     * Adds a new task to the priority queue.
+     */
+    void add(TimerTask task) {
+        // Grow backing store if necessary
+        if (size + 1 == queue.length)
+	    queue = Arrays.copyOf(queue, 2*queue.length);
+
+        queue[++size] = task;
+        fixUp(size);
+    }
+
+    /**
+     * Return the "head task" of the priority queue.  (The head task is an
+     * task with the lowest nextExecutionTime.)
+     */
+    TimerTask getMin() {
+        return queue[1];
+    }
+
+    /**
+     * Return the ith task in the priority queue, where i ranges from 1 (the
+     * head task, which is returned by getMin) to the number of tasks on the
+     * queue, inclusive.
+     */
+    TimerTask get(int i) {
+        return queue[i];
+    }
+
+    /**
+     * Remove the head task from the priority queue.
+     */
+    void removeMin() {
+        queue[1] = queue[size];
+        queue[size--] = null;  // Drop extra reference to prevent memory leak
+        fixDown(1);
+    }
+
+    /**
+     * Removes the ith element from queue without regard for maintaining
+     * the heap invariant.  Recall that queue is one-based, so
+     * 1 <= i <= size.
+     */
+    void quickRemove(int i) {
+        assert i <= size;
+
+        queue[i] = queue[size];
+        queue[size--] = null;  // Drop extra ref to prevent memory leak
+    }
+
+    /**
+     * Sets the nextExecutionTime associated with the head task to the
+     * specified value, and adjusts priority queue accordingly.
+     */
+    void rescheduleMin(long newTime) {
+        queue[1].nextExecutionTime = newTime;
+        fixDown(1);
+    }
+
+    /**
+     * Returns true if the priority queue contains no elements.
+     */
+    boolean isEmpty() {
+        return size==0;
+    }
+
+    /**
+     * Removes all elements from the priority queue.
+     */
+    void clear() {
+        // Null out task references to prevent memory leak
+        for (int i=1; i<=size; i++)
+            queue[i] = null;
+
+        size = 0;
+    }
+
+    /**
+     * Establishes the heap invariant (described above) assuming the heap
+     * satisfies the invariant except possibly for the leaf-node indexed by k
+     * (which may have a nextExecutionTime less than its parent's).
+     *
+     * This method functions by "promoting" queue[k] up the hierarchy
+     * (by swapping it with its parent) repeatedly until queue[k]'s
+     * nextExecutionTime is greater than or equal to that of its parent.
+     */
+    private void fixUp(int k) {
+        while (k > 1) {
+            int j = k >> 1;
+            if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
+                break;
+            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
+            k = j;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the subtree
+     * rooted at k, which is assumed to satisfy the heap invariant except
+     * possibly for node k itself (which may have a nextExecutionTime greater
+     * than its children's).
+     *
+     * This method functions by "demoting" queue[k] down the hierarchy
+     * (by swapping it with its smaller child) repeatedly until queue[k]'s
+     * nextExecutionTime is less than or equal to those of its children.
+     */
+    private void fixDown(int k) {
+        int j;
+        while ((j = k << 1) <= size && j > 0) {
+            if (j < size &&
+                queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
+                j++; // j indexes smallest kid
+            if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
+                break;
+            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
+            k = j;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     */
+    void heapify() {
+        for (int i = size/2; i >= 1; i--)
+            fixDown(i);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/auth/callback/ChoiceCallback.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,212 @@
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.auth.callback;
+
+/**
+ * <p> Underlying security services instantiate and pass a
+ * <code>ChoiceCallback</code> to the <code>handle</code>
+ * method of a <code>CallbackHandler</code> to display a list of choices
+ * and to retrieve the selected choice(s).
+ *
+ * @version 1.24, 05/05/07
+ * @see javax.security.auth.callback.CallbackHandler
+ */
+public class ChoiceCallback implements Callback, java.io.Serializable {
+
+    private static final long serialVersionUID = -3975664071579892167L;
+
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String prompt;
+    /**
+     * @serial the list of choices
+     * @since 1.4
+     */
+    private String[] choices;
+    /**
+     * @serial the choice to be used as the default choice
+     * @since 1.4
+     */
+    private int defaultChoice;
+    /**
+     * @serial whether multiple selections are allowed from the list of 
+     * choices 
+     * @since 1.4
+     */
+    private boolean multipleSelectionsAllowed;
+    /**
+     * @serial the selected choices, represented as indexes into the
+     *		<code>choices</code> list.
+     * @since 1.4
+     */
+    private int[] selections;
+
+    /**
+     * Construct a <code>ChoiceCallback</code> with a prompt,
+     * a list of choices, a default choice, and a boolean specifying
+     * whether or not multiple selections from the list of choices are allowed.
+     *
+     * <p>
+     *
+     * @param prompt the prompt used to describe the list of choices. <p>
+     *
+     * @param choices the list of choices. <p>
+     *
+     * @param defaultChoice the choice to be used as the default choice
+     *			when the list of choices are displayed.  This value
+     *			is represented as an index into the
+     *			<code>choices</code> array. <p>
+     *
+     * @param multipleSelectionsAllowed boolean specifying whether or
+     *			not multiple selections can be made from the
+     *			list of choices.
+     *
+     * @exception IllegalArgumentException if <code>prompt</code> is null,
+     *			if <code>prompt</code> has a length of 0,
+     *			if <code>choices</code> is null,
+     *			if <code>choices</code> has a length of 0,
+     *			if any element from <code>choices</code> is null,
+     *			if any element from <code>choices</code>
+     *			has a length of 0 or if <code>defaultChoice</code>
+     *			does not fall within the array boundaries of
+     *			<code>choices</code>.
+     */
+    public ChoiceCallback(String prompt, String[] choices,
+                int defaultChoice, boolean multipleSelectionsAllowed) {
+
+	if (prompt == null || prompt.length() == 0 ||
+	    choices == null || choices.length == 0 ||
+	    defaultChoice < 0 || defaultChoice >= choices.length)
+	    throw new IllegalArgumentException();
+
+	for (int i = 0; i < choices.length; i++) {
+	    if (choices[i] == null || choices[i].length() == 0)
+		throw new IllegalArgumentException();
+	}
+
+	this.prompt = prompt;
+	this.choices = choices;
+	this.defaultChoice = defaultChoice;
+	this.multipleSelectionsAllowed = multipleSelectionsAllowed;
+    }
+
+    /**
+     * Get the prompt.
+     *
+     * <p>
+     *
+     * @return the prompt.
+     */
+    public String getPrompt() {
+	return prompt;
+    }
+
+    /**
+     * Get the list of choices.
+     *
+     * <p>
+     *
+     * @return the list of choices.
+     */
+    public String[] getChoices() {
+	return choices;
+    }
+
+    /**
+     * Get the defaultChoice.
+     *
+     * <p>
+     *
+     * @return the defaultChoice, represented as an index into
+     *		the <code>choices</code> list.
+     */
+    public int getDefaultChoice() {
+	return defaultChoice;
+    }
+
+    /**
+     * Get the boolean determining whether multiple selections from
+     * the <code>choices</code> list are allowed.
+     *
+     * <p>
+     *
+     * @return whether multiple selections are allowed.
+     */
+    public boolean allowMultipleSelections() {
+	return multipleSelectionsAllowed;
+    }
+
+    /**
+     * Set the selected choice.
+     *
+     * <p>
+     *
+     * @param selection the selection represented as an index into the
+     *		<code>choices</code> list.
+     *
+     * @see #getSelectedIndexes
+     */
+    public void setSelectedIndex(int selection) {
+	this.selections = new int[1];
+	this.selections[0] = selection;
+    }
+
+    /**
+     * Set the selected choices.
+     *
+     * <p>
+     *
+     * @param selections the selections represented as indexes into the
+     *		<code>choices</code> list.
+     *
+     * @exception UnsupportedOperationException if multiple selections are
+     *		not allowed, as determined by
+     *		<code>allowMultipleSelections</code>.
+     *
+     * @see #getSelectedIndexes
+     */
+    public void setSelectedIndexes(int[] selections) {
+	if (!multipleSelectionsAllowed)
+	    throw new UnsupportedOperationException();
+	this.selections = selections;
+    }
+
+    /**
+     * Get the selected choices.
+     *
+     * <p>
+     *
+     * @return the selected choices, represented as indexes into the
+     *		<code>choices</code> list.
+     *
+     * @see #setSelectedIndexes
+     */
+    public int[] getSelectedIndexes() {
+	return selections;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/auth/callback/ConfirmationCallback.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,502 @@
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.auth.callback;
+
+/**
+ * <p> Underlying security services instantiate and pass a
+ * <code>ConfirmationCallback</code> to the <code>handle</code>
+ * method of a <code>CallbackHandler</code> to ask for YES/NO,
+ * OK/CANCEL, YES/NO/CANCEL or other similar confirmations.
+ *
+ * @version 1.23, 05/05/07
+ * @see javax.security.auth.callback.CallbackHandler
+ */
+public class ConfirmationCallback implements Callback, java.io.Serializable {
+
+    private static final long serialVersionUID = -9095656433782481624L;
+
+    /**
+     * Unspecified option type.
+     *
+     * <p> The <code>getOptionType</code> method returns this
+     * value if this <code>ConfirmationCallback</code> was instantiated
+     * with <code>options</code> instead of an <code>optionType</code>.
+     */
+    public static final int UNSPECIFIED_OPTION		= -1;
+
+    /**
+     * YES/NO confirmation option.
+     *
+     * <p> An underlying security service specifies this as the
+     * <code>optionType</code> to a <code>ConfirmationCallback</code>
+     * constructor if it requires a confirmation which can be answered
+     * with either <code>YES</code> or <code>NO</code>.
+     */
+    public static final int YES_NO_OPTION		= 0;
+
+    /**
+     * YES/NO/CANCEL confirmation confirmation option.
+     *
+     * <p> An underlying security service specifies this as the
+     * <code>optionType</code> to a <code>ConfirmationCallback</code>
+     * constructor if it requires a confirmation which can be answered
+     * with either <code>YES</code>, <code>NO</code> or <code>CANCEL</code>.
+     */
+    public static final int YES_NO_CANCEL_OPTION	= 1;
+
+    /**
+     * OK/CANCEL confirmation confirmation option.
+     *
+     * <p> An underlying security service specifies this as the
+     * <code>optionType</code> to a <code>ConfirmationCallback</code>
+     * constructor if it requires a confirmation which can be answered
+     * with either <code>OK</code> or <code>CANCEL</code>.
+     */
+    public static final int OK_CANCEL_OPTION		= 2;
+ 
+    /**
+     * YES option.
+     *
+     * <p> If an <code>optionType</code> was specified to this
+     * <code>ConfirmationCallback</code>, this option may be specified as a
+     * <code>defaultOption</code> or returned as the selected index.
+     */
+    public static final int YES				= 0;
+
+    /**
+     * NO option.
+     *
+     * <p> If an <code>optionType</code> was specified to this
+     * <code>ConfirmationCallback</code>, this option may be specified as a
+     * <code>defaultOption</code> or returned as the selected index.
+     */
+    public static final int NO				= 1;
+
+    /**
+     * CANCEL option.
+     *
+     * <p> If an <code>optionType</code> was specified to this
+     * <code>ConfirmationCallback</code>, this option may be specified as a
+     * <code>defaultOption</code> or returned as the selected index.
+     */
+    public static final int CANCEL			= 2;
+
+    /**
+     * OK option.
+     *
+     * <p> If an <code>optionType</code> was specified to this
+     * <code>ConfirmationCallback</code>, this option may be specified as a
+     * <code>defaultOption</code> or returned as the selected index.
+     */
+    public static final int OK				= 3;
+ 
+    /** INFORMATION message type.  */
+    public static final int INFORMATION			= 0;
+
+    /** WARNING message type. */
+    public static final int WARNING			= 1;
+
+    /** ERROR message type. */
+    public static final int ERROR			= 2;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String prompt;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private int messageType;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private int optionType = UNSPECIFIED_OPTION;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private int defaultOption;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String[] options;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private int selection;
+
+    /**
+     * Construct a <code>ConfirmationCallback</code> with a
+     * message type, an option type and a default option.
+     *
+     * <p> Underlying security services use this constructor if
+     * they require either a YES/NO, YES/NO/CANCEL or OK/CANCEL
+     * confirmation.
+     *
+     * <p>
+     *
+     * @param messageType the message type (<code>INFORMATION</code>,
+     *			<code>WARNING</code> or <code>ERROR</code>). <p>
+     *
+     * @param optionType the option type (<code>YES_NO_OPTION</code>,
+     *			<code>YES_NO_CANCEL_OPTION</code> or
+     *			<code>OK_CANCEL_OPTION</code>). <p>
+     *
+     * @param defaultOption the default option
+     *			from the provided optionType (<code>YES</code>,
+     *			<code>NO</code>, <code>CANCEL</code> or
+     *			<code>OK</code>).
+     *
+     * @exception IllegalArgumentException if messageType is not either
+     *			<code>INFORMATION</code>, <code>WARNING</code>,
+     *			or <code>ERROR</code>, if optionType is not either
+     *			<code>YES_NO_OPTION</code>,
+     *			<code>YES_NO_CANCEL_OPTION</code>, or
+     *			<code>OK_CANCEL_OPTION</code>,
+     *			or if <code>defaultOption</code>
+     *			does not correspond to one of the options in
+     *			<code>optionType</code>.
+     */
+    public ConfirmationCallback(int messageType,
+                int optionType, int defaultOption) {
+
+	if (messageType < INFORMATION || messageType > ERROR ||
+	    optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
+	    throw new IllegalArgumentException();
+
+	switch (optionType) {
+	case YES_NO_OPTION:
+	    if (defaultOption != YES && defaultOption != NO)
+		throw new IllegalArgumentException();
+	    break;
+	case YES_NO_CANCEL_OPTION:
+	    if (defaultOption != YES && defaultOption != NO &&
+		defaultOption != CANCEL)
+		throw new IllegalArgumentException();
+	    break;
+	case OK_CANCEL_OPTION:
+	    if (defaultOption != OK && defaultOption != CANCEL)
+		throw new IllegalArgumentException();
+	    break;
+	}
+		 
+	this.messageType = messageType;
+	this.optionType = optionType;
+	this.defaultOption = defaultOption;
+    }
+
+    /**
+     * Construct a <code>ConfirmationCallback</code> with a
+     * message type, a list of options and a default option.
+     *
+     * <p> Underlying security services use this constructor if
+     * they require a confirmation different from the available preset
+     * confirmations provided (for example, CONTINUE/ABORT or STOP/GO).
+     * The confirmation options are listed in the <code>options</code> array,
+     * and are displayed by the <code>CallbackHandler</code> implementation
+     * in a manner consistent with the way preset options are displayed.
+     *
+     * <p>
+     *
+     * @param messageType the message type (<code>INFORMATION</code>,
+     *			<code>WARNING</code> or <code>ERROR</code>). <p>
+     *
+     * @param options the list of confirmation options. <p>
+     *
+     * @param defaultOption the default option, represented as an index
+     *			into the <code>options</code> array.
+     *
+     * @exception IllegalArgumentException if messageType is not either
+     *			<code>INFORMATION</code>, <code>WARNING</code>,
+     *			or <code>ERROR</code>, if <code>options</code> is null,
+     *			if <code>options</code> has a length of 0,
+     *			if any element from <code>options</code> is null,
+     *			if any element from <code>options</code>
+     *			has a length of 0, or if <code>defaultOption</code>
+     *			does not lie within the array boundaries of
+     *			<code>options</code>.
+     */
+    public ConfirmationCallback(int messageType,
+                String[] options, int defaultOption) {
+
+	if (messageType < INFORMATION || messageType > ERROR ||
+	    options == null || options.length == 0 ||
+	    defaultOption < 0 || defaultOption >= options.length)
+	    throw new IllegalArgumentException();
+
+	for (int i = 0; i < options.length; i++) {
+	    if (options[i] == null || options[i].length() == 0)
+		throw new IllegalArgumentException();
+	}
+		 
+	this.messageType = messageType;
+	this.options = options;
+	this.defaultOption = defaultOption;
+    }
+
+    /**
+     * Construct a <code>ConfirmationCallback</code> with a prompt,
+     * message type, an option type and a default option.
+     *
+     * <p> Underlying security services use this constructor if
+     * they require either a YES/NO, YES/NO/CANCEL or OK/CANCEL
+     * confirmation.
+     *
+     * <p>
+     *
+     * @param prompt the prompt used to describe the list of options. <p>
+     *
+     * @param messageType the message type (<code>INFORMATION</code>,
+     *			<code>WARNING</code> or <code>ERROR</code>). <p>
+     *
+     * @param optionType the option type (<code>YES_NO_OPTION</code>,
+     *			<code>YES_NO_CANCEL_OPTION</code> or
+     *			<code>OK_CANCEL_OPTION</code>). <p>
+     *
+     * @param defaultOption the default option
+     *			from the provided optionType (<code>YES</code>,
+     *			<code>NO</code>, <code>CANCEL</code> or
+     *			<code>OK</code>).
+     *
+     * @exception IllegalArgumentException if <code>prompt</code> is null,
+     *			if <code>prompt</code> has a length of 0,
+     *			if messageType is not either
+     *			<code>INFORMATION</code>, <code>WARNING</code>,
+     *			or <code>ERROR</code>, if optionType is not either
+     *			<code>YES_NO_OPTION</code>,
+     *			<code>YES_NO_CANCEL_OPTION</code>, or
+     *			<code>OK_CANCEL_OPTION</code>,
+     *			or if <code>defaultOption</code>
+     *			does not correspond to one of the options in
+     *			<code>optionType</code>.
+     */
+    public ConfirmationCallback(String prompt, int messageType,
+                int optionType, int defaultOption) {
+
+	if (prompt == null || prompt.length() == 0 ||
+	    messageType < INFORMATION || messageType > ERROR ||
+	    optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
+	    throw new IllegalArgumentException();
+
+	switch (optionType) {
+	case YES_NO_OPTION:
+	    if (defaultOption != YES && defaultOption != NO)
+		throw new IllegalArgumentException();
+	    break;
+	case YES_NO_CANCEL_OPTION:
+	    if (defaultOption != YES && defaultOption != NO &&
+		defaultOption != CANCEL)
+		throw new IllegalArgumentException();
+	    break;
+	case OK_CANCEL_OPTION:
+	    if (defaultOption != OK && defaultOption != CANCEL)
+		throw new IllegalArgumentException();
+	    break;
+	}
+		 
+	this.prompt = prompt;
+	this.messageType = messageType;
+	this.optionType = optionType;
+	this.defaultOption = defaultOption;
+    }
+
+    /**
+     * Construct a <code>ConfirmationCallback</code> with a prompt,
+     * message type, a list of options and a default option.
+     *
+     * <p> Underlying security services use this constructor if
+     * they require a confirmation different from the available preset
+     * confirmations provided (for example, CONTINUE/ABORT or STOP/GO).
+     * The confirmation options are listed in the <code>options</code> array,
+     * and are displayed by the <code>CallbackHandler</code> implementation
+     * in a manner consistent with the way preset options are displayed.
+     *
+     * <p>
+     *
+     * @param prompt the prompt used to describe the list of options. <p>
+     *
+     * @param messageType the message type (<code>INFORMATION</code>,
+     *			<code>WARNING</code> or <code>ERROR</code>). <p>
+     *
+     * @param options the list of confirmation options. <p>
+     *
+     * @param defaultOption the default option, represented as an index
+     *			into the <code>options</code> array.
+     *
+     * @exception IllegalArgumentException if <code>prompt</code> is null,
+     *			if <code>prompt</code> has a length of 0,
+     *			if messageType is not either
+     *			<code>INFORMATION</code>, <code>WARNING</code>,
+     *			or <code>ERROR</code>, if <code>options</code> is null,
+     *			if <code>options</code> has a length of 0,
+     *			if any element from <code>options</code> is null,
+     *			if any element from <code>options</code>
+     *			has a length of 0, or if <code>defaultOption</code>
+     *			does not lie within the array boundaries of
+     *			<code>options</code>.
+     */
+    public ConfirmationCallback(String prompt, int messageType,
+                String[] options, int defaultOption) {
+
+	if (prompt == null || prompt.length() == 0 ||
+	    messageType < INFORMATION || messageType > ERROR ||
+	    options == null || options.length == 0 ||
+	    defaultOption < 0 || defaultOption >= options.length)
+	    throw new IllegalArgumentException();
+
+	for (int i = 0; i < options.length; i++) {
+	    if (options[i] == null || options[i].length() == 0)
+		throw new IllegalArgumentException();
+	}
+		 
+	this.prompt = prompt;
+	this.messageType = messageType;
+	this.options = options;
+	this.defaultOption = defaultOption;
+    }
+
+    /**
+     * Get the prompt.
+     *
+     * <p>
+     *
+     * @return the prompt, or null if this <code>ConfirmationCallback</code>
+     *		was instantiated without a <code>prompt</code>.
+     */
+    public String getPrompt() {
+	return prompt;
+    }
+
+    /**
+     * Get the message type.
+     *
+     * <p>
+     *
+     * @return the message type (<code>INFORMATION</code>,
+     *		<code>WARNING</code> or <code>ERROR</code>).
+     */
+    public int getMessageType() {
+	return messageType;
+    }
+
+    /**
+     * Get the option type.
+     *
+     * <p> If this method returns <code>UNSPECIFIED_OPTION</code>, then this
+     * <code>ConfirmationCallback</code> was instantiated with
+     * <code>options</code> instead of an <code>optionType</code>.
+     * In this case, invoke the <code>getOptions</code> method
+     * to determine which confirmation options to display.
+     *
+     * <p>
+     *
+     * @return the option type (<code>YES_NO_OPTION</code>,
+     *		<code>YES_NO_CANCEL_OPTION</code> or
+     *		<code>OK_CANCEL_OPTION</code>), or
+     *		<code>UNSPECIFIED_OPTION</code> if this
+     *		<code>ConfirmationCallback</code> was instantiated with
+     *		<code>options</code> instead of an <code>optionType</code>.
+     */
+    public int getOptionType() {
+	return optionType;
+    }
+
+    /**
+     * Get the confirmation options.
+     *
+     * <p>
+     *
+     * @return the list of confirmation options, or null if this
+     *		<code>ConfirmationCallback</code> was instantiated with
+     *		an <code>optionType</code> instead of <code>options</code>.
+     */
+    public String[] getOptions() {
+	return options;
+    }
+
+    /**
+     * Get the default option.
+     *
+     * <p>
+     *
+     * @return the default option, represented as
+     *		<code>YES</code>, <code>NO</code>, <code>OK</code> or
+     *		<code>CANCEL</code> if an <code>optionType</code>
+     *		was specified to the constructor of this
+     *		<code>ConfirmationCallback</code>.
+     *		Otherwise, this method returns the default option as
+     *		an index into the
+     *		<code>options</code> array specified to the constructor
+     *		of this <code>ConfirmationCallback</code>.
+     */
+    public int getDefaultOption() {
+	return defaultOption;
+    }
+
+    /**
+     * Set the selected confirmation option.
+     *
+     * <p>
+     *
+     * @param selection the selection represented as <code>YES</code>,
+     *		<code>NO</code>, <code>OK</code> or <code>CANCEL</code>
+     *		if an <code>optionType</code> was specified to the constructor
+     *		of this <code>ConfirmationCallback</code>.
+     *		Otherwise, the selection represents the index into the
+     *		<code>options</code> array specified to the constructor
+     *		of this <code>ConfirmationCallback</code>.
+     *
+     * @see #getSelectedIndex
+     */
+    public void setSelectedIndex(int selection) {
+	this.selection = selection;
+    }
+
+    /**
+     * Get the selected confirmation option.
+     *
+     * <p>
+     *
+     * @return the selected confirmation option represented as
+     *		<code>YES</code>, <code>NO</code>, <code>OK</code> or
+     *		<code>CANCEL</code> if an <code>optionType</code>
+     *		was specified to the constructor of this
+     *		<code>ConfirmationCallback</code>.
+     *		Otherwise, this method returns the selected confirmation
+     *		option as an index into the
+     *		<code>options</code> array specified to the constructor
+     *		of this <code>ConfirmationCallback</code>.
+     *
+     * @see #setSelectedIndex
+     */
+    public int getSelectedIndex() {
+	return selection;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/auth/callback/LanguageCallback.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,80 @@
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.auth.callback;
+
+import java.util.Locale;
+
+/**
+ * <p> Underlying security services instantiate and pass a
+ * <code>LanguageCallback</code> to the <code>handle</code>
+ * method of a <code>CallbackHandler</code> to retrieve the <code>Locale</code>
+ * used for localizing text.
+ *
+ * @version 1.21, 05/05/07
+ * @see javax.security.auth.callback.CallbackHandler
+ */
+public class LanguageCallback implements Callback, java.io.Serializable {
+
+    private static final long serialVersionUID = 2019050433478903213L;
+
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private Locale locale;
+
+    /**
+     * Construct a <code>LanguageCallback</code>.
+     */
+    public LanguageCallback() { }
+
+    /**
+     * Set the retrieved <code>Locale</code>.
+     *
+     * <p>
+     *
+     * @param locale the retrieved <code>Locale</code>.
+     *
+     * @see #getLocale
+     */
+    public void setLocale(Locale locale) {
+	this.locale = locale;
+    }
+ 
+    /**
+     * Get the retrieved <code>Locale</code>.
+     *
+     * <p>
+     *
+     * @return the retrieved <code>Locale</code>, or null
+     *		if no <code>Locale</code> could be retrieved.
+     *
+     * @see #setLocale
+     */
+    public Locale getLocale() {
+	return locale;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/auth/callback/NameCallback.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,145 @@
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.auth.callback;
+
+/**
+ * <p> Underlying security services instantiate and pass a
+ * <code>NameCallback</code> to the <code>handle</code>
+ * method of a <code>CallbackHandler</code> to retrieve name information.
+ *
+ * @version 1.21, 05/05/07
+ * @see javax.security.auth.callback.CallbackHandler
+ */
+public class NameCallback implements Callback, java.io.Serializable {
+
+    private static final long serialVersionUID = 3770938795909392253L;
+
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String prompt;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String defaultName;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String inputName;
+
+    /**
+     * Construct a <code>NameCallback</code> with a prompt.
+     *
+     * <p>
+     *
+     * @param prompt the prompt used to request the name.
+     *
+     * @exception IllegalArgumentException if <code>prompt</code> is null
+     *			or if <code>prompt</code> has a length of 0.
+     */
+    public NameCallback(String prompt) {
+	if (prompt == null || prompt.length() == 0)
+	    throw new IllegalArgumentException();
+	this.prompt = prompt;
+    }
+
+    /**
+     * Construct a <code>NameCallback</code> with a prompt
+     * and default name.
+     *
+     * <p>
+     *
+     * @param prompt the prompt used to request the information. <p>
+     *
+     * @param defaultName the name to be used as the default name displayed 
+     *			with the prompt.
+     *
+     * @exception IllegalArgumentException if <code>prompt</code> is null,
+     *			if <code>prompt</code> has a length of 0,
+     *			if <code>defaultName</code> is null,
+     *			or if <code>defaultName</code> has a length of 0.
+     */
+    public NameCallback(String prompt, String defaultName) {
+	if (prompt == null || prompt.length() == 0 ||
+	    defaultName == null || defaultName.length() == 0)
+	    throw new IllegalArgumentException();
+
+	this.prompt = prompt;
+	this.defaultName = defaultName;
+    }
+
+    /**
+     * Get the prompt.
+     *
+     * <p>
+     *
+     * @return the prompt.
+     */
+    public String getPrompt() {
+	return prompt;
+    }
+
+    /**
+     * Get the default name.
+     *
+     * <p>
+     *
+     * @return the default name, or null if this <code>NameCallback</code>
+     *		was not instantiated with a <code>defaultName</code>.
+     */
+    public String getDefaultName() {
+	return defaultName;
+    }
+
+    /**
+     * Set the retrieved name.
+     *
+     * <p>
+     *
+     * @param name the retrieved name (which may be null).
+     *
+     * @see #getName
+     */
+    public void setName(String name) {
+	this.inputName = name;
+    }
+
+    /**
+     * Get the retrieved name.
+     *
+     * <p>
+     *
+     * @return the retrieved name (which may be null)
+     *
+     * @see #setName
+     */
+    public String getName() {
+	return inputName;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/auth/callback/TextInputCallback.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,146 @@
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.auth.callback;
+
+/**
+ * <p> Underlying security services instantiate and pass a
+ * <code>TextInputCallback</code> to the <code>handle</code>
+ * method of a <code>CallbackHandler</code> to retrieve generic text
+ * information.
+ *
+ * @version 1.21, 05/05/07
+ * @see javax.security.auth.callback.CallbackHandler
+ */
+public class TextInputCallback implements Callback, java.io.Serializable {
+
+    private static final long serialVersionUID = -8064222478852811804L;
+
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String prompt;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String defaultText;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String inputText;
+
+    /**
+     * Construct a <code>TextInputCallback</code> with a prompt.
+     *
+     * <p>
+     *
+     * @param prompt the prompt used to request the information.
+     *
+     * @exception IllegalArgumentException if <code>prompt</code> is null
+     *			or if <code>prompt</code> has a length of 0.
+     */
+    public TextInputCallback(String prompt) {
+	if (prompt == null || prompt.length() == 0)
+	    throw new IllegalArgumentException();
+	this.prompt = prompt;
+    }
+
+    /**
+     * Construct a <code>TextInputCallback</code> with a prompt
+     * and default input value.
+     *
+     * <p>
+     *
+     * @param prompt the prompt used to request the information. <p>
+     *
+     * @param defaultText the text to be used as the default text displayed
+     *			with the prompt.
+     *
+     * @exception IllegalArgumentException if <code>prompt</code> is null,
+     *			if <code>prompt</code> has a length of 0,
+     *			if <code>defaultText</code> is null
+     *			or if <code>defaultText</code> has a length of 0.
+     */
+    public TextInputCallback(String prompt, String defaultText) {
+	if (prompt == null || prompt.length() == 0 ||
+	    defaultText == null || defaultText.length() == 0)
+	    throw new IllegalArgumentException();
+
+	this.prompt = prompt;
+	this.defaultText = defaultText;
+    }
+
+    /**
+     * Get the prompt.
+     *
+     * <p>
+     *
+     * @return the prompt.
+     */
+    public String getPrompt() {
+	return prompt;
+    }
+
+    /**
+     * Get the default text.
+     *
+     * <p>
+     *
+     * @return the default text, or null if this <code>TextInputCallback</code>
+     *		was not instantiated with <code>defaultText</code>.
+     */
+    public String getDefaultText() {
+	return defaultText;
+    }
+
+    /**
+     * Set the retrieved text.
+     *
+     * <p>
+     *
+     * @param text the retrieved text, which may be null.
+     *
+     * @see #getText
+     */
+    public void setText(String text) {
+	this.inputText = text;
+    }
+
+    /**
+     * Get the retrieved text.
+     *
+     * <p>
+     *
+     * @return the retrieved text, which may be null.
+     *
+     * @see #setText
+     */
+    public String getText() {
+	return inputText;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/auth/callback/TextOutputCallback.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,108 @@
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.auth.callback;
+
+/**
+ * <p> Underlying security services instantiate and pass a
+ * <code>TextOutputCallback</code> to the <code>handle</code>
+ * method of a <code>CallbackHandler</code> to display information messages,
+ * warning messages and error messages.
+ *
+ * @version 1.22, 05/05/07
+ * @see javax.security.auth.callback.CallbackHandler
+ */
+public class TextOutputCallback implements Callback, java.io.Serializable {
+
+    private static final long serialVersionUID = 1689502495511663102L;
+
+    /** Information message. */
+    public static final int INFORMATION		= 0;
+    /** Warning message. */
+    public static final int WARNING		= 1;
+    /** Error message. */
+    public static final int ERROR		= 2;
+
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private int messageType;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String message;
+
+    /**
+     * Construct a TextOutputCallback with a message type and message
+     * to be displayed.
+     *
+     * <p>
+     *
+     * @param messageType the message type (<code>INFORMATION</code>,
+     *			<code>WARNING</code> or <code>ERROR</code>). <p>
+     *
+     * @param message the message to be displayed. <p>
+     *
+     * @exception IllegalArgumentException if <code>messageType</code>
+     *			is not either <code>INFORMATION</code>,
+     *			<code>WARNING</code> or <code>ERROR</code>,
+     *			if <code>message</code> is null,
+     *			or if <code>message</code> has a length of 0.
+     */
+    public TextOutputCallback(int messageType, String message) {
+	if ((messageType != INFORMATION &&
+		messageType != WARNING && messageType != ERROR) ||
+	    message == null || message.length() == 0)
+	    throw new IllegalArgumentException();
+
+	this.messageType = messageType;
+	this.message = message;
+    }
+
+    /**
+     * Get the message type.
+     *
+     * <p>
+     *
+     * @return the message type (<code>INFORMATION</code>,
+     *			<code>WARNING</code> or <code>ERROR</code>).
+     */
+    public int getMessageType() {
+	return messageType;
+    }
+
+    /**
+     * Get the message to be displayed.
+     *
+     * <p>
+     *
+     * @return the message to be displayed.
+     */
+    public String getMessage() {
+	return message;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/sasl/AuthenticationException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.sasl;
+
+/**
+ * This exception is thrown by a SASL mechanism implementation 
+ * to indicate that the SASL
+ * exchange has failed due to reasons related to authentication, such as 
+ * an invalid identity, passphrase, or key.
+ * <p>
+ * Note that the lack of an AuthenticationException does not mean that
+ * the failure was not due to an authentication error.  A SASL mechanism
+ * implementation might throw the more general SaslException instead of
+ * AuthenticationException if it is unable to determine the nature
+ * of the failure, or if does not want to disclose the nature of
+ * the failure, for example, due to security reasons.
+ *
+ * @since 1.5
+ *
+ * @author Rosanna Lee
+ * @author Rob Weltman
+ */
+public class AuthenticationException extends SaslException {
+    /**
+     * Constructs a new instance of <tt>AuthenticationException</tt>.
+     * The root exception and the detailed message are null.
+     */
+    public AuthenticationException () {
+	super();
+    }
+
+    /**
+     * Constructs a new instance of <tt>AuthenticationException</tt> 
+     * with a detailed message.
+     * The root exception is null.
+     * @param detail A possibly null string containing details of the exception.
+     *
+     * @see java.lang.Throwable#getMessage
+     */
+    public AuthenticationException (String detail) {
+	super(detail);
+    }
+
+    /**
+     * Constructs a new instance of <tt>AuthenticationException</tt> with a detailed message
+     * and a root exception.
+     *
+     * @param detail A possibly null string containing details of the exception.
+     * @param ex A possibly null root exception that caused this exception.
+     *
+     * @see java.lang.Throwable#getMessage
+     * @see #getCause
+     */
+    public AuthenticationException (String detail, Throwable ex) {
+	super(detail, ex);
+    }
+
+    /** Use serialVersionUID from JSR 28 RI for interoperability */ 
+    private static final long serialVersionUID = -3579708765071815007L;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/sasl/Sasl.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,606 @@
+/*
+ * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.sasl;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import java.security.Provider;
+import java.security.Security;
+
+/**
+ * A static class for creating SASL clients and servers.
+ *<p>
+ * This class defines the policy of how to locate, load, and instantiate
+ * SASL clients and servers. 
+ *<p>
+ * For example, an application or library gets a SASL client by doing
+ * something like:
+ *<blockquote><pre>
+ * SaslClient sc = Sasl.createSaslClient(mechanisms,
+ *     authorizationId, protocol, serverName, props, callbackHandler);
+ *</pre></blockquote>
+ * It can then proceed to use the instance to create an authentication connection.
+ *<p>
+ * Similarly, a server gets a SASL server by using code that looks as follows:
+ *<blockquote><pre>
+ * SaslServer ss = Sasl.createSaslServer(mechanism,
+ *     protocol, serverName, props, callbackHandler);
+ *</pre></blockquote>
+ * 
+ * @since 1.5
+ *
+ * @author Rosanna Lee
+ * @author Rob Weltman
+ */
+public class Sasl {
+    // Cannot create one of these
+    private Sasl() { 
+    }
+
+    /**
+     * The name of a property that specifies the quality-of-protection to use.
+     * The property contains a comma-separated, ordered list
+     * of quality-of-protection values that the
+     * client or server is willing to support.  A qop value is one of
+     * <ul>
+     * <li><tt>"auth"</tt> - authentication only</li>
+     * <li><tt>"auth-int"</tt> - authentication plus integrity protection</li>
+     * <li><tt>"auth-conf"</tt> - authentication plus integrity and confidentiality
+     * protection</li>
+     * </ul>
+     *
+     * The order of the list specifies the preference order of the client or
+     * server. If this property is absent, the default qop is <tt>"auth"</tt>.
+     * The value of this constant is <tt>"javax.security.sasl.qop"</tt>.
+     */
+    public static final String QOP = "javax.security.sasl.qop";
+
+    /**
+     * The name of a property that specifies the cipher strength to use.
+     * The property contains a comma-separated, ordered list
+     * of cipher strength values that
+     * the client or server is willing to support. A strength value is one of
+     * <ul>
+     * <li><tt>"low"</tt></li>
+     * <li><tt>"medium"</tt></li>
+     * <li><tt>"high"</tt></li>
+     * </ul>
+     * The order of the list specifies the preference order of the client or
+     * server.  An implementation should allow configuration of the meaning
+     * of these values.  An application may use the Java Cryptography
+     * Extension (JCE) with JCE-aware mechanisms to control the selection of
+     * cipher suites that match the strength values.
+     * <BR>
+     * If this property is absent, the default strength is 
+     * <tt>"high,medium,low"</tt>.
+     * The value of this constant is <tt>"javax.security.sasl.strength"</tt>.
+     */
+    public static final String STRENGTH = "javax.security.sasl.strength";
+
+    /**
+     * The name of a property that specifies whether the
+     * server must authenticate to the client. The property contains 
+     * <tt>"true"</tt> if the server must
+     * authenticate the to client; <tt>"false"</tt> otherwise.
+     * The default is <tt>"false"</tt>.
+     * <br>The value of this constant is
+     * <tt>"javax.security.sasl.server.authentication"</tt>.
+     */
+    public static final String SERVER_AUTH = 
+    "javax.security.sasl.server.authentication";
+
+    /**
+     * The name of a property that specifies the maximum size of the receive
+     * buffer in bytes of <tt>SaslClient</tt>/<tt>SaslServer</tt>.
+     * The property contains the string representation of an integer.
+     * <br>If this property is absent, the default size
+     * is defined by the mechanism.
+     * <br>The value of this constant is <tt>"javax.security.sasl.maxbuffer"</tt>.
+     */
+    public static final String MAX_BUFFER = "javax.security.sasl.maxbuffer";
+
+    /**
+     * The name of a property that specifies the maximum size of the raw send
+     * buffer in bytes of <tt>SaslClient</tt>/<tt>SaslServer</tt>.
+     * The property contains the string representation of an integer.
+     * The value of this property is negotiated between the client and server
+     * during the authentication exchange.
+     * <br>The value of this constant is <tt>"javax.security.sasl.rawsendsize"</tt>.
+     */
+    public static final String RAW_SEND_SIZE = "javax.security.sasl.rawsendsize";
+
+    /**
+     * The name of a property that specifies whether to reuse previously
+     * authenticated session information. The property contains "true" if the
+     * mechanism implementation may attempt to reuse previously authenticated
+     * session information; it contains "false" if the implementation must
+     * not reuse previously authenticated session information.  A setting of
+     * "true" serves only as a hint: it does not necessarily entail actual
+     * reuse because reuse might not be possible due to a number of reasons,
+     * including, but not limited to, lack of mechanism support for reuse,
+     * expiration of reusable information, and the peer's refusal to support
+     * reuse.
+     *
+     * The property's default value is "false".  The value of this constant
+     * is "javax.security.sasl.reuse".
+     *
+     * Note that all other parameters and properties required to create a
+     * SASL client/server instance must be provided regardless of whether
+     * this property has been supplied. That is, you cannot supply any less
+     * information in anticipation of reuse.
+     * 
+     * Mechanism implementations that support reuse might allow customization
+     * of its implementation, for factors such as cache size, timeouts, and
+     * criteria for reuseability. Such customizations are
+     * implementation-dependent.
+     */
+     public static final String REUSE = "javax.security.sasl.reuse";
+
+    /**
+     * The name of a property that specifies
+     * whether mechanisms susceptible to simple plain passive attacks (e.g.,
+     * "PLAIN") are not permitted. The property
+     * contains <tt>"true"</tt> if such mechanisms are not permitted;
+     * <tt>"false"</tt> if such mechanisms are permitted.
+     * The default is <tt>"false"</tt>.
+     * <br>The value of this constant is 
+     * <tt>"javax.security.sasl.policy.noplaintext"</tt>.
+     */
+    public static final String POLICY_NOPLAINTEXT =
+    "javax.security.sasl.policy.noplaintext";
+
+    /**
+     * The name of a property that specifies whether
+     * mechanisms susceptible to active (non-dictionary) attacks
+     * are not permitted.
+     * The property contains <tt>"true"</tt> 
+     * if mechanisms susceptible to active attacks
+     * are not permitted; <tt>"false"</tt> if such mechanisms are permitted.
+     * The default is <tt>"false"</tt>.
+     * <br>The value of this constant is 
+     * <tt>"javax.security.sasl.policy.noactive"</tt>.
+     */
+    public static final String POLICY_NOACTIVE =
+    "javax.security.sasl.policy.noactive";
+
+    /**
+     * The name of a property that specifies whether
+     * mechanisms susceptible to passive dictionary attacks are not permitted.
+     * The property contains <tt>"true"</tt>
+     * if mechanisms susceptible to dictionary attacks are not permitted;
+     * <tt>"false"</tt> if such mechanisms are permitted.
+     * The default is <tt>"false"</tt>.
+     *<br>
+     * The value of this constant is 
+     * <tt>"javax.security.sasl.policy.nodictionary"</tt>.
+     */
+    public static final String POLICY_NODICTIONARY =
+    "javax.security.sasl.policy.nodictionary";
+
+    /**
+     * The name of a property that specifies whether mechanisms that accept
+     * anonymous login are not permitted. The property contains <tt>"true"</tt> 
+     * if mechanisms that accept anonymous login are not permitted; 
+     * <tt>"false"</tt>
+     * if such mechanisms are permitted. The default is <tt>"false"</tt>.
+     *<br>
+     * The value of this constant is 
+     * <tt>"javax.security.sasl.policy.noanonymous"</tt>.
+     */
+    public static final String POLICY_NOANONYMOUS =
+    "javax.security.sasl.policy.noanonymous";
+
+     /** 
+      * The name of a property that specifies whether mechanisms that implement
+      * forward secrecy between sessions are required. Forward secrecy
+      * means that breaking into one session will not automatically
+      * provide information for breaking into future sessions. 
+      * The property
+      * contains <tt>"true"</tt> if mechanisms that implement forward secrecy 
+      * between sessions are required; <tt>"false"</tt> if such mechanisms 
+      * are not required. The default is <tt>"false"</tt>.
+      *<br>
+      * The value of this constant is 
+      * <tt>"javax.security.sasl.policy.forward"</tt>.
+      */
+    public static final String POLICY_FORWARD_SECRECY =
+    "javax.security.sasl.policy.forward";
+
+    /**
+     * The name of a property that specifies whether
+     * mechanisms that pass client credentials are required. The property
+     * contains <tt>"true"</tt> if mechanisms that pass
+     * client credentials are required; <tt>"false"</tt>
+     * if such mechanisms are not required. The default is <tt>"false"</tt>.
+     *<br>
+     * The value of this constant is 
+     * <tt>"javax.security.sasl.policy.credentials"</tt>.
+     */
+    public static final String POLICY_PASS_CREDENTIALS =
+    "javax.security.sasl.policy.credentials";
+
+    /**
+     * The name of a property that specifies the credentials to use.
+     * The property contains a mechanism-specific Java credential object.
+     * Mechanism implementations may examine the value of this property 
+     * to determine whether it is a class that they support.
+     * The property may be used to supply credentials to a mechanism that
+     * supports delegated authentication.
+     *<br>
+     * The value of this constant is 
+     * <tt>"javax.security.sasl.credentials"</tt>.
+     */
+    public static final String CREDENTIALS = "javax.security.sasl.credentials";
+
+    /**
+     * Creates a <tt>SaslClient</tt> using the parameters supplied.
+     *
+     * This method uses the 
+<a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#Provider">JCA Security Provider Framework</a>, described in the 
+     * "Java Cryptography Architecture API Specification & Reference", for
+     * locating and selecting a <tt>SaslClient</tt> implementation.
+     *
+     * First, it 
+     * obtains an ordered list of <tt>SaslClientFactory</tt> instances from
+     * the registered security providers for the "SaslClientFactory" service
+     * and the specified SASL mechanism(s). It then invokes
+     * <tt>createSaslClient()</tt> on each factory instance on the list
+     * until one produces a non-null <tt>SaslClient</tt> instance. It returns
+     * the non-null <tt>SaslClient</tt> instance, or null if the search fails
+     * to produce a non-null <tt>SaslClient</tt> instance.
+     *<p>
+     * A security provider for SaslClientFactory registers with the
+     * JCA Security Provider Framework keys of the form <br>
+     * <tt>SaslClientFactory.<em>mechanism_name</em></tt>
+     * <br>
+     * and values that are class names of implementations of 
+     * <tt>javax.security.sasl.SaslClientFactory</tt>.
+     *
+     * For example, a provider that contains a factory class,
+     * <tt>com.wiz.sasl.digest.ClientFactory</tt>, that supports the
+     * "DIGEST-MD5" mechanism would register the following entry with the JCA:
+     * <tt>SaslClientFactory.DIGEST-MD5 com.wiz.sasl.digest.ClientFactory</tt>
+     *<p>
+     * See the
+     * "Java Cryptography Architecture API Specification & Reference" 
+     * for information about how to install and configure security service
+     *  providers.
+     *
+     * @param mechanisms The non-null list of mechanism names to try. Each is the
+     * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
+     * @param authorizationId The possibly null protocol-dependent 
+     * identification to be used for authorization.
+     * If null or empty, the server derives an authorization 
+     * ID from the client's authentication credentials.
+     * When the SASL authentication completes successfully, 
+     * the specified entity is granted access. 
+     *
+     * @param protocol The non-null string name of the protocol for which
+     * the authentication is being performed (e.g., "ldap").
+     *
+     * @param serverName The non-null fully-qualified host name of the server
+     * to authenticate to.
+     *
+     * @param props The possibly null set of properties used to
+     * select the SASL mechanism and to configure the authentication
+     * exchange of the selected mechanism.
+     * For example, if <tt>props</tt> contains the 
+     * <code>Sasl.POLICY_NOPLAINTEXT</code> property with the value 
+     * <tt>"true"</tt>, then the selected
+     * SASL mechanism must not be susceptible to simple plain passive attacks.
+     * In addition to the standard properties declared in this class, 
+     * other, possibly mechanism-specific, properties can be included. 
+     * Properties not relevant to the selected mechanism are ignored,
+     * including any map entries with non-String keys.
+     *
+     * @param cbh The possibly null callback handler to used by the SASL
+     * mechanisms to get further information from the application/library
+     * to complete the authentication. For example, a SASL mechanism might
+     * require the authentication ID, password and realm from the caller.
+     * The authentication ID is requested by using a <tt>NameCallback</tt>.
+     * The password is requested by using a <tt>PasswordCallback</tt>.
+     * The realm is requested by using a <tt>RealmChoiceCallback</tt> if there is a list
+     * of realms to choose from, and by using a <tt>RealmCallback</tt> if
+     * the realm must be entered. 
+     *
+     *@return A possibly null <tt>SaslClient</tt> created using the parameters
+     * supplied. If null, cannot find a <tt>SaslClientFactory</tt>
+     * that will produce one.
+     *@exception SaslException If cannot create a <tt>SaslClient</tt> because
+     * of an error.
+     */
+    public static SaslClient createSaslClient(
+	String[] mechanisms,
+	String authorizationId,
+	String protocol,
+	String serverName,
+	Map<String,?> props,
+	CallbackHandler cbh) throws SaslException {
+        
+        SaslClient mech = null;
+	SaslClientFactory fac;
+	String className;
+	String mechName;
+
+	for (int i = 0; i < mechanisms.length; i++) {
+	    if ((mechName=mechanisms[i]) == null) {
+		throw new NullPointerException(
+		    "Mechanism name cannot be null");
+	    } else if (mechName.length() == 0) {
+		continue;
+	    }
+	    String mechFilter = "SaslClientFactory." + mechName;
+	    Provider[] provs = Security.getProviders(mechFilter);
+	    for (int j = 0; provs != null && j < provs.length; j++) {
+		className = provs[j].getProperty(mechFilter);
+		if (className == null) {
+		    // Case is ignored
+		    continue;
+		}
+
+		fac = (SaslClientFactory) loadFactory(provs[j], className);
+		if (fac != null) {
+		    mech = fac.createSaslClient(
+			new String[]{mechanisms[i]}, authorizationId, 
+			protocol, serverName, props, cbh);
+		    if (mech != null) {
+			return mech;
+		    }
+		}
+	    }
+	}
+
+	return null;
+    }
+
+    private static Object loadFactory(Provider p, String className) 
+	throws SaslException {
+	try {
+	    /*  
+	     * Load the implementation class with the same class loader
+	     * that was used to load the provider.
+	     * In order to get the class loader of a class, the
+	     * caller's class loader must be the same as or an ancestor of
+	     * the class loader being returned. Otherwise, the caller must
+	     * have "getClassLoader" permission, or a SecurityException
+	     * will be thrown.
+	     */
+	    ClassLoader cl = p.getClass().getClassLoader();
+	    Class implClass;
+	    implClass = Class.forName(className, true, cl);
+	    return implClass.newInstance();
+	} catch (ClassNotFoundException e) {
+	    throw new SaslException("Cannot load class " + className, e);
+	} catch (InstantiationException e) {
+	    throw new SaslException("Cannot instantiate class " + className, e);
+	} catch (IllegalAccessException e) {
+	    throw new SaslException("Cannot access class " + className, e);
+	} catch (SecurityException e) {
+	    throw new SaslException("Cannot access class " + className, e);
+	}
+    }
+
+    
+    /**
+     * Creates a <tt>SaslServer</tt> for the specified mechanism. 
+     *
+     * This method uses the 
+<a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#Provider">JCA Security Provider Framework</a>, 
+     * described in the 
+     * "Java Cryptography Architecture API Specification & Reference", for
+     * locating and selecting a <tt>SaslServer</tt> implementation.
+     *
+     * First, it 
+     * obtains an ordered list of <tt>SaslServerFactory</tt> instances from
+     * the registered security providers for the "SaslServerFactory" service
+     * and the specified mechanism. It then invokes
+     * <tt>createSaslServer()</tt> on each factory instance on the list
+     * until one produces a non-null <tt>SaslServer</tt> instance. It returns
+     * the non-null <tt>SaslServer</tt> instance, or null if the search fails
+     * to produce a non-null <tt>SaslServer</tt> instance.
+     *<p>
+     * A security provider for SaslServerFactory registers with the
+     * JCA Security Provider Framework keys of the form <br>
+     * <tt>SaslServerFactory.<em>mechanism_name</em></tt>
+     * <br>
+     * and values that are class names of implementations of 
+     * <tt>javax.security.sasl.SaslServerFactory</tt>.
+     *
+     * For example, a provider that contains a factory class,
+     * <tt>com.wiz.sasl.digest.ServerFactory</tt>, that supports the
+     * "DIGEST-MD5" mechanism would register the following entry with the JCA:
+     * <tt>SaslServerFactory.DIGEST-MD5  com.wiz.sasl.digest.ServerFactory</tt>
+     *<p>
+     * See the
+     * "Java Cryptography Architecture API Specification & Reference" 
+     * for information about how to install and configure security 
+     * service providers.
+     *
+     * @param mechanism The non-null mechanism name. It must be an
+     * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
+     * @param protocol The non-null string name of the protocol for which
+     * the authentication is being performed (e.g., "ldap").
+     * @param serverName The non-null fully qualified host name of the server.
+     * @param props The possibly null set of properties used to
+     * select the SASL mechanism and to configure the authentication
+     * exchange of the selected mechanism.
+     * For example, if <tt>props</tt> contains the 
+     * <code>Sasl.POLICY_NOPLAINTEXT</code> property with the value 
+     * <tt>"true"</tt>, then the selected
+     * SASL mechanism must not be susceptible to simple plain passive attacks.
+     * In addition to the standard properties declared in this class, 
+     * other, possibly mechanism-specific, properties can be included. 
+     * Properties not relevant to the selected mechanism are ignored,
+     * including any map entries with non-String keys.
+     *
+     * @param cbh The possibly null callback handler to used by the SASL
+     * mechanisms to get further information from the application/library
+     * to complete the authentication. For example, a SASL mechanism might
+     * require the authentication ID, password and realm from the caller.
+     * The authentication ID is requested by using a <tt>NameCallback</tt>.
+     * The password is requested by using a <tt>PasswordCallback</tt>.
+     * The realm is requested by using a <tt>RealmChoiceCallback</tt> if there is a list
+     * of realms to choose from, and by using a <tt>RealmCallback</tt> if
+     * the realm must be entered. 
+     *
+     *@return A possibly null <tt>SaslServer</tt> created using the parameters
+     * supplied. If null, cannot find a <tt>SaslServerFactory</tt>
+     * that will produce one.
+     *@exception SaslException If cannot create a <tt>SaslServer</tt> because
+     * of an error.
+     **/
+    public static SaslServer
+	createSaslServer(String mechanism,
+                    String protocol,
+                    String serverName,
+                    Map<String,?> props,
+                    javax.security.auth.callback.CallbackHandler cbh)
+	throws SaslException {
+
+        SaslServer mech = null;
+	SaslServerFactory fac;
+	String className;
+
+	if (mechanism == null) {
+	    throw new NullPointerException("Mechanism name cannot be null");
+	} else if (mechanism.length() == 0) {
+	    return null;
+	}
+
+	String mechFilter = "SaslServerFactory." + mechanism;
+	Provider[] provs = Security.getProviders(mechFilter);
+	for (int j = 0; provs != null && j < provs.length; j++) {
+	    className = provs[j].getProperty(mechFilter);
+	    if (className == null) {
+		throw new SaslException("Provider does not support " +
+		    mechFilter);
+	    }
+	    fac = (SaslServerFactory) loadFactory(provs[j], className);
+	    if (fac != null) {
+		mech = fac.createSaslServer(
+		    mechanism, protocol, serverName, props, cbh);
+		if (mech != null) {
+		    return mech;
+		}
+	    }
+	}
+
+	return null;
+    }
+
+    /**
+     * Gets an enumeration of known factories for producing <tt>SaslClient</tt>.
+     * This method uses the same algorithm for locating factories as
+     * <tt>createSaslClient()</tt>.
+     * @return A non-null enumeration of known factories for producing
+     * <tt>SaslClient</tt>.
+     * @see #createSaslClient
+     */
+    public static Enumeration<SaslClientFactory> getSaslClientFactories() {
+	Set<Object> facs = getFactories("SaslClientFactory");
+	final Iterator<Object> iter = facs.iterator();
+	return new Enumeration<SaslClientFactory>() {
+	    public boolean hasMoreElements() {
+		return iter.hasNext();
+	    }
+	    public SaslClientFactory nextElement() {
+		return (SaslClientFactory)iter.next();
+	    }
+	};
+    }
+
+    /**
+     * Gets an enumeration of known factories for producing <tt>SaslServer</tt>.
+     * This method uses the same algorithm for locating factories as
+     * <tt>createSaslServer()</tt>.
+     * @return A non-null enumeration of known factories for producing
+     * <tt>SaslServer</tt>.
+     * @see #createSaslServer
+     */
+    public static Enumeration<SaslServerFactory> getSaslServerFactories() {
+	Set<Object> facs = getFactories("SaslServerFactory");
+	final Iterator<Object> iter = facs.iterator();
+	return new Enumeration<SaslServerFactory>() {
+	    public boolean hasMoreElements() {
+		return iter.hasNext();
+	    }
+	    public SaslServerFactory nextElement() {
+		return (SaslServerFactory)iter.next();
+	    }
+	};
+    }
+
+    private static Set<Object> getFactories(String serviceName) {
+	HashSet<Object> result = new HashSet<Object>();
+
+	if ((serviceName == null) || (serviceName.length() == 0) ||
+	    (serviceName.endsWith("."))) {
+	    return result;
+	}
+
+
+	Provider[] providers = Security.getProviders();
+	HashSet<String> classes = new HashSet<String>();
+	Object fac;
+
+	for (int i = 0; i < providers.length; i++) {
+	    classes.clear();
+
+	    // Check the keys for each provider.
+	    for (Enumeration e = providers[i].keys(); e.hasMoreElements(); ) {
+		String currentKey = (String)e.nextElement();
+		if (currentKey.startsWith(serviceName)) {
+		    // We should skip the currentKey if it contains a 
+		    // whitespace. The reason is: such an entry in the
+		    // provider property contains attributes for the
+		    // implementation of an algorithm. We are only interested
+		    // in entries which lead to the implementation
+		    // classes.
+		    if (currentKey.indexOf(" ") < 0) {
+			String className = providers[i].getProperty(currentKey);
+			if (!classes.contains(className)) {
+			    classes.add(className);
+			    try {
+				fac = loadFactory(providers[i], className);
+				if (fac != null) {
+				    result.add(fac);
+				} 
+			    }catch (Exception ignore) {
+			    }
+			}
+		    }
+		}
+	    }
+	}
+	return Collections.unmodifiableSet(result);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/sasl/SaslClient.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,225 @@
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.sasl;
+
+/**
+ * Performs SASL authentication as a client.
+ *<p>
+ * A protocol library such as one for LDAP gets an instance of this
+ * class in order to perform authentication defined by a specific SASL
+ * mechanism. Invoking methods on the <tt>SaslClient</tt> instance
+ * process challenges and create responses according to the SASL
+ * mechanism implemented by the <tt>SaslClient</tt>.
+ * As the authentication proceeds, the instance
+ * encapsulates the state of a SASL client's authentication exchange. 
+ *<p>
+ * Here's an example of how an LDAP library might use a <tt>SaslClient</tt>.
+ * It first gets an instance of a <tt>SaslClient</tt>:
+ *<blockquote><pre>
+ * SaslClient sc = Sasl.createSaslClient(mechanisms,
+ *     authorizationId, protocol, serverName, props, callbackHandler);
+ *</pre></blockquote>
+ * It can then proceed to use the client for authentication.
+ * For example, an LDAP library might use the client as follows:
+ *<blockquote><pre>
+ * // Get initial response and send to server
+ * byte[] response = (sc.hasInitialResponse() ? sc.evaluateChallenge(new byte[0]) :
+ *     null);
+ * LdapResult res = ldap.sendBindRequest(dn, sc.getName(), response);
+ * while (!sc.isComplete() && 
+ *     (res.status == SASL_BIND_IN_PROGRESS || res.status == SUCCESS)) {
+ *     response = sc.evaluateChallenge(res.getBytes());
+ *     if (res.status == SUCCESS) {
+ *         // we're done; don't expect to send another BIND
+ *         if (response != null) {
+ * 	       throw new SaslException(
+ * 	           "Protocol error: attempting to send response after completion");
+ * 	   }
+ *         break;
+ *     }
+ *     res = ldap.sendBindRequest(dn, sc.getName(), response);
+ * }
+ * if (sc.isComplete() && res.status == SUCCESS) {
+ *    String qop = (String) sc.getNegotiatedProperty(Sasl.QOP);
+ *    if (qop != null 
+ *        && (qop.equalsIgnoreCase("auth-int") 
+ *            || qop.equalsIgnoreCase("auth-conf"))) {
+ *
+ *      // Use SaslClient.wrap() and SaslClient.unwrap() for future
+ *      // communication with server
+ *	ldap.in = new SecureInputStream(sc, ldap.in);
+ *	ldap.out = new SecureOutputStream(sc, ldap.out);
+ *    }
+ * }
+ *</pre></blockquote>
+ *
+ * If the mechanism has an initial response, the library invokes
+ * <tt>evaluateChallenge()</tt> with an empty
+ * challenge and to get initial response.
+ * Protocols such as IMAP4, which do not include an initial response with
+ * their first authentication command to the server, initiates the
+ * authentication without first calling <tt>hasInitialResponse()</tt> 
+ * or <tt>evaluateChallenge()</tt>.
+ * When the server responds to the command, it sends an initial challenge.
+ * For a SASL mechanism in which the client sends data first, the server should
+ * have issued a challenge with no data. This will then result in a call
+ * (on the client) to <tt>evaluateChallenge()</tt> with an empty challenge.
+ *
+ * @since 1.5
+ *
+ * @see Sasl
+ * @see SaslClientFactory
+ *
+ * @author Rosanna Lee
+ * @author Rob Weltman
+ */
+public abstract interface SaslClient {
+
+    /**
+     * Returns the IANA-registered mechanism name of this SASL client.
+     * (e.g. "CRAM-MD5", "GSSAPI").
+     * @return A non-null string representing the IANA-registered mechanism name.
+     */
+    public abstract String getMechanismName();
+
+    /**
+     * Determines whether this mechanism has an optional initial response.
+     * If true, caller should call <tt>evaluateChallenge()</tt> with an
+     * empty array to get the initial response.
+     *
+     * @return true if this mechanism has an initial response.
+     */
+    public abstract boolean hasInitialResponse();
+
+    /**
+     * Evaluates the challenge data and generates a response.
+     * If a challenge is received from the server during the authentication 
+     * process, this method is called to prepare an appropriate next 
+     * response to submit to the server.
+     *
+     * @param challenge The non-null challenge sent from the server.
+     * The challenge array may have zero length. 
+     *
+     * @return The possibly null reponse to send to the server.
+     * It is null if the challenge accompanied a "SUCCESS" status and the challenge
+     * only contains data for the client to update its state and no response
+     * needs to be sent to the server. The response is a zero-length byte 
+     * array if the client is to send a response with no data. 
+     * @exception SaslException If an error occurred while processing
+     * the challenge or generating a response.
+     */
+    public abstract byte[] evaluateChallenge(byte[] challenge) 
+	throws SaslException;
+
+    /**
+      * Determines whether the authentication exchange has completed.
+      * This method may be called at any time, but typically, it
+      * will not be called until the caller has received indication
+      * from the server
+      * (in a protocol-specific manner) that the exchange has completed. 
+      *
+      * @return true if the authentication exchange has completed; false otherwise.
+      */
+    public abstract boolean isComplete();
+
+    /**
+     * Unwraps a byte array received from the server.
+     * This method can be called only after the authentication exchange has
+     * completed (i.e., when <tt>isComplete()</tt> returns true) and only if
+     * the authentication exchange has negotiated integrity and/or privacy 
+     * as the quality of protection; otherwise, an 
+     * <tt>IllegalStateException</tt> is thrown.
+     *<p>
+     * <tt>incoming</tt> is the contents of the SASL buffer as defined in RFC 2222
+     * without the leading four octet field that represents the length.
+     * <tt>offset</tt> and <tt>len</tt> specify the portion of <tt>incoming</tt>
+     * to use.
+     *
+     * @param incoming A non-null byte array containing the encoded bytes
+     * 		      from the server.
+     * @param offset The starting position at <tt>incoming</tt> of the bytes to use.
+     * @param len The number of bytes from <tt>incoming</tt> to use.
+     * @return A non-null byte array containing the decoded bytes.
+     * @exception SaslException if <tt>incoming</tt> cannot be successfully 
+     * unwrapped.
+     * @exception IllegalStateException if the authentication exchange has 
+     * not completed, or  if the negotiated quality of protection 
+     * has neither integrity nor privacy.
+     */
+    public abstract byte[] unwrap(byte[] incoming, int offset, int len)
+	throws SaslException;
+
+    /**
+     * Wraps a byte array to be sent to the server.
+     * This method can be called only after the authentication exchange has
+     * completed (i.e., when <tt>isComplete()</tt> returns true) and only if
+     * the authentication exchange has negotiated integrity and/or privacy 
+     * as the quality of protection; otherwise, an 
+     * <tt>IllegalStateException</tt> is thrown.
+     *<p>
+     * The result of this method will make up the contents of the SASL buffer 
+     * as defined in RFC 2222 without the leading four octet field that 
+     * represents the length.
+     * <tt>offset</tt> and <tt>len</tt> specify the portion of <tt>outgoing</tt>
+     * to use.
+     *
+     * @param outgoing A non-null byte array containing the bytes to encode.
+     * @param offset The starting position at <tt>outgoing</tt> of the bytes to use.
+     * @param len The number of bytes from <tt>outgoing</tt> to use.
+     * @return A non-null byte array containing the encoded bytes.
+     * @exception SaslException if <tt>outgoing</tt> cannot be successfully 
+     * wrapped.
+     * @exception IllegalStateException if the authentication exchange has 
+     * not completed, or if the negotiated quality of protection 
+     * has neither integrity nor privacy.
+     */
+    public abstract byte[] wrap(byte[] outgoing, int offset, int len) 
+	throws SaslException;
+
+    /**
+     * Retrieves the negotiated property.
+     * This method can be called only after the authentication exchange has
+     * completed (i.e., when <tt>isComplete()</tt> returns true); otherwise, an
+     * <tt>IllegalStateException</tt> is thrown.
+     * 
+     * @param propName The non-null property name.
+     * @return The value of the negotiated property. If null, the property was
+     * not negotiated or is not applicable to this mechanism.
+     * @exception IllegalStateException if this authentication exchange 
+     * has not completed
+     */
+
+    public abstract Object getNegotiatedProperty(String propName);
+
+     /**
+      * Disposes of any system resources or security-sensitive information
+      * the SaslClient might be using. Invoking this method invalidates
+      * the SaslClient instance. This method is idempotent.
+      * @throws SaslException If a problem was encountered while disposing
+      * the resources.
+      */
+    public abstract void dispose() throws SaslException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/sasl/SaslClientFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.sasl;
+
+import java.util.Map;
+import javax.security.auth.callback.CallbackHandler;
+
+/**
+ * An interface for creating instances of <tt>SaslClient</tt>.
+ * A class that implements this interface
+ * must be thread-safe and handle multiple simultaneous 
+ * requests. It must also have a public constructor that accepts no 
+ * argument. 
+ *<p>
+ * This interface is not normally accessed directly by a client, which will use the
+ * <tt>Sasl</tt> static methods
+ * instead. However, a particular environment may provide and install a
+ * new or different <tt>SaslClientFactory</tt>.
+ * 
+ * @since 1.5
+ *
+ * @see SaslClient
+ * @see Sasl
+ *
+ * @author Rosanna Lee
+ * @author Rob Weltman
+ */
+public abstract interface SaslClientFactory {
+    /**
+     * Creates a SaslClient using the parameters supplied.
+     *
+     * @param mechanisms The non-null list of mechanism names to try. Each is the
+     * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
+     * @param authorizationId The possibly null protocol-dependent 
+     * identification to be used for authorization.
+     * If null or empty, the server derives an authorization 
+     * ID from the client's authentication credentials.
+     * When the SASL authentication completes successfully, 
+     * the specified entity is granted access. 
+     * @param protocol The non-null string name of the protocol for which
+     * the authentication is being performed (e.g., "ldap").
+     * @param serverName The non-null fully qualified host name 
+     * of the server to authenticate to.
+     * @param props The possibly null set of properties used to select the SASL
+     * mechanism and to configure the authentication exchange of the selected
+     * mechanism. See the <tt>Sasl</tt> class for a list of standard properties. 
+     * Other, possibly mechanism-specific, properties can be included.
+     * Properties not relevant to the selected mechanism are ignored,
+     * including any map entries with non-String keys.
+     * 
+     * @param cbh The possibly null callback handler to used by the SASL
+     * mechanisms to get further information from the application/library
+     * to complete the authentication. For example, a SASL mechanism might
+     * require the authentication ID, password and realm from the caller.
+     * The authentication ID is requested by using a <tt>NameCallback</tt>.
+     * The password is requested by using a <tt>PasswordCallback</tt>.
+     * The realm is requested by using a <tt>RealmChoiceCallback</tt> if there is a list
+     * of realms to choose from, and by using a <tt>RealmCallback</tt> if
+     * the realm must be entered. 
+     *
+     *@return A possibly null <tt>SaslClient</tt> created using the parameters
+     * supplied. If null, this factory cannot produce a <tt>SaslClient</tt>
+     * using the parameters supplied.
+     *@exception SaslException If cannot create a <tt>SaslClient</tt> because
+     * of an error.
+     */
+    public abstract SaslClient createSaslClient(
+	String[] mechanisms,
+	String authorizationId,
+	String protocol,
+	String serverName,
+	Map<String,?> props,
+	CallbackHandler cbh) throws SaslException;
+
+    /**
+     * Returns an array of names of mechanisms that match the specified
+     * mechanism selection policies.
+     * @param props The possibly null set of properties used to specify the
+     * security policy of the SASL mechanisms. For example, if <tt>props</tt>
+     * contains the <tt>Sasl.POLICY_NOPLAINTEXT</tt> property with the value
+     * <tt>"true"</tt>, then the factory must not return any SASL mechanisms
+     * that are susceptible to simple plain passive attacks.
+     * See the <tt>Sasl</tt> class for a complete list of policy properties.
+     * Non-policy related properties, if present in <tt>props</tt>, are ignored,
+     * including any map entries with non-String keys.
+     * @return A non-null array containing a IANA-registered SASL mechanism names.
+     */
+    public abstract String[] getMechanismNames(Map<String,?> props);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/sasl/SaslException.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,129 @@
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.sasl;
+
+import java.io.IOException;
+
+/**
+ * This class represents an error that has occurred when using SASL.
+ *
+ * @since 1.5
+ *
+ * @author Rosanna Lee
+ * @author Rob Weltman
+ */
+
+public class SaslException extends IOException {
+    /**
+     * The possibly null root cause exception.
+     * @serial
+     */
+    // Required for serialization interoperability with JSR 28
+    private Throwable _exception;
+
+    /**
+     * Constructs a new instance of <tt>SaslException</tt>.
+     * The root exception and the detailed message are null.
+     */
+    public SaslException () {
+	super();
+    }
+
+    /**
+     * Constructs a new instance of <tt>SaslException</tt> with a detailed message.
+     * The root exception is null.
+     * @param detail A possibly null string containing details of the exception.
+     *
+     * @see java.lang.Throwable#getMessage
+     */
+    public SaslException (String detail) {
+	super(detail);
+    }
+
+    /**
+     * Constructs a new instance of <tt>SaslException</tt> with a detailed message
+     * and a root exception.
+     * For example, a SaslException might result from a problem with
+     * the callback handler, which might throw a NoSuchCallbackException if
+     * it does not support the requested callback, or throw an IOException
+     * if it had problems obtaining data for the callback. The
+     * SaslException's root exception would be then be the exception thrown
+     * by the callback handler.
+     *
+     * @param detail A possibly null string containing details of the exception.
+     * @param ex A possibly null root exception that caused this exception.
+     *
+     * @see java.lang.Throwable#getMessage
+     * @see #getCause
+     */
+    public SaslException (String detail, Throwable ex) {
+	super(detail);
+	if (ex != null) {
+	    initCause(ex);
+	}
+    }
+
+    /*
+     * Override Throwable.getCause() to ensure deserialized object from
+     * JSR 28 would return same value for getCause() (i.e., _exception).
+     */
+    public Throwable getCause() {
+	return _exception;
+    }
+
+    /*
+     * Override Throwable.initCause() to match getCause() by updating
+     * _exception as well.
+     */
+    public Throwable initCause(Throwable cause) {
+	super.initCause(cause);
+	_exception = cause;
+	return this;
+    }
+
+    /**
+     * Returns the string representation of this exception.
+     * The string representation contains
+     * this exception's class name, its detailed messsage, and if
+     * it has a root exception, the string representation of the root
+     * exception. This string representation
+     * is meant for debugging and not meant to be interpreted
+     * programmatically.
+     * @return The non-null string representation of this exception.
+     * @see java.lang.Throwable#getMessage
+     */
+    // Override Throwable.toString() to conform to JSR 28
+    public String toString() {
+	String answer = super.toString();
+	if (_exception != null && _exception != this) {
+	    answer += " [Caused by " + _exception.toString() + "]";
+	}
+	return answer;
+    }
+
+    /** Use serialVersionUID from JSR 28 RI for interoperability */ 
+    private static final long serialVersionUID = 4579784287983423626L;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/sasl/SaslServer.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2000-2004 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.sasl;
+
+/**
+ * Performs SASL authentication as a server.
+ *<p>
+ * A server such an LDAP server gets an instance of this
+ * class in order to perform authentication defined by a specific SASL
+ * mechanism. Invoking methods on the <tt>SaslServer</tt> instance
+ * generates challenges according to the SASL
+ * mechanism implemented by the <tt>SaslServer</tt>.
+ * As the authentication proceeds, the instance
+ * encapsulates the state of a SASL server's authentication exchange. 
+ *<p>
+ * Here's an example of how an LDAP server might use a <tt>SaslServer</tt>.
+ * It first gets an instance of a <tt>SaslServer</tt> for the SASL mechanism
+ * requested by the client:
+ *<blockquote><pre>
+ * SaslServer ss = Sasl.createSaslServer(mechanism,
+ *     "ldap", myFQDN, props, callbackHandler);
+ *</pre></blockquote>
+ * It can then proceed to use the server for authentication.
+ * For example, suppose the LDAP server received an LDAP BIND request
+ * containing the name of the SASL mechanism and an (optional) initial
+ * response. It then might use the server as follows:
+ *<blockquote><pre>
+ * while (!ss.isComplete()) {
+ *     try {
+ *         byte[] challenge = ss.evaluateResponse(response);
+ *         if (ss.isComplete()) {
+ *             status = ldap.sendBindResponse(mechanism, challenge, SUCCESS);
+ *         } else {
+ *             status = ldap.sendBindResponse(mechanism, challenge, 
+	           SASL_BIND_IN_PROGRESS);
+ *             response = ldap.readBindRequest();
+ *         }
+ *     } catch (SaslException e) {
+ * 	    status = ldap.sendErrorResponse(e);
+ * 	    break;
+ *     }
+ * }
+ * if (ss.isComplete() && status == SUCCESS) {
+ *    String qop = (String) sc.getNegotiatedProperty(Sasl.QOP);
+ *    if (qop != null 
+ *        && (qop.equalsIgnoreCase("auth-int") 
+ *            || qop.equalsIgnoreCase("auth-conf"))) {
+ *
+ *      // Use SaslServer.wrap() and SaslServer.unwrap() for future
+ *      // communication with client
+ *	ldap.in = new SecureInputStream(ss, ldap.in);
+ *	ldap.out = new SecureOutputStream(ss, ldap.out);
+ *    }
+ * }
+ *</pre></blockquote>
+ *
+ * @since 1.5
+ *
+ * @see Sasl
+ * @see SaslServerFactory
+ *
+ * @author Rosanna Lee
+ * @author Rob Weltman
+ */
+public abstract interface SaslServer {
+
+    /**
+     * Returns the IANA-registered mechanism name of this SASL server.
+     * (e.g. "CRAM-MD5", "GSSAPI").
+     * @return A non-null string representing the IANA-registered mechanism name.
+     */
+    public abstract String getMechanismName();
+
+    /**
+     * Evaluates the response data and generates a challenge.
+     *
+     * If a response is received from the client during the authentication 
+     * process, this method is called to prepare an appropriate next 
+     * challenge to submit to the client. The challenge is null if the 
+     * authentication has succeeded and no more challenge data is to be sent 
+     * to the client. It is non-null if the authentication must be continued 
+     * by sending a challenge to the client, or if the authentication has 
+     * succeeded but challenge data needs to be processed by the client. 
+     * <tt>isComplete()</tt> should be called 
+     * after each call to <tt>evaluateResponse()</tt>,to determine if any further 
+     * response is needed from the client. 
+     *
+     * @param response The non-null (but possibly empty) response sent
+     * by the client.
+     *
+     * @return The possibly null challenge to send to the client.
+     * It is null if the authentication has succeeded and there is
+     * no more challenge data to be sent to the client.
+     * @exception SaslException If an error occurred while processing
+     * the response or generating a challenge.
+     */
+    public abstract byte[] evaluateResponse(byte[] response) 
+	throws SaslException;
+
+    /**
+      * Determines whether the authentication exchange has completed.
+      * This method is typically called after each invocation of 
+      * <tt>evaluateResponse()</tt> to determine whether the 
+      * authentication has completed successfully or should be continued. 
+      * @return true if the authentication exchange has completed; false otherwise.
+      */
+    public abstract boolean isComplete();
+
+    /**
+     * Reports the authorization ID in effect for the client of this
+     * session. 
+     * This method can only be called if isComplete() returns true. 
+     * @return The authorization ID of the client.
+     * @exception IllegalStateException if this authentication session has not completed
+     */
+    public String getAuthorizationID();
+	
+    /**
+     * Unwraps a byte array received from the client.
+     * This method can be called only after the authentication exchange has
+     * completed (i.e., when <tt>isComplete()</tt> returns true) and only if
+     * the authentication exchange has negotiated integrity and/or privacy 
+     * as the quality of protection; otherwise, 
+     * an <tt>IllegalStateException</tt> is thrown.
+     *<p>
+     * <tt>incoming</tt> is the contents of the SASL buffer as defined in RFC 2222
+     * without the leading four octet field that represents the length.
+     * <tt>offset</tt> and <tt>len</tt> specify the portion of <tt>incoming</tt>
+     * to use.
+     *
+     * @param incoming A non-null byte array containing the encoded bytes
+     * 		      from the client.
+     * @param offset The starting position at <tt>incoming</tt> of the bytes to use.
+     * @param len The number of bytes from <tt>incoming</tt> to use.
+     * @return A non-null byte array containing the decoded bytes.
+     * @exception SaslException if <tt>incoming</tt> cannot be successfully 
+     * unwrapped.
+     * @exception IllegalStateException if the authentication exchange has 
+     * not completed, or if the negotiated quality of protection 
+     * has neither integrity nor privacy
+     */
+    public abstract byte[] unwrap(byte[] incoming, int offset, int len)
+	throws SaslException;
+
+    /**
+     * Wraps a byte array to be sent to the client.
+     * This method can be called only after the authentication exchange has
+     * completed (i.e., when <tt>isComplete()</tt> returns true) and only if
+     * the authentication exchange has negotiated integrity and/or privacy 
+     * as the quality of protection; otherwise, a <tt>SaslException</tt> is thrown.
+     *<p>
+     * The result of this method
+     * will make up the contents of the SASL buffer as defined in RFC 2222
+     * without the leading four octet field that represents the length.
+     * <tt>offset</tt> and <tt>len</tt> specify the portion of <tt>outgoing</tt>
+     * to use.
+     *
+     * @param outgoing A non-null byte array containing the bytes to encode.
+     * @param offset The starting position at <tt>outgoing</tt> of the bytes to use.
+     * @param len The number of bytes from <tt>outgoing</tt> to use.
+     * @return A non-null byte array containing the encoded bytes.
+     * @exception SaslException if <tt>outgoing</tt> cannot be successfully 
+     * wrapped.
+     * @exception IllegalStateException if the authentication exchange has 
+     * not completed, or if the negotiated quality of protection has 
+     * neither integrity nor privacy.
+     */
+    public abstract byte[] wrap(byte[] outgoing, int offset, int len) 
+	throws SaslException;
+
+    /**
+     * Retrieves the negotiated property.
+     * This method can be called only after the authentication exchange has
+     * completed (i.e., when <tt>isComplete()</tt> returns true); otherwise, an
+     * <tt>IllegalStateException</tt> is thrown.
+     * 
+     * @param propName the property
+     * @return The value of the negotiated property. If null, the property was
+     * not negotiated or is not applicable to this mechanism.
+     * @exception IllegalStateException if this authentication exchange has not completed
+     */
+
+    public abstract Object getNegotiatedProperty(String propName);
+
+     /**
+      * Disposes of any system resources or security-sensitive information
+      * the SaslServer might be using. Invoking this method invalidates
+      * the SaslServer instance. This method is idempotent.
+      * @throws SaslException If a problem was encountered while disposing
+      * the resources.
+      */
+    public abstract void dispose() throws SaslException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/javax/security/sasl/SaslServerFactory.java	Tue Jun 26 16:11:37 2007 +0100
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.security.sasl;
+
+import java.util.Map;
+import javax.security.auth.callback.CallbackHandler;
+
+/**
+ * An interface for creating instances of <tt>SaslServer</tt>.
+ * A class that implements this interface
+ * must be thread-safe and handle multiple simultaneous 
+ * requests. It must also have a public constructor that accepts no 
+ * argument. 
+ *<p>
+ * This interface is not normally accessed directly by a server, which will use the
+ * <tt>Sasl</tt> static methods
+ * instead. However, a particular environment may provide and install a
+ * new or different <tt>SaslServerFactory</tt>.
+ *
+ * @since 1.5
+ *
+ * @see SaslServer
+ * @see Sasl
+ *
+ * @author Rosanna Lee
+ * @author Rob Weltman
+ */
+public abstract interface SaslServerFactory {
+    /**
+     * Creates a <tt>SaslServer</tt> using the parameters supplied.
+     * It returns null
+     * if no <tt>SaslServer</tt> can be created using the parameters supplied.
+     * Throws <tt>SaslException</tt> if it cannot create a <tt>SaslServer</tt>
+     * because of an error.
+     *
+     * @param mechanism The non-null
+     * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
+     * @param protocol The non-null string name of the protocol for which
+     * the authentication is being performed (e.g., "ldap").
+     * @param serverName The non-null fully qualified host name of the server
+     * to authenticate to.
+     * @param props The possibly null set of properties used to select the SASL
+     * mechanism and to configure the authentication exchange of the selected
+     * mechanism. See the <tt>Sasl</tt> class for a list of standard properties. 
+     * Other, possibly mechanism-specific, properties can be included.
+     * Properties not relevant to the selected mechanism are ignored,
+     * including any map entries with non-String keys.
+     *
+     * @param cbh The possibly null callback handler to used by the SASL
+     * mechanisms to get further information from the application/library
+     * to complete the authentication. For example, a SASL mechanism might
+     * require the authentication ID, password and realm from the caller.
+     * The authentication ID is requested by using a <tt>NameCallback</tt>.
+     * The password is requested by using a <tt>PasswordCallback</tt>.
+     * The realm is requested by using a <tt>RealmChoiceCallback</tt> if there is a list
+     * of realms to choose from, and by using a <tt>RealmCallback</tt> if
+     * the realm must be entered. 
+     *
+     *@return A possibly null <tt>SaslServer</tt> created using the parameters
+     * supplied. If null, this factory cannot produce a <tt>SaslServer</tt>
+     * using the parameters supplied.
+     *@exception SaslException If cannot create a <tt>SaslServer</tt> because
+     * of an error.
+     */
+    public abstract SaslServer createSaslServer(
+	String mechanism,
+	String protocol,
+	String serverName,
+	Map<String,?> props,
+	CallbackHandler cbh) throws SaslException;
+
+    /**
+     * Returns an array of names of mechanisms that match the specified
+     * mechanism selection policies.
+     * @param props The possibly null set of properties used to specify the
+     * security policy of the SASL mechanisms. For example, if <tt>props</tt>
+     * contains the <tt>Sasl.POLICY_NOPLAINTEXT</tt> property with the value
+     * <tt>"true"</tt>, then the factory must not return any SASL mechanisms
+     * that are susceptible to simple plain passive attacks.
+     * See the <tt>Sasl</tt> class for a complete list of policy properties.
+     * Non-policy related properties, if present in <tt>props</tt>, are ignored,
+     * including any map entries with non-String keys.
+     * @return A non-null array containing a IANA-registered SASL mechanism names.
+     */
+    public abstract String[] getMechanismNames(Map<String,?> props);
+}