diff options
author | Casey Marshall <csm@gnu.org> | 2006-01-26 02:25:07 +0000 |
---|---|---|
committer | Casey Marshall <csm@gnu.org> | 2006-01-26 02:25:07 +0000 |
commit | bd5a522ce73b442dd07099c264bf251e6d8d6a63 (patch) | |
tree | b1cdc8f04689d9ea082589d3a7e61fef847ac1fa | |
parent | bf20436907439f2c47dc22eea41b3d3d5808aa74 (diff) | |
download | classpath-bd5a522ce73b442dd07099c264bf251e6d8d6a63.tar.gz |
2006-01-25 Casey Marshall <csm@gnu.org>
Merging GNU Crypto and Jessie.
* NEWS: mention the merge in the 0.21 notes.
* gnu/classpath/debug/Component.java (SSL_APPLICATION): removed.
(SSL_RECORD_LAYER): new constants.
* gnu/java/security/provider/Gnu.java (<init>): add new algorithms
to provider.
* resource/java/security/classpath.security: add new providers.
* gnu/javax/crypto/assembly/Assembly.java,
gnu/javax/crypto/assembly/Cascade.java,
gnu/javax/crypto/assembly/CascadeStage.java,
gnu/javax/crypto/assembly/CascadeTransformer.java,
gnu/javax/crypto/assembly/DeflateTransformer.java,
gnu/javax/crypto/assembly/Direction.java,
gnu/javax/crypto/assembly/LoopbackTransformer.java,
gnu/javax/crypto/assembly/ModeStage.java,
gnu/javax/crypto/assembly/Operation.java,
gnu/javax/crypto/assembly/PaddingTransformer.java,
gnu/javax/crypto/assembly/Stage.java,
gnu/javax/crypto/assembly/Transformer.java,
gnu/javax/crypto/assembly/TransformerException.java,
gnu/javax/crypto/cipher/Anubis.java,
gnu/javax/crypto/cipher/BaseCipher.java,
gnu/javax/crypto/cipher/Blowfish.java,
gnu/javax/crypto/cipher/Cast5.java,
gnu/javax/crypto/cipher/CipherFactory.java,
gnu/javax/crypto/cipher/DES.java,
gnu/javax/crypto/cipher/IBlockCipher.java,
gnu/javax/crypto/cipher/IBlockCipherSpi.java,
gnu/javax/crypto/cipher/Khazad.java,
gnu/javax/crypto/cipher/NullCipher.java,
gnu/javax/crypto/cipher/Rijndael.java,
gnu/javax/crypto/cipher/Serpent.java,
gnu/javax/crypto/cipher/Square.java,
gnu/javax/crypto/cipher/TripleDES.java,
gnu/javax/crypto/cipher/Twofish.java,
gnu/javax/crypto/cipher/WeakKeyException.java,
gnu/javax/crypto/jce/GnuCrypto.java,
gnu/javax/crypto/jce/GnuSasl.java,
gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java,
gnu/javax/crypto/jce/cipher/AESSpi.java,
gnu/javax/crypto/jce/cipher/ARCFourSpi.java,
gnu/javax/crypto/jce/cipher/AnubisSpi.java,
gnu/javax/crypto/jce/cipher/BlowfishSpi.java,
gnu/javax/crypto/jce/cipher/Cast5Spi.java,
gnu/javax/crypto/jce/cipher/CipherAdapter.java,
gnu/javax/crypto/jce/cipher/DESSpi.java,
gnu/javax/crypto/jce/cipher/KhazadSpi.java,
gnu/javax/crypto/jce/cipher/NullCipherSpi.java,
gnu/javax/crypto/jce/cipher/PBES2.java,
gnu/javax/crypto/jce/cipher/RijndaelSpi.java,
gnu/javax/crypto/jce/cipher/SerpentSpi.java,
gnu/javax/crypto/jce/cipher/SquareSpi.java,
gnu/javax/crypto/jce/cipher/TripleDESSpi.java,
gnu/javax/crypto/jce/cipher/TwofishSpi.java,
gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java,
gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java,
gnu/javax/crypto/jce/keyring/GnuKeyring.java,
gnu/javax/crypto/jce/mac/HMacHavalSpi.java,
gnu/javax/crypto/jce/mac/HMacMD2Spi.java,
gnu/javax/crypto/jce/mac/HMacMD4Spi.java,
gnu/javax/crypto/jce/mac/HMacMD5Spi.java,
gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java,
gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java,
gnu/javax/crypto/jce/mac/HMacSHA160Spi.java,
gnu/javax/crypto/jce/mac/HMacSHA256Spi.java,
gnu/javax/crypto/jce/mac/HMacSHA384Spi.java,
gnu/javax/crypto/jce/mac/HMacSHA512Spi.java,
gnu/javax/crypto/jce/mac/HMacTigerSpi.java,
gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java,
gnu/javax/crypto/jce/mac/MacAdapter.java,
gnu/javax/crypto/jce/mac/OMacAnubisImpl.java,
gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java,
gnu/javax/crypto/jce/mac/OMacCast5Impl.java,
gnu/javax/crypto/jce/mac/OMacDESImpl.java,
gnu/javax/crypto/jce/mac/OMacImpl.java,
gnu/javax/crypto/jce/mac/OMacKhazadImpl.java,
gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java,
gnu/javax/crypto/jce/mac/OMacSerpentImpl.java,
gnu/javax/crypto/jce/mac/OMacSquareImpl.java,
gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java,
gnu/javax/crypto/jce/mac/OMacTwofishImpl.java,
gnu/javax/crypto/jce/mac/TMMH16Spi.java,
gnu/javax/crypto/jce/mac/UHash32Spi.java,
gnu/javax/crypto/jce/mac/UMac32Spi.java,
gnu/javax/crypto/jce/params/BlockCipherParameters.java,
gnu/javax/crypto/jce/params/DEREncodingException.java,
gnu/javax/crypto/jce/params/DERReader.java,
gnu/javax/crypto/jce/params/DERWriter.java,
gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java,
gnu/javax/crypto/jce/prng/CSPRNGSpi.java,
gnu/javax/crypto/jce/prng/FortunaImpl.java,
gnu/javax/crypto/jce/prng/ICMRandomSpi.java,
gnu/javax/crypto/jce/prng/UMacRandomSpi.java,
gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java,
gnu/javax/crypto/jce/spec/TMMHParameterSpec.java,
gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java,
gnu/javax/crypto/key/BaseKeyAgreementParty.java,
gnu/javax/crypto/key/GnuSecretKey.java,
gnu/javax/crypto/key/IKeyAgreementParty.java,
gnu/javax/crypto/key/IncomingMessage.java,
gnu/javax/crypto/key/KeyAgreementException.java,
gnu/javax/crypto/key/KeyAgreementFactory.java,
gnu/javax/crypto/key/OutgoingMessage.java,
gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java,
gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java,
gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java,
gnu/javax/crypto/key/dh/DiffieHellmanSender.java,
gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java,
gnu/javax/crypto/key/dh/ElGamalReceiver.java,
gnu/javax/crypto/key/dh/ElGamalSender.java,
gnu/javax/crypto/key/dh/GnuDHKey.java,
gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java,
gnu/javax/crypto/key/dh/GnuDHPrivateKey.java,
gnu/javax/crypto/key/dh/GnuDHPublicKey.java,
gnu/javax/crypto/key/dh/RFC2631.java,
gnu/javax/crypto/key/srp6/SRP6Host.java,
gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java,
gnu/javax/crypto/key/srp6/SRP6SaslClient.java,
gnu/javax/crypto/key/srp6/SRP6SaslServer.java,
gnu/javax/crypto/key/srp6/SRP6TLSClient.java,
gnu/javax/crypto/key/srp6/SRP6TLSServer.java,
gnu/javax/crypto/key/srp6/SRP6User.java,
gnu/javax/crypto/key/srp6/SRPAlgorithm.java,
gnu/javax/crypto/key/srp6/SRPKey.java,
gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java,
gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java,
gnu/javax/crypto/key/srp6/SRPPrivateKey.java,
gnu/javax/crypto/key/srp6/SRPPublicKey.java,
gnu/javax/crypto/keyring/AuthenticatedEntry.java,
gnu/javax/crypto/keyring/BaseKeyring.java,
gnu/javax/crypto/keyring/BinaryDataEntry.java,
gnu/javax/crypto/keyring/CertPathEntry.java,
gnu/javax/crypto/keyring/CertificateEntry.java,
gnu/javax/crypto/keyring/CompressedEntry.java,
gnu/javax/crypto/keyring/EncryptedEntry.java,
gnu/javax/crypto/keyring/Entry.java,
gnu/javax/crypto/keyring/EnvelopeEntry.java,
gnu/javax/crypto/keyring/GnuPrivateKeyring.java,
gnu/javax/crypto/keyring/GnuPublicKeyring.java,
gnu/javax/crypto/keyring/IKeyring.java,
gnu/javax/crypto/keyring/IPrivateKeyring.java,
gnu/javax/crypto/keyring/IPublicKeyring.java,
gnu/javax/crypto/keyring/MalformedKeyringException.java,
gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java,
gnu/javax/crypto/keyring/MeteredInputStream.java,
gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java,
gnu/javax/crypto/keyring/PasswordEncryptedEntry.java,
gnu/javax/crypto/keyring/PasswordProtectedEntry.java,
gnu/javax/crypto/keyring/PrimitiveEntry.java,
gnu/javax/crypto/keyring/PrivateKeyEntry.java,
gnu/javax/crypto/keyring/Properties.java,
gnu/javax/crypto/keyring/PublicKeyEntry.java,
gnu/javax/crypto/mac/BaseMac.java,
gnu/javax/crypto/mac/HMac.java,
gnu/javax/crypto/mac/HMacFactory.java,
gnu/javax/crypto/mac/IMac.java,
gnu/javax/crypto/mac/MacFactory.java,
gnu/javax/crypto/mac/MacInputStream.java,
gnu/javax/crypto/mac/MacOutputStream.java,
gnu/javax/crypto/mac/OMAC.java,
gnu/javax/crypto/mac/TMMH16.java,
gnu/javax/crypto/mac/UHash32.java,
gnu/javax/crypto/mac/UMac32.java,
gnu/javax/crypto/mode/BaseMode.java,
gnu/javax/crypto/mode/CBC.java,
gnu/javax/crypto/mode/CFB.java,
gnu/javax/crypto/mode/CTR.java,
gnu/javax/crypto/mode/EAX.java,
gnu/javax/crypto/mode/ECB.java,
gnu/javax/crypto/mode/IAuthenticatedMode.java,
gnu/javax/crypto/mode/ICM.java,
gnu/javax/crypto/mode/IMode.java,
gnu/javax/crypto/mode/ModeFactory.java,
gnu/javax/crypto/mode/OFB.java,
gnu/javax/crypto/pad/BasePad.java,
gnu/javax/crypto/pad/IPad.java,
gnu/javax/crypto/pad/PKCS1_V1_5.java,
gnu/javax/crypto/pad/PKCS7.java,
gnu/javax/crypto/pad/PadFactory.java,
gnu/javax/crypto/pad/SSL3.java,
gnu/javax/crypto/pad/TBC.java,
gnu/javax/crypto/pad/TLS1.java,
gnu/javax/crypto/pad/WrongPaddingException.java,
gnu/javax/crypto/prng/ARCFour.java,
gnu/javax/crypto/prng/CSPRNG.java,
gnu/javax/crypto/prng/Fortuna.java,
gnu/javax/crypto/prng/ICMGenerator.java,
gnu/javax/crypto/prng/IPBE.java,
gnu/javax/crypto/prng/PBKDF2.java,
gnu/javax/crypto/prng/PRNGFactory.java,
gnu/javax/crypto/prng/UMacGenerator.java,
gnu/javax/crypto/sasl/AuthInfo.java,
gnu/javax/crypto/sasl/AuthInfoProviderFactory.java,
gnu/javax/crypto/sasl/ClientFactory.java,
gnu/javax/crypto/sasl/ClientMechanism.java,
gnu/javax/crypto/sasl/ConfidentialityException.java,
gnu/javax/crypto/sasl/IAuthInfoProvider.java,
gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java,
gnu/javax/crypto/sasl/IllegalMechanismStateException.java,
gnu/javax/crypto/sasl/InputBuffer.java,
gnu/javax/crypto/sasl/IntegrityException.java,
gnu/javax/crypto/sasl/NoSuchMechanismException.java,
gnu/javax/crypto/sasl/NoSuchUserException.java,
gnu/javax/crypto/sasl/OutputBuffer.java,
gnu/javax/crypto/sasl/SaslEncodingException.java,
gnu/javax/crypto/sasl/SaslInputStream.java,
gnu/javax/crypto/sasl/SaslOutputStream.java,
gnu/javax/crypto/sasl/SaslUtil.java,
gnu/javax/crypto/sasl/ServerFactory.java,
gnu/javax/crypto/sasl/ServerMechanism.java,
gnu/javax/crypto/sasl/UserAlreadyExistsException.java,
gnu/javax/crypto/sasl/anonymous/AnonymousClient.java,
gnu/javax/crypto/sasl/anonymous/AnonymousServer.java,
gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java,
gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java,
gnu/javax/crypto/sasl/crammd5/CramMD5Client.java,
gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java,
gnu/javax/crypto/sasl/crammd5/CramMD5Server.java,
gnu/javax/crypto/sasl/crammd5/CramMD5Util.java,
gnu/javax/crypto/sasl/crammd5/PasswordFile.java,
gnu/javax/crypto/sasl/plain/PasswordFile.java,
gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java,
gnu/javax/crypto/sasl/plain/PlainClient.java,
gnu/javax/crypto/sasl/plain/PlainRegistry.java,
gnu/javax/crypto/sasl/plain/PlainServer.java,
gnu/javax/crypto/sasl/srp/CALG.java,
gnu/javax/crypto/sasl/srp/ClientStore.java,
gnu/javax/crypto/sasl/srp/IALG.java,
gnu/javax/crypto/sasl/srp/KDF.java,
gnu/javax/crypto/sasl/srp/PasswordFile.java,
gnu/javax/crypto/sasl/srp/SRP.java,
gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java,
gnu/javax/crypto/sasl/srp/SRPClient.java,
gnu/javax/crypto/sasl/srp/SRPRegistry.java,
gnu/javax/crypto/sasl/srp/SRPServer.java,
gnu/javax/crypto/sasl/srp/SecurityContext.java,
gnu/javax/crypto/sasl/srp/ServerStore.java,
gnu/javax/crypto/sasl/srp/StoreEntry.java,
gnu/javax/net/ssl/Base64.java,
gnu/javax/net/ssl/EntropySource.java,
gnu/javax/net/ssl/NullManagerParameters.java,
gnu/javax/net/ssl/PrivateCredentials.java,
gnu/javax/net/ssl/SRPManagerParameters.java,
gnu/javax/net/ssl/SRPTrustManager.java,
gnu/javax/net/ssl/StaticTrustAnchors.java,
gnu/javax/net/ssl/provider/Alert.java,
gnu/javax/net/ssl/provider/AlertException.java,
gnu/javax/net/ssl/provider/Certificate.java,
gnu/javax/net/ssl/provider/CertificateRequest.java,
gnu/javax/net/ssl/provider/CertificateType.java,
gnu/javax/net/ssl/provider/CertificateVerify.java,
gnu/javax/net/ssl/provider/CipherSuite.java,
gnu/javax/net/ssl/provider/ClientHello.java,
gnu/javax/net/ssl/provider/ClientKeyExchange.java,
gnu/javax/net/ssl/provider/CompressionMethod.java,
gnu/javax/net/ssl/provider/Constructed.java,
gnu/javax/net/ssl/provider/ContentType.java,
gnu/javax/net/ssl/provider/Context.java,
gnu/javax/net/ssl/provider/DiffieHellman.java,
gnu/javax/net/ssl/provider/DigestInputStream.java,
gnu/javax/net/ssl/provider/DigestOutputStream.java,
gnu/javax/net/ssl/provider/Enumerated.java,
gnu/javax/net/ssl/provider/Extension.java,
gnu/javax/net/ssl/provider/Extensions.java,
gnu/javax/net/ssl/provider/Finished.java,
gnu/javax/net/ssl/provider/GNUSecurityParameters.java,
gnu/javax/net/ssl/provider/Handshake.java,
gnu/javax/net/ssl/provider/JCESecurityParameters.java,
gnu/javax/net/ssl/provider/JDBCSessionContext.java,
gnu/javax/net/ssl/provider/Jessie.java,
gnu/javax/net/ssl/provider/JessieDHPrivateKey.java,
gnu/javax/net/ssl/provider/JessieDHPublicKey.java,
gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java,
gnu/javax/net/ssl/provider/JessieRSAPublicKey.java,
gnu/javax/net/ssl/provider/KeyPool.java,
gnu/javax/net/ssl/provider/MacException.java,
gnu/javax/net/ssl/provider/OverflowException.java,
gnu/javax/net/ssl/provider/PRNG.java,
gnu/javax/net/ssl/provider/ProtocolVersion.java,
gnu/javax/net/ssl/provider/Random.java,
gnu/javax/net/ssl/provider/RecordInput.java,
gnu/javax/net/ssl/provider/RecordInputStream.java,
gnu/javax/net/ssl/provider/RecordOutputStream.java,
gnu/javax/net/ssl/provider/RecordingInputStream.java,
gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java,
gnu/javax/net/ssl/provider/SSLHMac.java,
gnu/javax/net/ssl/provider/SSLRSASignature.java,
gnu/javax/net/ssl/provider/SSLRandom.java,
gnu/javax/net/ssl/provider/SSLServerSocket.java,
gnu/javax/net/ssl/provider/SSLServerSocketFactory.java,
gnu/javax/net/ssl/provider/SSLSocket.java,
gnu/javax/net/ssl/provider/SSLSocketFactory.java,
gnu/javax/net/ssl/provider/SSLSocketInputStream.java,
gnu/javax/net/ssl/provider/SSLSocketOutputStream.java,
gnu/javax/net/ssl/provider/SecurityParameters.java,
gnu/javax/net/ssl/provider/ServerHello.java,
gnu/javax/net/ssl/provider/ServerKeyExchange.java,
gnu/javax/net/ssl/provider/Session.java,
gnu/javax/net/ssl/provider/SessionContext.java,
gnu/javax/net/ssl/provider/Signature.java,
gnu/javax/net/ssl/provider/SynchronizedRandom.java,
gnu/javax/net/ssl/provider/TLSHMac.java,
gnu/javax/net/ssl/provider/TLSRandom.java,
gnu/javax/net/ssl/provider/Util.java,
gnu/javax/net/ssl/provider/X509KeyManagerFactory.java,
gnu/javax/net/ssl/provider/X509TrustManagerFactory.java,
gnu/javax/net/ssl/provider/XMLSessionContext.java,
gnu/javax/security/auth/Password.java,
gnu/javax/security/auth/callback/AWTCallbackHandler.java,
gnu/javax/security/auth/callback/AbstractCallbackHandler.java,
gnu/javax/security/auth/callback/ConsoleCallbackHandler.java,
gnu/javax/security/auth/callback/DefaultCallbackHandler.java,
gnu/javax/security/auth/callback/GnuCallbacks.java,
gnu/javax/security/auth/callback/SwingCallbackHandler.java,
gnu/java/security/Registry.java,
gnu/java/security/Properties.java,
gnu/java/security/hash/BaseHash.java,
gnu/java/security/hash/HashFactory.java,
gnu/java/security/hash/Haval.java,
gnu/java/security/hash/IMessageDigest.java,
gnu/java/security/hash/MD2.java,
gnu/java/security/hash/MD4.java,
gnu/java/security/hash/MD5.java,
gnu/java/security/hash/RipeMD128.java,
gnu/java/security/hash/RipeMD160.java,
gnu/java/security/hash/Sha160.java,
gnu/java/security/hash/Sha256.java,
gnu/java/security/hash/Sha384.java,
gnu/java/security/hash/Sha512.java,
gnu/java/security/hash/Tiger.java,
gnu/java/security/hash/Whirlpool.java,
gnu/java/security/jce/hash/HavalSpi.java,
gnu/java/security/jce/hash/MD2Spi.java,
gnu/java/security/jce/hash/MD4Spi.java,
gnu/java/security/jce/hash/MD5Spi.java,
gnu/java/security/jce/hash/MessageDigestAdapter.java,
gnu/java/security/jce/hash/RipeMD128Spi.java,
gnu/java/security/jce/hash/RipeMD160Spi.java,
gnu/java/security/jce/hash/Sha160Spi.java,
gnu/java/security/jce/hash/Sha256Spi.java,
gnu/java/security/jce/hash/Sha384Spi.java,
gnu/java/security/jce/hash/Sha512Spi.java,
gnu/java/security/jce/hash/TigerSpi.java,
gnu/java/security/jce/hash/WhirlpoolSpi.java,
gnu/java/security/jce/prng/HavalRandomSpi.java,
gnu/java/security/jce/prng/MD2RandomSpi.java,
gnu/java/security/jce/prng/MD4RandomSpi.java,
gnu/java/security/jce/prng/MD5RandomSpi.java,
gnu/java/security/jce/prng/RipeMD128RandomSpi.java,
gnu/java/security/jce/prng/RipeMD160RandomSpi.java,
gnu/java/security/jce/prng/SecureRandomAdapter.java,
gnu/java/security/jce/prng/Sha160RandomSpi.java,
gnu/java/security/jce/prng/Sha256RandomSpi.java,
gnu/java/security/jce/prng/Sha384RandomSpi.java,
gnu/java/security/jce/prng/Sha512RandomSpi.java,
gnu/java/security/jce/prng/TigerRandomSpi.java,
gnu/java/security/jce/prng/WhirlpoolRandomSpi.java,
gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java,
gnu/java/security/jce/sig/DSSRawSignatureSpi.java,
gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java,
gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java,
gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java,
gnu/java/security/jce/sig/SignatureAdapter.java,
gnu/java/security/key/IKeyPairCodec.java,
gnu/java/security/key/IKeyPairGenerator.java,
gnu/java/security/key/KeyPairCodecFactory.java,
gnu/java/security/key/KeyPairGeneratorFactory.java,
gnu/java/security/key/dss/DSSKey.java,
gnu/java/security/key/dss/DSSKeyPairGenerator.java,
gnu/java/security/key/dss/DSSKeyPairRawCodec.java,
gnu/java/security/key/dss/DSSPrivateKey.java,
gnu/java/security/key/dss/DSSPublicKey.java,
gnu/java/security/key/dss/FIPS186.java,
gnu/java/security/key/rsa/GnuRSAKey.java,
gnu/java/security/key/rsa/GnuRSAPrivateKey.java,
gnu/java/security/key/rsa/GnuRSAPublicKey.java,
gnu/java/security/key/rsa/RSAKeyPairGenerator.java,
gnu/java/security/key/rsa/RSAKeyPairRawCodec.java,
gnu/java/security/prng/BasePRNG.java,
gnu/java/security/prng/EntropySource.java,
gnu/java/security/prng/IRandom.java,
gnu/java/security/prng/LimitReachedException.java,
gnu/java/security/prng/MDGenerator.java,
gnu/java/security/prng/PRNGFactory.java,
gnu/java/security/prng/RandomEvent.java,
gnu/java/security/prng/RandomEventListener.java,
gnu/java/security/sig/BaseSignature.java,
gnu/java/security/sig/ISignature.java,
gnu/java/security/sig/ISignatureCodec.java,
gnu/java/security/sig/SignatureFactory.java,
gnu/java/security/sig/dss/DSSSignature.java,
gnu/java/security/sig/dss/DSSSignatureRawCodec.java,
gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java,
gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java,
gnu/java/security/sig/rsa/EMSA_PSS.java,
gnu/java/security/sig/rsa/RSA.java,
gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java,
gnu/java/security/sig/rsa/RSAPSSSignature.java,
gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java,
gnu/java/security/util/Base64.java,
gnu/java/security/util/ExpirableObject.java,
gnu/java/security/util/Prime2.java,
gnu/java/security/util/Sequence.java,
gnu/java/security/util/SimpleList.java,
gnu/java/security/util/Util.java,
resource/gnu/javax/security/auth/callback/MessagesBundle.properties:
new files imported from GNU Crypto and Jessie.
424 files changed, 92710 insertions, 15 deletions
@@ -1,3 +1,434 @@ +2006-01-25 Casey Marshall <csm@gnu.org> + + Merging GNU Crypto and Jessie. + + * NEWS: mention the merge in the 0.21 notes. + * gnu/classpath/debug/Component.java (SSL_APPLICATION): removed. + (SSL_RECORD_LAYER): new constants. + * gnu/java/security/provider/Gnu.java (<init>): add new algorithms + to provider. + * resource/java/security/classpath.security: add new providers. + * gnu/javax/crypto/assembly/Assembly.java, + gnu/javax/crypto/assembly/Cascade.java, + gnu/javax/crypto/assembly/CascadeStage.java, + gnu/javax/crypto/assembly/CascadeTransformer.java, + gnu/javax/crypto/assembly/DeflateTransformer.java, + gnu/javax/crypto/assembly/Direction.java, + gnu/javax/crypto/assembly/LoopbackTransformer.java, + gnu/javax/crypto/assembly/ModeStage.java, + gnu/javax/crypto/assembly/Operation.java, + gnu/javax/crypto/assembly/PaddingTransformer.java, + gnu/javax/crypto/assembly/Stage.java, + gnu/javax/crypto/assembly/Transformer.java, + gnu/javax/crypto/assembly/TransformerException.java, + gnu/javax/crypto/cipher/Anubis.java, + gnu/javax/crypto/cipher/BaseCipher.java, + gnu/javax/crypto/cipher/Blowfish.java, + gnu/javax/crypto/cipher/Cast5.java, + gnu/javax/crypto/cipher/CipherFactory.java, + gnu/javax/crypto/cipher/DES.java, + gnu/javax/crypto/cipher/IBlockCipher.java, + gnu/javax/crypto/cipher/IBlockCipherSpi.java, + gnu/javax/crypto/cipher/Khazad.java, + gnu/javax/crypto/cipher/NullCipher.java, + gnu/javax/crypto/cipher/Rijndael.java, + gnu/javax/crypto/cipher/Serpent.java, + gnu/javax/crypto/cipher/Square.java, + gnu/javax/crypto/cipher/TripleDES.java, + gnu/javax/crypto/cipher/Twofish.java, + gnu/javax/crypto/cipher/WeakKeyException.java, + gnu/javax/crypto/jce/GnuCrypto.java, + gnu/javax/crypto/jce/GnuSasl.java, + gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java, + gnu/javax/crypto/jce/cipher/AESSpi.java, + gnu/javax/crypto/jce/cipher/ARCFourSpi.java, + gnu/javax/crypto/jce/cipher/AnubisSpi.java, + gnu/javax/crypto/jce/cipher/BlowfishSpi.java, + gnu/javax/crypto/jce/cipher/Cast5Spi.java, + gnu/javax/crypto/jce/cipher/CipherAdapter.java, + gnu/javax/crypto/jce/cipher/DESSpi.java, + gnu/javax/crypto/jce/cipher/KhazadSpi.java, + gnu/javax/crypto/jce/cipher/NullCipherSpi.java, + gnu/javax/crypto/jce/cipher/PBES2.java, + gnu/javax/crypto/jce/cipher/RijndaelSpi.java, + gnu/javax/crypto/jce/cipher/SerpentSpi.java, + gnu/javax/crypto/jce/cipher/SquareSpi.java, + gnu/javax/crypto/jce/cipher/TripleDESSpi.java, + gnu/javax/crypto/jce/cipher/TwofishSpi.java, + gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/keyring/GnuKeyring.java, + gnu/javax/crypto/jce/mac/HMacHavalSpi.java, + gnu/javax/crypto/jce/mac/HMacMD2Spi.java, + gnu/javax/crypto/jce/mac/HMacMD4Spi.java, + gnu/javax/crypto/jce/mac/HMacMD5Spi.java, + gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java, + gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java, + gnu/javax/crypto/jce/mac/HMacSHA160Spi.java, + gnu/javax/crypto/jce/mac/HMacSHA256Spi.java, + gnu/javax/crypto/jce/mac/HMacSHA384Spi.java, + gnu/javax/crypto/jce/mac/HMacSHA512Spi.java, + gnu/javax/crypto/jce/mac/HMacTigerSpi.java, + gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java, + gnu/javax/crypto/jce/mac/MacAdapter.java, + gnu/javax/crypto/jce/mac/OMacAnubisImpl.java, + gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java, + gnu/javax/crypto/jce/mac/OMacCast5Impl.java, + gnu/javax/crypto/jce/mac/OMacDESImpl.java, + gnu/javax/crypto/jce/mac/OMacImpl.java, + gnu/javax/crypto/jce/mac/OMacKhazadImpl.java, + gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java, + gnu/javax/crypto/jce/mac/OMacSerpentImpl.java, + gnu/javax/crypto/jce/mac/OMacSquareImpl.java, + gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java, + gnu/javax/crypto/jce/mac/OMacTwofishImpl.java, + gnu/javax/crypto/jce/mac/TMMH16Spi.java, + gnu/javax/crypto/jce/mac/UHash32Spi.java, + gnu/javax/crypto/jce/mac/UMac32Spi.java, + gnu/javax/crypto/jce/params/BlockCipherParameters.java, + gnu/javax/crypto/jce/params/DEREncodingException.java, + gnu/javax/crypto/jce/params/DERReader.java, + gnu/javax/crypto/jce/params/DERWriter.java, + gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java, + gnu/javax/crypto/jce/prng/CSPRNGSpi.java, + gnu/javax/crypto/jce/prng/FortunaImpl.java, + gnu/javax/crypto/jce/prng/ICMRandomSpi.java, + gnu/javax/crypto/jce/prng/UMacRandomSpi.java, + gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java, + gnu/javax/crypto/jce/spec/TMMHParameterSpec.java, + gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java, + gnu/javax/crypto/key/BaseKeyAgreementParty.java, + gnu/javax/crypto/key/GnuSecretKey.java, + gnu/javax/crypto/key/IKeyAgreementParty.java, + gnu/javax/crypto/key/IncomingMessage.java, + gnu/javax/crypto/key/KeyAgreementException.java, + gnu/javax/crypto/key/KeyAgreementFactory.java, + gnu/javax/crypto/key/OutgoingMessage.java, + gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java, + gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java, + gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java, + gnu/javax/crypto/key/dh/DiffieHellmanSender.java, + gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java, + gnu/javax/crypto/key/dh/ElGamalReceiver.java, + gnu/javax/crypto/key/dh/ElGamalSender.java, + gnu/javax/crypto/key/dh/GnuDHKey.java, + gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java, + gnu/javax/crypto/key/dh/GnuDHPrivateKey.java, + gnu/javax/crypto/key/dh/GnuDHPublicKey.java, + gnu/javax/crypto/key/dh/RFC2631.java, + gnu/javax/crypto/key/srp6/SRP6Host.java, + gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java, + gnu/javax/crypto/key/srp6/SRP6SaslClient.java, + gnu/javax/crypto/key/srp6/SRP6SaslServer.java, + gnu/javax/crypto/key/srp6/SRP6TLSClient.java, + gnu/javax/crypto/key/srp6/SRP6TLSServer.java, + gnu/javax/crypto/key/srp6/SRP6User.java, + gnu/javax/crypto/key/srp6/SRPAlgorithm.java, + gnu/javax/crypto/key/srp6/SRPKey.java, + gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java, + gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java, + gnu/javax/crypto/key/srp6/SRPPrivateKey.java, + gnu/javax/crypto/key/srp6/SRPPublicKey.java, + gnu/javax/crypto/keyring/AuthenticatedEntry.java, + gnu/javax/crypto/keyring/BaseKeyring.java, + gnu/javax/crypto/keyring/BinaryDataEntry.java, + gnu/javax/crypto/keyring/CertPathEntry.java, + gnu/javax/crypto/keyring/CertificateEntry.java, + gnu/javax/crypto/keyring/CompressedEntry.java, + gnu/javax/crypto/keyring/EncryptedEntry.java, + gnu/javax/crypto/keyring/Entry.java, + gnu/javax/crypto/keyring/EnvelopeEntry.java, + gnu/javax/crypto/keyring/GnuPrivateKeyring.java, + gnu/javax/crypto/keyring/GnuPublicKeyring.java, + gnu/javax/crypto/keyring/IKeyring.java, + gnu/javax/crypto/keyring/IPrivateKeyring.java, + gnu/javax/crypto/keyring/IPublicKeyring.java, + gnu/javax/crypto/keyring/MalformedKeyringException.java, + gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java, + gnu/javax/crypto/keyring/MeteredInputStream.java, + gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java, + gnu/javax/crypto/keyring/PasswordEncryptedEntry.java, + gnu/javax/crypto/keyring/PasswordProtectedEntry.java, + gnu/javax/crypto/keyring/PrimitiveEntry.java, + gnu/javax/crypto/keyring/PrivateKeyEntry.java, + gnu/javax/crypto/keyring/Properties.java, + gnu/javax/crypto/keyring/PublicKeyEntry.java, + gnu/javax/crypto/mac/BaseMac.java, + gnu/javax/crypto/mac/HMac.java, + gnu/javax/crypto/mac/HMacFactory.java, + gnu/javax/crypto/mac/IMac.java, + gnu/javax/crypto/mac/MacFactory.java, + gnu/javax/crypto/mac/MacInputStream.java, + gnu/javax/crypto/mac/MacOutputStream.java, + gnu/javax/crypto/mac/OMAC.java, + gnu/javax/crypto/mac/TMMH16.java, + gnu/javax/crypto/mac/UHash32.java, + gnu/javax/crypto/mac/UMac32.java, + gnu/javax/crypto/mode/BaseMode.java, + gnu/javax/crypto/mode/CBC.java, + gnu/javax/crypto/mode/CFB.java, + gnu/javax/crypto/mode/CTR.java, + gnu/javax/crypto/mode/EAX.java, + gnu/javax/crypto/mode/ECB.java, + gnu/javax/crypto/mode/IAuthenticatedMode.java, + gnu/javax/crypto/mode/ICM.java, + gnu/javax/crypto/mode/IMode.java, + gnu/javax/crypto/mode/ModeFactory.java, + gnu/javax/crypto/mode/OFB.java, + gnu/javax/crypto/pad/BasePad.java, + gnu/javax/crypto/pad/IPad.java, + gnu/javax/crypto/pad/PKCS1_V1_5.java, + gnu/javax/crypto/pad/PKCS7.java, + gnu/javax/crypto/pad/PadFactory.java, + gnu/javax/crypto/pad/SSL3.java, + gnu/javax/crypto/pad/TBC.java, + gnu/javax/crypto/pad/TLS1.java, + gnu/javax/crypto/pad/WrongPaddingException.java, + gnu/javax/crypto/prng/ARCFour.java, + gnu/javax/crypto/prng/CSPRNG.java, + gnu/javax/crypto/prng/Fortuna.java, + gnu/javax/crypto/prng/ICMGenerator.java, + gnu/javax/crypto/prng/IPBE.java, + gnu/javax/crypto/prng/PBKDF2.java, + gnu/javax/crypto/prng/PRNGFactory.java, + gnu/javax/crypto/prng/UMacGenerator.java, + gnu/javax/crypto/sasl/AuthInfo.java, + gnu/javax/crypto/sasl/AuthInfoProviderFactory.java, + gnu/javax/crypto/sasl/ClientFactory.java, + gnu/javax/crypto/sasl/ClientMechanism.java, + gnu/javax/crypto/sasl/ConfidentialityException.java, + gnu/javax/crypto/sasl/IAuthInfoProvider.java, + gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java, + gnu/javax/crypto/sasl/IllegalMechanismStateException.java, + gnu/javax/crypto/sasl/InputBuffer.java, + gnu/javax/crypto/sasl/IntegrityException.java, + gnu/javax/crypto/sasl/NoSuchMechanismException.java, + gnu/javax/crypto/sasl/NoSuchUserException.java, + gnu/javax/crypto/sasl/OutputBuffer.java, + gnu/javax/crypto/sasl/SaslEncodingException.java, + gnu/javax/crypto/sasl/SaslInputStream.java, + gnu/javax/crypto/sasl/SaslOutputStream.java, + gnu/javax/crypto/sasl/SaslUtil.java, + gnu/javax/crypto/sasl/ServerFactory.java, + gnu/javax/crypto/sasl/ServerMechanism.java, + gnu/javax/crypto/sasl/UserAlreadyExistsException.java, + gnu/javax/crypto/sasl/anonymous/AnonymousClient.java, + gnu/javax/crypto/sasl/anonymous/AnonymousServer.java, + gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java, + gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java, + gnu/javax/crypto/sasl/crammd5/CramMD5Client.java, + gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java, + gnu/javax/crypto/sasl/crammd5/CramMD5Server.java, + gnu/javax/crypto/sasl/crammd5/CramMD5Util.java, + gnu/javax/crypto/sasl/crammd5/PasswordFile.java, + gnu/javax/crypto/sasl/plain/PasswordFile.java, + gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java, + gnu/javax/crypto/sasl/plain/PlainClient.java, + gnu/javax/crypto/sasl/plain/PlainRegistry.java, + gnu/javax/crypto/sasl/plain/PlainServer.java, + gnu/javax/crypto/sasl/srp/CALG.java, + gnu/javax/crypto/sasl/srp/ClientStore.java, + gnu/javax/crypto/sasl/srp/IALG.java, + gnu/javax/crypto/sasl/srp/KDF.java, + gnu/javax/crypto/sasl/srp/PasswordFile.java, + gnu/javax/crypto/sasl/srp/SRP.java, + gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java, + gnu/javax/crypto/sasl/srp/SRPClient.java, + gnu/javax/crypto/sasl/srp/SRPRegistry.java, + gnu/javax/crypto/sasl/srp/SRPServer.java, + gnu/javax/crypto/sasl/srp/SecurityContext.java, + gnu/javax/crypto/sasl/srp/ServerStore.java, + gnu/javax/crypto/sasl/srp/StoreEntry.java, + gnu/javax/net/ssl/Base64.java, + gnu/javax/net/ssl/EntropySource.java, + gnu/javax/net/ssl/NullManagerParameters.java, + gnu/javax/net/ssl/PrivateCredentials.java, + gnu/javax/net/ssl/SRPManagerParameters.java, + gnu/javax/net/ssl/SRPTrustManager.java, + gnu/javax/net/ssl/StaticTrustAnchors.java, + gnu/javax/net/ssl/provider/Alert.java, + gnu/javax/net/ssl/provider/AlertException.java, + gnu/javax/net/ssl/provider/Certificate.java, + gnu/javax/net/ssl/provider/CertificateRequest.java, + gnu/javax/net/ssl/provider/CertificateType.java, + gnu/javax/net/ssl/provider/CertificateVerify.java, + gnu/javax/net/ssl/provider/CipherSuite.java, + gnu/javax/net/ssl/provider/ClientHello.java, + gnu/javax/net/ssl/provider/ClientKeyExchange.java, + gnu/javax/net/ssl/provider/CompressionMethod.java, + gnu/javax/net/ssl/provider/Constructed.java, + gnu/javax/net/ssl/provider/ContentType.java, + gnu/javax/net/ssl/provider/Context.java, + gnu/javax/net/ssl/provider/DiffieHellman.java, + gnu/javax/net/ssl/provider/DigestInputStream.java, + gnu/javax/net/ssl/provider/DigestOutputStream.java, + gnu/javax/net/ssl/provider/Enumerated.java, + gnu/javax/net/ssl/provider/Extension.java, + gnu/javax/net/ssl/provider/Extensions.java, + gnu/javax/net/ssl/provider/Finished.java, + gnu/javax/net/ssl/provider/GNUSecurityParameters.java, + gnu/javax/net/ssl/provider/Handshake.java, + gnu/javax/net/ssl/provider/JCESecurityParameters.java, + gnu/javax/net/ssl/provider/JDBCSessionContext.java, + gnu/javax/net/ssl/provider/Jessie.java, + gnu/javax/net/ssl/provider/JessieDHPrivateKey.java, + gnu/javax/net/ssl/provider/JessieDHPublicKey.java, + gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java, + gnu/javax/net/ssl/provider/JessieRSAPublicKey.java, + gnu/javax/net/ssl/provider/KeyPool.java, + gnu/javax/net/ssl/provider/MacException.java, + gnu/javax/net/ssl/provider/OverflowException.java, + gnu/javax/net/ssl/provider/PRNG.java, + gnu/javax/net/ssl/provider/ProtocolVersion.java, + gnu/javax/net/ssl/provider/Random.java, + gnu/javax/net/ssl/provider/RecordInput.java, + gnu/javax/net/ssl/provider/RecordInputStream.java, + gnu/javax/net/ssl/provider/RecordOutputStream.java, + gnu/javax/net/ssl/provider/RecordingInputStream.java, + gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java, + gnu/javax/net/ssl/provider/SSLHMac.java, + gnu/javax/net/ssl/provider/SSLRSASignature.java, + gnu/javax/net/ssl/provider/SSLRandom.java, + gnu/javax/net/ssl/provider/SSLServerSocket.java, + gnu/javax/net/ssl/provider/SSLServerSocketFactory.java, + gnu/javax/net/ssl/provider/SSLSocket.java, + gnu/javax/net/ssl/provider/SSLSocketFactory.java, + gnu/javax/net/ssl/provider/SSLSocketInputStream.java, + gnu/javax/net/ssl/provider/SSLSocketOutputStream.java, + gnu/javax/net/ssl/provider/SecurityParameters.java, + gnu/javax/net/ssl/provider/ServerHello.java, + gnu/javax/net/ssl/provider/ServerKeyExchange.java, + gnu/javax/net/ssl/provider/Session.java, + gnu/javax/net/ssl/provider/SessionContext.java, + gnu/javax/net/ssl/provider/Signature.java, + gnu/javax/net/ssl/provider/SynchronizedRandom.java, + gnu/javax/net/ssl/provider/TLSHMac.java, + gnu/javax/net/ssl/provider/TLSRandom.java, + gnu/javax/net/ssl/provider/Util.java, + gnu/javax/net/ssl/provider/X509KeyManagerFactory.java, + gnu/javax/net/ssl/provider/X509TrustManagerFactory.java, + gnu/javax/net/ssl/provider/XMLSessionContext.java, + gnu/javax/security/auth/Password.java, + gnu/javax/security/auth/callback/AWTCallbackHandler.java, + gnu/javax/security/auth/callback/AbstractCallbackHandler.java, + gnu/javax/security/auth/callback/ConsoleCallbackHandler.java, + gnu/javax/security/auth/callback/DefaultCallbackHandler.java, + gnu/javax/security/auth/callback/GnuCallbacks.java, + gnu/javax/security/auth/callback/SwingCallbackHandler.java, + gnu/java/security/Registry.java, + gnu/java/security/Properties.java, + gnu/java/security/hash/BaseHash.java, + gnu/java/security/hash/HashFactory.java, + gnu/java/security/hash/Haval.java, + gnu/java/security/hash/IMessageDigest.java, + gnu/java/security/hash/MD2.java, + gnu/java/security/hash/MD4.java, + gnu/java/security/hash/MD5.java, + gnu/java/security/hash/RipeMD128.java, + gnu/java/security/hash/RipeMD160.java, + gnu/java/security/hash/Sha160.java, + gnu/java/security/hash/Sha256.java, + gnu/java/security/hash/Sha384.java, + gnu/java/security/hash/Sha512.java, + gnu/java/security/hash/Tiger.java, + gnu/java/security/hash/Whirlpool.java, + gnu/java/security/jce/hash/HavalSpi.java, + gnu/java/security/jce/hash/MD2Spi.java, + gnu/java/security/jce/hash/MD4Spi.java, + gnu/java/security/jce/hash/MD5Spi.java, + gnu/java/security/jce/hash/MessageDigestAdapter.java, + gnu/java/security/jce/hash/RipeMD128Spi.java, + gnu/java/security/jce/hash/RipeMD160Spi.java, + gnu/java/security/jce/hash/Sha160Spi.java, + gnu/java/security/jce/hash/Sha256Spi.java, + gnu/java/security/jce/hash/Sha384Spi.java, + gnu/java/security/jce/hash/Sha512Spi.java, + gnu/java/security/jce/hash/TigerSpi.java, + gnu/java/security/jce/hash/WhirlpoolSpi.java, + gnu/java/security/jce/prng/HavalRandomSpi.java, + gnu/java/security/jce/prng/MD2RandomSpi.java, + gnu/java/security/jce/prng/MD4RandomSpi.java, + gnu/java/security/jce/prng/MD5RandomSpi.java, + gnu/java/security/jce/prng/RipeMD128RandomSpi.java, + gnu/java/security/jce/prng/RipeMD160RandomSpi.java, + gnu/java/security/jce/prng/SecureRandomAdapter.java, + gnu/java/security/jce/prng/Sha160RandomSpi.java, + gnu/java/security/jce/prng/Sha256RandomSpi.java, + gnu/java/security/jce/prng/Sha384RandomSpi.java, + gnu/java/security/jce/prng/Sha512RandomSpi.java, + gnu/java/security/jce/prng/TigerRandomSpi.java, + gnu/java/security/jce/prng/WhirlpoolRandomSpi.java, + gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java, + gnu/java/security/jce/sig/DSSRawSignatureSpi.java, + gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java, + gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java, + gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java, + gnu/java/security/jce/sig/SignatureAdapter.java, + gnu/java/security/key/IKeyPairCodec.java, + gnu/java/security/key/IKeyPairGenerator.java, + gnu/java/security/key/KeyPairCodecFactory.java, + gnu/java/security/key/KeyPairGeneratorFactory.java, + gnu/java/security/key/dss/DSSKey.java, + gnu/java/security/key/dss/DSSKeyPairGenerator.java, + gnu/java/security/key/dss/DSSKeyPairRawCodec.java, + gnu/java/security/key/dss/DSSPrivateKey.java, + gnu/java/security/key/dss/DSSPublicKey.java, + gnu/java/security/key/dss/FIPS186.java, + gnu/java/security/key/rsa/GnuRSAKey.java, + gnu/java/security/key/rsa/GnuRSAPrivateKey.java, + gnu/java/security/key/rsa/GnuRSAPublicKey.java, + gnu/java/security/key/rsa/RSAKeyPairGenerator.java, + gnu/java/security/key/rsa/RSAKeyPairRawCodec.java, + gnu/java/security/prng/BasePRNG.java, + gnu/java/security/prng/EntropySource.java, + gnu/java/security/prng/IRandom.java, + gnu/java/security/prng/LimitReachedException.java, + gnu/java/security/prng/MDGenerator.java, + gnu/java/security/prng/PRNGFactory.java, + gnu/java/security/prng/RandomEvent.java, + gnu/java/security/prng/RandomEventListener.java, + gnu/java/security/sig/BaseSignature.java, + gnu/java/security/sig/ISignature.java, + gnu/java/security/sig/ISignatureCodec.java, + gnu/java/security/sig/SignatureFactory.java, + gnu/java/security/sig/dss/DSSSignature.java, + gnu/java/security/sig/dss/DSSSignatureRawCodec.java, + gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java, + gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java, + gnu/java/security/sig/rsa/EMSA_PSS.java, + gnu/java/security/sig/rsa/RSA.java, + gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java, + gnu/java/security/sig/rsa/RSAPSSSignature.java, + gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java, + gnu/java/security/util/Base64.java, + gnu/java/security/util/ExpirableObject.java, + gnu/java/security/util/Prime2.java, + gnu/java/security/util/Sequence.java, + gnu/java/security/util/SimpleList.java, + gnu/java/security/util/Util.java, + resource/gnu/javax/security/auth/callback/MessagesBundle.properties: + new files imported from GNU Crypto and Jessie. + 2006-01-25 Tom Tromey <tromey@redhat.com> * gnu/java/net/protocol/http/ChunkedInputStream.java (read): @@ -1,3 +1,12 @@ +New in release 0.21 (to be released) + +* GNU Crypto and Jessie have been merged into Classpath; this will + provide Classpath with a wide array of cryptographic algorithms + (ciphers, message digests, etc.) and implementations of SSL version + 3 and TLS version 1. These roughly complement the public + `java.security.' `javax.crypto,' and `javax.net.ssl' packages, and + are service providers implementing the underlying algorithms. + New in release 0.20 (Jan 13, 2006) * New StAX pull parser and SAX-over-StAX driver. Lots of DOM, SAX/StAX, diff --git a/gnu/classpath/debug/Component.java b/gnu/classpath/debug/Component.java index 242419ce4..af030ed27 100644 --- a/gnu/classpath/debug/Component.java +++ b/gnu/classpath/debug/Component.java @@ -89,9 +89,9 @@ public final class Component extends Level public static final Component SSL_HANDSHAKE = new Component ("SSL HANDSHAKE", 0); /** - * Traces the application messages during SSL communications. + * Traces record layer messages during SSL communications. */ - public static final Component SSL_APPLICATION = new Component ("SSL APPLICATION", 1); + public static final Component SSL_RECORD_LAYER = new Component ("SSL RECORD LAYER", 1); /** * Trace details about the SSL key exchange. diff --git a/gnu/java/security/Properties.java b/gnu/java/security/Properties.java new file mode 100644 index 000000000..813888c20 --- /dev/null +++ b/gnu/java/security/Properties.java @@ -0,0 +1,374 @@ +/* Properties.java -- run-time configuration properties. + Copyright (C) 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.java.security; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.PropertyPermission; + +/** + * <p>A global object containing build-specific properties that affect the + * behaviour of the generated binaries from this library.</p> + */ +public final class Properties +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "Properties"; + + private static final boolean DEBUG = false; + + // private static final int debuglevel = 9; + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(final String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String VERSION = "gnu.crypto.version"; + + public static final String PROPERTIES_FILE = "gnu.crypto.properties.file"; + + public static final String REPRODUCIBLE_PRNG = "gnu.crypto.with.reproducible.prng"; + + public static final String CHECK_WEAK_KEYS = "gnu.crypto.with.check.for.weak.keys"; + + public static final String DO_RSA_BLINDING = "gnu.crypto.with.rsa.blinding"; + + private static final String TRUE = Boolean.TRUE.toString(); + + private static final String FALSE = Boolean.FALSE.toString(); + + private static final HashMap props = new HashMap(); + + private static Properties singleton = null; + + private boolean reproducible = false; + + private boolean checkForWeakKeys = true; + + private boolean doRSABlinding = true; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private Properties() + { + super(); + init(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the string representation of the library global configuration + * property with the designated <code>key</code>.</p> + * + * @param key the case-insensitive, non-null and non-empty name of a + * configuration property. + * @return the string representation of the designated property, or + * <code>null</code> if such property is not yet set, or <code>key</code> is + * empty. + */ + public static final synchronized String getProperty(String key) + { + if (key == null) + return null; + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(key, "read")); + key = key.trim().toLowerCase(); + if ("".equals(key)) + return null; + return (String) props.get(key); + } + + /** + * <p>Sets the value of a designated library global configuration property, + * to a string representation of what should be a legal value.</p> + * + * @param key the case-insensitive, non-null and non-empty name of a + * configuration property. + * @param value the non-null, non-empty string representation of a legal + * value of the configuration property named by <code>key</code>. + */ + public static final synchronized void setProperty(String key, String value) + { + if (key == null || value == null) + return; + key = key.trim().toLowerCase(); + if ("".equals(key)) + return; + if (key.equals(VERSION)) + return; + value = value.trim(); + if ("".equals(value)) + return; + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(key, "write")); + if (key.equals(REPRODUCIBLE_PRNG) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) + setReproducible(Boolean.valueOf(value).booleanValue()); + else if (key.equals(CHECK_WEAK_KEYS) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) + setCheckForWeakKeys(Boolean.valueOf(value).booleanValue()); + else if (key.equals(DO_RSA_BLINDING) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) + setDoRSABlinding(Boolean.valueOf(value).booleanValue()); + else + props.put(key, value); + } + + /** + * <p>A convenience method that returns, as a boolean, the library global + * configuration property indicating if the default Pseudo Random Number + * Generator produces, or not, the same bit stream when instantiated.</p> + * + * @return <code>true</code> if the default PRNG produces the same bit stream + * with every VM instance. Returns <code>false</code> if the default PRNG is + * seeded with the time of day of its first invocation. + */ + public static final synchronized boolean isReproducible() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(REPRODUCIBLE_PRNG, "read")); + return instance().reproducible; + } + + /** + * <p>A convenience method that returns, as a boolean, the library global + * configuration property indicating if the implementations of symmetric + * key block ciphers check, or not, for possible/potential weak and semi-weak + * keys that may be produced in the course of generating round encryption + * and/or decryption keys.</p> + * + * @return <code>true</code> if the cipher implementations check for weak and + * semi-weak keys. Returns <code>false</code> if the cipher implementations + * do not check for weak or semi-weak keys. + */ + public static final synchronized boolean checkForWeakKeys() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(CHECK_WEAK_KEYS, "read")); + return instance().checkForWeakKeys; + } + + /** + * <p>A convenience method that returns, as a boolean, the library global + * configuration property indicating if RSA decryption (RSADP primitive), + * does, or not, blinding against timing attacks.</p> + * + * @return <code>true</code> if the RSA decryption primitive includes a + * blinding operation. Returns <code>false</code> if the RSA decryption + * primitive does not include the additional blinding operation. + */ + public static final synchronized boolean doRSABlinding() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(DO_RSA_BLINDING, "read")); + return instance().doRSABlinding; + } + + /** + * <p>A convenience method to set the global property for reproducibility of + * the default PRNG bit stream output.</p> + * + * @param value if <code>true</code> then the default PRNG bit stream output + * is the same with every invocation of the VM. + */ + public static final synchronized void setReproducible(final boolean value) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(REPRODUCIBLE_PRNG, "write")); + instance().reproducible = value; + props.put(REPRODUCIBLE_PRNG, String.valueOf(value)); + } + + /** + * <p>A convenience method to set the global property for checking for weak + * and semi-weak cipher keys.</p> + * + * @param value if <code>true</code> then the cipher implementations will + * invoke additional checks for weak and semi-weak key values that may get + * generated. + */ + public static final synchronized void setCheckForWeakKeys(final boolean value) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(CHECK_WEAK_KEYS, "write")); + instance().checkForWeakKeys = value; + props.put(CHECK_WEAK_KEYS, String.valueOf(value)); + } + + /** + * <p>A convenience method to set the global property fo adding a blinding + * operation when executing the RSA decryption primitive.</p> + * + * @param value if <code>true</code> then the code for performing the RSA + * decryption primitive will include a blinding operation. + */ + public static final synchronized void setDoRSABlinding(final boolean value) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(DO_RSA_BLINDING, "write")); + instance().doRSABlinding = value; + props.put(DO_RSA_BLINDING, String.valueOf(value)); + } + + private static final synchronized Properties instance() + { + if (singleton == null) + singleton = new Properties(); + return singleton; + } + + // Instance methods + // ------------------------------------------------------------------------- + private void init() + { + // default values + props.put(REPRODUCIBLE_PRNG, (reproducible ? "true" : "false")); + props.put(CHECK_WEAK_KEYS, (checkForWeakKeys ? "true" : "false")); + props.put(DO_RSA_BLINDING, (doRSABlinding ? "true" : "false")); + + // 1. allow site-wide override by reading a properties file + String propFile = null; + try + { + propFile = (String) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return System.getProperty(PROPERTIES_FILE); + } + }); + } + catch (SecurityException se) + { + if (DEBUG) + debug("Reading property " + PROPERTIES_FILE + + " not allowed. Ignored."); + } + if (propFile != null) + { + try + { + final java.util.Properties temp = new java.util.Properties(); + final FileInputStream fin = new FileInputStream(propFile); + temp.load(fin); + temp.list(System.out); + props.putAll(temp); + } + catch (IOException ioe) + { + if (DEBUG) + debug("IO error reading " + propFile + ": " + ioe.getMessage()); + } + catch (SecurityException se) + { + if (DEBUG) + debug("Security error reading " + propFile + ": " + + se.getMessage()); + } + } + + // 2. allow vm-specific override by allowing -D options in launcher + handleBooleanProperty(REPRODUCIBLE_PRNG); + handleBooleanProperty(CHECK_WEAK_KEYS); + handleBooleanProperty(DO_RSA_BLINDING); + + // re-sync the 'known' properties + reproducible = new Boolean((String) props.get(REPRODUCIBLE_PRNG)).booleanValue(); + checkForWeakKeys = new Boolean((String) props.get(CHECK_WEAK_KEYS)).booleanValue(); + doRSABlinding = new Boolean((String) props.get(DO_RSA_BLINDING)).booleanValue(); + + // This does not change. + props.put(VERSION, Registry.VERSION_STRING); + } + + private void handleBooleanProperty(final String name) + { + String s = null; + try + { + s = System.getProperty(name); + } + catch (SecurityException x) + { + if (DEBUG) + debug("SecurityManager forbids reading system properties. Ignored"); + } + if (s != null) + { + s = s.trim().toLowerCase(); + // we have to test for explicit "true" or "false". anything else may + // hide valid value set previously + if (s.equals(TRUE) || s.equals(FALSE)) + { + if (DEBUG) + debug("Setting " + name + " to '" + s + "'"); + props.put(name, s); + } + else + { + if (DEBUG) + debug("Invalid value for -D" + name + ": " + s + ". Ignored"); + } + } + } +} diff --git a/gnu/java/security/Registry.java b/gnu/java/security/Registry.java new file mode 100644 index 000000000..eaea2277d --- /dev/null +++ b/gnu/java/security/Registry.java @@ -0,0 +1,429 @@ +/* Registry.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.java.security; + +/** + * A placeholder for <i>names</i> and <i>literals</i> used throughout this + * library. + */ +public interface Registry +{ + + // Constants + // ------------------------------------------------------------------------- + + /** The name of our Providers. */ + String GNU_CRYPTO = "GNU-CRYPTO"; + + String GNU_SASL = "GNU-SASL"; + + String GNU_SECURITY = "GNU-SECURITY"; + + /** Our version number. */ + String VERSION_STRING = "2.1.0"; + + // Names of properties to use in Maps when initialising primitives ......... + + // Symmetric block cipher algorithms and synonyms........................... + + String ANUBIS_CIPHER = "anubis"; + + String BLOWFISH_CIPHER = "blowfish"; + + String DES_CIPHER = "des"; + + String KHAZAD_CIPHER = "khazad"; + + String RIJNDAEL_CIPHER = "rijndael"; + + String SERPENT_CIPHER = "serpent"; + + String SQUARE_CIPHER = "square"; + + String TRIPLEDES_CIPHER = "tripledes"; + + String TWOFISH_CIPHER = "twofish"; + + String CAST5_CIPHER = "cast5"; + + String NULL_CIPHER = "null"; + + /** AES is synonymous to Rijndael for 128-bit block size only. */ + String AES_CIPHER = "aes"; + + /** TripleDES is also known as DESede. */ + String DESEDE_CIPHER = "desede"; + + /** CAST5 is also known as CAST-128. */ + String CAST128_CIPHER = "cast128"; + + String CAST_128_CIPHER = "cast-128"; + + // Message digest algorithms and synonyms................................... + + String WHIRLPOOL_HASH = "whirlpool"; + + String RIPEMD128_HASH = "ripemd128"; + + String RIPEMD160_HASH = "ripemd160"; + + String SHA160_HASH = "sha-160"; + + String SHA256_HASH = "sha-256"; + + String SHA384_HASH = "sha-384"; + + String SHA512_HASH = "sha-512"; + + String TIGER_HASH = "tiger"; + + String HAVAL_HASH = "haval"; + + String MD5_HASH = "md5"; + + String MD4_HASH = "md4"; + + String MD2_HASH = "md2"; + + /** RIPEMD-128 is synonymous to RIPEMD128. */ + String RIPEMD_128_HASH = "ripemd-128"; + + /** RIPEMD-160 is synonymous to RIPEMD160. */ + String RIPEMD_160_HASH = "ripemd-160"; + + /** SHA-1 is synonymous to SHA-160. */ + String SHA_1_HASH = "sha-1"; + + /** SHA1 is synonymous to SHA-160. */ + String SHA1_HASH = "sha1"; + + /** SHA is synonymous to SHA-160. */ + String SHA_HASH = "sha"; + + // Symmetric block cipher modes of operations............................... + + /** Electronic CodeBook mode. */ + String ECB_MODE = "ecb"; + + /** Counter (NIST) mode. */ + String CTR_MODE = "ctr"; + + /** Integer Counter Mode (David McGrew). */ + String ICM_MODE = "icm"; + + /** Output Feedback Mode (NIST). */ + String OFB_MODE = "ofb"; + + /** Cipher block chaining mode (NIST). */ + String CBC_MODE = "cbc"; + + /** Cipher feedback mode (NIST). */ + String CFB_MODE = "cfb"; + + /** Authenticated-Encrypted mode. */ + String EAX_MODE = "eax"; + + // Padding scheme names and synonyms........................................ + + /** PKCS#7 padding scheme. */ + String PKCS7_PAD = "pkcs7"; + + /** Trailing Bit Complement padding scheme. */ + String TBC_PAD = "tbc"; + + /** EME-PKCS1-v1_5 padding as described in section 7.2 in RFC-3447. */ + String EME_PKCS1_V1_5_PAD = "eme-pkcs1-v1.5"; + + /** SSLv3 padding scheme. */ + String SSL3_PAD = "ssl3"; + + /** TLSv1 padding scheme. */ + String TLS1_PAD = "tls1"; + + // Pseudo-random number generators.......................................... + + /** (Apparently) RC4 keystream PRNG. */ + String ARCFOUR_PRNG = "arcfour"; + + /** We use "rc4" as an alias for "arcfour". */ + String RC4_PRNG = "rc4"; + + /** PRNG based on David McGrew's Integer Counter Mode. */ + String ICM_PRNG = "icm"; + + /** PRNG based on a designated hash function. */ + String MD_PRNG = "md"; + + /** PRNG based on UMAC's Key Derivation Function. */ + String UMAC_PRNG = "umac-kdf"; + + /** + * PRNG based on PBKDF2 from PKCS #5 v.2. This is suffixed with the name + * of a MAC to be used as a PRF. + */ + String PBKDF2_PRNG_PREFIX = "pbkdf2-"; + + /** The continuously-seeded pseudo-random number generator. */ + String CSPRNG_PRNG = "csprng"; + + /** The Fortuna PRNG. */ + String FORTUNA_PRNG = "fortuna"; + + /** The Fortuna generator PRNG. */ + String FORTUNA_GENERATOR_PRNG = "fortuna-generator"; + + // Asymmetric keypair generators............................................ + + String DSS_KPG = "dss"; + + String RSA_KPG = "rsa"; + + String DH_KPG = "dh"; + + String SRP_KPG = "srp"; + + /** DSA is synonymous to DSS. */ + String DSA_KPG = "dsa"; + + // Signature-with-appendix schemes.......................................... + + String DSS_SIG = "dss"; + + String RSA_PSS_SIG = "rsa-pss"; + + String RSA_PKCS1_V1_5_SIG = "rsa-pkcs1-v1.5"; + + /** DSA is synonymous to DSS. */ + String DSA_SIG = "dsa"; + + // Key agreement protocols ................................................. + + String DH_KA = "dh"; + + String ELGAMAL_KA = "elgamal"; + + String SRP6_KA = "srp6"; + + String SRP_SASL_KA = "srp-sasl"; + + String SRP_TLS_KA = "srp-tls"; + + // Keyed-Hash Message Authentication Code .................................. + + /** Name prefix of every HMAC implementation. */ + String HMAC_NAME_PREFIX = "hmac-"; + + // Other MAC algorithms .................................................... + + /** The One-key CBC MAC. */ + String OMAC_PREFIX = "omac-"; + + /** Message Authentication Code using Universal Hashing (Ted Krovetz). */ + String UHASH32 = "uhash32"; + + String UMAC32 = "umac32"; + + /** The Truncated Multi-Modular Hash Function -v1 (David McGrew). */ + String TMMH16 = "tmmh16"; + + // String TMMH32 = "tmmh32"; + + // Format IDs used to identify how we externalise asymmetric keys .......... + String RAW_ENCODING = "gnu.crypto.raw.format"; + + int RAW_ENCODING_ID = 1; + + // Magic bytes we generate/expect in externalised asymmetric keys .......... + // the four bytes represent G (0x47) for GNU, 1 (0x01) for Raw format, + // D (0x44) for DSS, R (0x52) for RSA, H (0x48) for Diffie-Hellman, or S + // (0x53) for SRP-6, and finally P (0x50) for Public, p (0x70) for private, + // or S (0x53) for signature. + byte[] MAGIC_RAW_DSS_PUBLIC_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x44, + 0x50 }; + + byte[] MAGIC_RAW_DSS_PRIVATE_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x44, + 0x70 }; + + byte[] MAGIC_RAW_DSS_SIGNATURE = new byte[] { 0x47, RAW_ENCODING_ID, 0x44, + 0x53 }; + + byte[] MAGIC_RAW_RSA_PUBLIC_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x52, + 0x50 }; + + byte[] MAGIC_RAW_RSA_PRIVATE_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x52, + 0x70 }; + + byte[] MAGIC_RAW_RSA_PSS_SIGNATURE = new byte[] { 0x47, RAW_ENCODING_ID, + 0x52, 0x53 }; + + byte[] MAGIC_RAW_DH_PUBLIC_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x48, + 0x50 }; + + byte[] MAGIC_RAW_DH_PRIVATE_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x48, + 0x70 }; + + byte[] MAGIC_RAW_SRP_PUBLIC_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x53, + 0x50 }; + + byte[] MAGIC_RAW_SRP_PRIVATE_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x53, + 0x70 }; + + // SASL Property names ..................................................... + + String SASL_PREFIX = "gnu.crypto.sasl"; + + /** Name of username property. */ + String SASL_USERNAME = SASL_PREFIX + ".username"; + + /** Name of password property. */ + String SASL_PASSWORD = SASL_PREFIX + ".password"; + + /** Name of authentication information provider packages. */ + String SASL_AUTH_INFO_PROVIDER_PKGS = SASL_PREFIX + + ".auth.info.provider.pkgs"; + + /** SASL authorization ID. */ + String SASL_AUTHORISATION_ID = SASL_PREFIX + ".authorisation.ID"; + + /** SASL protocol. */ + String SASL_PROTOCOL = SASL_PREFIX + ".protocol"; + + /** SASL Server name. */ + String SASL_SERVER_NAME = SASL_PREFIX + ".server.name"; + + /** SASL Callback handler. */ + String SASL_CALLBACK_HANDLER = SASL_PREFIX + ".callback.handler"; + + /** SASL channel binding. */ + String SASL_CHANNEL_BINDING = SASL_PREFIX + ".channel.binding"; + + // SASL data element size limits ........................................... + + /** The size limit, in bytes, of a SASL OS (Octet Sequence) element. */ + int SASL_ONE_BYTE_MAX_LIMIT = 255; + + /** + * The size limit, in bytes, of both a SASL MPI (Multi-Precision Integer) + * element and a SASL Text element. + */ + int SASL_TWO_BYTE_MAX_LIMIT = 65535; + + /** The size limit, in bytes, of a SASL EOS (Extended Octet Sequence) element. */ + int SASL_FOUR_BYTE_MAX_LIMIT = 2147483383; + + /** The size limit, in bytes, of a SASL Buffer. */ + int SASL_BUFFER_MAX_LIMIT = 2147483643; + + // Canonical names of SASL mechanisms ...................................... + + String SASL_ANONYMOUS_MECHANISM = "ANONYMOUS"; + + String SASL_CRAM_MD5_MECHANISM = "CRAM-MD5"; + + String SASL_PLAIN_MECHANISM = "PLAIN"; + + String SASL_SRP_MECHANISM = "SRP"; + + // Canonical names of Integrity Protection algorithms ...................... + + String SASL_HMAC_MD5_IALG = "HMACwithMD5"; + + String SASL_HMAC_SHA_IALG = "HMACwithSHA"; + + // Quality Of Protection string representations ............................ + + /** authentication only. */ + String QOP_AUTH = "auth"; + + /** authentication plus integrity protection. */ + String QOP_AUTH_INT = "auth-int"; + + /** authentication plus integrity and confidentiality protection. */ + String QOP_AUTH_CONF = "auth-conf"; + + // SASL mechanism strength string representation ........................... + + String STRENGTH_HIGH = "high"; + + String STRENGTH_MEDIUM = "medium"; + + String STRENGTH_LOW = "low"; + + // SASL Server Authentication requirement .................................. + + /** Server must authenticate to the client. */ + String SERVER_AUTH_TRUE = "true"; + + /** Server does not need to, or cannot, authenticate to the client. */ + String SERVER_AUTH_FALSE = "false"; + + // SASL mechanism reuse capability ......................................... + + String REUSE_TRUE = "true"; + + String REUSE_FALSE = "false"; + + // Keyrings ............................................................... + + byte[] GKR_MAGIC = new byte[] { 0x47, 0x4b, 0x52, 0x01 }; + + // Ring usage fields. + int GKR_PRIVATE_KEYS = 1 << 0; + + int GKR_PUBLIC_CREDENTIALS = 1 << 1; + + int GKR_CERTIFICATES = 1 << 2; + + // HMac types. + int GKR_HMAC_MD5_128 = 0; + + int GKR_HMAC_SHA_160 = 1; + + int GKR_HMAC_MD5_96 = 2; + + int GKR_HMAC_SHA_96 = 3; + + // Cipher types. + int GKR_CIPHER_AES_128_OFB = 0; + + int GKR_CIPHER_AES_128_CBC = 1; + + // Methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/hash/BaseHash.java b/gnu/java/security/hash/BaseHash.java new file mode 100644 index 000000000..720b83539 --- /dev/null +++ b/gnu/java/security/hash/BaseHash.java @@ -0,0 +1,206 @@ +/* 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; + +/** + * <p>A base abstract class to facilitate hash implementations.</p> + */ +public abstract class BaseHash implements IMessageDigest +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial constructor for use by concrete subclasses.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IMessageDigest interface implementation --------------------------------- + + 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(); + } + + // methods to be implemented by concrete subclasses ------------------------ + + public abstract Object clone(); + + public abstract boolean selfTest(); + + /** + * <p>Returns the byte array to use as padding before completing a hash + * operation.</p> + * + * @return the bytes to pad the remaining bytes in the buffer before + * completing a hash operation. + */ + protected abstract byte[] padBuffer(); + + /** + * <p>Constructs the result from the contents of the current context.</p> + * + * @return the output of the completed hash operation. + */ + protected abstract byte[] getResult(); + + /** Resets the instance for future re-use. */ + protected abstract void resetContext(); + + /** + * <p>The block digest transformation per se.</p> + * + * @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); +} diff --git a/gnu/java/security/hash/HashFactory.java b/gnu/java/security/hash/HashFactory.java new file mode 100644 index 000000000..e52092123 --- /dev/null +++ b/gnu/java/security/hash/HashFactory.java @@ -0,0 +1,178 @@ +/* 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; + +/** + * <p>A <i>Factory</i> to instantiate message digest algorithm instances.</p> + */ +public class HashFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + private HashFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Return an instance of a hash algorithm given its name.</p> + * + * @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; + } + + /** + * <p>Returns a {@link Set} of names of hash algorithms supported by this + * <i>Factory</i>.</p> + * + * @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); + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/hash/Haval.java b/gnu/java/security/hash/Haval.java new file mode 100644 index 000000000..f9f3282f2 --- /dev/null +++ b/gnu/java/security/hash/Haval.java @@ -0,0 +1,759 @@ +/* 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; + +/** + * <p>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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + */ + public Haval() + { + this(HAVAL_128_BIT, HAVAL_3_ROUND); + } + + /** + * <p>Calls the constructor with two arguments using the designated output + * size, and {@link #HAVAL_3_ROUND} for the value of number of rounds.</p> + * + * @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); + } + + /** + * <p>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.</p> + * + * @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; + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Haval(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + 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; + result[padding++] = (byte) (((bl & 0x03) << 6) | ((rounds & 0x07) << 3) | (HAVAL_VERSION & 0x07)); + 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) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new Haval().digest()))); + } + return valid.booleanValue(); + } + + // helper methods ---------------------------------------------------------- + + /** 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; + } +} diff --git a/gnu/java/security/hash/IMessageDigest.java b/gnu/java/security/hash/IMessageDigest.java new file mode 100644 index 000000000..b3d7f69ca --- /dev/null +++ b/gnu/java/security/hash/IMessageDigest.java @@ -0,0 +1,135 @@ +/* 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; + +/** + * <p>The basic visible methods of any hash algorithm.</p> + * + * <p>A hash (or message digest) algorithm produces its output by iterating a + * basic compression function on blocks of data.</p> + */ +public interface IMessageDigest extends Cloneable +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the canonical name of this algorithm.</p> + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * <p>Returns the output length in bytes of this message digest algorithm.</p> + * + * @return the output length in bytes of this message digest algorithm. + */ + int hashSize(); + + /** + * <p>Returns the algorithm's (inner) block size in bytes.</p> + * + * @return the algorithm's inner block size in bytes. + */ + int blockSize(); + + /** + * <p>Continues a message digest operation using the input byte.</p> + * + * @param b the input byte to digest. + */ + void update(byte b); + + /** + * <p>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.</p> + * + * @param in the input block. + */ + void update(byte[] in); + + /** + * <p>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.</p> + * + * @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); + + /** + * <p>Completes the message digest by performing final operations such as + * padding and resetting the instance.</p> + * + * @return the array of bytes representing the hash value. + */ + byte[] digest(); + + /** + * <p>Resets the current context of this instance clearing any eventually cached + * intermediary values.</p> + */ + void reset(); + + /** + * <p>A basic test. Ensures that the digest of a pre-determined message is equal + * to a known pre-computed value.</p> + * + * @return <tt>true</tt> if the implementation passes a basic self-test. + * Returns <tt>false</tt> otherwise. + */ + boolean selfTest(); + + /** + * <p>Returns a clone copy of this instance.</p> + * + * @return a clone copy of this instance. + */ + Object clone(); +} diff --git a/gnu/java/security/hash/MD2.java b/gnu/java/security/hash/MD2.java new file mode 100644 index 000000000..41e876983 --- /dev/null +++ b/gnu/java/security/hash/MD2.java @@ -0,0 +1,301 @@ +/* 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; + +/** + * <p>An implementation of the MD2 message digest algorithm.</p> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Creates a new MD2 digest ready for use. */ + public MD2() + { + super(Registry.MD2_HASH, DIGEST_LENGTH, BLOCK_LENGTH); + } + + /** + * <p>Private constructor used for cloning.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new MD2(this); + } + + // Implementation of abstract methods in BaseHash -------------------------- + + 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) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new MD2().digest()))); + } + return valid.booleanValue(); + } + + /** + * <p>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).</p> + * + * @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; + } + + /** + * <p>Adds <code>BLOCK_LENGTH</code> bytes to the running digest.</p> + * + * @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) + { + // encryptBlock(in, off); + // updateCheckSum(in, off); + updateCheckSumAndEncryptBlock(in, off); + } + + // Private instance methods ------------------------------------------------ + + /** + * Updates the checksum with the <code>BLOCK_LENGTH</code> bytes from the + * given array starting at <code>off</code>. + */ + /* + private void updateCheckSum(byte[] in, int off) { + byte l = checksum[BLOCK_LENGTH-1]; + for (int i = 0; i < BLOCK_LENGTH; i++) { + byte b = in[off+i]; + // l = (byte)((checksum[i] & 0xFF) ^ (PI[((b & 0xFF) ^ (l & 0xFF))] & 0xFF)); + l = (byte)(checksum[i] ^ PI[(b ^ l) & 0xFF]); + checksum[i] = l; + } + } + */ + /** + * 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] & 0xFF) ^ (PI[t & 0xFF] & 0xFF)); + t = (byte) (work[j] ^ PI[t & 0xFF]); + work[j] = t; + } + // t = (byte)((t + i) & 0xFF); + 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] & 0xFF) ^ (b & 0xFF)); + work[BLOCK_LENGTH * 2 + i] = (byte) (work[i] ^ b); + // l = (byte)((checksum[i] & 0xFF) ^ (PI[((b & 0xFF) ^ (l & 0xFF))] & 0xFF)); + 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] & 0xFF) ^ (PI[t & 0xFF] & 0xFF)); + t = (byte) (work[j] ^ PI[t & 0xFF]); + work[j] = t; + } + // t = (byte)((t + i) & 0xFF); + t = (byte) (t + i); + } + } +} diff --git a/gnu/java/security/hash/MD4.java b/gnu/java/security/hash/MD4.java new file mode 100644 index 000000000..54dda358b --- /dev/null +++ b/gnu/java/security/hash/MD4.java @@ -0,0 +1,328 @@ +/* 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; + +/** + * <p>An implementation of Ron Rivest's MD4 message digest algorithm.</p> + * + * <p>MD4 was the precursor to the stronger {@link gnu.crypto.hash.MD5} + * algorithm, and while not considered cryptograpically secure itself, MD4 is + * in use in various applications. It is slightly faster than MD5.</p> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Public constructor. Initializes the chaining variables, sets the byte + * count to <code>0</code>, and creates a new block of <code>512</code> bits. + * </p> + */ + public MD4() + { + super(Registry.MD4_HASH, DIGEST_LENGTH, BLOCK_LENGTH); + } + + /** + * <p>Trivial private constructor for cloning purposes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new MD4(this); + } + + // Implementation of abstract methods in BashHash -------------------------- + + protected byte[] getResult() + { + byte[] digest = { (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) }; + return digest; + } + + protected void resetContext() + { + a = A; + b = B; + c = C; + d = D; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new MD4().digest()))); + } + 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; + } +} diff --git a/gnu/java/security/hash/MD5.java b/gnu/java/security/hash/MD5.java new file mode 100644 index 000000000..463292984 --- /dev/null +++ b/gnu/java/security/hash/MD5.java @@ -0,0 +1,365 @@ +/* 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; + +/** + * <p>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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public MD5() + { + super(Registry.MD5_HASH, 16, BLOCK_SIZE); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new MD5(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + 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() + { + byte[] result = 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) }; + + return result; + } + + protected void resetContext() + { + // magic MD5/RIPEMD128 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new MD5().digest()))); + } + return valid.booleanValue(); + } +} diff --git a/gnu/java/security/hash/RipeMD128.java b/gnu/java/security/hash/RipeMD128.java new file mode 100644 index 000000000..83e8f2504 --- /dev/null +++ b/gnu/java/security/hash/RipeMD128.java @@ -0,0 +1,291 @@ +/* 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; + +/** + * <p>RIPEMD-128 is a 128-bit message digest.</p> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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]; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public RipeMD128() + { + super(Registry.RIPEMD128_HASH, 16, BLOCK_SIZE); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new RipeMD128(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + 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() + { + byte[] result = 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) }; + + return result; + } + + protected void resetContext() + { + // magic RIPEMD128 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean + (DIGEST0.equals(Util.toString(new RipeMD128().digest()))); + } + return valid.booleanValue(); + } +} diff --git a/gnu/java/security/hash/RipeMD160.java b/gnu/java/security/hash/RipeMD160.java new file mode 100644 index 000000000..73ecc5161 --- /dev/null +++ b/gnu/java/security/hash/RipeMD160.java @@ -0,0 +1,328 @@ +/* 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; + +/** + * <p>RIPEMD-160 is a 160-bit message digest.</p> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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]; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public RipeMD160() + { + super(Registry.RIPEMD160_HASH, 20, BLOCK_SIZE); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return (new RipeMD160(this)); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + 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() + { + byte[] result = 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) }; + + return result; + } + + protected void resetContext() + { + // magic RIPEMD160 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + h4 = 0xC3D2E1F0; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean + (DIGEST0.equals(Util.toString(new RipeMD160().digest()))); + } + return valid.booleanValue(); + } +} diff --git a/gnu/java/security/hash/Sha160.java b/gnu/java/security/hash/Sha160.java new file mode 100644 index 000000000..bf5f45652 --- /dev/null +++ b/gnu/java/security/hash/Sha160.java @@ -0,0 +1,308 @@ +/* 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; + +/** + * <p>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> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Sha160() + { + super(Registry.SHA160_HASH, 20, BLOCK_SIZE); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final int[] G(int hh0, int hh1, int hh2, int hh3, int hh4, + byte[] in, int offset) + { + // int[] w = new int[80]; + // int i, T; + // for (i = 0; i < 16; i++) { + // w[i] = in[offset++] << 24 | + // (in[offset++] & 0xFF) << 16 | + // (in[offset++] & 0xFF) << 8 | + // (in[offset++] & 0xFF); + // } + // for (i = 16; i < 80; i++) { + // T = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]; + // w[i] = T << 1 | T >>> 31; + // } + + // return sha(hh0, hh1, hh2, hh3, hh4, in, offset, w); + return sha(hh0, hh1, hh2, hh3, hh4, in, offset); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Sha160(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected void transform(byte[] in, int offset) + { + // int i, T; + // for (i = 0; i < 16; i++) { + // W[i] = in[offset++] << 24 | + // (in[offset++] & 0xFF) << 16 | + // (in[offset++] & 0xFF) << 8 | + // (in[offset++] & 0xFF); + // } + // for (i = 16; i < 80; i++) { + // T = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; + // W[i] = T << 1 | T >>> 31; + // } + + // int[] result = sha(h0, h1, h2, h3, h4, in, offset, W); + 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() + { + byte[] result = 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 }; + + return result; + } + + 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 = new Boolean(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + // SHA specific methods ---------------------------------------------------- + + private static final synchronized int[] + // sha(int hh0, int hh1, int hh2, int hh3, int hh4, byte[] in, int offset, int[] w) { + 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; + } + + // rounds 0-19 + for (r = 0; r < 20; r++) + { + 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; + } + + // rounds 20-39 + for (r = 20; r < 40; r++) + { + 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; + } + + // rounds 40-59 + for (r = 40; r < 60; r++) + { + 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; + } + + // rounds 60-79 + for (r = 60; r < 80; r++) + { + 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 }; + } +} diff --git a/gnu/java/security/hash/Sha256.java b/gnu/java/security/hash/Sha256.java new file mode 100644 index 000000000..9ef70a1a6 --- /dev/null +++ b/gnu/java/security/hash/Sha256.java @@ -0,0 +1,278 @@ +/* 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; + +/** + * <p>Implementation of SHA2-1 [SHA-256] per the IETF Draft Specification.</p> + * + * <p>References:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Sha256() + { + super(Registry.SHA256_HASH, 32, BLOCK_SIZE); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Sha256(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + 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 = new Boolean(DIGEST0.equals(result)); + } + + return valid.booleanValue(); + } + + // SHA specific methods ---------------------------------------------------- + + private static final synchronized 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 }; + } +} diff --git a/gnu/java/security/hash/Sha384.java b/gnu/java/security/hash/Sha384.java new file mode 100644 index 000000000..2f619dc98 --- /dev/null +++ b/gnu/java/security/hash/Sha384.java @@ -0,0 +1,322 @@ +/* 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; + +/** + * <p>Implementation of SHA2-2 [SHA-384] per the IETF Draft Specification.</p> + * + * <p>References:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Sha384() + { + super(Registry.SHA384_HASH, 48, BLOCK_SIZE); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Sha384(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + 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-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 = new Boolean(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + // SHA specific methods ---------------------------------------------------- + + private static final synchronized 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 }; + } +} diff --git a/gnu/java/security/hash/Sha512.java b/gnu/java/security/hash/Sha512.java new file mode 100644 index 000000000..798b34dfc --- /dev/null +++ b/gnu/java/security/hash/Sha512.java @@ -0,0 +1,322 @@ +/* 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; + +/** + * <p>Implementation of SHA2-3 [SHA-512] per the IETF Draft Specification.</p> + * + * <p>References:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Sha512() + { + super(Registry.SHA512_HASH, 64, BLOCK_SIZE); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Sha512(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + 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 = new Boolean(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + // SHA specific methods ---------------------------------------------------- + + private static final synchronized 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 }; + } +} diff --git a/gnu/java/security/hash/Tiger.java b/gnu/java/security/hash/Tiger.java new file mode 100644 index 000000000..f39fed30d --- /dev/null +++ b/gnu/java/security/hash/Tiger.java @@ -0,0 +1,943 @@ +/* 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> + * + * <p>References:</p> + * <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 +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + 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; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * 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; + } + + // Instance methods implementing BaseHash. + // ----------------------------------------------------------------------- + + public Object clone() + { + return new Tiger(this); + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new Tiger().digest()))); + } + 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; + } +} diff --git a/gnu/java/security/hash/Whirlpool.java b/gnu/java/security/hash/Whirlpool.java new file mode 100644 index 000000000..8c5d9f360 --- /dev/null +++ b/gnu/java/security/hash/Whirlpool.java @@ -0,0 +1,626 @@ +/* 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.Registry; +import gnu.java.security.util.Util; + +/** + * <p>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> + * + * <p><b>IMPORTANT</b>: This implementation is not thread-safe.</p> + * + * <p>References:</p> + * + * <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@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li> + * </ol> + */ +public final class Whirlpool extends BaseHash +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + + private static final int debuglevel = 3; + + // Constants and variables + // ------------------------------------------------------------------------- + + 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 = "470F0409ABAA446E49667D4EBE12A14387CEDBD10DD17B8243CAD550A089DC0F" + + "EEA7AA40F6C2AAAB71C6EBD076E43C7CFCA0AD32567897DCB5969861049A0F5A"; + + private static final int R = 10; // default number of rounds + + private static final String Sd = // 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"; + + 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]; + + 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 code - to intialise lookup tables -------------------------------- + + static + { + long time = System.currentTimeMillis(); + + int ROOT = 0x11d; // para. 2.1 [WHIRLPOOL] + int i, r, j; + long s, s2, s3, s4, s5, s8, s9, t; + char c; + final byte[] S = new byte[256]; + for (i = 0; i < 256; i++) + { + c = Sd.charAt(i >>> 1); + + s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFFL; + s2 = s << 1; + if (s2 > 0xFFL) + { + s2 ^= ROOT; + } + s3 = s2 ^ s; + s4 = s2 << 1; + if (s4 > 0xFFL) + { + s4 ^= ROOT; + } + s5 = s4 ^ s; + s8 = s4 << 1; + if (s8 > 0xFFL) + { + s8 ^= ROOT; + } + s9 = s8 ^ s; + + S[i] = (byte) s; + T0[i] = t = s << 56 | s << 48 | s3 << 40 | s << 32 | s5 << 24 + | s8 << 16 | s9 << 8 | s5; + 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 = 1, i = 0, j = 0; r < R + 1; r++) + { + rc[i++] = (S[j++] & 0xFFL) << 56 | (S[j++] & 0xFFL) << 48 + | (S[j++] & 0xFFL) << 40 | (S[j++] & 0xFFL) << 32 + | (S[j++] & 0xFFL) << 24 | (S[j++] & 0xFFL) << 16 + | (S[j++] & 0xFFL) << 8 | (S[j++] & 0xFFL); + } + + time = System.currentTimeMillis() - time; + + if (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static data"); + System.out.println(); + + System.out.println(); + System.out.println("T0[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T0[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T1[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T1[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T2[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T2[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T3[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T3[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T4[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T4[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T5[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T6[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T7[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("rc[]:"); + for (i = 0; i < R; i++) + { + System.out.println("0x" + Util.toString(rc[i])); + } + System.out.println(); + + System.out.println(); + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Whirlpool() + { + super(Registry.WHIRLPOOL_HASH, 20, BLOCK_SIZE); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return (new Whirlpool(this)); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + 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 + byte[] result = 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 }; + + return result; + } + + protected void resetContext() + { + H0 = H1 = H2 = H3 = H4 = H5 = H6 = H7 = 0L; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean( + DIGEST0.equals(Util.toString(new Whirlpool().digest()))); + } + return valid.booleanValue(); + } +} diff --git a/gnu/java/security/jce/hash/HavalSpi.java b/gnu/java/security/jce/hash/HavalSpi.java new file mode 100644 index 000000000..e127779ef --- /dev/null +++ b/gnu/java/security/jce/hash/HavalSpi.java @@ -0,0 +1,68 @@ +/* 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 <code>HAVAL</code> <i>Service Provider Interface</i> + * (<b>SPI</b>) Adapter.<p> + * + * @version Revision: $ + */ +public class HavalSpi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public HavalSpi() + { + super(Registry.HAVAL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/MD2Spi.java b/gnu/java/security/jce/hash/MD2Spi.java new file mode 100644 index 000000000..5b6b0e1e1 --- /dev/null +++ b/gnu/java/security/jce/hash/MD2Spi.java @@ -0,0 +1,69 @@ +/* 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; + +/** + * <p>The implementation of the MD2 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter.</p> + * + * @version $Revision: 1.1 $ + */ +public class MD2Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public MD2Spi() + { + super(Registry.MD2_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/MD4Spi.java b/gnu/java/security/jce/hash/MD4Spi.java new file mode 100644 index 000000000..8be449934 --- /dev/null +++ b/gnu/java/security/jce/hash/MD4Spi.java @@ -0,0 +1,69 @@ +/* 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; + +/** + * <p>The implementation of the MD4 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter.</p> + * + * @version $Revision: 1.1 $ + */ +public class MD4Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public MD4Spi() + { + super(Registry.MD4_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/MD5Spi.java b/gnu/java/security/jce/hash/MD5Spi.java new file mode 100644 index 000000000..92fb6ab38 --- /dev/null +++ b/gnu/java/security/jce/hash/MD5Spi.java @@ -0,0 +1,68 @@ +/* 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.<p> + * + * @version $Revision: 1.1 $ + */ +public class MD5Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public MD5Spi() + { + super(Registry.MD5_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/MessageDigestAdapter.java b/gnu/java/security/jce/hash/MessageDigestAdapter.java new file mode 100644 index 000000000..9b8a73d55 --- /dev/null +++ b/gnu/java/security/jce/hash/MessageDigestAdapter.java @@ -0,0 +1,147 @@ +/* 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.crypto 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 java.security.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 Crypto provider implement the {@link java.lang.Cloneable} interface.<p> + * + * @version $Revision: 1.1 $ + */ +class MessageDigestAdapter extends MessageDigestSpi implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying hash instance. */ + private IMessageDigest adaptee; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * 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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // java.security.MessageDigestSpi interface implementation + // ------------------------------------------------------------------------- + + 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(); + } +} diff --git a/gnu/java/security/jce/hash/RipeMD128Spi.java b/gnu/java/security/jce/hash/RipeMD128Spi.java new file mode 100644 index 000000000..b8e90d4bf --- /dev/null +++ b/gnu/java/security/jce/hash/RipeMD128Spi.java @@ -0,0 +1,68 @@ +/* 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.<p> + * + * @version $Revision: 1.1 $ + */ +public class RipeMD128Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RipeMD128Spi() + { + super(Registry.RIPEMD128_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/RipeMD160Spi.java b/gnu/java/security/jce/hash/RipeMD160Spi.java new file mode 100644 index 000000000..49615e2fc --- /dev/null +++ b/gnu/java/security/jce/hash/RipeMD160Spi.java @@ -0,0 +1,68 @@ +/* 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.<p> + * + * @version $Revision: 1.1 $ + */ +public class RipeMD160Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RipeMD160Spi() + { + super(Registry.RIPEMD160_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/Sha160Spi.java b/gnu/java/security/jce/hash/Sha160Spi.java new file mode 100644 index 000000000..a9b72634d --- /dev/null +++ b/gnu/java/security/jce/hash/Sha160Spi.java @@ -0,0 +1,68 @@ +/* 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.<p> + * + * @version $Revision: 1.1 $ + */ +public class Sha160Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha160Spi() + { + super(Registry.SHA160_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/Sha256Spi.java b/gnu/java/security/jce/hash/Sha256Spi.java new file mode 100644 index 000000000..9eeaebdea --- /dev/null +++ b/gnu/java/security/jce/hash/Sha256Spi.java @@ -0,0 +1,68 @@ +/* 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; + +/** + * <p>The implementation of the SHA-2-1 (256-bit) <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter.</p> + * + * @version $Revision: 1.1 $ + */ +public class Sha256Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha256Spi() + { + super(Registry.SHA256_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/Sha384Spi.java b/gnu/java/security/jce/hash/Sha384Spi.java new file mode 100644 index 000000000..96e1e6eb0 --- /dev/null +++ b/gnu/java/security/jce/hash/Sha384Spi.java @@ -0,0 +1,68 @@ +/* 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; + +/** + * <p>The implementation of the SHA-2-2 (384-bit) <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter.</p> + * + * @version $Revision: 1.1 $ + */ +public class Sha384Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha384Spi() + { + super(Registry.SHA384_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/Sha512Spi.java b/gnu/java/security/jce/hash/Sha512Spi.java new file mode 100644 index 000000000..75c617046 --- /dev/null +++ b/gnu/java/security/jce/hash/Sha512Spi.java @@ -0,0 +1,68 @@ +/* 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; + +/** + * <p>The implementation of the SHA-2-3 (512-bit) <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter.</p> + * + * @version $Revision: 1.1 $ + */ +public class Sha512Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha512Spi() + { + super(Registry.SHA512_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/TigerSpi.java b/gnu/java/security/jce/hash/TigerSpi.java new file mode 100644 index 000000000..b355d78d0 --- /dev/null +++ b/gnu/java/security/jce/hash/TigerSpi.java @@ -0,0 +1,69 @@ +/* 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; + +/** + * <p>The implementation of the Tiger <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter.</p> + * + * @version $Revision: 1.1 $ + */ +public class TigerSpi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public TigerSpi() + { + super(Registry.TIGER_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/WhirlpoolSpi.java b/gnu/java/security/jce/hash/WhirlpoolSpi.java new file mode 100644 index 000000000..e42e74ddb --- /dev/null +++ b/gnu/java/security/jce/hash/WhirlpoolSpi.java @@ -0,0 +1,68 @@ +/* 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.<p> + * + * @version $Revision: 1.1 $ + */ +public class WhirlpoolSpi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public WhirlpoolSpi() + { + super(Registry.WHIRLPOOL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/HavalRandomSpi.java b/gnu/java/security/jce/prng/HavalRandomSpi.java new file mode 100644 index 000000000..0c39a37fd --- /dev/null +++ b/gnu/java/security/jce/prng/HavalRandomSpi.java @@ -0,0 +1,66 @@ +/* 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.<p> + */ +public class HavalRandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public HavalRandomSpi() + { + super(Registry.HAVAL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/MD2RandomSpi.java b/gnu/java/security/jce/prng/MD2RandomSpi.java new file mode 100644 index 000000000..72a7f4873 --- /dev/null +++ b/gnu/java/security/jce/prng/MD2RandomSpi.java @@ -0,0 +1,66 @@ +/* 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.<p> + */ +public class MD2RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public MD2RandomSpi() + { + super(Registry.MD2_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/MD4RandomSpi.java b/gnu/java/security/jce/prng/MD4RandomSpi.java new file mode 100644 index 000000000..f5f98f8f3 --- /dev/null +++ b/gnu/java/security/jce/prng/MD4RandomSpi.java @@ -0,0 +1,66 @@ +/* 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.<p> + */ +public class MD4RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public MD4RandomSpi() + { + super(Registry.MD4_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/MD5RandomSpi.java b/gnu/java/security/jce/prng/MD5RandomSpi.java new file mode 100644 index 000000000..0181247bc --- /dev/null +++ b/gnu/java/security/jce/prng/MD5RandomSpi.java @@ -0,0 +1,66 @@ +/* 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.<p> + */ +public class MD5RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public MD5RandomSpi() + { + super(Registry.MD5_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/RipeMD128RandomSpi.java b/gnu/java/security/jce/prng/RipeMD128RandomSpi.java new file mode 100644 index 000000000..5580716a4 --- /dev/null +++ b/gnu/java/security/jce/prng/RipeMD128RandomSpi.java @@ -0,0 +1,66 @@ +/* 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; + +/** + * <p>The implementation of the RIPEMD128-based SecureRandom <i>Service Provider + * Interface</i> (<b>SPI</b>) adapter.<p> + */ +public class RipeMD128RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RipeMD128RandomSpi() + { + super(Registry.RIPEMD128_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/RipeMD160RandomSpi.java b/gnu/java/security/jce/prng/RipeMD160RandomSpi.java new file mode 100644 index 000000000..734fe824a --- /dev/null +++ b/gnu/java/security/jce/prng/RipeMD160RandomSpi.java @@ -0,0 +1,66 @@ +/* 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.<p> + */ +public class RipeMD160RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RipeMD160RandomSpi() + { + super(Registry.RIPEMD160_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/SecureRandomAdapter.java b/gnu/java/security/jce/prng/SecureRandomAdapter.java new file mode 100644 index 000000000..e7cb72091 --- /dev/null +++ b/gnu/java/security/jce/prng/SecureRandomAdapter.java @@ -0,0 +1,126 @@ +/* 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.HashMap; + +/** + * <p>The implementation of a generic {@link java.security.SecureRandom} adapter + * class to wrap gnu.crypto prng instances based on Message Digest algorithms.</p> + * + * <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> + * + * <p>All the abstract methods in the {@link SecureRandomSpi} class are + * implemented by this class and all its sub-classes.</p> + */ +abstract class SecureRandomAdapter extends SecureRandomSpi +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying prng instance. */ + private MDGenerator adaptee = new MDGenerator(); + + /** The name of the message digest algorithm used by the adaptee. */ + private String mdName; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial protected constructor.</p> + * + * @param mdName the canonical name of the underlying hash algorithm. + */ + protected SecureRandomAdapter(String mdName) + { + super(); + + this.mdName = mdName; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.SecureRandomSpi interface implementation ------------------ + + 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) + { + HashMap attributes = new HashMap(); + attributes.put(MDGenerator.MD_NAME, mdName); + attributes.put(MDGenerator.SEEED, seed); + adaptee.init(attributes); + } +} diff --git a/gnu/java/security/jce/prng/Sha160RandomSpi.java b/gnu/java/security/jce/prng/Sha160RandomSpi.java new file mode 100644 index 000000000..c93b02d3f --- /dev/null +++ b/gnu/java/security/jce/prng/Sha160RandomSpi.java @@ -0,0 +1,66 @@ +/* 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.<p> + */ +public class Sha160RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha160RandomSpi() + { + super(Registry.SHA160_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/Sha256RandomSpi.java b/gnu/java/security/jce/prng/Sha256RandomSpi.java new file mode 100644 index 000000000..736996430 --- /dev/null +++ b/gnu/java/security/jce/prng/Sha256RandomSpi.java @@ -0,0 +1,66 @@ +/* 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; + +/** + * <p>The implementation of the SHA-256 based SecureRandom <i>Service Provider + * Interface</i> (<b>SPI</b>) adapter.</p> + */ +public class Sha256RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha256RandomSpi() + { + super(Registry.SHA256_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/Sha384RandomSpi.java b/gnu/java/security/jce/prng/Sha384RandomSpi.java new file mode 100644 index 000000000..afbf19303 --- /dev/null +++ b/gnu/java/security/jce/prng/Sha384RandomSpi.java @@ -0,0 +1,66 @@ +/* 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; + +/** + * <p>The implementation of the SHA-384 based SecureRandom <i>Service Provider + * Interface</i> (<b>SPI</b>) adapter.</p> + */ +public class Sha384RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha384RandomSpi() + { + super(Registry.SHA384_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/Sha512RandomSpi.java b/gnu/java/security/jce/prng/Sha512RandomSpi.java new file mode 100644 index 000000000..b2b337760 --- /dev/null +++ b/gnu/java/security/jce/prng/Sha512RandomSpi.java @@ -0,0 +1,66 @@ +/* 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; + +/** + * <p>The implementation of the SHA-512 based SecureRandom <i>Service Provider + * Interface</i> (<b>SPI</b>) adapter.</p> + */ +public class Sha512RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha512RandomSpi() + { + super(Registry.SHA512_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/TigerRandomSpi.java b/gnu/java/security/jce/prng/TigerRandomSpi.java new file mode 100644 index 000000000..b4795b98e --- /dev/null +++ b/gnu/java/security/jce/prng/TigerRandomSpi.java @@ -0,0 +1,66 @@ +/* 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.<p> + */ +public class TigerRandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public TigerRandomSpi() + { + super(Registry.TIGER_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java b/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java new file mode 100644 index 000000000..f327f9df2 --- /dev/null +++ b/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java @@ -0,0 +1,66 @@ +/* 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.<p> + */ +public class WhirlpoolRandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public WhirlpoolRandomSpi() + { + super(Registry.WHIRLPOOL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java b/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java new file mode 100644 index 000000000..5cb1380d2 --- /dev/null +++ b/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java @@ -0,0 +1,113 @@ +/* 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.SecureRandom; +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.crypto 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 Crypto provider + * uses a default <i>modulus</i> size (keysize) of 1024 bits.<p> + * + * @version $Revision: 1.1 $ + */ +public class DSSKeyPairGeneratorSpi extends KeyPairGeneratorAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public DSSKeyPairGeneratorSpi() + { + super(Registry.DSS_KPG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public void initialize(int keysize, SecureRandom random) + { + HashMap attributes = new HashMap(); + attributes.put(DSSKeyPairGenerator.MODULUS_LENGTH, new Integer(keysize)); + if (random != null) + { + attributes.put(DSSKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + } + + adaptee.setup(attributes); + } + + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + HashMap attributes = new HashMap(); + if (params != null) + { + if (!(params instanceof DSAParameterSpec)) + { + throw new InvalidAlgorithmParameterException("params"); + } + + attributes.put(DSSKeyPairGenerator.DSS_PARAMETERS, params); + } + + if (random != null) + { + attributes.put(DSSKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + } + + adaptee.setup(attributes); + } +} diff --git a/gnu/java/security/jce/sig/DSSRawSignatureSpi.java b/gnu/java/security/jce/sig/DSSRawSignatureSpi.java new file mode 100644 index 000000000..16e4ddd4e --- /dev/null +++ b/gnu/java/security/jce/sig/DSSRawSignatureSpi.java @@ -0,0 +1,70 @@ +/* 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.<p> + * + * @version $Revision: 1.1 $ + */ +public class DSSRawSignatureSpi extends SignatureAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public DSSRawSignatureSpi() + { + super(Registry.DSS_SIG, new DSSSignatureRawCodec()); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java b/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java new file mode 100644 index 000000000..21a596a5f --- /dev/null +++ b/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java @@ -0,0 +1,109 @@ +/* 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.KeyPairGeneratorSpi; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The implementation of a generic {@link java.security.KeyPairGenerator} + * adapter class to wrap gnu.crypto 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 Crypto provider + * supplies (and document) default values to be used. For example, the GNU + * Crypto provider uses a default <i>modulus</i> size (keysize) of 1024 bits for + * the DSS (Digital Signature Standard) a.k.a <i>DSA</i>.<p> + * + * @version $Revision: 1.1 $ + */ +abstract class KeyPairGeneratorAdapter extends KeyPairGeneratorSpi +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying keypair instance. */ + protected IKeyPairGenerator adaptee; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial protected constructor. + * + * @param kpgName the canonical name of the keypair generator algorithm. + */ + protected KeyPairGeneratorAdapter(String kpgName) + { + super(); + + this.adaptee = KeyPairGeneratorFactory.getInstance(kpgName); + } + + // Class methods + // ------------------------------------------------------------------------- + + // java.security.KeyPairGeneratorSpi interface implementation + // ------------------------------------------------------------------------- + + public abstract void initialize(int keysize, SecureRandom random); + + public abstract void initialize(AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException; + + public KeyPair generateKeyPair() + { + return adaptee.generate(); + } +} diff --git a/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java b/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java new file mode 100644 index 000000000..54783eacf --- /dev/null +++ b/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java @@ -0,0 +1,111 @@ +/* RSAKeyPairGeneratorSpi.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.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.crypto 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 Crypto provider + * uses a default <i>modulus</i> size (keysize) of 1024 bits.<p> + */ +public class RSAKeyPairGeneratorSpi extends KeyPairGeneratorAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RSAKeyPairGeneratorSpi() + { + super(Registry.RSA_KPG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public void initialize(int keysize, SecureRandom random) + { + HashMap attributes = new HashMap(); + attributes.put(RSAKeyPairGenerator.MODULUS_LENGTH, new Integer(keysize)); + if (random != null) + { + attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + } + + 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); + } + + adaptee.setup(attributes); + } +} diff --git a/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java b/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java new file mode 100644 index 000000000..e44b8adf1 --- /dev/null +++ b/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java @@ -0,0 +1,69 @@ +/* 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.<p> + * + * @version $Revision: 1.1 $ + */ +public class RSAPSSRawSignatureSpi extends SignatureAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RSAPSSRawSignatureSpi() + { + super(Registry.RSA_PSS_SIG, new RSAPSSSignatureRawCodec()); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/sig/SignatureAdapter.java b/gnu/java/security/jce/sig/SignatureAdapter.java new file mode 100644 index 000000000..6f393478d --- /dev/null +++ b/gnu/java/security/jce/sig/SignatureAdapter.java @@ -0,0 +1,258 @@ +/* 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.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; + +/** + * The implementation of a generic {@link java.security.Signature} adapter class + * to wrap gnu.crypto 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 java.security.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 Crypto provider implement the {@link java.lang.Cloneable} interface.<p> + * + * @version $Revision: 1.1 $ + */ +class SignatureAdapter extends SignatureSpi implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying signature instance. */ + private ISignature adaptee; + + /** Our underlying signature encoder/decoder engine. */ + private ISignatureCodec codec; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial protected constructor.<p> + * + * @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.<p> + * + * @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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // java.security.SignatureSpi interface implementation + // ------------------------------------------------------------------------- + + 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(String.valueOf(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(String.valueOf(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(String.valueOf(x)); + } + } + + public void engineUpdate(byte b) throws SignatureException + { + try + { + adaptee.update(b); + } + catch (IllegalStateException x) + { + throw new SignatureException(String.valueOf(x)); + } + } + + public void engineUpdate(byte[] b, int off, int len) + throws SignatureException + { + try + { + adaptee.update(b, off, len); + } + catch (IllegalStateException x) + { + throw new SignatureException(String.valueOf(x)); + } + } + + public byte[] engineSign() throws SignatureException + { + Object signature = null; + try + { + signature = adaptee.sign(); + } + catch (IllegalStateException x) + { + throw new SignatureException(String.valueOf(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("len"); + } + + System.arraycopy(signature, 0, outbuf, offset, result); + return result; + } + + public boolean engineVerify(byte[] sigBytes) throws SignatureException + { + Object signature = codec.decodeSignature(sigBytes); + boolean result = false; + try + { + result = adaptee.verify(signature); + } + catch (IllegalStateException x) + { + throw new SignatureException(String.valueOf(x)); + } + + 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"); + } +} diff --git a/gnu/java/security/key/IKeyPairCodec.java b/gnu/java/security/key/IKeyPairCodec.java new file mode 100644 index 000000000..7ebfe7458 --- /dev/null +++ b/gnu/java/security/key/IKeyPairCodec.java @@ -0,0 +1,121 @@ +/* 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; + +/** + * <p>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.</p> + * + * @version $Revision: 1.1 $ + */ +public interface IKeyPairCodec +{ + + // Constants + // ------------------------------------------------------------------------- + + /** Constant identifying the <i>Raw</i> encoding format. */ + int RAW_FORMAT = Registry.RAW_ENCODING_ID; + + // Method(s) + // ------------------------------------------------------------------------- + + /** + * <p>Returns the unique identifier (within this library) of the format used + * to externalise public and private keys.</p> + * + * @return the identifier of the format, the object supports. + */ + int getFormatID(); + + /** + * <p>Encodes an instance of a public key for storage or transmission purposes.</p> + * + * @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); + + /** + * <p>Encodes an instance of a private key for storage or transmission purposes.</p> + * + * @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); + + /** + * <p>Decodes an instance of an external public key into its native Java + * representation.</p> + * + * @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); + + /** + * <p>Decodes an instance of an external private key into its native Java + * representation.</p> + * + * @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); +} diff --git a/gnu/java/security/key/IKeyPairGenerator.java b/gnu/java/security/key/IKeyPairGenerator.java new file mode 100644 index 000000000..219863d33 --- /dev/null +++ b/gnu/java/security/key/IKeyPairGenerator.java @@ -0,0 +1,82 @@ +/* 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.<p> + * + * @version $Revision: 1.1 $ + */ +public interface IKeyPairGenerator +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * Returns the canonical name of this keypair generator.<p> + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * [Re]-initialises this instance for use with a given set of attributes.<p> + * + * @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(); +} diff --git a/gnu/java/security/key/KeyPairCodecFactory.java b/gnu/java/security/key/KeyPairCodecFactory.java new file mode 100644 index 000000000..0bf9e6657 --- /dev/null +++ b/gnu/java/security/key/KeyPairCodecFactory.java @@ -0,0 +1,263 @@ +/* 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.DSSKeyPairRawCodec; +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.RSAKeyPairRawCodec; + +import java.lang.reflect.Constructor; +import java.util.Set; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * <p>A <i>Factory</i> class to instantiate key encoder/decoder instances.</p> + * + * @version $Revision: 1.1 $ + */ +public class KeyPairCodecFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyPairCodecFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a keypair codec given its name.</p> + * + * @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(); + 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; + } + + /** + * <p>Returns an instance of a keypair codec given a byte array that is + * assumed to contain a previously encoded key (public or private).</p> + * + * @param buffer a byte array containing a previously encoded key. + * @return an instance of the keypair codec, or <code>null</code> if none + * found. + */ + public static IKeyPairCodec getInstance(byte[] buffer) + { + if (buffer == null) + { + return null; + } + // our codecs prefix the stream with a 4-byte magic + if (buffer.length < 5) + { + return null; + } + // the first byte is always 0x47 + if (buffer[0] != 0x47) + { + return null; + } + // so far we only have RAW codecs + if (buffer[1] != Registry.RAW_ENCODING_ID) + { + return null; + } + IKeyPairCodec result = null; + switch (buffer[2]) + { + case 0x44: + result = new DSSKeyPairRawCodec(); + break; + case 0x52: + result = new RSAKeyPairRawCodec(); + break; + case 0x48: + result = makeInstance ("gnu.javax.crypto.key.dh.DHKeyPairRawCodec"); + break; + case 0x53: + result = makeInstance ("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec"); + break; + } + + return result; + } + + /** + * <p>Returns an instance of a keypair codec given a key.</p> + * + * @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; + } + + IKeyPairCodec result = null; + if (key instanceof PublicKey) + { + if (key instanceof DSSPublicKey) + { + result = new DSSKeyPairRawCodec(); + } + else if (key instanceof GnuRSAPublicKey) + { + result = new RSAKeyPairRawCodec(); + } + else if (matches (key, "gnu.javax.crypto.key.dh.GnuDHPublicKey")) + { + result = makeInstance ("gnu.javax.crypto.key.dh.DHKeyPairRawCodec"); + } + else if (matches (key, "gnu.javax.crypto.key.srp6.SRPPublicKey")) + { + result = makeInstance ("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec"); + } + } + else if (key instanceof PrivateKey) + { + if (key instanceof DSSPrivateKey) + { + result = new DSSKeyPairRawCodec(); + } + else if (key instanceof GnuRSAPrivateKey) + { + result = new RSAKeyPairRawCodec(); + } + else if (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.SRPPrivateKey")) + { + result = makeInstance ("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec"); + } + } + + return result; + } + + /** + * <p>Returns a {@link Set} of keypair codec names supported by this + * <i>Factory</i>.</p> + * + * @return a {@link Set} of keypair codec names (Strings). + */ + public static final Set getNames() + { + return KeyPairGeneratorFactory.getNames(); + } + + 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; + } + } +} diff --git a/gnu/java/security/key/KeyPairGeneratorFactory.java b/gnu/java/security/key/KeyPairGeneratorFactory.java new file mode 100644 index 000000000..edcc186e2 --- /dev/null +++ b/gnu/java/security/key/KeyPairGeneratorFactory.java @@ -0,0 +1,148 @@ +/* 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; + +/** + * <p>A Factory to instantiate asymmetric keypair generators.</p> + * + * @version $Revision: 1.1 $ + */ +public class KeyPairGeneratorFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyPairGeneratorFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a keypair generator given its name.</p> + * + * @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.equals(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; + } + + /** + * <p>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.</p> + * + * @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.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) + { + IllegalArgumentException iae = + new IllegalArgumentException ("strong crypto key pair generator not available: " + + clazz); + iae.initCause (x); + throw iae; + } + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/key/dss/DSSKey.java b/gnu/java/security/key/dss/DSSKey.java new file mode 100644 index 000000000..c052d3fde --- /dev/null +++ b/gnu/java/security/key/dss/DSSKey.java @@ -0,0 +1,173 @@ +/* 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.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.Key; +import java.security.interfaces.DSAKey; +import java.security.interfaces.DSAParams; +import java.security.spec.DSAParameterSpec; + +/** + * <p>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> + * + * <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> + * + * @version $Revision: 1.1 $ + * @see DSSPrivateKey#getEncoded + * @see DSSPublicKey#getEncoded + */ +public abstract class DSSKey implements Key, DSAKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * A prime modulus, where <code>2<sup>L-1</sup> < p < 2<sup>L</sup></code> + * for <code>512 <= L <= 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> < q + * < 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 < h < 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial protected constructor.</p> + * + * @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(BigInteger p, BigInteger q, BigInteger g) + { + super(); + + this.p = p; + this.q = q; + this.g = g; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.DSAKey interface implementation ---------------- + + public DSAParams getParams() + { + return new DSAParameterSpec(p, q, g); + } + + // java.security.Key interface implementation ------------------------------ + + public String getAlgorithm() + { + return Registry.DSS_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(IKeyPairCodec.RAW_FORMAT); + } + + public String getFormat() + { + return null; + } + + // Other instance methods -------------------------------------------------- + + /** + * <p>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> + * + * @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 DSAKey)) + { + return false; + } + DSAKey that = (DSAKey) obj; + return p.equals(that.getParams().getP()) + && q.equals(that.getParams().getQ()) + && g.equals(that.getParams().getG()); + } + + // abstract methods to be implemented by subclasses ------------------------ + + public abstract byte[] getEncoded(int format); +} diff --git a/gnu/java/security/key/dss/DSSKeyPairGenerator.java b/gnu/java/security/key/dss/DSSKeyPairGenerator.java new file mode 100644 index 000000000..3f9c80625 --- /dev/null +++ b/gnu/java/security/key/dss/DSSKeyPairGenerator.java @@ -0,0 +1,360 @@ +/* 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.Registry; +import gnu.java.security.hash.Sha160; +import gnu.java.security.key.IKeyPairGenerator; + +import java.io.PrintWriter; +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; + +/** + * <p>A key-pair generator for asymetric keys to use in conjunction with the DSS + * (Digital Signature Standard).</p> + * + * References:<br> + * <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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "dss"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = new BigInteger("2"); + + /** 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 defaults. */ + public static final String USE_DEFAULTS = "gnu.crypto.dss.use.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"; + + /** Default value for the modulus length. */ + private static final int DEFAULT_MODULUS_LENGTH = 1024; + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.key.IKeyPairGenerator interface implementation --------------- + + public String name() + { + return Registry.DSS_KPG; + } + + /** + * <p>Configures this instance.</p> + * + * @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; + } + + // 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: + 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); + + // 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 (DEBUG && debuglevel > 0) + { + debug("seed: " + seed.toString(16)); + debug("counter: " + counter.intValue()); + debug("q: " + q.toString(16)); + debug("p: " + p.toString(16)); + debug("e: " + e.toString(16)); + debug("g: " + g.toString(16)); + } + } + + BigInteger x = nextX(); + BigInteger y = g.modPow(x, p); + + PublicKey pubK = new DSSPublicKey(p, q, g, y); + PrivateKey secK = new DSSPrivateKey(p, q, g, x); + + return new KeyPair(pubK, secK); + } + + // Other instance methods -------------------------------------------------- + + /** + * <p>This method applies the following algorithm described in 3.1 of + * FIPS-186:</p> + * + * <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> + * + * <p>Note that in this implementation, XSEED, the optional user input, is + * always zero.</p> + */ + 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; + } + + /** + * <p>Fills the designated byte array with random data.</p> + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + { + new SecureRandom ().nextBytes(buffer); + } + } +} diff --git a/gnu/java/security/key/dss/DSSKeyPairRawCodec.java b/gnu/java/security/key/dss/DSSKeyPairRawCodec.java new file mode 100644 index 000000000..86e5b0bef --- /dev/null +++ b/gnu/java/security/key/dss/DSSKeyPairRawCodec.java @@ -0,0 +1,383 @@ +/* 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; + +/** + * <p>An object that implements the {@link IKeyPairCodec} operations for the + * <i>Raw</i> format to use with DSS keypairs.</p> + * + * @version $Revision: 1.1 $ + */ +public class DSSKeyPairRawCodec implements IKeyPairCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairCodec interface implementation ------------------ + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * <p>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> + * + * <p>The <i>Raw</i> format for a DSA public key, 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_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); + } + + /** + * <p>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> + * + * <p>The <i>Raw</i> format for a DSA private key, 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_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); + } +} diff --git a/gnu/java/security/key/dss/DSSPrivateKey.java b/gnu/java/security/key/dss/DSSPrivateKey.java new file mode 100644 index 000000000..dc73c5e89 --- /dev/null +++ b/gnu/java/security/key/dss/DSSPrivateKey.java @@ -0,0 +1,179 @@ +/* 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.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.interfaces.DSAPrivateKey; + +/** + * <p>An object that embodies a DSS (Digital Signature Standard) private key.</p> + * + * @version $Revision: 1.1 $ + * @see #getEncoded + */ +public class DSSPrivateKey extends DSSKey implements PrivateKey, DSAPrivateKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * <p>A randomly or pseudorandomly generated integer with <code>0 < x < + * q</code>.</p> + */ + private final BigInteger x; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial constructor.</p> + * + * @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) + { + super(p, q, g); + + this.x = x; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>A class method that takes the output of the <code>encodePrivateKey()</code> + * method of a DSS keypair codec object (an instance implementing + * {@link gnu.crypto.key.IKeyPairCodec} for DSS keys, and re-constructs an + * instance of this object.</p> + * + * @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) + { + // 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_DSS_PRIVATE_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new DSSKeyPairRawCodec(); + return (DSSPrivateKey) codec.decodePrivateKey(k); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.DSAPrivateKey interface implementation --------- + + public BigInteger getX() + { + return x; + } + + // Other instance methods -------------------------------------------------- + + /** + * <p>Returns the encoded form of this private key according to the + * designated format.</p> + * + * @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; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + * <p>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.</p> + * + * @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()); + } +} diff --git a/gnu/java/security/key/dss/DSSPublicKey.java b/gnu/java/security/key/dss/DSSPublicKey.java new file mode 100644 index 000000000..a76ce92b2 --- /dev/null +++ b/gnu/java/security/key/dss/DSSPublicKey.java @@ -0,0 +1,179 @@ +/* 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.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.interfaces.DSAPublicKey; + +/** + * <p>An object that embodies a DSS (Digital Signature Standard) public key.</p> + * + * @version $Revision: 1.1 $ + * @see #getEncoded + */ +public class DSSPublicKey extends DSSKey implements PublicKey, DSAPublicKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * <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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial constructor.</p> + * + * @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) + { + super(p, q, g); + + this.y = y; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>A class method that takes the output of the <code>encodePublicKey()</code> + * method of a DSS keypair codec object (an instance implementing + * {@link gnu.crypto.key.IKeyPairCodec} for DSS keys, and re-constructs an + * instance of this object.</p> + * + * @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) + { + // 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_DSS_PUBLIC_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new DSSKeyPairRawCodec(); + return (DSSPublicKey) codec.decodePublicKey(k); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.DSAPublicKey interface implementation ---------- + + public BigInteger getY() + { + return y; + } + + // Other instance methods -------------------------------------------------- + + /** + * <p>Returns the encoded form of this public key according to the designated + * format.</p> + * + * @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; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + * <p>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.</p> + * + * @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()); + } +} diff --git a/gnu/java/security/key/dss/FIPS186.java b/gnu/java/security/key/dss/FIPS186.java new file mode 100644 index 000000000..796f24bd3 --- /dev/null +++ b/gnu/java/security/key/dss/FIPS186.java @@ -0,0 +1,286 @@ +/* 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.Prime2; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * <p>An implementation of the DSA parameters generation as described in + * FIPS-186.</p> + * + * References:<br> + * <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. + * + * @version $Revision: 1.1 $ + */ +public class FIPS186 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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 = new BigInteger("2"); + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public FIPS186(int L, SecureRandom rnd) + { + super(); + + this.L = L; + this.rnd = rnd; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * 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> < q < 2<sup>160</sup></code></li> + * <li><code>2<sup>L-1</sup> < p < 2<sup>L</sup></code> for a + * specified <code>L</code>, where <code>L = 512 + 64j</code> for some + * <code>0 <= j <= 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 gnu.crypto.hash.Sha160} and a user supplied <i>SEED</i> + * to construct a prime, <code>q</code>, in the range 2<sup>159</sup> < q + * < 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> < X < 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 (Prime2.isProbablePrime(q)) + { + 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 (Prime2.isProbablePrime(p)) + { + 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 }; + } + + // helper methods ---------------------------------------------------------- + + /** + * 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 + { + new SecureRandom ().nextBytes(buffer); + } + } +} diff --git a/gnu/java/security/key/rsa/GnuRSAKey.java b/gnu/java/security/key/rsa/GnuRSAKey.java new file mode 100644 index 000000000..a92ef50a5 --- /dev/null +++ b/gnu/java/security/key/rsa/GnuRSAKey.java @@ -0,0 +1,171 @@ +/* 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.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.Key; +import java.security.interfaces.RSAKey; + +/** + * <p>A base asbtract class for both public and private RSA keys.</p> + * + * @version $Revision: 1.1 $ + */ +public abstract class GnuRSAKey implements Key, RSAKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The public modulus of an RSA key pair. */ + private final BigInteger n; + + /** The public exponent of an RSA key pair. */ + private final BigInteger e; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial protected constructor.</p> + * + * @param n the public modulus <code>n</code>. + * @param e the public exponent <code>e</code>. + */ + // protected GnuRSAKey(BigInteger n) { + protected GnuRSAKey(final BigInteger n, final BigInteger e) + { + super(); + + this.n = n; + this.e = e; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.RSAKey interface implementation ---------------- + + public BigInteger getModulus() + { + return getN(); + } + + // java.security.Key interface implementation ------------------------------ + + public String getAlgorithm() + { + return Registry.RSA_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(IKeyPairCodec.RAW_FORMAT); + } + + public String getFormat() + { + return null; + } + + // Other instance methods -------------------------------------------------- + + /** + * <p>Returns the modulus <code>n</code>.</p> + * + * @return the modulus <code>n</code>. + */ + public BigInteger getN() + { + return n; + } + + /** + * <p>Returns the public exponent <code>e</code>.</p> + * + * @return the public exponent <code>e</code>. + */ + public BigInteger getPublicExponent() + { + return getE(); + } + + /** + * <p>Same as {@link #getPublicExponent()}.</p> + * + * @return the public exponent <code>e</code>. + */ + public BigInteger getE() + { + return e; + } + + /** + * <p>Returns <code>true</code> if the designated object is an instance of + * {@link RSAKey} and has the same RSA parameter values as this one.</p> + * + * @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()); + } + + // abstract methods to be implemented by subclasses ------------------------ + + public abstract byte[] getEncoded(int format); +} diff --git a/gnu/java/security/key/rsa/GnuRSAPrivateKey.java b/gnu/java/security/key/rsa/GnuRSAPrivateKey.java new file mode 100644 index 000000000..851ea271b --- /dev/null +++ b/gnu/java/security/key/rsa/GnuRSAPrivateKey.java @@ -0,0 +1,255 @@ +/* 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.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; + +/** + * <p>An object that embodies an RSA private key.</p> + * + * <p>References:</p> + * <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> + * + * @version $Revision: 1.1 $ + */ +public class GnuRSAPrivateKey extends GnuRSAKey implements PrivateKey, + RSAPrivateCrtKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The first prime divisor of the modulus. */ + private final BigInteger p; + + /** The second prime divisor of the modulus. */ + private final BigInteger q; + + /** The public exponent of an RSA key. */ + // private final BigInteger e; + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial constructor.</p> + * + * @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(final BigInteger p, final BigInteger q, + final BigInteger e, final BigInteger d) + { + // super(p.multiply(q)); + super(p.multiply(q), e); + + this.p = p; + this.q = q; + // this.e = e; + this.d = d; + + // 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), + dP = e.modInverse(p.subtract(BigInteger.ONE)); + dQ = e.modInverse(q.subtract(BigInteger.ONE)); + // and the CRT coefficient qInv is a positive integer less than p + // satisfying + // q * qInv = 1 (mod p). + qInv = q.modInverse(p); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>A class method that takes the output of the <code>encodePrivateKey()</code> + * method of an RSA keypair codec object (an instance implementing + * {@link gnu.crypto.key.IKeyPairCodec} for RSA keys, and re-constructs an + * instance of this object.</p> + * + * @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) + { + // 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_RSA_PRIVATE_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + final IKeyPairCodec codec = new RSAKeyPairRawCodec(); + return (GnuRSAPrivateKey) codec.decodePrivateKey(k); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.RSAPrivateCrtKey interface implementation ------ + + // public BigInteger getPublicExponent() { + // return e; + // } + + 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; + } + + // java.security.interfaces.RSAPrivateKey interface implementation --------- + + public BigInteger getPrivateExponent() + { + return d; + } + + // Other instance methods -------------------------------------------------- + + /** + * <p>Returns the encoded form of this private key according to the + * designated format.</p> + * + * @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 gnu.crypto.key.rsa.RSAKeyPairRawCodec + */ + public byte[] getEncoded(final int format) + { + final byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new RSAKeyPairRawCodec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + * <p>Returns <code>true</code> if the designated object is an instance of + * this class and has the same RSA parameter values as this one.</p> + * + * @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; + } +} diff --git a/gnu/java/security/key/rsa/GnuRSAPublicKey.java b/gnu/java/security/key/rsa/GnuRSAPublicKey.java new file mode 100644 index 000000000..0e5cdb4cf --- /dev/null +++ b/gnu/java/security/key/rsa/GnuRSAPublicKey.java @@ -0,0 +1,179 @@ +/* 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.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; + +/** + * <p>An object that encapsulates an RSA public key.</p> + * + * <p>References:</p> + * <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> + * + * @version $Revision: 1.1 $ + */ +public class GnuRSAPublicKey extends GnuRSAKey implements PublicKey, + RSAPublicKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The public exponent of an RSA public key. */ + // private final BigInteger e; + // Constructor(s) + // ------------------------------------------------------------------------- + /** + * <p>Trivial constructor.</p> + * + * @param n the modulus. + * @param e the public exponent. + */ + public GnuRSAPublicKey(final BigInteger n, final BigInteger e) + { + // super(n); + super(n, e); + // + // this.e = e; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>A class method that takes the output of the <code>encodePublicKey()</code> + * method of an RSA keypair codec object (an instance implementing + * {@link gnu.crypto.key.IKeyPairCodec} for RSA keys, and re-constructs an + * instance of this object.</p> + * + * @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) + { + // 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_RSA_PUBLIC_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + final IKeyPairCodec codec = new RSAKeyPairRawCodec(); + return (GnuRSAPublicKey) codec.decodePublicKey(k); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.RSAPublicKey interface implementation ---------- + + // public BigInteger getPublicExponent() { + // return e; + // } + + // Other instance methods -------------------------------------------------- + + /** + * <p>Returns the encoded form of this public key according to the designated + * format.</p> + * + * @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; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + * <p>Returns <code>true</code> if the designated object is an instance of + * this class and has the same RSA parameter values as this one.</p> + * + * @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) && e.equals(that.getPublicExponent()); + return super.equals(that) + && getPublicExponent().equals(that.getPublicExponent()); + } +} diff --git a/gnu/java/security/key/rsa/RSAKeyPairGenerator.java b/gnu/java/security/key/rsa/RSAKeyPairGenerator.java new file mode 100644 index 000000000..a9738e751 --- /dev/null +++ b/gnu/java/security/key/rsa/RSAKeyPairGenerator.java @@ -0,0 +1,236 @@ +/* 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.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.Prime2; + +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; + +/** + * <p>A key-pair generator for asymetric keys to use in conjunction with the RSA + * scheme.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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"; + + /** Default value for the modulus length. */ + private static final int DEFAULT_MODULUS_LENGTH = 1024; + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // gnu.crypto.key.IKeyPairGenerator interface implementation --------------- + + public String name() + { + return Registry.RSA_KPG; + } + + /** + * <p>Configures this instance.</p> + * + * @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) + { + // 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); + } + } + + /** + * <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() + { + 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 + && Prime2.isProbablePrime(p) && 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 && Prime2.isProbablePrime(q) + && 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(n, e); + PrivateKey secK = new GnuRSAPrivateKey(p, q, e, d); + + return new KeyPair(pubK, secK); + } + + // helper methods ---------------------------------------------------------- + + /** + * <p>Fills the designated byte array with random data.</p> + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + { + new SecureRandom ().nextBytes(buffer); + } + } +} diff --git a/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java b/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java new file mode 100644 index 000000000..fb7cea99e --- /dev/null +++ b/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java @@ -0,0 +1,332 @@ +/* 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; + +/** + * <p>An object that implements the {@link IKeyPairCodec} interface for the + * <i>Raw</i> format to use with RSA keypairs.</p> + * + * @version $Revision: 1.1 $ + */ +public class RSAKeyPairRawCodec implements IKeyPairCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.key.IKeyPairCodec interface implementation ------------------- + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * <p>Returns the encoded form of the designated RSA public key according to + * the <i>Raw</i> format supported by this library.</p> + * + * <p>The <i>Raw</i> format for an RSA public key, 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_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); + } + + /** + * <p>Returns the encoded form of the designated RSA private key according to + * the <i>Raw</i> format supported by this library.</p> + * + * <p>The <i>Raw</i> format for an RSA private key, 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_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); + } +} diff --git a/gnu/java/security/prng/BasePRNG.java b/gnu/java/security/prng/BasePRNG.java new file mode 100644 index 000000000..13aa33650 --- /dev/null +++ b/gnu/java/security/prng/BasePRNG.java @@ -0,0 +1,195 @@ +/* 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; + +/** + * <p>An abstract class to facilitate implementing PRNG algorithms.</p> + */ +public abstract class BasePRNG implements IRandom +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial constructor for use by concrete subclasses.</p> + * + * @param name the canonical name of this instance. + */ + protected BasePRNG(String name) + { + super(); + + this.name = name; + initialised = false; + buffer = new byte[0]; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IRandom interface implementation ---------------------------------------- + + 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"); + } + + // Instance methods + // ------------------------------------------------------------------------- + + public boolean isInitialised() + { + return initialised; + } + + private byte nextByteInternal() throws LimitReachedException + { + if (ndx >= buffer.length) + { + this.fillBlock(); + ndx = 0; + } + + return buffer[ndx++]; + } + + // abstract methods to implement by subclasses ----------------------------- + + public Object clone() throws CloneNotSupportedException + { + return super.clone(); + } + + public abstract void setup(Map attributes); + + public abstract void fillBlock() throws LimitReachedException; +} diff --git a/gnu/java/security/prng/EntropySource.java b/gnu/java/security/prng/EntropySource.java new file mode 100644 index 000000000..260c668f8 --- /dev/null +++ b/gnu/java/security/prng/EntropySource.java @@ -0,0 +1,62 @@ +/* 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 diff --git a/gnu/java/security/prng/IRandom.java b/gnu/java/security/prng/IRandom.java new file mode 100644 index 000000000..2c89e7ad5 --- /dev/null +++ b/gnu/java/security/prng/IRandom.java @@ -0,0 +1,180 @@ +/* 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; + +/** + * <p>The basic visible methods of any pseudo-random number generator.</p> + * + * <p>The [HAC] defines a PRNG (as implemented in this library) as follows:</p> + * + * <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>st bit of <code>S</code> with a + * probability significantly grater 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 underlting + * 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 and + * 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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the canonical name of this instance.</p> + * + * @return the canonical name of this instance. */ + String name(); + + /** + * <p>Initialises the pseudo-random number generator scheme with the + * appropriate attributes.</p> + * + * @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); + + /** + * <p>Returns the next 8 bits of random data generated from this instance.</p> + * + * @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; + + /** + * <p>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; + + /** + * <p>Supplement, or possibly replace, the random state of this PRNG with + * a random byte.</p> + * + * <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}.</p> + * + * @param b The byte to add. + */ + void addRandomByte(byte b); + + /** + * <p>Supplement, or possibly replace, the random state of this PRNG with + * a sequence of new random bytes.</p> + * + * <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}.</p> + * + * @param in The buffer of new random bytes to add. + */ + void addRandomBytes(byte[] in); + + /** + * <p>Supplement, or possibly replace, the random state of this PRNG with + * a sequence of new random bytes.</p> + * + * <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}.</p> + * + * @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); + + /** + * <p>Returns a clone copy of this instance.</p> + * + * @return a clone copy of this instance. + */ + Object clone() throws CloneNotSupportedException; +}
\ No newline at end of file diff --git a/gnu/java/security/prng/LimitReachedException.java b/gnu/java/security/prng/LimitReachedException.java new file mode 100644 index 000000000..2fd8bfa7f --- /dev/null +++ b/gnu/java/security/prng/LimitReachedException.java @@ -0,0 +1,69 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public LimitReachedException() + { + super(); + } + + public LimitReachedException(String msg) + { + super(msg); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instant methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/java/security/prng/MDGenerator.java b/gnu/java/security/prng/MDGenerator.java new file mode 100644 index 000000000..b43ca33a6 --- /dev/null +++ b/gnu/java/security/prng/MDGenerator.java @@ -0,0 +1,124 @@ +/* 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; + +/** + * <p>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.</p> + */ +public class MDGenerator extends BasePRNG implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public MDGenerator() + { + super(Registry.MD_PRNG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BaseRandom ------------------------ + + 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); + } +} diff --git a/gnu/java/security/prng/PRNGFactory.java b/gnu/java/security/prng/PRNGFactory.java new file mode 100644 index 000000000..8b5141456 --- /dev/null +++ b/gnu/java/security/prng/PRNGFactory.java @@ -0,0 +1,109 @@ +/* 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.Iterator; +import java.util.Set; + +/** + * <p>A Factory to instantiate pseudo random number generators.</p> + */ +public class PRNGFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + protected PRNGFactory() + { + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a padding algorithm given its name.</p> + * + * @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; + } + + /** + * <p>Returns a {@link Set} of names of padding algorithms supported by this + * <i>Factory</i>.</p> + * + * @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); + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/prng/RandomEvent.java b/gnu/java/security/prng/RandomEvent.java new file mode 100644 index 000000000..c07062125 --- /dev/null +++ b/gnu/java/security/prng/RandomEvent.java @@ -0,0 +1,82 @@ +/* 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; + +/** + * An interface 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; + } +}
\ No newline at end of file diff --git a/gnu/java/security/prng/RandomEventListener.java b/gnu/java/security/prng/RandomEventListener.java new file mode 100644 index 000000000..1dc14619f --- /dev/null +++ b/gnu/java/security/prng/RandomEventListener.java @@ -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); +}
\ No newline at end of file diff --git a/gnu/java/security/provider/Gnu.java b/gnu/java/security/provider/Gnu.java index e553bbcbd..849015214 100644 --- a/gnu/java/security/provider/Gnu.java +++ b/gnu/java/security/provider/Gnu.java @@ -97,11 +97,25 @@ public final class Gnu extends Provider put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA"); put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); + 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.DSA", gnu.java.security.provider.DSAKeyPairGenerator.class.getName()); put("KeyPairGenerator.DiffieHellman", DiffieHellmanKeyPairGeneratorImpl.class.getName ()); + put("KeyPairGenerator.DSS", gnu.java.security.jce.sig.DSSKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.DSS KeySize", "1024"); + put("KeyPairGenerator.DSS ImplementedIn", "Software"); + put("KeyPairGenerator.RSA", gnu.java.security.jce.sig.RSAKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.RSA KeySize", "1024"); + put("KeyPairGenerator.RSA ImplementedIn", "Software"); + put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA"); put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA"); put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA"); @@ -128,13 +142,57 @@ public final class Gnu extends Provider put("Alg.Alias.KeyFactory.DH", "DiffieHellman"); // Message Digests - put("MessageDigest.SHA", gnu.java.security.provider.SHA.class.getName()); - put("MessageDigest.MD5", gnu.java.security.provider.MD5.class.getName()); +// put("MessageDigest.SHA", gnu.java.security.provider.SHA.class.getName()); +// put("MessageDigest.MD5", gnu.java.security.provider.MD5.class.getName()); // Format "Alias", "Actual Name" - put("Alg.Alias.MessageDigest.SHA1", "SHA"); - put("Alg.Alias.MessageDigest.SHA-1", "SHA"); - put("Alg.Alias.MessageDigest.SHA-160", "SHA"); +// put("Alg.Alias.MessageDigest.SHA1", "SHA"); +// put("Alg.Alias.MessageDigest.SHA-1", "SHA"); +// put("Alg.Alias.MessageDigest.SHA-160", "SHA"); + + 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.DSA", @@ -153,6 +211,41 @@ public final class Gnu extends Provider put("SecureRandom.SHA1PRNG", gnu.java.security.provider.SHA1PRNG.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()); @@ -166,14 +259,6 @@ public final class Gnu extends Provider // CertStore put("CertStore.Collection", CollectionCertStoreImpl.class.getName()); - // KeyAgreement - put("KeyAgreement.DiffieHellman", gnu.javax.crypto.DiffieHellmanImpl.class.getName()); - put("Alg.Alias.KeyAgreement.DH", "DiffieHellman"); - - // Cipher - put("Cipher.RSAES-PKCS1-v1_5", gnu.javax.crypto.RSACipherImpl.class.getName()); - put("Alg.Alias.Cipher.RSA", "RSAES-PKCS1-v1_5"); - return null; } }); diff --git a/gnu/java/security/sig/BaseSignature.java b/gnu/java/security/sig/BaseSignature.java new file mode 100644 index 000000000..f82346feb --- /dev/null +++ b/gnu/java/security/sig/BaseSignature.java @@ -0,0 +1,247 @@ +/* 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 java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.util.Map; +import java.util.Random; + +/** + * <p>A base abstract class to facilitate implementations of concrete + * Signatures.</p> + */ +public abstract class BaseSignature implements ISignature +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial constructor.</p> + * + * @param schemeName the name of this signature scheme. + * @param md the underlying instance of the message digest algorithm. + */ + protected BaseSignature(String schemeName, IMessageDigest md) + { + super(); + + this.schemeName = schemeName; + this.md = md; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.sig.ISignature interface implementation ---------------------- + + public String name() + { + return schemeName; + } + + 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); + } + + // abstract methods to be implemented by concrete subclasses --------------- + + 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; + + // Other instance methods -------------------------------------------------- + + /** Initialises the internal fields of this instance. */ + protected void init() + { + md.reset(); + rnd = null; + irnd = null; + publicKey = null; + privateKey = null; + } + + /** + * <p>Fills the designated byte array with random data.</p> + * + * @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(): " + + String.valueOf(x)); + } + catch (LimitReachedException x) + { + throw new RuntimeException("nextRandomBytes(): " + + String.valueOf(x)); + } + } + else + { + new SecureRandom ().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; + } + } +} diff --git a/gnu/java/security/sig/ISignature.java b/gnu/java/security/sig/ISignature.java new file mode 100644 index 000000000..77653ee37 --- /dev/null +++ b/gnu/java/security/sig/ISignature.java @@ -0,0 +1,169 @@ +/* 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; + +/** + * <p>The visible methods of every signature-with-appendix scheme.</p> + * + * <p>The Handbook of Applied Cryptography (HAC), by A. Menezes & 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> + * + * <p>References:</p> + * <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> + * + * @version $Revision: 1.1 $ + */ +public interface ISignature extends Cloneable +{ + + // Constants + // ------------------------------------------------------------------------- + + /** 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.crypto.prng.IRandom} instance to + * use. The default is to use a classloader singleton from + * {@link gnu.crypto.util.PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.sig.prng"; + + // Methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the canonical name of this signature scheme.</p> + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * <p>Initialises this instance for signature verification.</p> + * + * @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; + + /** + * <p>Initialises this instance for signature generation.</p> + * + * @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; + + /** + * <p>Digests one byte of a message for signing or verification purposes.</p> + * + * @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; + + /** + * <p>Digests a sequence of bytes from a message for signing or verification + * purposes.</p> + * + * @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; + + /** + * <p>Terminates a signature generation phase by digesting and processing the + * context of the underlying message digest algorithm instance.</p> + * + * @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; + + /** + * <p>Terminates a signature verification phase by digesting and processing + * the context of the underlying message digest algorithm instance.</p> + * + * @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; + + /** + * <p>Returns a clone copy of this instance.</p> + * + * @return a clone copy of this instance. + */ + Object clone(); +} diff --git a/gnu/java/security/sig/ISignatureCodec.java b/gnu/java/security/sig/ISignatureCodec.java new file mode 100644 index 000000000..119eca5fd --- /dev/null +++ b/gnu/java/security/sig/ISignatureCodec.java @@ -0,0 +1,68 @@ +/* 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; + +/** + * <p>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.</p> + * + * @version $Revision: 1.1 $ + */ +public interface ISignatureCodec +{ + + // Constants + // ------------------------------------------------------------------------- + + /** Constant identifying the <i>Raw</i> encoding format. */ + int RAW_FORMAT = Registry.RAW_ENCODING_ID; + + // Method(s) + // ------------------------------------------------------------------------- + + int getFormatID(); + + byte[] encodeSignature(Object signature); + + Object decodeSignature(byte[] input); +} diff --git a/gnu/java/security/sig/SignatureFactory.java b/gnu/java/security/sig/SignatureFactory.java new file mode 100644 index 000000000..9bac354d7 --- /dev/null +++ b/gnu/java/security/sig/SignatureFactory.java @@ -0,0 +1,122 @@ +/* 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.RSAPSSSignature; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5Signature; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * <p>A Factory to instantiate signature-with-appendix handlers.</p> + * + * @version $Revision: 1.1 $ + */ +public class SignatureFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private SignatureFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a signature-with-appendix scheme given its name.</p> + * + * @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(); + ISignature result = null; + if (ssa.equalsIgnoreCase(Registry.DSA_SIG) || ssa.equals(Registry.DSS_SIG)) + { + result = new DSSSignature(); + } + else if (ssa.equalsIgnoreCase(Registry.RSA_PSS_SIG)) + { + result = new RSAPSSSignature(); + } + else if (ssa.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG)) + { + result = new RSAPKCS1V1_5Signature(); + } + + return result; + } + + /** + * <p>Returns a {@link Set} of signature-with-appendix scheme names supported + * by this <i>Factory</i>.</p> + * + * @return a {@link Set} of signature-with-appendix scheme names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(Registry.DSS_SIG); + hs.add(Registry.RSA_PSS_SIG); + hs.add(Registry.RSA_PKCS1_V1_5_SIG); + + return Collections.unmodifiableSet(hs); + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/sig/dss/DSSSignature.java b/gnu/java/security/sig/dss/DSSSignature.java new file mode 100644 index 000000000..6bedfaefa --- /dev/null +++ b/gnu/java/security/sig/dss/DSSSignature.java @@ -0,0 +1,347 @@ +/* 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; + +/** + * <p>The DSS (Digital Signature Standard) algorithm makes use of the following + * parameters:</p> + * + * <ol> + * <li>p: A prime modulus, where <code>2<sup>L-1</sup> < p < 2<sup>L</sup> + * </code> for <code>512 <= L <= 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> + * < q < 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 < h < 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 < x + * < 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 < k + * < 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> + * + * <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:</p> + * + * <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 < k-1 < 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> + * + * <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> + * + * <p>The signature is transmitted along with the message to the verifier.</p> + * + * <p>References:</p> + * <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> + * + * @version $Revision: 1.1 $ + */ +public class DSSSignature extends BaseSignature +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** 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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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); + } + + // Implementation of abstract methods in superclass + // ------------------------------------------------------------------------- + + 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 + { + // BigInteger p = ((DSAPrivateKey) privateKey).getParams().getP(); + // BigInteger q = ((DSAPrivateKey) privateKey).getParams().getQ(); + // BigInteger g = ((DSAPrivateKey) privateKey).getParams().getG(); + // BigInteger x = ((DSAPrivateKey) privateKey).getX(); + // BigInteger m = new BigInteger(1, md.digest()); + // BigInteger k, r, s; + // + // 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; + // } + final BigInteger[] rs = computeRS(md.digest()); + + // return encodeSignature(r, s); + return encodeSignature(rs[0], rs[1]); + } + + protected boolean verifySignature(Object sig) throws IllegalStateException + { + final BigInteger[] rs = decodeSignature(sig); + // BigInteger r = rs[0]; + // BigInteger s = rs[1]; + // + // BigInteger g = ((DSAPublicKey) publicKey).getParams().getG(); + // BigInteger p = ((DSAPublicKey) publicKey).getParams().getP(); + // BigInteger q = ((DSAPublicKey) publicKey).getParams().getQ(); + // BigInteger y = ((DSAPublicKey) publicKey).getY(); + // BigInteger w = s.modInverse(q); + // + // byte bytes[] = md.digest(); + // BigInteger u1 = w.multiply(new BigInteger(1, bytes)).mod(q); + // BigInteger u2 = r.multiply(w).mod(q); + // + // BigInteger v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q); + // return v.equals(r); + return checkRS(rs, md.digest()); + } + + // Other instance methods + // ------------------------------------------------------------------------- + + /** + * Returns the output of a signature generation phase.<p> + * + * @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}.<p> + * + * @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); + } +} diff --git a/gnu/java/security/sig/dss/DSSSignatureRawCodec.java b/gnu/java/security/sig/dss/DSSSignatureRawCodec.java new file mode 100644 index 000000000..02f6b1ddc --- /dev/null +++ b/gnu/java/security/sig/dss/DSSSignatureRawCodec.java @@ -0,0 +1,191 @@ +/* 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; + +/** + * <p>An object that implements the {@link ISignatureCodec} operations for the + * <i>Raw</i> format to use with DSS signatures.</p> + * + * @version $Revision: 1.1 $ + */ +public class DSSSignatureRawCodec implements ISignatureCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.sig.ISignatureCodec interface implementation ----------------- + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * <p>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> + * + * <p>The <i>Raw</i> format for a DSA 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_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 java.math.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("key"); + } + + 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 }; + } +} diff --git a/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java b/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java new file mode 100644 index 000000000..d6bbfe56b --- /dev/null +++ b/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java @@ -0,0 +1,305 @@ +/* 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 java.io.ByteArrayOutputStream; +import java.security.SecureRandom; +import java.security.interfaces.RSAKey; +import java.util.Random; + +/** + * <p>An implementation of the EME-PKCS1-V1.5 encoding and decoding methods.</p> + * + * <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> + * + * <p>References:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private int k; + + private ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + private EME_PKCS1_V1_5(final int k) + { + super(); + + this.k = k; + } + + // Class methods + // ------------------------------------------------------------------------- + + 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); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>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> + * + * <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:</p> + * + * <pre> + * EM = 0x00 || 0x02 || PS || 0x00 || M. + * </pre> + * + * <p>This method uses a default PRNG to obtain the padding bytes.</p> + * + * @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. + SecureRandom rnd = new SecureRandom (); + rnd.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); + } + + /** + * <p>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.</p> + * + * @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); + } + + /** + * <p>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); + } + + /** + * <p>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:</p> + * + * <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.</p> + + * @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; + } + + // helper methods ---------------------------------------------------------- + + 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; + + } +} diff --git a/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java b/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java new file mode 100644 index 000000000..d8e7f2a48 --- /dev/null +++ b/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java @@ -0,0 +1,299 @@ +/* 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; + +/** + * <p>An implementation of the EMSA-PKCS1-V1.5 encoding scheme.</p> + * + * <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> + * + * <p>References:</p> + * <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> + * + * @version $Revision: 1.1 $ + */ +public class EMSA_PKCS1_V1_5 implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /* 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial private constructor to enforce use through Factory method.</p> + * + * @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 + } + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of this object given a designated name of a hash + * function.</p> + * + * @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 ID"); + } + return new EMSA_PKCS1_V1_5(hash); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation -------------------------------------- + + public Object clone() + { + return getInstance(hash.name()); + } + + // own methods ------------------------------------------------------------- + + /** + * <p>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).</p> + * + * @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; + } +} diff --git a/gnu/java/security/sig/rsa/EMSA_PSS.java b/gnu/java/security/sig/rsa/EMSA_PSS.java new file mode 100644 index 000000000..d11a861b5 --- /dev/null +++ b/gnu/java/security/sig/rsa/EMSA_PSS.java @@ -0,0 +1,432 @@ +/* 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.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import java.io.PrintWriter; +import java.util.Arrays; + +/** + * <p>An implementation of the EMSA-PSS encoding/decoding scheme.</p> + * + * <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> + * + * <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> + * + * <p>References:</p> + * <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> + * + * @version $Revision: 1.1 $ + */ +public class EMSA_PSS implements Cloneable +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "emsa-pss"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The underlying hash function to use with this instance. */ + private IMessageDigest hash; + + /** The output size of the hash function in octets. */ + private int hLen; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial private constructor to enforce use through Factory method.</p> + * + * @param hash the message digest instance to use with this scheme instance. + */ + private EMSA_PSS(IMessageDigest hash) + { + super(); + + this.hash = hash; + hLen = hash.hashSize(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of this object given a designated name of a hash + * function.</p> + * + * @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); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation -------------------------------------- + + public Object clone() + { + return getInstance(hash.name()); + } + + // own methods ------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @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 (DEBUG && debuglevel > 8) + { + debug("dbMask (encode): " + Util.toString(dbMask)); + debug("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; + } + + /** + * <p>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>.</p> + * + * @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 (DEBUG && debuglevel > 8) + { + debug("mHash: " + Util.toString(mHash)); + debug("EM: " + Util.toString(EM)); + debug("emBits: " + String.valueOf(emBits)); + debug("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 (DEBUG && debuglevel > 8) + { + debug("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 (DEBUG && debuglevel > 8) + { + debug("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 (DEBUG && debuglevel > 8) + { + debug("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 (DEBUG && debuglevel > 8) + { + debug("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 (DEBUG && debuglevel > 8) + { + debug("dbMask (decode): " + Util.toString(dbMask)); + debug("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 (DEBUG && debuglevel > 8) + { + debug("DB[" + String.valueOf(i) + "] != 0x00"); + } + return false; + } + } + if (DB[i] != 0x01) + { // i == emLen -hLen -sLen -2 + if (DEBUG && debuglevel > 8) + { + debug("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); + } + + // helper methods ---------------------------------------------------------- + + /** + * <p>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.</p> + * + * @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; + } +} diff --git a/gnu/java/security/sig/rsa/RSA.java b/gnu/java/security/sig/rsa/RSA.java new file mode 100644 index 000000000..4ef7232f1 --- /dev/null +++ b/gnu/java/security/sig/rsa/RSA.java @@ -0,0 +1,355 @@ +/* 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.key.rsa.GnuRSAKey; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * <p>Utility methods related to the RSA algorithm.</p> + * + * <p>References:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final BigInteger ZERO = BigInteger.ZERO; + + private static final BigInteger ONE = BigInteger.ONE; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial private constructor to enforce Singleton pattern. */ + private RSA() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Signature and verification methods -------------------------------------- + + /** + * <p>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.<p> + * + * @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"); + } + } + + /** + * <p>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.</p> + * + * @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"); + } + } + + // Encryption and decryption methods --------------------------------------- + + /** + * <p>An implementation of the <code>RSAEP</code> algorithm.</p> + * + * @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"); + } + } + + /** + * <p>An implementation of the <code>RSADP</code> algorithm.</p> + * + * @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"); + } + } + + // Conversion methods ------------------------------------------------------ + + /** + * <p>Converts a <i>multi-precision integer</i> (MPI) <code>s</code> into an + * octet sequence of length <code>k</code>.</p> + * + * @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; + } + + // helper methods ---------------------------------------------------------- + + 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; + } + + /** + * <p>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>.</p> + * + * @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]; + SecureRandom rnd = new SecureRandom (); + int b; + do + { + rnd.nextBytes(bl); + b = bl[0] & 0xFF; + } + while (b < lower || b > upper); + final byte[] buffer = new byte[b]; // 256-bit MPI + rnd.nextBytes(buffer); + return new BigInteger(1, buffer); + } +} diff --git a/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java b/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java new file mode 100644 index 000000000..b859fc358 --- /dev/null +++ b/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java @@ -0,0 +1,242 @@ +/* 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; + +/** + * <p>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> + * + * <p>References:</p> + * <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> + * + * @version $Revision: 1.1 $ + */ +public class RSAPKCS1V1_5Signature extends BaseSignature +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The underlying EMSA-PKCS1-v1.5 instance for this object. */ + private EMSA_PKCS1_V1_5 pkcs1; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Default 0-arguments constructor. Uses SHA-1 as the default hash. + */ + public RSAPKCS1V1_5Signature() + { + this(Registry.SHA160_HASH); + } + + /** + * <p>Constructs an instance of this object using the designated message + * digest algorithm as its underlying hash function.</p> + * + * @param mdName the canonical name of the underlying hash function. + */ + public RSAPKCS1V1_5Signature(final String mdName) + { + super(Registry.RSA_PKCS1_V1_5_SIG, HashFactory.getInstance(mdName)); + + pkcs1 = EMSA_PKCS1_V1_5.getInstance(mdName); + } + + /** 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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in superclass ------------------------ + + 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); + } +} diff --git a/gnu/java/security/sig/rsa/RSAPSSSignature.java b/gnu/java/security/sig/rsa/RSAPSSSignature.java new file mode 100644 index 000000000..3458d11da --- /dev/null +++ b/gnu/java/security/sig/rsa/RSAPSSSignature.java @@ -0,0 +1,343 @@ +/* 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.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.io.PrintWriter; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * <p>The RSA-PSS signature scheme is a public-key encryption scheme combining + * the RSA algorithm with the Probabilistic Signature Scheme (PSS) encoding + * method.</p> + * + * <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> + * + * <p>References:</pr> + * <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> + * + * @version $Revision: 1.1 $ + */ +public class RSAPSSSignature extends BaseSignature +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "rsa-pss"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 1; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * 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); + } + + /** + * <p>Constructs an instance of this object using the designated message + * digest algorithm as its underlying hash function, and having 0-octet + * <i>salt</i>.</p> + * + * @param mdName the canonical name of the underlying hash function. + */ + public RSAPSSSignature(String mdName) + { + this(mdName, 0); + } + + /** + * <p>Constructs an instance of this object using the designated message + * digest algorithm as its underlying hash function.</p> + * + * @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) + { + super(Registry.RSA_PSS_SIG, HashFactory.getInstance(mdName)); + + pss = EMSA_PSS.getInstance(mdName); + 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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in superclass ------------------------ + + 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 (DEBUG && debuglevel > 8) + { + debug("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 (DEBUG && debuglevel > 8) + { + debug("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; + } + + // Other instance methods -------------------------------------------------- + + /** + * Converts the <i>signature representative</i> <code>s</code> to a signature + * <code>S</code> of length <code>k</code> octets; i.e. + * <code>S = I2OSP(s, k)</code>, where <code>k = CEILING(modBits/8)</code>. + * + * @param s the <i>signature representative</i>. + * @param k the length of the output. + * @return the signature as an octet sequence. + * @exception IllegalArgumentException if the length in octets of meaningful + * bytes of <code>s</code> is greater than <code>k</code>, implying that + * <code>s</code> is not less than the RSA <i>modulus</i>. + */ + // private Object encodeSignature(BigInteger s, int k) { + // if (DEBUG && debuglevel > 8) { + // debug("s.bitLength(): "+String.valueOf(s.bitLength())); + // debug("k: "+String.valueOf(k)); + // } + // byte[] result = s.toByteArray(); + // if (DEBUG && debuglevel > 8) { + // debug("s: "+Util.toString(result)); + // debug("s (bytes): "+String.valueOf(result.length)); + // } + // if (result.length < k) { + // 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 + // int limit = result.length - k; + // for (int i = 0; i < limit; i++) { + // if (result[i] != 0x00) { + // throw new IllegalArgumentException("integer too large"); + // } + // } + // byte[] newResult = new byte[k]; + // System.arraycopy(result, limit, newResult, 0, k); + // result = newResult; + // } + // return result; + // } + /** + * Returns the output of a previously generated signature object as an octet + * sequence.<p> + * + * @return the octet sequence <code>S</code>. + */ + // private byte[] decodeSignature(Object signature) { + // return (byte[]) signature; + // } +} diff --git a/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java b/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java new file mode 100644 index 000000000..64a972ca3 --- /dev/null +++ b/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java @@ -0,0 +1,159 @@ +/* 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; + +/** + * <p>An object that implements the {@link gnu.crypto.sig.ISignatureCodec} + * operations for the <i>Raw</i> format to use with RSA-PSS signatures.</p> + * + * @version $Revision: 1.1 $ + */ +public class RSAPSSSignatureRawCodec implements ISignatureCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairCodec interface implementation + // ------------------------------------------------------------------------- + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * <p>Returns the encoded form of the designated RSA-PSS signature object + * according to the <i>Raw</i> format supported by this library.</p> + * + * <p>The <i>Raw</i> format for an RSA-PSS 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_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("key"); + } + + 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; + } +} diff --git a/gnu/java/security/util/Base64.java b/gnu/java/security/util/Base64.java new file mode 100644 index 000000000..f9998c38f --- /dev/null +++ b/gnu/java/security/util/Base64.java @@ -0,0 +1,396 @@ +/* Base64.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.util; + +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; + +/** + * Most of this implementation is from Robert Harder's public domain Base64 + * code (version 1.4.1 available from <http://iharder.net/xmlizable>). + */ +public class Base64 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "Base64"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 9; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Maximum line length (76) of Base64 output. */ + private static final int MAX_LINE_LENGTH = 76; + + /** The new line character (\n) as one byte. */ + private static final byte NEW_LINE = (byte) '\n'; + + /** The equals sign (=) as a byte. */ + private static final byte EQUALS_SIGN = (byte) '='; + + private static final byte WHITE_SPACE_ENC = -5; // white space in encoding + + private static final byte EQUALS_SIGN_ENC = -1; // equals sign in encoding + + /** The 64 valid Base64 values. */ + private static final byte[] ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', + (byte) 'D', (byte) 'E', (byte) 'F', + (byte) 'G', (byte) 'H', (byte) 'I', + (byte) 'J', (byte) 'K', (byte) 'L', + (byte) 'M', (byte) 'N', (byte) 'O', + (byte) 'P', (byte) 'Q', (byte) 'R', + (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', + (byte) 'Y', (byte) 'Z', (byte) 'a', + (byte) 'b', (byte) 'c', (byte) 'd', + (byte) 'e', (byte) 'f', (byte) 'g', + (byte) 'h', (byte) 'i', (byte) 'j', + (byte) 'k', (byte) 'l', (byte) 'm', + (byte) 'n', (byte) 'o', (byte) 'p', + (byte) 'q', (byte) 'r', (byte) 's', + (byte) 't', (byte) 'u', (byte) 'v', + (byte) 'w', (byte) 'x', (byte) 'y', + (byte) 'z', (byte) '0', (byte) '1', + (byte) '2', (byte) '3', (byte) '4', + (byte) '5', (byte) '6', (byte) '7', + (byte) '8', (byte) '9', (byte) '+', + (byte) '/' }; + + /** + * Translates a Base64 value to either its 6-bit reconstruction value or a + * negative number indicating some other meaning. + */ + private static final byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9, -9, -9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9 // Decimal 123 - 126 + }; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial private ctor to enfore Singleton pattern. */ + private Base64() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * Encodes a byte array into Base64 notation. Equivalent to calling + * <code>encode(source, 0, source.length)</code>. + * + * @param src the data to convert. + */ + public static final String encode(final byte[] src) + { + return encode(src, 0, src.length, true); + } + + /** + * Encodes a byte array into Base64 notation. + * + * @param src the data to convert. + * @param off offset in array where conversion should begin. + * @param len length of data to convert. + * @param breakLines break lines at 80 characters or less. + */ + public static final String encode(final byte[] src, final int off, + final int len, final boolean breakLines) + { + final int len43 = len * 4 / 3; + final byte[] outBuff = new byte[len43 // Main 4:3 + + ((len % 3) > 0 ? 4 : 0) // Account for padding + + (breakLines ? (len43 / MAX_LINE_LENGTH) + : 0)]; // New lines + int d = 0; + int e = 0; + final int len2 = len - 2; + int lineLength = 0; + for (; d < len2; d += 3, e += 4) + { + encode3to4(src, d + off, 3, outBuff, e); + lineLength += 4; + if (breakLines && lineLength == MAX_LINE_LENGTH) + { + outBuff[e + 4] = NEW_LINE; + e++; + lineLength = 0; + } + } + + if (d < len) + { // padding needed + encode3to4(src, d + off, len - d, outBuff, e); + e += 4; + } + + return new String(outBuff, 0, e); + } + + /** + * Decodes data from Base64 notation. + * + * @param s the string to decode. + * @return the decoded data. + */ + public static final byte[] decode(final String s) + throws UnsupportedEncodingException + { + final byte[] bytes; + bytes = s.getBytes("US-ASCII"); + return decode(bytes, 0, bytes.length); + } + + /** + * Decodes Base64 content in byte array format and returns the decoded byte + * array. + * + * @param src the Base64 encoded data. + * @param off the offset of where to begin decoding. + * @param len the length of characters to decode. + * @return the decoded data. + * @throws IllegalArgumentException if <code>src</code> contains an illegal + * Base-64 character. + */ + public static byte[] decode(final byte[] src, final int off, final int len) + { + final int len34 = len * 3 / 4; + final byte[] outBuff = new byte[len34]; // Upper limit on size of output + int outBuffPosn = 0; + final byte[] b4 = new byte[4]; + int b4Posn = 0; + int i; + byte sbiCrop, sbiDecode; + for (i = off; i < off + len; i++) + { + sbiCrop = (byte) (src[i] & 0x7F); // Only the low seven bits + sbiDecode = DECODABET[sbiCrop]; + if (sbiDecode >= WHITE_SPACE_ENC) + { // White space, Equals sign or better + if (sbiDecode >= EQUALS_SIGN_ENC) + { + b4[b4Posn++] = sbiCrop; + if (b4Posn > 3) + { + outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn); + b4Posn = 0; + // If that was the equals sign, break out of 'for' loop + if (sbiCrop == EQUALS_SIGN) + break; + } // end if: quartet built + } // end if: equals sign or better + } + else + { + throw new IllegalArgumentException("Illegal BASE-64 character at #" + + i + ": " + src[i] + + "(decimal)"); + } + } + + final byte[] result = new byte[outBuffPosn]; + System.arraycopy(outBuff, 0, result, 0, outBuffPosn); + return result; + } + + /** + * <p>Encodes up to three bytes of the array <code>src</code> and writes + * the resulting four Base64 bytes to <code>dest</code>. The source and + * destination arrays can be manipulated anywhere along their length by + * specifying <code>sOffset</code> and <code>dOffset</code>.</p> + * + * <p>This method does not check to make sure the arrays are large enough to + * accomodate <code>sOffset + 3</code> for the <code>src</code> array or + * <code>dOffset + 4</code> for the <code>dest</code> array. The actual + * number of significant bytes in the input array is given by + * <code>numBytes</code>.</p> + * + * @param src the array to convert. + * @param sOffset the index where conversion begins. + * @param numBytes the number of significant bytes in your array. + * @param dest the array to hold the conversion. + * @param dOffset the index where output will be put. + * @return the <code>destination</code> array. + */ + private static final byte[] encode3to4(final byte[] src, final int sOffset, + final int numBytes, final byte[] dest, + final int dOffset) + { + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3F 0x3F 0x3F Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + final int inBuff = (numBytes > 0 ? ((src[sOffset] << 24) >>> 8) : 0) + | (numBytes > 1 ? ((src[sOffset + 1] << 24) >>> 16) : 0) + | (numBytes > 2 ? ((src[sOffset + 2] << 24) >>> 24) : 0); + switch (numBytes) + { + case 3: + dest[dOffset] = ALPHABET[(inBuff >>> 18)]; + dest[dOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3F]; + dest[dOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3F]; + dest[dOffset + 3] = ALPHABET[(inBuff) & 0x3F]; + break; + case 2: + dest[dOffset] = ALPHABET[(inBuff >>> 18)]; + dest[dOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3F]; + dest[dOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3F]; + dest[dOffset + 3] = EQUALS_SIGN; + break; + case 1: + dest[dOffset] = ALPHABET[(inBuff >>> 18)]; + dest[dOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3F]; + dest[dOffset + 2] = EQUALS_SIGN; + dest[dOffset + 3] = EQUALS_SIGN; + break; + } + return dest; + } + + /** + * <p>Decodes four bytes from array <code>src</code> and writes the + * resulting bytes (up to three of them) to <code>dest</code>.</p> + * + * <p>The source and destination arrays can be manipulated anywhere along + * their length by specifying <code>sOffset</code> and <code>dOffset</code>. + * </p> + * + * <p>This method does not check to make sure your arrays are large enough + * to accomodate <code>sOffset + 4</code> for the <code>src</code> array or + * <code>dOffset + 3</code> for the <code>dest</code> array. This method + * returns the actual number of bytes that were converted from the Base64 + * encoding.</p> + * + * @param src the array to convert. + * @param sOffset the index where conversion begins. + * @param dest the array to hold the conversion. + * @param dOffset the index where output will be put. + * @return the number of decoded bytes converted. + */ + private static final int decode4to3(final byte[] src, final int sOffset, + final byte[] dest, final int dOffset) + { + if (src[sOffset + 2] == EQUALS_SIGN) + { // Example: Dk== + final int outBuff = ((DECODABET[src[sOffset]] & 0xFF) << 18) + | ((DECODABET[src[sOffset + 1]] & 0xFF) << 12); + dest[dOffset] = (byte) (outBuff >>> 16); + return 1; + } + + if (src[sOffset + 3] == EQUALS_SIGN) + { // Example: DkL= + final int outBuff = ((DECODABET[src[sOffset]] & 0xFF) << 18) + | ((DECODABET[src[sOffset + 1]] & 0xFF) << 12) + | ((DECODABET[src[sOffset + 2]] & 0xFF) << 6); + dest[dOffset] = (byte) (outBuff >>> 16); + dest[dOffset + 1] = (byte) (outBuff >>> 8); + return 2; + } + + try + { // Example: DkLE + final int outBuff = ((DECODABET[src[sOffset]] & 0xFF) << 18) + | ((DECODABET[src[sOffset + 1]] & 0xFF) << 12) + | ((DECODABET[src[sOffset + 2]] & 0xFF) << 6) + | ((DECODABET[src[sOffset + 3]] & 0xFF)); + dest[dOffset] = (byte) (outBuff >> 16); + dest[dOffset + 1] = (byte) (outBuff >> 8); + dest[dOffset + 2] = (byte) outBuff; + return 3; + } + catch (Exception x) + { + if (DEBUG && debuglevel > 8) + { + debug("" + src[sOffset] + ": " + (DECODABET[src[sOffset]])); + debug("" + src[sOffset + 1] + ": " + (DECODABET[src[sOffset + 1]])); + debug("" + src[sOffset + 2] + ": " + (DECODABET[src[sOffset + 2]])); + debug("" + src[sOffset + 3] + ": " + (DECODABET[src[sOffset + 3]])); + } + return -1; + } + } +} diff --git a/gnu/java/security/util/ExpirableObject.java b/gnu/java/security/util/ExpirableObject.java new file mode 100644 index 000000000..2d4452015 --- /dev/null +++ b/gnu/java/security/util/ExpirableObject.java @@ -0,0 +1,172 @@ +/* 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 +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + /** + * 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; + + // Constructors. + // ------------------------------------------------------------------------- + + /** + * 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); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + /** + * 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; + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * The task that destroys the target when the timeout elapses. + */ + private final class Destroyer extends TimerTask + { + + // Fields. + // ----------------------------------------------------------------------- + + private final ExpirableObject target; + + // Constructor. + // ----------------------------------------------------------------------- + + Destroyer(final ExpirableObject target) + { + super(); + this.target = target; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void run() + { + try + { + if (!target.isDestroyed()) + target.doDestroy(); + } + catch (DestroyFailedException dfe) + { + } + } + } +} diff --git a/gnu/java/security/util/Prime2.java b/gnu/java/security/util/Prime2.java new file mode 100644 index 000000000..bf8df55ad --- /dev/null +++ b/gnu/java/security/util/Prime2.java @@ -0,0 +1,632 @@ +/* Prime2.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.util; + +import gnu.java.security.Properties; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; +import java.math.BigInteger; +import java.util.Map; +import java.util.Random; +import java.util.WeakHashMap; + +/** + * <p>A collection of prime number related utilities used in this library.</p> + */ +public class Prime2 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "prime"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int DEFAULT_CERTAINTY = 20; // XXX is this a good value? + + private static final BigInteger ZERO = BigInteger.ZERO; + + private static final BigInteger ONE = BigInteger.ONE; + + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** + * The first SMALL_PRIME primes: Algorithm P, section 1.3.2, The Art of + * Computer Programming, Donald E. Knuth. + */ + private static final int SMALL_PRIME_COUNT = 1000; + + private static final BigInteger[] SMALL_PRIME = new BigInteger[SMALL_PRIME_COUNT]; + static + { + long time = -System.currentTimeMillis(); + SMALL_PRIME[0] = TWO; + int N = 3; + int J = 0; + int prime; + P2: while (true) + { + SMALL_PRIME[++J] = BigInteger.valueOf(N); + if (J >= 999) + { + break P2; + } + P4: while (true) + { + N += 2; + P6: for (int K = 1; true; K++) + { + prime = SMALL_PRIME[K].intValue(); + if ((N % prime) == 0) + { + continue P4; + } + else if ((N / prime) <= prime) + { + continue P2; + } + } + } + } + time += System.currentTimeMillis(); + if (DEBUG && debuglevel > 8) + { + StringBuffer sb; + for (int i = 0; i < (SMALL_PRIME_COUNT / 10); i++) + { + sb = new StringBuffer(); + for (int j = 0; j < 10; j++) + { + sb.append(String.valueOf(SMALL_PRIME[i * 10 + j])).append(" "); + } + debug(sb.toString()); + } + } + if (DEBUG && debuglevel > 4) + { + debug("Generating first " + String.valueOf(SMALL_PRIME_COUNT) + + " primes took: " + String.valueOf(time) + " ms."); + } + } + + private static final Map knownPrimes = new WeakHashMap(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private Prime2() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Trial division for the first 1000 small primes.</p> + * + * <p>Returns <code>true</code> if at least one small prime, among the first + * 1000 ones, was found to divide the designated number. Retuens <code>false</code> + * otherwise.</p> + * + * @param w the number to test. + * @return <code>true</code> if at least one small prime was found to divide + * the designated number. + */ + public static boolean hasSmallPrimeDivisor(BigInteger w) + { + BigInteger prime; + for (int i = 0; i < SMALL_PRIME_COUNT; i++) + { + prime = SMALL_PRIME[i]; + if (w.mod(prime).equals(ZERO)) + { + if (DEBUG && debuglevel > 4) + { + debug(prime.toString(16) + " | " + w.toString(16) + "..."); + } + return true; + } + } + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " has no small prime divisors..."); + } + return false; + } + + /** + * <p>Java port of Colin Plumb primality test (Euler Criterion) + * implementation for a base of 2 --from bnlib-1.1 release, function + * primeTest() in prime.c. this is his comments; (bn is our w).</p> + * + * <p>"Now, check that bn is prime. If it passes to the base 2, it's prime + * beyond all reasonable doubt, and everything else is just gravy, but it + * gives people warm fuzzies to do it.</p> + * + * <p>This starts with verifying Euler's criterion for a base of 2. This is + * the fastest pseudoprimality test that I know of, saving a modular squaring + * over a Fermat test, as well as being stronger. 7/8 of the time, it's as + * strong as a strong pseudoprimality test, too. (The exception being when + * <code>bn == 1 mod 8</code> and <code>2</code> is a quartic residue, i.e. + * <code>bn</code> is of the form <code>a^2 + (8*b)^2</code>.) The precise + * series of tricks used here is not documented anywhere, so here's an + * explanation. Euler's criterion states that if <code>p</code> is prime + * then <code>a^((p-1)/2)</code> is congruent to <code>Jacobi(a,p)</code>, + * modulo <code>p</code>. <code>Jacobi(a, p)</code> is a function which is + * <code>+1</code> if a is a square modulo <code>p</code>, and <code>-1</code> + * if it is not. For <code>a = 2</code>, this is particularly simple. It's + * <code>+1</code> if <code>p == +/-1 (mod 8)</code>, and <code>-1</code> if + * <code>m == +/-3 (mod 8)</code>. If <code>p == 3 (mod 4)</code>, then all + * a strong test does is compute <code>2^((p-1)/2)</code>. and see if it's + * <code>+1</code> or <code>-1</code>. (Euler's criterion says <i>which</i> + * it should be.) If <code>p == 5 (mod 8)</code>, then <code>2^((p-1)/2)</code> + * is <code>-1</code>, so the initial step in a strong test, looking at + * <code>2^((p-1)/4)</code>, is wasted --you're not going to find a + * <code>+/-1</code> before then if it <b>is</b> prime, and it shouldn't + * have either of those values if it isn't. So don't bother.</p> + * + * <p>The remaining case is <code>p == 1 (mod 8)</code>. In this case, we + * expect <code>2^((p-1)/2) == 1 (mod p)</code>, so we expect that the + * square root of this, <code>2^((p-1)/4)</code>, will be <code>+/-1 (mod p) + * </code>. Evaluating this saves us a modular squaring 1/4 of the time. If + * it's <code>-1</code>, a strong pseudoprimality test would call <code>p</code> + * prime as well. Only if the result is <code>+1</code>, indicating that + * <code>2</code> is not only a quadratic residue, but a quartic one as well, + * does a strong pseudoprimality test verify more things than this test does. + * Good enough.</p> + * + * <p>We could back that down another step, looking at <code>2^((p-1)/8)</code> + * if there was a cheap way to determine if <code>2</code> were expected to + * be a quartic residue or not. Dirichlet proved that <code>2</code> is a + * quadratic residue iff <code>p</code> is of the form <code>a^2 + (8*b^2)</code>. + * All primes <code>== 1 (mod 4)</code> can be expressed as <code>a^2 + + * (2*b)^2</code>, but I see no cheap way to evaluate this condition."</p> + * + * @param w the number to test. + * @return <code>true</code> iff the designated number passes Euler criterion + * as implemented by Colin Plumb in his <i>bnlib</i> version 1.1. + */ + + // FIXME this method incorrectly returns false for certain primes, notably + // 38737, 61681, 65537, 229153, and 274177. + public static boolean passEulerCriterion(final BigInteger w) + { + // first check if it's already a known prime + WeakReference obj = (WeakReference) knownPrimes.get(w); + if (obj != null && w.equals(obj.get())) + { + if (DEBUG && debuglevel > 4) + { + debug("found in known primes"); + } + return true; + } + + BigInteger w_minus_one = w.subtract(ONE); + BigInteger e = w_minus_one; + // l is the 3 least-significant bits of e + int l = e.and(BigInteger.valueOf(7L)).intValue(); + int j = 1; // Where to start in prime array for strong prime tests + BigInteger A; + int k; + + if ((l & 7) != 0) + { + e = e.shiftRight(1); + A = TWO.modPow(e, w); + if ((l & 7) == 6) + { // bn == 7 mod 8, expect +1 + if (A.bitCount() != 1) + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " fails Euler criterion #1..."); + } + return false; // Not prime + } + k = 1; + } + else + { // bn == 3 or 5 mod 8, expect -1 == bn-1 + A = A.add(ONE); + if (!A.equals(w)) + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " fails Euler criterion #2..."); + } + return false; // Not prime + } + k = 1; + if ((l & 4) != 0) + { // bn == 5 mod 8, make odd for strong tests + e = e.shiftRight(1); + k = 2; + } + } + } + else + { // bn == 1 mod 8, expect 2^((bn-1)/4) == +/-1 mod bn + e = e.shiftRight(2); + A = TWO.modPow(e, w); + if (A.bitCount() == 1) + { + j = 0; // Re-do strong prime test to base 2 + } + else + { + A = A.add(ONE); + if (!A.equals(w)) + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " fails Euler criterion #3..."); + } + return false; // Not prime + } + } + // bnMakeOdd(n) = d * 2^s. Replaces n with d and returns s. + k = e.getLowestSetBit(); + e = e.shiftRight(k); + k += 2; + } + // It's prime! Now go on to confirmation tests + + // Now, e = (bn-1)/2^k is odd. k >= 1, and has a given value with + // probability 2^-k, so its expected value is 2. j = 1 in the usual case + // when the previous test was as good as a strong prime test, but 1/8 of + // the time, j = 0 because the strong prime test to the base 2 needs to + // be re-done. + //for (int i = j; i < SMALL_PRIME_COUNT; i++) { + for (int i = j; i < 13; i++) + { // try only the first 13 primes + A = SMALL_PRIME[i]; + A = A.modPow(e, w); + if (A.bitCount() == 1) + { + continue; // Passed this test + } + l = k; + while (true) + { + // A = A.add(ONE); + // if (A.equals(w)) { // Was result bn-1? + if (A.equals(w_minus_one)) + { // Was result bn-1? + break; // Prime + } + if (--l == 0) + { // Reached end, not -1? luck? + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " fails Euler criterion #4..."); + } + return false; // Failed, not prime + } + // This portion is executed, on average, once + // A = A.subtract(ONE); // Put a back where it was + A = A.modPow(TWO, w); + if (A.bitCount() == 1) + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " fails Euler criterion #5..."); + } + return false; // Failed, not prime + } + } + // It worked (to the base primes[i]) + } + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " passes Euler criterion..."); + } + + // store it in the known primes weak hash-map + knownPrimes.put(w, new WeakReference(w)); + + return true; + } + + /** + * <p>Checks Fermat's Little Theorem for base <i>b</i>; i.e. + * <code><i>b</i>**(w-1) == 1 (mod w)</code>.</p> + * + * @param w the number to test. + * @param t the number of random bases to test. + * @return <code>true</code> iff <code><i>b</i>**(w-1) == 1 (mod w)</code>, + * for some <i>b</i>. + */ + public static boolean passFermatLittleTheorem(final BigInteger w, int t) + { + final BigInteger w_minus_one = w.subtract(ONE); + if (t <= 0) + { + t = 10; // XXX + } + if (!TWO.modPow(w_minus_one, w).equals(ONE)) + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " fails Fermat's little theorem for base 2"); + } + return false; + } + for (int i = 0; i < t; i++) + { + byte[] buf = new byte[(w.bitLength() + 7) / 8 - 1]; + BigInteger base = null; + do + { + new Random ().nextBytes(buf); + base = new BigInteger(1, buf); + } + while (base.compareTo(TWO) < 0 || base.compareTo(w_minus_one) > 0); + if (!base.modPow(w_minus_one, w).equals(ONE)) + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + + " fails Fermat's little theorem for base " + + base.toString(16)); + } + return false; + } + } + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " passes Fermat's little theorem for " + t + + " bases..."); + } + return true; + } + + /** + * <p>Applies the Miller-Rabin strong probabilistic primality test.</p> + * + * <p>The HAC (Handbook of Applied Cryptography), Alfred Menezes & al. Note + * 4.57 states that for <code>q</code>, <code>n=18</code> is enough while + * for <code>p</code>, <code>n=6</code> (512 bits) or <code>n=3</cdoe> (1024 + * bits) are enough to yield <i>robust</i> primality tests. The values used + * are from table 4.4 given in Note 4.49.</p> + * + * @param w the number to test. + * @return <code>true</code> iff the designated number passes the Miller- + * Rabin probabilistic primality test for a computed number of rounds. + */ + public static boolean passMillerRabin(BigInteger n, int t) + { + int nbytes = (n.bitLength() + 7) / 8; + byte[] ab = new byte[nbytes]; + + // 1. Write n - 1 = 2^s * r. + BigInteger n_minus_1 = n.subtract(ONE); + BigInteger r = n_minus_1; + int s = 0; + while (!r.testBit(0)) + { + r = r.shiftRight(1); + s++; + } + + // 2. For i from 1 to t, do: + for (int i = 0; i < t; i++) + { + + // 2.1 Choose a random integer a, 2 <= a <= n - 2. + BigInteger a; + do + { + new Random ().nextBytes(ab); + a = new BigInteger(1, ab); + } + while (a.compareTo(TWO) < 0 || a.compareTo(n) > 0); + + // 2.2 Compute y = a^r mod n. + BigInteger y = a.modPow(r, n); + + // If y != 1 and y != n - 1, then: + if (!y.equals(ONE) && !y.equals(n_minus_1)) + { + for (int j = 1; j < s - 1 && !y.equals(n_minus_1); j++) + { + // Compute y = y^2 mod n. + y = y.modPow(TWO, n); + + // If y = 1 return "composite" + if (y.equals(ONE)) + { + if (DEBUG && debuglevel > 4) + { + debug(n.toString(16) + " fails Miller-Rabin test..."); + } + return false; + } + } + // If y != n - 1 return "composite" + if (!y.equals(n_minus_1)) + { + if (DEBUG && debuglevel > 4) + { + debug(n.toString(16) + " fails Miller-Rabin test..."); + } + return false; + } + } + } + if (DEBUG && debuglevel > 4) + { + debug(n.toString(16) + " passes Miller-Rabin test..."); + } + return true; + } + + public static boolean isProbablePrime(BigInteger w) + { + return isProbablePrime(w, DEFAULT_CERTAINTY); + } + + /** + * <p>This implementation does not rely solely on the Miller-Rabin strong + * probabilistic primality test to claim the primality of the designated + * number. It instead, tries dividing the designated number by the first 1000 + * small primes, and if no divisor was found, invokes a port of Colin Plumb's + * implementation of the Euler Criterion, then tries the Miller-Rabin test.</p> + * + * @param w the integer to test. + * @param certainty the certainty with which to compute the test. + * @param doMillerRabin if <code>true</code> and the designated integer was + * already found to be a probable prime, then also do a Miller-Rabin test. + * @return <code>true</code> iff the designated number has no small prime + * divisor passes the Euler criterion, and optionally a Miller-Rabin test. + */ + public static boolean isProbablePrime(BigInteger w, int certainty) + { + // Nonnumbers are not prime. + if (w == null) + { + return false; + } + + // eliminate trivial cases when w == 0 or 1 + if (w.equals(ZERO) || w.equals(ONE)) + { + return false; + } + + // Test if w is a known small prime. + for (int i = 0; i < SMALL_PRIME_COUNT; i++) + { + if (w.equals(SMALL_PRIME[i])) + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " is a small prime"); + } + return true; + } + } + + // trial division with first 1000 primes + if (hasSmallPrimeDivisor(w)) + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " has a small prime divisor. Rejected..."); + } + return false; + } + + // Do a check with Fermat's little theorem. + // if (passFermatLittleTheorem(w, certainty)) { + // if (DEBUG && debuglevel > 4) { + // debug(w.toString(16)+" passes Fermat's little theorem..."); + // } + // } else { + // if (DEBUG && debuglevel > 4) { + // debug(w.toString(16)+" fails Fermat's little theorem. Rejected..."); + // } + // return false; + // } + + // Euler's criterion. + // if (passEulerCriterion(w)) { + // if (DEBUG && debuglevel > 4) { + // debug(w.toString(16)+" passes Euler's criterion..."); + // } + // } else { + // if (DEBUG && debuglevel > 4) { + // debug(w.toString(16)+" fails Euler's criterion. Rejected..."); + // } + // return false; + // } + + // Miller-Rabin probabilistic primality test. + if (passMillerRabin(w, certainty)) + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " passes Miller-Rabin PPT..."); + } + } + else + { + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " fails Miller-Rabin PPT. Rejected..."); + } + return false; + } + + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " is probable prime. Accepted..."); + } + + // now compare to JDK primality test + if (DEBUG && debuglevel > 0 && !w.isProbablePrime(certainty)) + { + System.err.println("The gnu.crypto library and the JDK disagree on " + + "whether 0x" + w.toString(16) + + " is a probable prime or not."); + System.err.println("While this library claims it is, the JDK claims" + + " the opposite."); + System.err.println("Please contact the maintainer of this library, " + + "and provide this message for further investigation. TIA"); + } + + return true; + } +} diff --git a/gnu/java/security/util/Sequence.java b/gnu/java/security/util/Sequence.java new file mode 100644 index 000000000..5edc7942e --- /dev/null +++ b/gnu/java/security/util/Sequence.java @@ -0,0 +1,149 @@ +/* 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 +{ + + // Field. + // ------------------------------------------------------------------------ + + private final Integer[] sequence; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * 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[] { new Integer(start), new Integer(end) }; + } + else + { + sequence = new Integer[] { new Integer(start) }; + } + } + else + { + LinkedList l = new LinkedList(); + for (int i = start; i != end; i += span) + { + l.add(new Integer(i)); + } + l.add(new Integer(end)); + sequence = (Integer[]) l.toArray(new Integer[l.size()]); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + 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(); + } +} diff --git a/gnu/java/security/util/SimpleList.java b/gnu/java/security/util/SimpleList.java new file mode 100644 index 000000000..b2525c4b8 --- /dev/null +++ b/gnu/java/security/util/SimpleList.java @@ -0,0 +1,171 @@ +/* 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 +{ + + // Fields. + // ------------------------------------------------------------------------ + + private final Object[] elements; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a singleton list. + * + * @param e1 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(); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + 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(); + } +} diff --git a/gnu/java/security/util/Util.java b/gnu/java/security/util/Util.java new file mode 100644 index 000000000..53f8e3c2c --- /dev/null +++ b/gnu/java/security/util/Util.java @@ -0,0 +1,692 @@ +/* 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; + +/** + * <p>A collection of utility methods used throughout this project.</p> + * + * @version $Revision: 1.1 $ + */ +public class Util +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // 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(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private Util() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns a string of hexadecimal digits from a byte array. Each byte is + * converted to 2 hex symbols; zero(es) included.</p> + * + * <p>This method calls the method with same name and three arguments as:</p> + * + * <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); + } + + /** + * <p>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> + * + * @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); + } + + /** + * <p>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> + * + * <p>This method calls the method with same name and three arguments as:</p> + * + * <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); + } + + /** + * <p>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> + * + * <p>The byte array is treated as a large little-endian integer, and + * is returned as a large big-endian integer.</p> + * + * @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; + } + + /** + * <p>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.</p> + * + * @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; + } + + /** + * <p>Returns a number from <code>0</code> to <code>15</code> corresponding + * to the designated hexadecimal digit.</p> + * + * @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); + } + + /** + * <p>Returns a string of 8 hexadecimal digits (most significant digit first) + * corresponding to the unsigned integer <code>n</code>.</p> + * + * @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); + } + + /** + * <p>Returns a string of hexadecimal digits from an integer array. Each int + * is converted to 4 hex symbols.</p> + */ + 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); + } + + /** + * <p>Returns a string of 16 hexadecimal digits (most significant digit first) + * corresponding to the unsigned long <code>n</code>.</p> + * + * @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); + } + + /** + * <p>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.</p> + * + * @throws ArrayIndexOutOfBoundsException if the length is odd. + */ + public static String toUnicodeString(byte[] ba) + { + return toUnicodeString(ba, 0, ba.length); + } + + /** + * <p>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.</p> + * + * @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(); + } + + /** + * <p>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.</p> + * + * @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; + } + + /** + * <p>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> + * + * <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.</p> + * + * @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, ""); + } + + /** + * <p>Returns a string of 2 hexadecimal digits (most significant digit first) + * corresponding to the lowest 8 bits of <code>n</code>.</p> + * + * @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); + } + + /** + * <p>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> + * + * <p>Used by SASL password file manipulation primitives.</p> + * + * @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"; + } + + /** + * <p>The inverse function of the above.</p> + * + * <p>Converts a string representing the encoding of some bytes in Base-64 + * to their original form.</p> + * + * @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 ---------------------------------------------------- + + /** + * <p>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.</p> + * + * @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; + } + + /** + * <p>Returns a hexadecimal dump of the trimmed bytes of a {@link BigInteger}. + * </p> + * + * @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)); + } +} diff --git a/gnu/javax/crypto/assembly/Assembly.java b/gnu/javax/crypto/assembly/Assembly.java new file mode 100644 index 000000000..1d70eff87 --- /dev/null +++ b/gnu/javax/crypto/assembly/Assembly.java @@ -0,0 +1,298 @@ +/* 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; + +/** + * <p>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> + * + * <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>.</p> + * + * @see Transformer + * @version $Revision: 1.1 $ + */ +public class Assembly +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial constructor that sets the <i>chain</i> to a + * <code>LoopbackTransformer</code>. + */ + public Assembly() + { + super(); + + wired = null; + head = new LoopbackTransformer(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * 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; + } + + // helper methods ---------------------------------------------------------- + + private void wireTransformer(Transformer t, Operation mode) + { + if (t.tail != null) + { + throw new IllegalArgumentException(); + } + t.setMode(mode); + t.tail = head; + head = t; + } +} diff --git a/gnu/javax/crypto/assembly/Cascade.java b/gnu/javax/crypto/assembly/Cascade.java new file mode 100644 index 000000000..20cd3de9d --- /dev/null +++ b/gnu/javax/crypto/assembly/Cascade.java @@ -0,0 +1,405 @@ +/* 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; + +/** + * <p>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> + * + * <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> + * + * <p>The term "block ciphers" used above refers to implementations of + * {@link gnu.crypto.mode.IMode}, including the {@link gnu.crypto.mode.ECB} + * mode which basically exposes a symmetric-key block cipher algorithm as a + * <i>Mode</i> of Operations.</p> + * + * <p>References:</p> + * + * <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> + * + * @version $Revision: 1.1 $ + */ +public class Cascade +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Cascade() + { + super(); + + stages = new HashMap(3); + stageKeys = new LinkedList(); + wired = null; + blockSize = 0; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * 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(); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * 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; + } +} diff --git a/gnu/javax/crypto/assembly/CascadeStage.java b/gnu/javax/crypto/assembly/CascadeStage.java new file mode 100644 index 000000000..71a8b178f --- /dev/null +++ b/gnu/javax/crypto/assembly/CascadeStage.java @@ -0,0 +1,109 @@ +/* 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; + +/** + * <p>A Cascade <i>Stage</i> in a Cascade Cipher.</p> + * + * @version $Revision: 1.1 $ + */ +class CascadeStage extends Stage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private Cascade delegate; + + // Constructor(s) + // ------------------------------------------------------------------------- + + CascadeStage(Cascade cascade, Direction forwardDirection) + { + super(forwardDirection); + + this.delegate = cascade; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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(flow.equals(forward) ? forward : backward); + // delegate.init(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(); + } +} diff --git a/gnu/javax/crypto/assembly/CascadeTransformer.java b/gnu/javax/crypto/assembly/CascadeTransformer.java new file mode 100644 index 000000000..325571dcd --- /dev/null +++ b/gnu/javax/crypto/assembly/CascadeTransformer.java @@ -0,0 +1,139 @@ +/* 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}. + * + * @version $Revision: 1.1 $ + */ +class CascadeTransformer extends Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private Cascade delegate; + + private int blockSize; + + // Constructor(s) + // ------------------------------------------------------------------------- + + CascadeTransformer(Cascade delegate) + { + super(); + + this.delegate = delegate; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instant methods + // ------------------------------------------------------------------------- + + 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) + { + throw new TransformerException( + "lastUpdateDelegate()", + new IllegalStateException( + "Cascade transformer, after last " + + "update, must be empty but isn't")); + } + 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; + } +} diff --git a/gnu/javax/crypto/assembly/DeflateTransformer.java b/gnu/javax/crypto/assembly/DeflateTransformer.java new file mode 100644 index 000000000..35328a6c1 --- /dev/null +++ b/gnu/javax/crypto/assembly/DeflateTransformer.java @@ -0,0 +1,233 @@ +/* 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; + +/** + * <p>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> + * + * <p>This {@link Transformer} uses a {@link Deflater} instance to carry on the + * compression, and an {@link Inflater} to do the decompression.</p> + * + * <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.</p> + * + * @version Revision: $ + */ +class DeflateTransformer extends Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private Deflater compressor; + + private Inflater decompressor; + + private int outputBlockSize = 512; // default zlib buffer size + + private byte[] zlibBuffer; + + // Constructor(s) + // ------------------------------------------------------------------------- + + DeflateTransformer() + { + super(); + + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + throw new TransformerException( + "initDelegate()", + new IllegalStateException( + "Compression transformer missing its tail!")); + } + 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 outputBlockSize; + 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(byte[] in, int offset, int length) + // throws TransformerException { + // // process multiples of blocksize as much as possible + // byte[] result = this.updateDelegate(in, offset, length); + // inBuffer.write(result, 0, result.length); + // if (wired == Direction.FORWARD) { // compressing + // if (!compressor.finished()) { + // compressor.finish(); + // while (!compressor.finished()) { + // compress(); + // } + // } + // } else { // decompressing + // if (!decompressor.finished()) { + // throw new TransformerException("lastUpdateDelegate()", + // new IllegalStateException("Compression transformer, after last " + // +"update, must be finished but isn't")); + // } + // } + // + // 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()) + { + throw new TransformerException( + "lastUpdateDelegate()", + new IllegalStateException( + "Compression transformer, after last " + + "update, must be finished but isn't")); + } + } + 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); + } + } + } +} diff --git a/gnu/javax/crypto/assembly/Direction.java b/gnu/javax/crypto/assembly/Direction.java new file mode 100644 index 000000000..2e8ef1145 --- /dev/null +++ b/gnu/javax/crypto/assembly/Direction.java @@ -0,0 +1,92 @@ +/* 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; + +/** + * <p>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> + * + * <p>The possible values for this type are two:</p> + * <ol> + * <li>FORWARD: equivalent to {@link gnu.crypto.mode.IMode#ENCRYPTION}, and + * its inverse value</li> + * <li>REVERSED: equivalent to {@link gnu.crypto.mode.IMode#DECRYPTION}.</li> + * </ol> + * + * @version $Revision: 1.1 $ + */ +public final class Direction +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final Direction FORWARD = new Direction(1); + + public static final Direction REVERSED = new Direction(2); + + private int value; + + // Constructor(s) + // ------------------------------------------------------------------------- + + private Direction(int value) + { + super(); + + this.value = value; + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final Direction reverse(Direction d) + { + return (d.equals(FORWARD) ? REVERSED : FORWARD); + } + + // Instance methods + // ------------------------------------------------------------------------- + + public String toString() + { + return (this == FORWARD ? "forward" : "reversed"); + } +} diff --git a/gnu/javax/crypto/assembly/LoopbackTransformer.java b/gnu/javax/crypto/assembly/LoopbackTransformer.java new file mode 100644 index 000000000..62791264f --- /dev/null +++ b/gnu/javax/crypto/assembly/LoopbackTransformer.java @@ -0,0 +1,116 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +final class LoopbackTransformer extends Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial protected constructor. */ + LoopbackTransformer() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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(); + } + + // abstract methods to be implemented by concrete subclasses --------------- + + 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]; + } +} diff --git a/gnu/javax/crypto/assembly/ModeStage.java b/gnu/javax/crypto/assembly/ModeStage.java new file mode 100644 index 000000000..1cd8fd915 --- /dev/null +++ b/gnu/javax/crypto/assembly/ModeStage.java @@ -0,0 +1,129 @@ +/* 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; + +/** + * <p>An {@link IMode} {@link Stage} in a {@link Cascade} Cipher chain.</p> + * + * <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.</p> + * + * @version $Revision: 1.1 $ + */ +class ModeStage extends Stage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private IMode delegate; + + private transient Set cachedBlockSizes; + + // Constructor(s) + // ------------------------------------------------------------------------- + + ModeStage(IMode mode, Direction forwardDirection) + { + super(forwardDirection); + + delegate = mode; + cachedBlockSizes = null; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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, + new Integer(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(); + } +} diff --git a/gnu/javax/crypto/assembly/Operation.java b/gnu/javax/crypto/assembly/Operation.java new file mode 100644 index 000000000..2646e1f33 --- /dev/null +++ b/gnu/javax/crypto/assembly/Operation.java @@ -0,0 +1,89 @@ +/* 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; + +/** + * <p>An enumeration type for specifying the operation type of a + * {@link Transformer}.</p> + * + * <p>The possible values for this type are two:</p> + * <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> + * + * @version $Revision: 1.1 $ + */ +public final class Operation +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final Operation PRE_PROCESSING = new Operation(1); + + public static final Operation POST_PROCESSING = new Operation(2); + + private int value; + + // Constructor(s) + // ------------------------------------------------------------------------- + + private Operation(int value) + { + super(); + + this.value = value; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public String toString() + { + return (this == PRE_PROCESSING ? "pre-processing" : "post-processing"); + } +} diff --git a/gnu/javax/crypto/assembly/PaddingTransformer.java b/gnu/javax/crypto/assembly/PaddingTransformer.java new file mode 100644 index 000000000..8af46a72a --- /dev/null +++ b/gnu/javax/crypto/assembly/PaddingTransformer.java @@ -0,0 +1,178 @@ +/* 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; + +/** + * <p>An Adapter to use any {@link IPad} as a {@link Transformer} in an + * {@link Assembly}.</p> + * + * <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.</p> + * + * @version $Revision: 1.1 $ + */ +class PaddingTransformer extends Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private IPad delegate; + + private int outputBlockSize = 1; + + // Constructor(s) + // ------------------------------------------------------------------------- + + PaddingTransformer(IPad padding) + { + super(); + + this.delegate = padding; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + throw new TransformerException( + "initDelegate()", + new IllegalStateException( + "Padding transformer missing its tail!")); + } + 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; + } +} diff --git a/gnu/javax/crypto/assembly/Stage.java b/gnu/javax/crypto/assembly/Stage.java new file mode 100644 index 000000000..e44985534 --- /dev/null +++ b/gnu/javax/crypto/assembly/Stage.java @@ -0,0 +1,218 @@ +/* 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; + +/** + * <p>A <i>Stage</i> in a Cascade Cipher.</p> + * + * <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.</p> + * <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.</p> + * <pre> + * FORWARD REVERSED + * +------+ +------+ + * | | | | + * | +--in --+ +--in --+ | + * ---+ | Stage | | Stage | +--- + * +--out--+ +--out--+ + * | | + * +---------------+ + * </pre> + * + * @see ModeStage + * @see CascadeStage + * @version $Revision: 1.1 $ + */ +public abstract class Stage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String DIRECTION = "gnu.crypto.assembly.stage.direction"; + + protected Direction forward; + + protected Direction wired; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected Stage(Direction forwardDirection) + { + super(); + + this.forward = forwardDirection; + this.wired = null; + } + + // Class methods + // ------------------------------------------------------------------------- + + 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); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * 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 methods to be implemented by concrete subclasses --------------- + + abstract void initDelegate(Map attributes) throws InvalidKeyException; + + abstract void resetDelegate(); + + abstract void updateDelegate(byte[] in, int inOffset, byte[] out, + int outOffset); +} diff --git a/gnu/javax/crypto/assembly/Transformer.java b/gnu/javax/crypto/assembly/Transformer.java new file mode 100644 index 000000000..c62c4677f --- /dev/null +++ b/gnu/javax/crypto/assembly/Transformer.java @@ -0,0 +1,460 @@ +/* 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; + +/** + * <p>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.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> + * + * <p>A <code>Transformer</code> is characterised by the followings:<p> + * <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.</p> + * + * @see CascadeTransformer + * @see PaddingTransformer + * @see DeflateTransformer + * @version $Revision: 1.1 $ + */ +public abstract class Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String DIRECTION = "gnu.crypto.assembly.transformer.direction"; + + // public static final String MODE = "gnu.crypto.assembly.transformer.mode"; + + protected Direction wired; + + protected Operation mode; + + protected Transformer tail = null; + + protected ByteArrayOutputStream inBuffer = new ByteArrayOutputStream(2048); + + protected ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(2048); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial protected constructor. */ + protected Transformer() + { + super(); + + this.wired = null; + } + + // Class methods + // ------------------------------------------------------------------------- + + 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(); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * 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; + } + + // helper methods ---------------------------------------------------------- + + 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 methods to be implemented by concrete subclasses --------------- + + 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; +} diff --git a/gnu/javax/crypto/assembly/TransformerException.java b/gnu/javax/crypto/assembly/TransformerException.java new file mode 100644 index 000000000..412f0f0f1 --- /dev/null +++ b/gnu/javax/crypto/assembly/TransformerException.java @@ -0,0 +1,158 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private Throwable _exception = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + 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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instant methods + // ------------------------------------------------------------------------- + + 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(); + } +} diff --git a/gnu/javax/crypto/cipher/Anubis.java b/gnu/javax/crypto/cipher/Anubis.java new file mode 100644 index 000000000..63b97ce4e --- /dev/null +++ b/gnu/javax/crypto/cipher/Anubis.java @@ -0,0 +1,583 @@ +/* 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.Registry; +import gnu.java.security.util.Util; + +//import java.io.PrintWriter; +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * <p>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> + * + * <p>References:</p> + * + * <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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + // private static final String NAME = "anubis"; + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + // private static final PrintWriter err = new PrintWriter(System.out, true); + // private static void debug(String s) { + // err.println(">>> "+NAME+": "+s); + // } + + // Constants and variables + // ------------------------------------------------------------------------- + + 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 <= N <= 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 code - to initialise lookup tables ------------------------------- + + 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 (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static data"); + System.out.println(); + + System.out.println(); + System.out.println("T0[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T0[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T1[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T1[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T2[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T2[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T3[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T3[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T4[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T4[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T5[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("rc[]:"); + for (i = 0; i < 18; i++) + { + System.out.println("0x" + Util.toString(rc[i])); + } + System.out.println(); + + System.out.println(); + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Anubis() + { + super(Registry.ANUBIS_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("T=" + Util.toString(out, j - 15, 16)); + System.out.println(); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Anubis result = new Anubis(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 4; n < 10; n++) + { + al.add(new Integer(n * 32 / 8)); + } + + return Collections.unmodifiableList(al).iterator(); + } + + /** + * <p>Expands a user-supplied key material into a session key for a + * designated <i>block size</i>.</p> + * + * @param uk the 32N-bit user-supplied key material; 4 <= N <= 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 (DEBUG && debuglevel > 8) + { + System.out.println(); + System.out.println("Key schedule"); + System.out.println(); + System.out.println("Ke[]:"); + for (r = 0; r < R + 1; r++) + { + System.out.print("#" + r + ": "); + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(Ke[r][j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("Kd[]:"); + for (r = 0; r < R + 1; r++) + { + System.out.print("#" + r + ": "); + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(Kd[r][j]) + ", "); + System.out.println(); + } + System.out.println(); + } + + 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 = new Boolean(result); + } + return valid.booleanValue(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/BaseCipher.java b/gnu/javax/crypto/cipher/BaseCipher.java new file mode 100644 index 000000000..9d62311ed --- /dev/null +++ b/gnu/javax/crypto/cipher/BaseCipher.java @@ -0,0 +1,304 @@ +/* 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.util.Util; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +/** + * <p>A basic abstract class to facilitate implementing symmetric key block + * ciphers.</p> + */ +public abstract class BaseCipher implements IBlockCipher, IBlockCipherSpi +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial constructor for use by concrete subclasses.</p> + * + * @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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IBlockCipher interface implementation ----------------------------------- + + 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) + { + // currentBlockSize = 0; + 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; + } + + // own methods ------------------------------------------------------------- + + 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) + { + x.printStackTrace(System.err); + 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) + { + x.printStackTrace(System.err); + return false; + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Blowfish.java b/gnu/javax/crypto/cipher/Blowfish.java new file mode 100644 index 000000000..5cb958ee4 --- /dev/null +++ b/gnu/javax/crypto/cipher/Blowfish.java @@ -0,0 +1,749 @@ +/* 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:</p> + * <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 +{ + + // Constants and variables + // ----------------------------------------------------------------- + + 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"); + + // Constructors + // ----------------------------------------------------------------------- + + public Blowfish() + { + super(Registry.BLOWFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Clonable interface implementation. + // ----------------------------------------------------------------------- + + public Object clone() + { + Blowfish result = new Blowfish(); + result.currentBlockSize = currentBlockSize; + return result; + } + + // Implementations of abstract methods from BaseCipher + // ----------------------------------------------------------------------- + + public Iterator keySizes() + { + return new Sequence(8, MAX_KEY_LENGTH, 8).iterator(); + // return new Iterator() { + // private int i = 0; + + // public boolean hasNext() { + // return i <= MAX_KEY_LENGTH-8; + // } + + // public Object next() { + // if (hasNext()) { + // i += 8; + // return new Integer(i); + // } + // return null; + // } + + // public void remove() { + // throw new UnsupportedOperationException(); + // } + // }; + } + + public Iterator blockSizes() + { + return Collections.singleton(new Integer(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; + } + + // Own methods + // ----------------------------------------------------------------- + + /** 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 = new Boolean(result); + } + return valid.booleanValue(); + } + + // Inner classes. + // ----------------------------------------------------------------------- + + /** A simple wrapper for the P- and S-boxes. */ + private class Context implements Cloneable + { + + // Constants and variables. + // -------------------------------------------------------------------- + + /** The P-array. */ + int[] p, s0, s1, s2, s3; + + // Constructors. + // -------------------------------------------------------------------- + + /** 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(); + } + + // Clonable interface implementation. + // -------------------------------------------------------------------- + + public Object clone() + { + return new Context(this); + } + } + + private class Block + { + int left, right; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Cast5.java b/gnu/javax/crypto/cipher/Cast5.java new file mode 100644 index 000000000..cbdfe61f5 --- /dev/null +++ b/gnu/javax/crypto/cipher/Cast5.java @@ -0,0 +1,1391 @@ +/* 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; + +/** + * <p>An implmenetation of the <code>CAST5</code> (a.k.a. CAST-128) algorithm, + * as per <i>RFC-2144</i>, dated May 1997.</p> + * + * <p>In this RFC, <i>Carlisle Adams</i> (the CA in CAST, ST stands for + * <i>Stafford Tavares</i>) describes CAST5 as:</p> + * + * <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> + * + * <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:</p> + * + * <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:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Cast5() + { + super(Registry.CAST5_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * 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 }; + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Cast5 result = new Cast5(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 5; n < 17; n++) + { + al.add(new Integer(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; + } + + /** + * <p>The full encryption algorithm is given in the following four steps.</p> + * + * <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> + * + * <p>Looking at the iterations/rounds in pairs we have:</p> + * + * <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 = new Boolean(result); + } + return valid.booleanValue(); + } + + // helper methods ---------------------------------------------------------- + + 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]; + } + + // Inner class(es) + // ========================================================================= + + /** 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; + } +} diff --git a/gnu/javax/crypto/cipher/CipherFactory.java b/gnu/javax/crypto/cipher/CipherFactory.java new file mode 100644 index 000000000..082bfb8fa --- /dev/null +++ b/gnu/javax/crypto/cipher/CipherFactory.java @@ -0,0 +1,169 @@ +/* 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; + +/** + * <p>A <i>Factory</i> to instantiate symmetric block cipher instances.</p> + */ +public class CipherFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private CipherFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a block cipher given its name.</p> + * + * @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; + } + + /** + * <p>Returns a {@link Set} of symmetric key block cipher implementation + * names supported by this <i>Factory</i>.</p> + * + * @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); + } + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/DES.java b/gnu/javax/crypto/cipher/DES.java new file mode 100644 index 000000000..8b7627cea --- /dev/null +++ b/gnu/javax/crypto/cipher/DES.java @@ -0,0 +1,894 @@ +/* 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; + +/** + * <p>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> + * + * <p>New applications should not use DES except for compatibility.</p> + * + * <p>This version is based upon the description and sample implementation in + * [1].</p> + * + * <p>References:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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") }; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Default 0-argument constructor. */ + public DES() + { + super(Registry.DES_CIPHER, BLOCK_SIZE, KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @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 < KEY_SIZE; i++) + { + kb[i] ^= (PARITY[kb[i] & 0xff] == 8) ? 1 : 0; + } + } + + /** + * <p>Test if a byte array, which must be at least 8 bytes long, is parity + * adjusted.</p> + * + * @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; + } + + /** + * <p>Test if a key is a weak key.</p> + * + * @param kb The key to test. + * @return <code>true</code> if the key is weak. + */ + public static boolean isWeak(byte[] kb) + { + // return Arrays.equals(kb, WEAK_KEYS[0]) || Arrays.equals(kb, WEAK_KEYS[1]) + // || Arrays.equals(kb, WEAK_KEYS[2]) || Arrays.equals(kb, WEAK_KEYS[3]) + // || Arrays.equals(kb, WEAK_KEYS[4]) || Arrays.equals(kb, WEAK_KEYS[5]) + // || Arrays.equals(kb, WEAK_KEYS[6]) || Arrays.equals(kb, WEAK_KEYS[7]); + for (int i = 0; i < WEAK_KEYS.length; i++) + { + if (Arrays.equals(WEAK_KEYS[i], kb)) + { + return true; + } + } + return false; + } + + /** + * <p>Test if a key is a semi-weak key.</p> + * + * @param kb The key to test. + * @return <code>true</code> if this key is semi-weak. + */ + public static boolean isSemiWeak(byte[] kb) + { + // return Arrays.equals(kb, SEMIWEAK_KEYS[0]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[1]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[2]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[3]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[4]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[5]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[6]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[7]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[8]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[9]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[10]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[11]); + for (int i = 0; i < SEMIWEAK_KEYS.length; i++) + { + if (Arrays.equals(SEMIWEAK_KEYS[i], kb)) + { + return true; + } + } + return false; + } + + /** + * <p>Test if the designated byte array represents a possibly weak key.</p> + * + * @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; + } + + /** + * <p>The core DES function. This is used for both encryption and decryption, + * the only difference being the key.</p> + * + * @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; + } + + // Instance methods implementing BaseCipher + // ------------------------------------------------------------------------- + + public Object clone() + { + return new DES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(new Integer(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + return Collections.singleton(new Integer(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); + } + + // Inner classe(s) + // ========================================================================= + + /** + * Simple wrapper class around the session keys. Package-private so TripleDES + * can see it. + */ + final class Context + { + + // Constants and variables + // ---------------------------------------------------------------------- + + private static final int EXPANDED_KEY_SIZE = 32; + + /** The encryption key. */ + int[] ek; + + /** The decryption key. */ + int[] dk; + + // Constructor(s) + // ---------------------------------------------------------------------- + + /** Default 0-arguments constructor. */ + Context() + { + ek = new int[EXPANDED_KEY_SIZE]; + dk = new int[EXPANDED_KEY_SIZE]; + } + + // Class methods + // ---------------------------------------------------------------------- + + // Instance methods + // ---------------------------------------------------------------------- + + 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; + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/IBlockCipher.java b/gnu/javax/crypto/cipher/IBlockCipher.java new file mode 100644 index 000000000..238ee280f --- /dev/null +++ b/gnu/javax/crypto/cipher/IBlockCipher.java @@ -0,0 +1,205 @@ +/* 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; + +/** + * <p>The basic visible methods of any symmetric key block cipher.</p> + * + * <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> + * + * <p>Possible initialisation values for an instance of this type are:</p> + * + * <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.</p> + */ +public interface IBlockCipher extends Cloneable +{ + + // Constants + // ------------------------------------------------------------------------- + + /** + * <p>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}.</p> + */ + String CIPHER_BLOCK_SIZE = "gnu.crypto.cipher.block.size"; + + /** + * <p>Property name of the user-supplied key material. The value associated + * to this property name is taken to be a byte array.</p> + */ + String KEY_MATERIAL = "gnu.crypto.cipher.key.material"; + + // Methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the canonical name of this instance.</p> + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * <p>Returns the default value, in bytes, of the algorithm's block size.</p> + * + * @return the default value, in bytes, of the algorithm's block size. + */ + int defaultBlockSize(); + + /** + * <p>Returns the default value, in bytes, of the algorithm's key size.</p> + * + * @return the default value, in bytes, of the algorithm's key size. + */ + int defaultKeySize(); + + /** + * <p>Returns an {@link Iterator} over the supported block sizes. Each + * element returned by this object is an {@link Integer}.</p> + * + * @return an {@link Iterator} over the supported block sizes. + */ + Iterator blockSizes(); + + /** + * <p>Returns an {@link Iterator} over the supported key sizes. Each element + * returned by this object is an {@link Integer}.</p> + * + * @return an {@link Iterator} over the supported key sizes. + */ + Iterator keySizes(); + + /** + * <p>Returns a clone of this instance.</p> + * + * @return a clone copy of this instance. + */ + Object clone(); + + /** + * <p>Initialises the algorithm with designated attributes. Permissible names + * and values are described in the class documentation above.</p> + * + * @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; + + /** + * <p>Returns the currently set block size for this instance.</p> + * + * @return the current block size for this instance. + * @exception IllegalStateException if the instance is not initialised. + */ + int currentBlockSize() throws IllegalStateException; + + /** + * <p>Resets the algorithm instance for re-initialisation and use with other + * characteristics. This method always succeeds.</p> + */ + void reset(); + + /** + * <p>Encrypts exactly one block of plaintext.</p> + * + * @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; + + /** + * <p>Decrypts exactly one block of ciphertext.</p> + * + * @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; + + /** + * <p>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).</p> + * + * @return <code>true</code> if the implementation passes simple + * <i>correctness</i> tests. Returns <code>false</code> otherwise. + */ + boolean selfTest(); +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/IBlockCipherSpi.java b/gnu/javax/crypto/cipher/IBlockCipherSpi.java new file mode 100644 index 000000000..6fe07ca7f --- /dev/null +++ b/gnu/javax/crypto/cipher/IBlockCipherSpi.java @@ -0,0 +1,128 @@ +/* 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; + +/** + * <p>Package-private interface exposing mandatory methods to be implemented by + * concrete {@link gnu.crypto.cipher.BaseCipher} sub-classes.</p> + */ +interface IBlockCipherSpi extends Cloneable +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an {@link java.util.Iterator} over the supported block sizes. + * Each element returned by this object is a {@link java.lang.Integer}.</p> + * + * @return an <code>Iterator</code> over the supported block sizes. + */ + Iterator blockSizes(); + + /** + * <p>Returns an {@link java.util.Iterator} over the supported key sizes. + * Each element returned by this object is a {@link java.lang.Integer}.</p> + * + * @return an <code>Iterator</code> over the supported key sizes. + */ + Iterator keySizes(); + + /** + * <p>Expands a user-supplied key material into a session key for a + * designated <i>block size</i>.</p> + * + * @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; + + /** + * <p>Encrypts exactly one block of plaintext.</p> + * + * @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); + + /** + * <p>Decrypts exactly one block of ciphertext.</p> + * + * @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); + + /** + * <p>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).</p> + * + * @return <code>true</code> if the implementation passes simple + * <i>correctness</i> tests. Returns <code>false</code> otherwise. + */ + boolean selfTest(); +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Khazad.java b/gnu/javax/crypto/cipher/Khazad.java new file mode 100644 index 000000000..b6c27833e --- /dev/null +++ b/gnu/javax/crypto/cipher/Khazad.java @@ -0,0 +1,521 @@ +/* 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.Registry; +import gnu.java.security.util.Util; + +//import java.io.PrintWriter; +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * <p>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> + * + * <p>References:</p> + * + * <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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + // private static final String NAME = "khazad"; + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + // private static final PrintWriter err = new PrintWriter(System.out, true); + // private static void debug(String s) { + // err.println(">>> "+NAME+": "+s); + // } + + // Constants and variables + // ------------------------------------------------------------------------- + + 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 code - to intialise lookup tables -------------------------------- + + 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 (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static data"); + System.out.println(); + + System.out.println(); + System.out.println("T0[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T0[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T1[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T1[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T2[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T2[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T3[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T3[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T4[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T4[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T5[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T6[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T6[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T7[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T7[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("rc[]:"); + for (i = 0; i < R + 1; i++) + System.out.print("0x" + Util.toString(rc[i][0]) + + Util.toString(rc[i][1])); + System.out.println(); + + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Khazad() + { + super(Registry.KHAZAD_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("T=" + Util.toString(out, j - 7, 8)); + System.out.println(); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Khazad result = new Khazad(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_KEY_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + /** + * <p>Expands a user-supplied key material into a session key for a + * designated <i>block size</i>.</p> + * + * @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 (DEBUG && debuglevel > 8) + { + System.out.println(); + System.out.println("Key schedule"); + System.out.println(); + System.out.println("Ke[]:"); + for (r = 0; r < R + 1; r++) + { + System.out.println("#" + r + ": 0x" + Util.toString(Ke[r][0]) + + Util.toString(Ke[r][1])); + } + System.out.println(); + System.out.println("Kd[]:"); + for (r = 0; r < R + 1; r++) + { + System.out.println("#" + r + ": 0x" + Util.toString(Kd[r][0]) + + Util.toString(Kd[r][1])); + } + System.out.println(); + } + + 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 = new Boolean(result); + } + return valid.booleanValue(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/NullCipher.java b/gnu/javax/crypto/cipher/NullCipher.java new file mode 100644 index 000000000..09252db90 --- /dev/null +++ b/gnu/javax/crypto/cipher/NullCipher.java @@ -0,0 +1,129 @@ +/* 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; + +/** + * <p>The implementation of a Null block cipher.</p> + * + * <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.</p> + */ +public final class NullCipher extends BaseCipher +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public NullCipher() + { + super(Registry.NULL_CIPHER, 16, 16); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + NullCipher result = new NullCipher(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(64 / 8)); + al.add(new Integer(128 / 8)); + al.add(new Integer(192 / 8)); + al.add(new Integer(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 8; n < 64; n++) + { + al.add(new Integer(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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Rijndael.java b/gnu/javax/crypto/cipher/Rijndael.java new file mode 100644 index 000000000..058c8b346 --- /dev/null +++ b/gnu/javax/crypto/cipher/Rijndael.java @@ -0,0 +1,859 @@ +/* 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.Registry; +import gnu.java.security.util.Util; + +//import java.io.PrintWriter; +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * <p>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> + * + * <p>References:</p> + * + * <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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + // private static final String NAME = "rijndael"; + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + // private static final PrintWriter err = new PrintWriter(System.out, true); + // private static void debug(String s) { + // err.println(">>> "+NAME+": "+s); + // } + + // Constants and variables + // ------------------------------------------------------------------------- + + 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 code - to intialise lookup tables -------------------------------- + + 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 (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static Data"); + System.out.println(); + System.out.println("S[]:"); + for (i = 0; i < 16; i++) + { + for (j = 0; j < 16; j++) + { + System.out.print("0x" + Util.toString(S[i * 16 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("Si[]:"); + for (i = 0; i < 16; i++) + { + for (j = 0; j < 16; j++) + { + System.out.print("0x" + Util.toString(Si[i * 16 + j]) + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("T1[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T1[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T2[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T2[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T3[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T3[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T4[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T4[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T5[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T6[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T6[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T7[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T7[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T8[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T8[i * 4 + j]) + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("U1[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(U1[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("U2[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(U2[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("U3[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(U3[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("U4[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.println("0x" + Util.toString(U4[i * 4 + j]) + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("rcon[]:"); + for (i = 0; i < 5; i++) + { + for (j = 0; j < 6; j++) + { + System.out.print("0x" + Util.toString(rcon[i * 6 + j]) + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Rijndael() + { + super(Registry.RIJNDAEL_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the number of rounds for a given Rijndael's key and block + * sizes.</p> + * + * @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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("CT=" + Util.toString(out, outOffset - bs + 1, bs)); + System.out.println(); + } + } + + 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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("PT=" + Util.toString(out, outOffset - bs + 1, bs)); + System.out.println(); + } + } + + 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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("CT=" + Util.toString(out, j - 15, 16)); + System.out.println(); + } + } + + 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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("PT=" + Util.toString(out, j - 15, 16)); + System.out.println(); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Rijndael result = new Rijndael(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(128 / 8)); + al.add(new Integer(192 / 8)); + al.add(new Integer(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(128 / 8)); + al.add(new Integer(192 / 8)); + al.add(new Integer(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 = new Boolean(result); + } + return valid.booleanValue(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Serpent.java b/gnu/javax/crypto/cipher/Serpent.java new file mode 100644 index 000000000..b323b5017 --- /dev/null +++ b/gnu/javax/crypto/cipher/Serpent.java @@ -0,0 +1,1830 @@ +/* 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; + +/** + * <p>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> + * + * <p>Serpent was designed by Ross Anderson, Eli Biham, and Lars Knudsen as a + * proposed cipher for the Advanced Encryption Standard.</p> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial zero-argument constructor. */ + public Serpent() + { + super(Registry.SERPENT_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Serpent result = new Serpent(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + return Collections.singleton(new Integer(DEFAULT_BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + ArrayList keySizes = new ArrayList(); + keySizes.add(new Integer(16)); + keySizes.add(new Integer(24)); + keySizes.add(new Integer(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 = new Boolean(result); + } + return valid.booleanValue(); + } + + // Own methods. ---------------------------------------------------------- + + // 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; + } + + // These S-Box functions are used in the key setup. + + /** 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; + } + + // Inner classes. + // ----------------------------------------------------------------------- + + private class Key implements Cloneable + { + + // Constants and variables. + // -------------------------------------------------------------------- + + 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; + + // Constructors. + // -------------------------------------------------------------------- + + /** 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; + } + + // Cloneable interface implementation. + // -------------------------------------------------------------------- + + public Object clone() + { + return new Key(this); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Square.java b/gnu/javax/crypto/cipher/Square.java new file mode 100644 index 000000000..15cb8b536 --- /dev/null +++ b/gnu/javax/crypto/cipher/Square.java @@ -0,0 +1,520 @@ +/* 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; + +/** + * <p>Square is a 128-bit key, 128-bit block cipher algorithm developed by Joan + * Daemen, Lars Knudsen and Vincent Rijmen.</p> + * + * <p>References:</p> + * + * <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> + * + * @version $Revision: 1.1 $ + */ +public final class Square extends BaseCipher +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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 code - to intialise lookup tables + // ------------------------------------------------------------------------- + + static + { + int i, j; + /* + // Generate exp and log tables used in multiplication over GF(2 ** m) + byte[] exp = new byte[256]; + byte[] log = new byte[256]; + + exp[0] = 1; + for (i = 1; i < 256; i++) { + j = exp[i - 1] << 1; + if ((j & 0x100) != 0) { + j ^= ROOT; // reduce j (mod ROOT) + } + + exp[i] = (byte) j; + log[j & 0xFF] = (byte) i; + } + + // Compute the substitution box Se[] and its inverse Sd[] based on + // F(x) = x**{-1} plus affine transform of the output. + Se[0] = 0; + Se[1] = 1; + for (i = 2; i < 256; i++) { + Se[i] = exp[(255 - log[i]) & 0xFF]; + } + + // Let Se[i] be represented as an 8-row vector V over GF(2); the affine + // transformation is A * V + T, where the rows of the 8 x 8 matrix A are + // contained in trans[0]...trans[7] and the 8-row vector T is contained + // in 0xB1. + int[] trans = new int[] {0x01, 0x03, 0x05, 0x0F, 0x1F, 0x3D, 0x7B, 0xD6}; + int u, v; + for (i = 0; i < 256; i++) { + v = 0xB1; // affine part of the transform + for (j = 0; j < 8; j++) { + u = Se[i] & trans[j] & 0xFF; // column-wise mult. over GF(2) + u ^= u >>> 4; // sum of all bits of u over GF(2) + u ^= u >>> 2; + u ^= u >>> 1; + u &= 1; + v ^= u << j; // row alignment of the result + } + Se[i] = (byte) v; + Sd[v] = (byte) i; // inverse substitution box + } + + System.out.println("Se="+Util.toUnicodeString(Se)); + System.out.println("Sd="+Util.toUnicodeString(Sd)); + */ + /**/ + // 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); + } + /**/ + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Square() + { + super(Registry.SQUARE_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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; + } + + /** + * <p>Applies the Theta function to an input <i>in</i> in order to produce in + * <i>out</i> an internal session sub-key.</p> + * + * <p>Both <i>in</i> and <i>out</i> are arrays of four ints.</p> + * + * <p>Pseudo-code is:</p> + * + * <pre> + * for (i = 0; i < 4; i++) { + * out[i] = 0; + * for (j = 0, n = 24; j < 4; j++, n -= 8) { + * k = mul(in[i] >>> 24, G[0][j]) ^ + * mul(in[i] >>> 16, G[1][j]) ^ + * mul(in[i] >>> 8, G[2][j]) ^ + * mul(in[i] , G[3][j]); + * out[i] ^= k << 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; + } + } + + /** + * <p>Left rotate a 32-bit chunk.</p> + * + * @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); + } + + /** + * <p>Right rotate a 32-bit chunk.</p> + * + * @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); + } + + /** + * <p>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> + * + * <p>For best performance call it with abs(b) < abs(a).</p> + * + * @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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Square result = new Square(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(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 = new Boolean(result); + } + return valid.booleanValue(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/TripleDES.java b/gnu/javax/crypto/cipher/TripleDES.java new file mode 100644 index 000000000..9b44c9ca7 --- /dev/null +++ b/gnu/javax/crypto/cipher/TripleDES.java @@ -0,0 +1,196 @@ +/* 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.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 improve + * the security (at the cost of speed) of plain DES. + * + * <p>Triple-DES runs the DES algorithm three times with three + * independent 56 bit keys. To encrypt:</p> + * + * <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:</p> + * + * <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> + * + * <p>References:</p> + * <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 +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** Triple-DES only operates on 64 bit blocks. */ + public static final int BLOCK_SIZE = 8; + + /** 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; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * Default 0-arguments constructor. + */ + public TripleDES() + { + super(Registry.TRIPLEDES_CIPHER, BLOCK_SIZE, KEY_SIZE); + des = new DES(); + } + + // Class methods. + // ----------------------------------------------------------------------- + + /** + * Transform a key so it will be parity adjusted. + * + * @param kb The key bytes to adjust. + * @param offset The starting offset into the key bytes. + * @see DES#adjustParity(byte[],int) + */ + public static void adjustParity(byte[] kb, int offset) + { + DES.adjustParity(kb, offset); + DES.adjustParity(kb, offset + 8); + DES.adjustParity(kb, offset + 16); + } + + /** + * Tests if a byte array has already been parity adjusted. + * + * @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 DES.isParityAdjusted(kb, offset) + && DES.isParityAdjusted(kb, offset + 8) + && DES.isParityAdjusted(kb, offset + 16); + } + + // Methods implementing BaseCipher. + // ----------------------------------------------------------------------- + + public Object clone() + { + return new TripleDES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(new Integer(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + return Collections.singleton(new Integer(KEY_SIZE)).iterator(); + } + + public Object makeKey(byte[] kb, int bs) throws InvalidKeyException + { + if (kb.length != KEY_SIZE) + throw new InvalidKeyException("TripleDES key must be 24 bytes"); + + if (!isParityAdjusted(kb, 0)) + adjustParity(kb, 0); + + byte[] k1 = new byte[DES.KEY_SIZE], k2 = new byte[DES.KEY_SIZE], k3 = new byte[DES.KEY_SIZE]; + System.arraycopy(kb, 0, k1, 0, DES.KEY_SIZE); + System.arraycopy(kb, DES.KEY_SIZE, k2, 0, DES.KEY_SIZE); + System.arraycopy(kb, 2 * DES.KEY_SIZE, k3, 0, DES.KEY_SIZE); + Context ctx = new Context(); + + ctx.k1 = (DES.Context) des.makeKey(k1, bs); + ctx.k2 = (DES.Context) des.makeKey(k2, bs); + 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); + } + + // Inner classes. + // ----------------------------------------------------------------------- + + private final class Context + { + DES.Context k1, k2, k3; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Twofish.java b/gnu/javax/crypto/cipher/Twofish.java new file mode 100644 index 000000000..bea7f5d2c --- /dev/null +++ b/gnu/javax/crypto/cipher/Twofish.java @@ -0,0 +1,909 @@ +/* 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.Registry; +import gnu.java.security.util.Util; + +//import java.io.PrintWriter; +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * <p>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> + * + * <p>Twofish is designed by Bruce Schneier, Doug Whiting, John Kelsey, Chris + * Hall, David Wagner and Niels Ferguson.</p> + * + * <p>References:</p> + * + * <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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + // private static final String NAME = "twofish"; + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + // private static final PrintWriter err = new PrintWriter(System.out, true); + // private static void debug(String s) { + // err.println(">>> "+NAME+": "+s); + // } + + // Constants and variables + // ------------------------------------------------------------------------- + + 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 TOTAL_SUBKEYS = ROUND_SUBKEYS + 2*MAX_ROUNDS; + + 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 = 0x169; + 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 code - to intialise the MDS matrix and lookup tables ------------- + + 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 | // fill matrix w/ above elements + 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 (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static Data"); + System.out.println(); + System.out.println("MDS[0][]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(MDS[0][i * 4 + j]) + + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("MDS[1][]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(MDS[1][i * 4 + j]) + + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("MDS[2][]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(MDS[2][i * 4 + j]) + + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("MDS[3][]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(MDS[3][i * 4 + j]) + + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + 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_1(int x) { + // return x; + // } + + 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); + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Twofish() + { + super(Registry.TWOFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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) + { + // int result = 0; + // switch (N%4) { + // case 0: result = b0(x); break; + // case 1: result = b1(x); break; + // case 2: result = b2(x); break; + // case 3: result = b3(x); break; + // } + // return result; + // profiling shows that the code spends too long in this method. + // following constructs seem to improve, albeit marginally, performance + switch (N % 4) + { + case 0: + return x & 0xFF; + case 1: + return (x >>> 8) & 0xFF; + case 2: + return (x >>> 16) & 0xFF; + default: + return x >>> 24; + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Twofish result = new Twofish(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(8)); // 64-bit + al.add(new Integer(16)); // 128-bit + al.add(new Integer(24)); // 192-bit + al.add(new Integer(32)); // 256-bit + + return Collections.unmodifiableList(al).iterator(); + } + + /** + * <p>Expands a user-supplied key material into a session key for a designated + * <i>block size</i>.</p> + * + * @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 (DEBUG && debuglevel > 7) + { + System.out.println("S-box[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(sBox[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(sBox[256 + i * 4 + j]) + + ", "); + } + System.out.println(); + } + System.out.println(); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(sBox[512 + i * 4 + j]) + + ", "); + } + System.out.println(); + } + System.out.println(); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(sBox[768 + i * 4 + j]) + + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("User (odd, even) keys --> S-Box keys:"); + for (i = 0; i < k64Cnt; i++) + { + System.out.println("0x" + Util.toString(k32o[i]) + " 0x" + + Util.toString(k32e[i]) + " --> 0x" + + Util.toString(sBoxKey[k64Cnt - 1 - i])); + } + System.out.println(); + System.out.println("Round keys:"); + for (i = 0; i < ROUND_SUBKEYS + 2 * ROUNDS; i += 2) + { + System.out.println("0x" + Util.toString(subKeys[i]) + " 0x" + + Util.toString(subKeys[i + 1])); + } + System.out.println(); + } + + 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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("CT=" + Util.toString(out, outOffset - 15, 16)); + System.out.println(); + } + } + + 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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("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 (DEBUG && debuglevel > 6) + { + System.out.println("PT=" + Util.toString(out, outOffset - 15, 16)); + System.out.println(); + } + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + { + result = testKat(KAT_KEY, KAT_CT); + } + valid = new Boolean(result); + } + return valid.booleanValue(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/cipher/WeakKeyException.java b/gnu/javax/crypto/cipher/WeakKeyException.java new file mode 100644 index 000000000..4454e0e45 --- /dev/null +++ b/gnu/javax/crypto/cipher/WeakKeyException.java @@ -0,0 +1,71 @@ +/* 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; + +/** + * <p>Checked exception thrown to indicate that a weak key has been generated + * and or specified instead of a valid non-weak value.</p> + */ +public class WeakKeyException extends InvalidKeyException +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public WeakKeyException() + { + super(); + } + + public WeakKeyException(String msg) + { + super(msg); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/GnuCrypto.java b/gnu/javax/crypto/jce/GnuCrypto.java new file mode 100644 index 000000000..276f61ea3 --- /dev/null +++ b/gnu/javax/crypto/jce/GnuCrypto.java @@ -0,0 +1,569 @@ +/* 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; + +/** + * <p>The GNU Crypto implementation of the Java Cryptographic Extension (JCE) + * Provider.</p> + * + * @see java.security.Provider + */ +public final class GnuCrypto extends Provider +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>The <a href="http://www.gnu.org/software/gnu-crypto/">GNU Crypto</a> + * Provider.</p> + */ + 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()); + + // 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()); + + // 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.DiffieHellman", + gnu.javax.crypto.DiffieHellmanImpl.class.getName()); + put("Alg.Alias.KeyAgreement.DH", "DiffieHellman"); + + // 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"); + + return null; + } + }); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns a {@link Set} of names of symmetric key block cipher algorithms + * available from this {@link Provider}.</p> + * + * @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; + } + + /** + * <p>Returns a {@link Set} of names of MAC algorithms available from + * this {@link Provider}.</p> + * + * @return a {@link Set} of MAC names (Strings). + */ + public static final Set getMacNames() + { + return MacFactory.getNames(); + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/javax/crypto/jce/GnuSasl.java b/gnu/javax/crypto/jce/GnuSasl.java new file mode 100644 index 000000000..6ee86ae19 --- /dev/null +++ b/gnu/javax/crypto/jce/GnuSasl.java @@ -0,0 +1,114 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public GnuSasl() + { + super (Registry.GNU_SASL, 2.1, "GNU Crypto 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; + } + }); + } + + /** + * <p>Returns a {@link Set} of names of SASL Client mechanisms available from + * this {@link Provider}.</p> + * + * @return a {@link Set} of SASL Client mechanisms (Strings). + */ + public static final Set getSaslClientMechanismNames() + { + return ClientFactory.getNames(); + } + + /** + * <p>Returns a {@link Set} of names of SASL Server mechanisms available from + * this {@link Provider}.</p> + * + * @return a {@link Set} of SASL Server mechanisms (Strings). + */ + public static final Set getSaslServerMechanismNames() + { + return ServerFactory.getNames(); + } +} diff --git a/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java b/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java new file mode 100644 index 000000000..59231c6c7 --- /dev/null +++ b/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java @@ -0,0 +1,229 @@ +/* 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 +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + protected String macName; + + private static final int DEFAULT_ITERATION_COUNT = 1000; + + private static final int DEFAULT_KEY_LEN = 32; + + // Constructor. + // ------------------------------------------------------------------------ + + protected PBKDF2SecretKeyFactory(String macName) + { + this.macName = macName; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + 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, new Integer(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()); + } + + // Inner classes. + // ------------------------------------------------------------------------ + + 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"); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/AESSpi.java b/gnu/javax/crypto/jce/cipher/AESSpi.java new file mode 100644 index 000000000..ba7466fc3 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/AESSpi.java @@ -0,0 +1,104 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class AESSpi extends CipherAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public AESSpi() + { + super(Registry.AES_CIPHER, 16); + } + + // Methods from CipherAdapter + // ----------------------------------------------------------------------- + + 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/ARCFourSpi.java b/gnu/javax/crypto/jce/cipher/ARCFourSpi.java new file mode 100644 index 000000000..8fc1fe4cb --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/ARCFourSpi.java @@ -0,0 +1,208 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public class ARCFourSpi extends CipherSpi +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + private IRandom keystream; + + // Constructors. + // ----------------------------------------------------------------------- + + public ARCFourSpi() + { + super(); + keystream = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + } + + // Methods implementing CipherSpi. + // ----------------------------------------------------------------------- + + 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/AnubisSpi.java b/gnu/javax/crypto/jce/cipher/AnubisSpi.java new file mode 100644 index 000000000..ac2f596c8 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/AnubisSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class AnubisSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public AnubisSpi() + { + super(Registry.ANUBIS_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/BlowfishSpi.java b/gnu/javax/crypto/jce/cipher/BlowfishSpi.java new file mode 100644 index 000000000..d1a28616d --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/BlowfishSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class BlowfishSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public BlowfishSpi() + { + super(Registry.BLOWFISH_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/Cast5Spi.java b/gnu/javax/crypto/jce/cipher/Cast5Spi.java new file mode 100644 index 000000000..b1d4cf703 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/Cast5Spi.java @@ -0,0 +1,68 @@ +/* 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. + * + * @version Revision: $ + */ +public class Cast5Spi extends CipherAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Cast5Spi() + { + super(Registry.CAST5_CIPHER); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/CipherAdapter.java b/gnu/javax/crypto/jce/cipher/CipherAdapter.java new file mode 100644 index 000000000..9667a67ff --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/CipherAdapter.java @@ -0,0 +1,507 @@ +/* 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.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.cipher.CipherFactory; +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.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; + +/** + * <p>The implementation of a generic {@link Cipher} <i>Adapter</i> class to + * wrap GNU Crypto cipher instances.</p> + * + * <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> + * + * <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.</p> + * + * @version $Revision: 1.1 $ + */ +class CipherAdapter extends CipherSpi +{ + + // Constants and variables. + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Protected constructor to be called by subclasses. The cipher name + * argument should be the appropriate one listed in {@link gnu.crypto.Registry}. + * The basic cipher instance is created, along with an instance of the + * {@link gnu.crypto.mode.ECB} mode and no padding.</p> + * + * @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, new Integer(blockLen)); + } + + /** + * <p>Creates a new cipher adapter with the default block size.</p> + * + * @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, new Integer(blockLen)); + } + + // Instance methods implementing javax.crypto.CipherSpi. + // ------------------------------------------------------------------------- + + 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, new Integer(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() + { + BlockCipherParameterSpec spec = new BlockCipherParameterSpec( + (byte[]) attributes.get(IMode.IV), + cipher.currentBlockSize(), + 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 + { + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + attributes.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + break; + case Cipher.DECRYPT_MODE: + attributes.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + break; + } + if (!key.getFormat().equalsIgnoreCase("RAW")) + { + throw new InvalidKeyException("bad key format " + key.getFormat()); + } + byte[] kb = key.getEncoded(); + if (keyLen == 0) + { + keyLen = kb.length; + } + else if (keyLen < kb.length) + { + 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) + { + byte[] iv = new byte[blockLen]; + random.nextBytes(iv); + attributes.put(IMode.IV, iv); + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(blockLen)); + keyLen = 0; + } + else if (params instanceof BlockCipherParameterSpec) + { + attributes.put( + IBlockCipher.CIPHER_BLOCK_SIZE, + new Integer( + ((BlockCipherParameterSpec) params).getBlockSize())); + attributes.put(IMode.IV, ((BlockCipherParameterSpec) params).getIV()); + keyLen = ((BlockCipherParameterSpec) params).getKeySize(); + blockLen = ((BlockCipherParameterSpec) params).getBlockSize(); + } + else if (params instanceof IvParameterSpec) + { + attributes.put(IMode.IV, ((IvParameterSpec) params).getIV()); + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(blockLen)); + keyLen = 0; + } + engineInit(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 off, int len) + { + final int blockSize = mode.currentBlockSize(); + final int count = (partLen + len) / blockSize; + final byte[] out = new byte[count * blockSize]; + try + { + engineUpdate(input, off, len, 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 + // { + // int blockSize = mode.currentBlockSize(); + // int count = (partLen + inLen) / blockSize; + // if (count * blockSize > out.length - outOff) { + // throw new ShortBufferException(); + // } + // byte[] buf; + // if (partLen > 0 && count > 0) { + // buf = new byte[partLen + inLen]; + // System.arraycopy(partBlock, 0, buf, 0, partLen); + // if (in != null && inLen > 0) { + // System.arraycopy(in, inOff, buf, partLen, inLen); + // } + // partLen = 0; + // inOff = 0; + // } else { + // buf = in; + // } + // for (int i = 0; i < count; i++) { + // mode.update(buf, i * blockSize + inOff, out, i * blockSize + outOff); + // } + // if (inOff + inLen > count * blockSize) { + // partLen = (inOff + inLen) - (count * blockSize); + // System.arraycopy(in, count * blockSize, partBlock, 0, partLen); + // } + // return count * blockSize; + // } + + 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(); + final int blockCount = (partLen + inLen) / blockSize; + 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; + try + { + padLen = pad.unpad(buf, 0, buf.length); + } + catch (WrongPaddingException wpe) + { + throw new BadPaddingException(wpe.getMessage()); + } + result = new byte[buf.length - padLen]; + System.arraycopy(buf, 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/DESSpi.java b/gnu/javax/crypto/jce/cipher/DESSpi.java new file mode 100644 index 000000000..f3ec8220a --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/DESSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class DESSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public DESSpi() + { + super(Registry.DES_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/KhazadSpi.java b/gnu/javax/crypto/jce/cipher/KhazadSpi.java new file mode 100644 index 000000000..7f43dd010 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/KhazadSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class KhazadSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public KhazadSpi() + { + super(Registry.KHAZAD_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/NullCipherSpi.java b/gnu/javax/crypto/jce/cipher/NullCipherSpi.java new file mode 100644 index 000000000..0876c9585 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/NullCipherSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class NullCipherSpi extends CipherAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public NullCipherSpi() + { + super(Registry.NULL_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/PBES2.java b/gnu/javax/crypto/jce/cipher/PBES2.java new file mode 100644 index 000000000..28b327d83 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/PBES2.java @@ -0,0 +1,1352 @@ +/* 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; + +/** + * <p>.</p> + * + * @version $Revision: 1.1 $ + */ +public abstract class PBES2 extends CipherAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The HMac (PRF) algorithm name. */ + protected String macName; + + // Constructor(s) + // ------------------------------------------------------------------------- + + 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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + 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, new Integer(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(shouldNotHappen); + throw new Error(String.valueOf(shouldNotHappen)); + } + return new SecretKeySpec(dk, cipher.name()); + } + + // Inner classe(s) + // ========================================================================= + + public static class HMacSHA1 extends PBES2 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacSHA1(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA1"); + } + + public HMacSHA1(String cipher) + { + super(cipher, "HMAC-SHA1"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacMD5(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD5"); + } + + public HMacMD5(String cipher) + { + super(cipher, "HMAC-MD5"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacMD2(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD2"); + } + + public HMacMD2(String cipher) + { + super(cipher, "HMAC-MD2"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacMD4(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD4"); + } + + public HMacMD4(String cipher) + { + super(cipher, "HMAC-MD4"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacHaval(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-HAVAL"); + } + + public HMacHaval(String cipher) + { + super(cipher, "HMAC-HAVAL"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacRipeMD128(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD128"); + } + + public HMacRipeMD128(String cipher) + { + super(cipher, "HMAC-RIPEMD128"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacRipeMD160(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD160"); + } + + public HMacRipeMD160(String cipher) + { + super(cipher, "HMAC-RIPEMD160"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacSHA256(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-256"); + } + + public HMacSHA256(String cipher) + { + super(cipher, "HMAC-SHA-256"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacSHA384(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-384"); + } + + public HMacSHA384(String cipher) + { + super(cipher, "HMAC-SHA-384"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacSHA512(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-512"); + } + + public HMacSHA512(String cipher) + { + super(cipher, "HMAC-SHA-512"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacTiger(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-TIGER"); + } + + public HMacTiger(String cipher) + { + super(cipher, "HMAC-TIGER"); + } + + // Inner classe(s) + // ====================================================================== + + 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 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacWhirlpool(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-WHIRLPOOL"); + } + + public HMacWhirlpool(String cipher) + { + super(cipher, "HMAC-WHIRLPOOL"); + } + + // Inner classe(s) + // ====================================================================== + + 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"); + } + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/RijndaelSpi.java b/gnu/javax/crypto/jce/cipher/RijndaelSpi.java new file mode 100644 index 000000000..1a67f934b --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/RijndaelSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class RijndaelSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public RijndaelSpi() + { + super(Registry.RIJNDAEL_CIPHER, 16); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/SerpentSpi.java b/gnu/javax/crypto/jce/cipher/SerpentSpi.java new file mode 100644 index 000000000..394a0ce0a --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/SerpentSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class SerpentSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public SerpentSpi() + { + super(Registry.SERPENT_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/SquareSpi.java b/gnu/javax/crypto/jce/cipher/SquareSpi.java new file mode 100644 index 000000000..bb59cd224 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/SquareSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class SquareSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public SquareSpi() + { + super(Registry.SQUARE_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/TripleDESSpi.java b/gnu/javax/crypto/jce/cipher/TripleDESSpi.java new file mode 100644 index 000000000..cec30f653 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/TripleDESSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class TripleDESSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public TripleDESSpi() + { + super(Registry.TRIPLEDES_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/TwofishSpi.java b/gnu/javax/crypto/jce/cipher/TwofishSpi.java new file mode 100644 index 000000000..34f2d95d6 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/TwofishSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class TwofishSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public TwofishSpi() + { + super(Registry.TWOFISH_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java new file mode 100644 index 000000000..e8d7788e8 --- /dev/null +++ b/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public AnubisKeyGeneratorImpl () + { + super (Registry.ANUBIS_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f9725eae0 --- /dev/null +++ b/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java @@ -0,0 +1,53 @@ +/* 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; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class AnubisSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public AnubisSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java new file mode 100644 index 000000000..a0e687acd --- /dev/null +++ b/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public BlowfishKeyGeneratorImpl () + { + super (Registry.BLOWFISH_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..4b3620bc1 --- /dev/null +++ b/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java @@ -0,0 +1,53 @@ +/* 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; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class BlowfishSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public BlowfishSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java new file mode 100644 index 000000000..18d26e67f --- /dev/null +++ b/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public Cast5KeyGeneratorImpl () + { + super (Registry.CAST5_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java new file mode 100644 index 000000000..4bd31711e --- /dev/null +++ b/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java @@ -0,0 +1,53 @@ +/* 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; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class Cast5SecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public Cast5SecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java new file mode 100644 index 000000000..19c54653a --- /dev/null +++ b/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java @@ -0,0 +1,73 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public DESKeyGeneratorImpl () + { + super (Registry.DES_CIPHER); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + 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); + } +} diff --git a/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java new file mode 100644 index 000000000..e0f1c5860 --- /dev/null +++ b/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java @@ -0,0 +1,80 @@ +/* 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); + } +} diff --git a/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java new file mode 100644 index 000000000..15e109940 --- /dev/null +++ b/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java @@ -0,0 +1,80 @@ +/* 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); + } +} diff --git a/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java new file mode 100644 index 000000000..c01391e44 --- /dev/null +++ b/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public KhazadKeyGeneratorImpl () + { + super (Registry.KHAZAD_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java new file mode 100644 index 000000000..c86e01110 --- /dev/null +++ b/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* 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; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class KhazadSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public KhazadSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java new file mode 100644 index 000000000..535e573ad --- /dev/null +++ b/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public RijndaelKeyGeneratorImpl () + { + super (Registry.RIJNDAEL_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java new file mode 100644 index 000000000..4aab584a2 --- /dev/null +++ b/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* 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; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class RijndaelSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public RijndaelSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java new file mode 100644 index 000000000..72defe1d7 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java @@ -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()); + } +} diff --git a/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java new file mode 100644 index 000000000..0a6265573 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java @@ -0,0 +1,120 @@ +/* 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 +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected final int defaultKeySize; + protected final List keySizes; + protected final String algorithm; + protected boolean init; + protected int currentKeySize; + protected SecureRandom random; + + // Constructors. + // ------------------------------------------------------------------------- + + 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; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + 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 (new Integer (keySize))) + throw new InvalidParameterException ("unsupported key size: " + keySize); + currentKeySize = keySize; + this.random = random; + init = true; + } + + protected void engineInit (SecureRandom random) + { + engineInit (defaultKeySize << 3, random); + } +} diff --git a/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java new file mode 100644 index 000000000..766860a96 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public SerpentKeyGeneratorImpl () + { + super (Registry.SERPENT_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java new file mode 100644 index 000000000..6e80671fa --- /dev/null +++ b/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* 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; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class SerpentSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public SerpentSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java new file mode 100644 index 000000000..4bfbeb668 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public SquareKeyGeneratorImpl () + { + super (Registry.SQUARE_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java new file mode 100644 index 000000000..d1d5d5514 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* 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; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class SquareSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public SquareSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java new file mode 100644 index 000000000..eb423fcd1 --- /dev/null +++ b/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public TripleDESKeyGeneratorImpl () + { + super (Registry.TRIPLEDES_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java new file mode 100644 index 000000000..ae7e22fee --- /dev/null +++ b/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public TwofishKeyGeneratorImpl () + { + super (Registry.TWOFISH_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..e6ca80b63 --- /dev/null +++ b/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* 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; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class TwofishSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public TwofishSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/keyring/GnuKeyring.java b/gnu/javax/crypto/jce/keyring/GnuKeyring.java new file mode 100644 index 000000000..d74d386b4 --- /dev/null +++ b/gnu/javax/crypto/jce/keyring/GnuKeyring.java @@ -0,0 +1,413 @@ +/* GnuKeyring.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.keyring; + +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.security.Key; +import java.security.KeyStoreSpi; +import java.security.KeyStoreException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +import java.util.Arrays; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import javax.crypto.SecretKey; + +import gnu.java.security.Registry; +import gnu.javax.crypto.keyring.IKeyring; +import gnu.javax.crypto.keyring.IPrivateKeyring; +import gnu.javax.crypto.keyring.IPublicKeyring; +import gnu.javax.crypto.keyring.GnuPrivateKeyring; +import gnu.javax.crypto.keyring.GnuPublicKeyring; +import gnu.javax.crypto.keyring.MalformedKeyringException; +import gnu.javax.crypto.keyring.PrimitiveEntry; + +public class GnuKeyring extends KeyStoreSpi +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + private boolean loaded; + + private IKeyring keyring; + + // Constructor. + // ------------------------------------------------------------------------ + + public GnuKeyring() + { + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public Enumeration engineAliases() + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return new Enumeration() + { + public boolean hasMoreElements() + { + return false; + } + + public Object nextElement() + { + throw new NoSuchElementException(); + } + }; + } + return keyring.aliases(); + } + + public boolean engineContainsAlias(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return false; + } + return keyring.containsAlias(alias); + } + + public void engineDeleteEntry(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring != null) + { + keyring.remove(alias); + } + } + + public Certificate engineGetCertificate(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + if (!(keyring instanceof IPublicKeyring)) + { + throw new IllegalStateException("not a public keyring"); + } + return ((IPublicKeyring) keyring).getCertificate(alias); + } + + public String engineGetCertificateAlias(Certificate cert) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + if (!(keyring instanceof IPublicKeyring)) + { + throw new IllegalStateException("not a public keyring"); + } + Enumeration aliases = keyring.aliases(); + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + Certificate cert2 = ((IPublicKeyring) keyring).getCertificate(alias); + if (cert.equals(cert2)) + { + return alias; + } + } + return null; + } + + public void engineSetCertificateEntry(String alias, Certificate cert) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + keyring = new GnuPublicKeyring("HMAC-SHA-1", 20); + } + if (!(keyring instanceof IPublicKeyring)) + { + throw new IllegalStateException("not a public keyring"); + } + ((IPublicKeyring) keyring).putCertificate(alias, cert); + } + + public Certificate[] engineGetCertificateChain(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + if (!(keyring instanceof IPrivateKeyring)) + { + throw new IllegalStateException("not a private keyring"); + } + return ((IPrivateKeyring) keyring).getCertPath(alias); + } + + public Date engineGetCreationDate(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + List entries = keyring.get(alias); + if (entries.size() == 0) + { + return null; + } + for (Iterator it = entries.iterator(); it.hasNext();) + { + Object o = it.next(); + if (o instanceof PrimitiveEntry) + { + return ((PrimitiveEntry) o).getCreationDate(); + } + } + return null; + } + + public Key engineGetKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + if (!(keyring instanceof IPrivateKeyring)) + { + throw new IllegalStateException("not a private keyring"); + } + if (password == null) + { + if (((IPrivateKeyring) keyring).containsPublicKey(alias)) + { + return ((IPrivateKeyring) keyring).getPublicKey(alias); + } + } + if (((IPrivateKeyring) keyring).containsPrivateKey(alias)) + { + return ((IPrivateKeyring) keyring).getPrivateKey(alias, password); + } + return null; + } + + public void engineSetKeyEntry(String alias, Key key, char[] password, + Certificate[] chain) throws KeyStoreException + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + keyring = new GnuPrivateKeyring("HMAC-SHA-1", 20, "AES", "OFB", 16); + } + if (!(keyring instanceof IPrivateKeyring)) + { + throw new IllegalStateException("not a private keyring"); + } + if (key instanceof PublicKey) + { + ((IPrivateKeyring) keyring).putPublicKey(alias, (PublicKey) key); + return; + } + if (!(key instanceof PrivateKey) && !(key instanceof SecretKey)) + { + throw new KeyStoreException("cannot store keys of type " + + key.getClass().getName()); + } + try + { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + ((IPrivateKeyring) keyring).putCertPath(alias, chain); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce.toString()); + } + ((IPrivateKeyring) keyring).putPrivateKey(alias, key, password); + } + + public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) + throws KeyStoreException + { + throw new KeyStoreException("method not supported"); + } + + public boolean engineIsCertificateEntry(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return false; + } + if (!(keyring instanceof IPublicKeyring)) + { + return false; + } + return ((IPublicKeyring) keyring).containsCertificate(alias); + } + + public boolean engineIsKeyEntry(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return false; + } + if (!(keyring instanceof IPrivateKeyring)) + { + return false; + } + return ((IPrivateKeyring) keyring).containsPublicKey(alias) + || ((IPrivateKeyring) keyring).containsPrivateKey(alias); + } + + public void engineLoad(InputStream in, char[] password) throws IOException + { + if (in != null) + { + if (!in.markSupported()) + { + in = new BufferedInputStream(in); + } + 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(); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_IN, in); + attr.put(IKeyring.KEYRING_PASSWORD, password); + switch (usage) + { + case GnuPublicKeyring.USAGE: + keyring = new GnuPublicKeyring(); + break; + case GnuPrivateKeyring.USAGE: + keyring = new GnuPrivateKeyring(); + break; + default: + throw new MalformedKeyringException("unsupported ring usage: " + + Integer.toBinaryString(usage)); + } + keyring.load(attr); + } + loaded = true; + } + + public void engineStore(OutputStream out, char[] password) throws IOException + { + if (!loaded || keyring == null) + { + throw new IllegalStateException ("not loaded"); + } + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_OUT, out); + attr.put(IKeyring.KEYRING_PASSWORD, password); + keyring.store(attr); + } + + public int engineSize() + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return 0; + } + return keyring.size(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacHavalSpi.java b/gnu/javax/crypto/jce/mac/HMacHavalSpi.java new file mode 100644 index 000000000..df1319cbf --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacHavalSpi.java @@ -0,0 +1,67 @@ +/* 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. + * + * @version Revision: $ + */ +public class HMacHavalSpi extends MacAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public HMacHavalSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.HAVAL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacMD2Spi.java b/gnu/javax/crypto/jce/mac/HMacMD2Spi.java new file mode 100644 index 000000000..935f5e5a3 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacMD2Spi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class HMacMD2Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacMD2Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD2_HASH); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacMD4Spi.java b/gnu/javax/crypto/jce/mac/HMacMD4Spi.java new file mode 100644 index 000000000..49507a6dd --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacMD4Spi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class HMacMD4Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacMD4Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD4_HASH); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacMD5Spi.java b/gnu/javax/crypto/jce/mac/HMacMD5Spi.java new file mode 100644 index 000000000..3bc0fea6b --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacMD5Spi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class HMacMD5Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacMD5Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD5_HASH); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java b/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java new file mode 100644 index 000000000..6a57e6c9d --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class HMacRipeMD128Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacRipeMD128Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD128_HASH); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java b/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java new file mode 100644 index 000000000..a47e1a5c7 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class HMacRipeMD160Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacRipeMD160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD160_HASH); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java b/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java new file mode 100644 index 000000000..e251dc373 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class HMacSHA160Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacSHA160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA160_HASH); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java b/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java new file mode 100644 index 000000000..7caa26041 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java @@ -0,0 +1,67 @@ +/* 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; + +/** + * <p>The implementation of the HMAC-SHA-256 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter.</p> + * + * @version $Revision: 1.1 $ + */ +public final class HMacSHA256Spi extends MacAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ----------------------------------------------------------------------- + + public HMacSHA256Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA256_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java b/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java new file mode 100644 index 000000000..d3e454b54 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java @@ -0,0 +1,67 @@ +/* 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; + +/** + * <p>The implementation of the HMAC-SHA-384 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter.</p> + * + * @version $Revision: 1.1 $ + */ +public class HMacSHA384Spi extends MacAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ----------------------------------------------------------------------- + + public HMacSHA384Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA384_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java b/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java new file mode 100644 index 000000000..f02267c84 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java @@ -0,0 +1,67 @@ +/* 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; + +/** + * <p>The implementation of the HMAC-SHA-512 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter.</p> + * + * @version $Revision: 1.1 $ + */ +public class HMacSHA512Spi extends MacAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ----------------------------------------------------------------------- + + public HMacSHA512Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA512_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacTigerSpi.java b/gnu/javax/crypto/jce/mac/HMacTigerSpi.java new file mode 100644 index 000000000..e4eb26ca9 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacTigerSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class HMacTigerSpi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacTigerSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.TIGER_HASH); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java b/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java new file mode 100644 index 000000000..8e2ef6d2f --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class HMacWhirlpoolSpi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacWhirlpoolSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.WHIRLPOOL_HASH); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/MacAdapter.java b/gnu/javax/crypto/jce/mac/MacAdapter.java new file mode 100644 index 000000000..86cc29c30 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/MacAdapter.java @@ -0,0 +1,142 @@ +/* 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; + +/** + * <p>The implementation of a generic {@link javax.crypto.Mac} adapter class + * to wrap GNU Crypto MAC instances.</p> + * + * <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.</p> + * + * @version $Revision: 1.1 $ + */ +class MacAdapter extends MacSpi implements Cloneable +{ + + // Constants and variables + // ----------------------------------------------------------------------- + + /** Our MAC instance. */ + protected IMac mac; + + /** Our MAC attributes. */ + protected Map attributes; + + // Constructor(s) + // ----------------------------------------------------------------------- + + /** + * <p>Creates a new Mac instance for the given name.</p> + * + * @param name The name of the mac to create. + */ + protected MacAdapter(String name) + { + mac = MacFactory.getInstance(name); + attributes = new HashMap(); + } + + // Class methods + // ----------------------------------------------------------------------- + + // Instance methods + // ----------------------------------------------------------------------- + + // Cloneable interface implementation ------------------------------------ + + public Object clone() throws CloneNotSupportedException + { + return super.clone(); + } + + // Instance methods implementing javax.crypto.MacSpi --------------------- + + 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java b/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java new file mode 100644 index 000000000..4bfda4fd6 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacAnubisImpl() + { + super(Registry.OMAC_PREFIX + Registry.ANUBIS_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java b/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java new file mode 100644 index 000000000..8d168e57b --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacBlowfishImpl() + { + super(Registry.OMAC_PREFIX + Registry.BLOWFISH_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacCast5Impl.java b/gnu/javax/crypto/jce/mac/OMacCast5Impl.java new file mode 100644 index 000000000..3385d116b --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacCast5Impl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacCast5Impl() + { + super(Registry.OMAC_PREFIX + Registry.CAST5_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacDESImpl.java b/gnu/javax/crypto/jce/mac/OMacDESImpl.java new file mode 100644 index 000000000..3fb23bdef --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacDESImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.DES_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacImpl.java b/gnu/javax/crypto/jce/mac/OMacImpl.java new file mode 100644 index 000000000..f91902ae5 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacImpl.java @@ -0,0 +1,137 @@ +/* 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; +import javax.crypto.MacSpi; + +public abstract class OMacImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + protected OMacImpl(String name) + { + super(Registry.OMAC_PREFIX + name); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + 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); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java b/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java new file mode 100644 index 000000000..82c047c25 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacKhazadImpl() + { + super(Registry.OMAC_PREFIX + Registry.KHAZAD_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java b/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java new file mode 100644 index 000000000..47d3f6aae --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacRijndaelImpl() + { + super(Registry.OMAC_PREFIX + Registry.RIJNDAEL_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java b/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java new file mode 100644 index 000000000..bec2c1f5c --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacSerpentImpl() + { + super(Registry.OMAC_PREFIX + Registry.SERPENT_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacSquareImpl.java b/gnu/javax/crypto/jce/mac/OMacSquareImpl.java new file mode 100644 index 000000000..0442b7caf --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacSquareImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacSquareImpl() + { + super(Registry.OMAC_PREFIX + Registry.SQUARE_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java b/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java new file mode 100644 index 000000000..0defdd1fd --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacTripleDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.TRIPLEDES_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java b/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java new file mode 100644 index 000000000..a12f9f30e --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java @@ -0,0 +1,53 @@ +/* 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 +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacTwofishImpl() + { + super(Registry.OMAC_PREFIX + Registry.TWOFISH_CIPHER); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/TMMH16Spi.java b/gnu/javax/crypto/jce/mac/TMMH16Spi.java new file mode 100644 index 000000000..0a4222237 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/TMMH16Spi.java @@ -0,0 +1,91 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class TMMH16Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public TMMH16Spi() + { + super(Registry.TMMH16); + } + + // Instance methods overriding MacAdapter. + // ----------------------------------------------------------------------- + + 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()); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/UHash32Spi.java b/gnu/javax/crypto/jce/mac/UHash32Spi.java new file mode 100644 index 000000000..a24b8e59c --- /dev/null +++ b/gnu/javax/crypto/jce/mac/UHash32Spi.java @@ -0,0 +1,59 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class UHash32Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public UHash32Spi() + { + super(Registry.UHASH32); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/UMac32Spi.java b/gnu/javax/crypto/jce/mac/UMac32Spi.java new file mode 100644 index 000000000..52c58f36f --- /dev/null +++ b/gnu/javax/crypto/jce/mac/UMac32Spi.java @@ -0,0 +1,91 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public final class UMac32Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public UMac32Spi() + { + super(Registry.UMAC32); + } + + // Instance methods overriding MacAdapter. + // ----------------------------------------------------------------------- + + 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()); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/params/BlockCipherParameters.java b/gnu/javax/crypto/jce/params/BlockCipherParameters.java new file mode 100644 index 000000000..bae7cbf88 --- /dev/null +++ b/gnu/javax/crypto/jce/params/BlockCipherParameters.java @@ -0,0 +1,209 @@ +/* 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.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; + +/** + * An implementation of algorithm parameters for the GNU Crypto block + * ciphers. This encompasses the cipher's block size, its key size, and + * an optional initialization vector (IV). + */ +public class BlockCipherParameters extends AlgorithmParametersSpi +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** + * The underlying block cipher specification. + */ + protected BlockCipherParameterSpec cipherSpec; + + private static final String DEFAULT_FORMAT = "ASN.1"; + + // Instance methods implementing AlgorithmParametersSpi. + // ----------------------------------------------------------------------- + + /** + * Return these parameters encoded in ASN.1 (DER). + * + * <p>For GNU Crypto block ciphers we will define these parameters as + * + * <blockquote> + * <pre>BlockCipherParameters ::= SEQUENCE { + * blockSize INTEGER, + * keySize INTEGER, + * initializationVector OCTET STRING OPTIONAL }</pre> + * </blockquote> + * + * @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 + "\""); + } + // This is probably a bad idea. + /* + int len = 12 + ((cipherSpec.getIV() != null) + ? cipherSpec.getIV().length + 2 : 0); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x30); + out.write(len); + out.write(0x02); + out.write(4); + out.write(cipherSpec.getBlockSize() >>> 24 & 0xff); + out.write(cipherSpec.getBlockSize() >>> 16 & 0xff); + out.write(cipherSpec.getBlockSize() >>> 8 & 0xff); + out.write(cipherSpec.getBlockSize() & 0xff); + out.write(0x02); + out.write(4); + out.write(cipherSpec.getKeySize() >>> 24 & 0xff); + out.write(cipherSpec.getKeySize() >>> 16 & 0xff); + out.write(cipherSpec.getKeySize() >>> 8 & 0xff); + out.write(cipherSpec.getKeySize() & 0xff); + if (cipherSpec.getIV() != null) { + out.write(0x04); + len = cipherSpec.getIV().length; + out.write(len & 0xff); + out.write(cipherSpec.getIV()); + } + out.write(0); out.write(0); + return out.toByteArray();*/ + DERWriter writer = new DERWriter(); + return writer.joinarrays( + writer.writeBigInteger(BigInteger.valueOf(cipherSpec.getBlockSize())), + writer.writeBigInteger(BigInteger.valueOf(cipherSpec.getKeySize())), + (cipherSpec.getIV() != null) ? writer.writeBigInteger(new BigInteger( + cipherSpec.getIV())) + : 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 + { + // This is probably an equally bad idea. + /*if (encoded[0] != 0x30) { + throw new IOException("malformed ASN.1 sequence"); + } + if (encoded[2] != 0x02 || encoded[3] != 4) { + throw new IOException("malformed ASN.1 sequence"); + } + int blockSize = encoded[4] << 24 | encoded[5] << 16 + | encoded[6] << 8 | encoded[7]; + if (encoded[8] != 0x02 || encoded[9] != 4) { + throw new IOException("malformed ASN.1 sequence"); + } + int keySize = encoded[10] << 24 | encoded[11] << 16 + | encoded[12] << 8 | encoded[13]; + if (encoded[14] == 0x04) { + int len = encoded[15] & 0xff; + byte[] iv = new byte[len]; + System.arraycopy(encoded, 16, iv, 0, len); + cipherSpec = new BlockCipherParameterSpec(iv, blockSize, keySize); + } else if (encoded[14] == 0) { + cipherSpec = new BlockCipherParameterSpec(blockSize, keySize); + } else { + throw new IOException("malformed ASN.1 sequence"); + }*/ + 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); + System.out.println(cipherSpec); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class c) + throws InvalidParameterSpecException + { + if (c.isInstance(cipherSpec)) + { + return cipherSpec; + } + throw new InvalidParameterSpecException(); + } + + protected String engineToString() + { + return cipherSpec.toString(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/params/DEREncodingException.java b/gnu/javax/crypto/jce/params/DEREncodingException.java new file mode 100644 index 000000000..ddfa6e1de --- /dev/null +++ b/gnu/javax/crypto/jce/params/DEREncodingException.java @@ -0,0 +1,53 @@ +/* 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/params/DERReader.java b/gnu/javax/crypto/jce/params/DERReader.java new file mode 100644 index 000000000..f61423255 --- /dev/null +++ b/gnu/javax/crypto/jce/params/DERReader.java @@ -0,0 +1,160 @@ +/* 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); + //System.out.println("Type: " + type); + + //get tag + int tag = (0x1f & identifier); + //if( tag == 0x1f) + // tag = getIdentifier(tmp); + //System.out.println("Tag: " + tag); + + //get length + byte len = source[tmp]; //may be length of length parameter + long length = 0x7f & len; + int i; + if ((0x80 & len) != 0) + { + //System.out.println("Extra Long Length"); + len &= 0x7f; + //System.out.println("Length of Length: " + len); + //get length here + length = 0; + for (i = 0; i < len; i++) + { + tmp++; + length <<= 8; + length += (source[tmp] < 0) ? (256 + source[tmp]) : source[tmp]; + //System.out.println("Length of Length: " + length); + } + tmp++; + } + else + tmp++; + + /*System.out.println("Position: " + tmp); + System.out.println("Length: " + length); + for( i = 0; i < 10; i++) + System.out.print(source[tmp + i] + " "); + System.out.println();*/ + + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/params/DERWriter.java b/gnu/javax/crypto/jce/params/DERWriter.java new file mode 100644 index 000000000..876c2cd6c --- /dev/null +++ b/gnu/javax/crypto/jce/params/DERWriter.java @@ -0,0 +1,154 @@ +/* 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; + //System.out.println("Identifier1: " + b[0]); + return b; + } + else + { + b = new byte[1]; + b[0] = (byte) ((translateLeadIdentifierByte(identifierencoding) | (byte) (identifier & 0x1f)) & 0xdf); + //System.out.println("Identifier2: " + b[0]); + 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)); + //System.out.println("Length byte count: " + count); + 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))); + //System.out.println("Length1 byte1: " + (length >>> (8 * ( count - i) ))); + //System.out.println("Length1 byte2: " + b[i]); + } + + //System.out.println("Length1: " + length); + return b; + } + else + { + b = new byte[1]; + b[0] = (byte) (length & 0x7f); + //System.out.println("Length2: " + length); + return b; + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java b/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java new file mode 100644 index 000000000..0c071561b --- /dev/null +++ b/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java @@ -0,0 +1,120 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying prng instance. */ + private IRandom adaptee; + + /** Have we been initialized? */ + private boolean virgin; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Default 0-arguments constructor. + */ + public ARCFourRandomSpi() + { + super(); + adaptee = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + virgin = true; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.SecureRandomSpi interface implementation ------------------ + + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/CSPRNGSpi.java b/gnu/javax/crypto/jce/prng/CSPRNGSpi.java new file mode 100644 index 000000000..c0aa015b0 --- /dev/null +++ b/gnu/javax/crypto/jce/prng/CSPRNGSpi.java @@ -0,0 +1,114 @@ +/* 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.Registry; +import gnu.javax.crypto.prng.CSPRNG; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +import java.net.MalformedURLException; +import java.security.SecureRandomSpi; + +/** + * The implementation of the continuously-seeded SecureRandom + * <i>Service Provider Interface</i> (<b>SPI</b>) adapter.<p> + */ +public class CSPRNGSpi extends SecureRandomSpi +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private final IRandom adaptee; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public CSPRNGSpi() throws ClassNotFoundException, MalformedURLException, + NumberFormatException + { + super(); + + adaptee = CSPRNG.getSystemInstance(); + } + + // Instance methods + // ------------------------------------------------------------------------- + + 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/FortunaImpl.java b/gnu/javax/crypto/jce/prng/FortunaImpl.java new file mode 100644 index 000000000..7006bbbad --- /dev/null +++ b/gnu/javax/crypto/jce/prng/FortunaImpl.java @@ -0,0 +1,85 @@ +/* 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/ICMRandomSpi.java b/gnu/javax/crypto/jce/prng/ICMRandomSpi.java new file mode 100644 index 000000000..d04b782f9 --- /dev/null +++ b/gnu/javax/crypto/jce/prng/ICMRandomSpi.java @@ -0,0 +1,260 @@ +/* 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.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.ICMGenerator; +import gnu.java.security.prng.LimitReachedException; + +import java.io.PrintWriter; +import java.math.BigInteger; +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; + +/** + * <p>An <em>Adapter</em> class around {@link ICMGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}.</p> + */ +public class ICMRandomSpi extends SecureRandomSpi +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "ICMRandomSpi"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 0; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + private static void resetLocalPRNG() + { + if (DEBUG && debuglevel > 8) + debug(">>> 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, new Integer(ndxLen)); + byte[] index = new byte[ndxLen]; + rand.nextBytes(index); + attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); + + prng.setup(attributes); + if (DEBUG && debuglevel > 8) + debug("<<< resetLocalPRNG()"); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.SecureRandomSpi interface implementation ------------------ + + public byte[] engineGenerateSeed(int numBytes) + { + if (DEBUG && debuglevel > 8) + debug(">>> engineGenerateSeed()"); + if (numBytes < 1) + { + if (DEBUG && debuglevel > 8) + debug("<<< engineGenerateSeed()"); + return new byte[0]; + } + byte[] result = new byte[numBytes]; + this.engineNextBytes(result); + if (DEBUG && debuglevel > 8) + debug("<<< engineGenerateSeed()"); + return result; + } + + public void engineNextBytes(byte[] bytes) + { + if (DEBUG && debuglevel > 8) + debug(">>> 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 (DEBUG) + { + debug(LIMIT_REACHED_MSG + String.valueOf(x)); + x.printStackTrace(err); + debug(RESEED); + } + resetLocalPRNG(); + } + } + if (DEBUG && debuglevel > 8) + debug("<<< engineNextBytes()"); + } + + public void engineSetSeed(byte[] seed) + { + if (DEBUG && debuglevel > 8) + debug(">>> 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 (DEBUG) + { + debug(MSG + String.valueOf(x)); + debug(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, new Integer(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 (DEBUG && debuglevel > 8) + debug("<<< engineSetSeed()"); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/UMacRandomSpi.java b/gnu/javax/crypto/jce/prng/UMacRandomSpi.java new file mode 100644 index 000000000..7dad68b2f --- /dev/null +++ b/gnu/javax/crypto/jce/prng/UMacRandomSpi.java @@ -0,0 +1,207 @@ +/* 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.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.io.PrintWriter; +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; + +/** + * <p>An <em>Adapter</em> class around {@link UMacGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}.</p> + */ +public class UMacRandomSpi extends SecureRandomSpi +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "UMacRandomSpi"; + + private static final boolean DEBUG = false; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + 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, new Integer(index)); + + prng.setup(attributes); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.SecureRandomSpi interface implementation ------------------ + + 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 (DEBUG) + { + debug(MSG + String.valueOf(x)); + debug(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, new Integer(material[16] & 0xFF)); + + adaptee.init(attributes); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java b/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java new file mode 100644 index 000000000..63e7740ec --- /dev/null +++ b/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java @@ -0,0 +1,139 @@ +/* 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 Crypto are the cipher's name, its block + * and key sizes, and an optional initialization vector. + */ +public class BlockCipherParameterSpec implements AlgorithmParameterSpec +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** + * 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; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * 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); + } + + // Instance methods. + // ----------------------------------------------------------------------- + + /** + * 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 + " }"; + } +} diff --git a/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java b/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java new file mode 100644 index 000000000..0ebec0991 --- /dev/null +++ b/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java @@ -0,0 +1,129 @@ +/* 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.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 +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** The keystream. */ + protected IRandom keystream; + + /** The tag length. */ + protected Integer tagLength; + + /** The prefix. */ + protected byte[] prefix; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * 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); + } + + // Instance methods. + // ----------------------------------------------------------------------- + + /** + * 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java b/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java new file mode 100644 index 000000000..47d807d49 --- /dev/null +++ b/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java @@ -0,0 +1,82 @@ +/* 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 +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** The <i>Nonce</i> material. */ + protected byte[] nonce; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * Create a new parameter instance. + * + * @param nonce The nonce material. + */ + public UMac32ParameterSpec(byte[] nonce) + { + this.nonce = nonce; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + /** + * Return the nonce material. + * + * @return The nonce material. + */ + public byte[] getNonce() + { + return nonce; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/key/BaseKeyAgreementParty.java b/gnu/javax/crypto/key/BaseKeyAgreementParty.java new file mode 100644 index 000000000..5aba47448 --- /dev/null +++ b/gnu/javax/crypto/key/BaseKeyAgreementParty.java @@ -0,0 +1,198 @@ +/* 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 java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +/** + * <p>A base abstract class to facilitate implementations of concrete key + * agreement protocol handlers.</p> + */ +public abstract class BaseKeyAgreementParty implements IKeyAgreementParty +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected BaseKeyAgreementParty(String name) + { + super(); + + this.name = name; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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; + } + } + + // abstract methods to be implemented by concrete subclasses --------------- + + 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(); + + // helper methods ---------------------------------------------------------- + + /** + * 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; + new SecureRandom ().nextBytes(buffer); + } + } + else + { + new SecureRandom ().nextBytes(buffer); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/key/GnuSecretKey.java b/gnu/javax/crypto/key/GnuSecretKey.java new file mode 100644 index 000000000..93b21a67c --- /dev/null +++ b/gnu/javax/crypto/key/GnuSecretKey.java @@ -0,0 +1,149 @@ +/* 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 +{ + + // Field. + // ------------------------------------------------------------------------ + + private final byte[] key; + + private final String algorithm; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * 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; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * 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) + " ]"; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/key/IKeyAgreementParty.java b/gnu/javax/crypto/key/IKeyAgreementParty.java new file mode 100644 index 000000000..05aef5e51 --- /dev/null +++ b/gnu/javax/crypto/key/IKeyAgreementParty.java @@ -0,0 +1,105 @@ +/* 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; + +/** + * <p>The visible methods of an key agreement protocol participating party.</p> + */ +public interface IKeyAgreementParty +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the canonical name of the key agreement protocol.</p> + * + * @return the canonical name of the key agreement protocol. + */ + String name(); + + /** + * <p>Sets up the instance to operate with specific attributes.</p> + * + * @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; + + /** + * <p>Processes an incoming message at one end, generating a message that + * will be processed by the other party(ies).</p> + * + * @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; + + /** + * <p>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(); + + /** + * <p>Returns the byte array containing the shared secret as generated by + * this party.</p> + * + * @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(); +}
\ No newline at end of file diff --git a/gnu/javax/crypto/key/IncomingMessage.java b/gnu/javax/crypto/key/IncomingMessage.java new file mode 100644 index 000000000..721b0faed --- /dev/null +++ b/gnu/javax/crypto/key/IncomingMessage.java @@ -0,0 +1,293 @@ +/* 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.KeyPairCodecFactory; + +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * <p>An implementation of an incoming message for use with key agreement + * protocols.</p> + */ +public class IncomingMessage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Constructs an incoming message given the message's encoded form, + * including its header bytes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a message given its encoded contents, excluding + * the message's header bytes.</p> + * + * <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); + } + + /** + * <p>Returns an instance of a message given its encoded contents, excluding + * the message's header bytes.</p> + * + * @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; + } + + /** + * <p>Converts two octets into the number that they represent.</p> + * + * @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; + } + + /** + * <p>Converts four octets into the number that they represent.</p> + * + * @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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + public boolean hasMoreElements() + { + return (in.available() > 0); + } + + public PublicKey readPublicKey() throws KeyAgreementException + { + if (in.available() < 4) + { + 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"); + } + + byte[] kb = new byte[elementLength]; + in.read(kb, 0, elementLength); + + // instantiate the right codec and decode + IKeyPairCodec kpc = KeyPairCodecFactory.getInstance(kb); + if (kpc == null) + { + throw new KeyAgreementException( + "invalid public key, or encoded with an unknown codec"); + } + + return kpc.decodePublicKey(kb); + } + + public PrivateKey readPrivateKey() throws KeyAgreementException + { + if (in.available() < 4) + { + 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"); + } + + byte[] kb = new byte[elementLength]; + in.read(kb, 0, elementLength); + + // instantiate the right codec and decode + IKeyPairCodec kpc = KeyPairCodecFactory.getInstance(kb); + if (kpc == null) + { + throw new KeyAgreementException( + "invalid private key, or encoded with an unknown codec"); + } + + return kpc.decodePrivateKey(kb); + } + + /** + * <p>Decodes an MPI from the current message's contents.</p> + * + * @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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/key/KeyAgreementException.java b/gnu/javax/crypto/key/KeyAgreementException.java new file mode 100644 index 000000000..c2fa434a2 --- /dev/null +++ b/gnu/javax/crypto/key/KeyAgreementException.java @@ -0,0 +1,187 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** @serial The possibly <code>null</code> <i>root</i> cause exception. */ + private Throwable cause = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Constructs a new instance of <code>KeyAgreementException</code>. The + * root exception and the detailed message are <code>null</code>.</p> + */ + public KeyAgreementException() + { + super(); + } + + /** + * <p>Constructs a new instance of <code>KeyAgreementException</code> with a + * detailed message. The <i>root</i> exception is <code>null</code>.</p> + * + * @param detail a possibly <code>null</code> string containing details of + * the exception. + * @see Throwable#getMessage() + */ + public KeyAgreementException(String detail) + { + super(detail); + } + + /** + * <p>Constructs a new instance of <code>KeyAgreementException</code> with a + * detailed message and a <i>root</i> exception.</p> + * + * @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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @return the possibly <code>null</code> exception that caused this one. + */ + public Throwable getCause() + { + return cause; + } + + /** + * <p>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>.</p> + */ + public void printStackTrace() + { + super.printStackTrace(); + if (cause != null) + { + cause.printStackTrace(); + } + } + + /** + * <p>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.</p> + * + * @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); + } + } + + /** + * <p>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.</p> + * + * @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); + } + } + + /** + * <p>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.</p> + * + * @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(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/key/KeyAgreementFactory.java b/gnu/javax/crypto/key/KeyAgreementFactory.java new file mode 100644 index 000000000..e2a7faba1 --- /dev/null +++ b/gnu/javax/crypto/key/KeyAgreementFactory.java @@ -0,0 +1,181 @@ +/* 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; + +/** + * <p>A <i>Factory</i> class to generate key agreement protocol handlers.</p> + */ +public class KeyAgreementFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + private KeyAgreementFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @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; + } + + /** + * <p>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.</p> + * + * @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; + } + + /** + * <p>Returns a {@link Set} of key agreement protocol names supported by this + * <i>Factory</i>.</p> + * + * @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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/key/OutgoingMessage.java b/gnu/javax/crypto/key/OutgoingMessage.java new file mode 100644 index 000000000..7a74370cc --- /dev/null +++ b/gnu/javax/crypto/key/OutgoingMessage.java @@ -0,0 +1,212 @@ +/* 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.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.math.BigInteger; + +/** + * <p>An implementation of outgoing messages for use with key agreement + * protocols.</p> + */ +public class OutgoingMessage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The internal output stream. */ + private ByteArrayOutputStream out; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public OutgoingMessage() + { + super(); + + out = new ByteArrayOutputStream(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the encoded form of the current message including the 4-byte + * length header.</p> + * + * @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; + } + + /** + * <p>Returns the encoded form of the current message excluding the 4-byte + * length header.</p> + * + * @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(); + } + + /** + * <p>Encodes a public key into the message.</p> + * + * @param k the public key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writePublicKey(PublicKey k) throws KeyAgreementException + { + IKeyPairCodec kpc = KeyPairCodecFactory.getInstance(k); + if (kpc == null) + { + throw new KeyAgreementException(""); + } + byte[] b = kpc.encodePublicKey(k); + int length = b.length; + if (length > Registry.SASL_FOUR_BYTE_MAX_LIMIT) + { + throw new KeyAgreementException("encoded public key is too long"); + } + byte[] lengthBytes = { (byte) (length >>> 24), (byte) (length >>> 16), + (byte) (length >>> 8), (byte) length }; + out.write(lengthBytes, 0, 4); + out.write(b, 0, b.length); + } + + /** + * <p>Encodes a private key into the message.</p> + * + * @param k the private key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writePrivateKey(PrivateKey k) throws KeyAgreementException + { + IKeyPairCodec kpc = KeyPairCodecFactory.getInstance(k); + if (kpc == null) + { + throw new KeyAgreementException(""); + } + byte[] b = kpc.encodePrivateKey(k); + int length = b.length; + if (length > Registry.SASL_FOUR_BYTE_MAX_LIMIT) + { + throw new KeyAgreementException("encoded private key is too long"); + } + byte[] lengthBytes = { (byte) (length >>> 24), (byte) (length >>> 16), + (byte) (length >>> 8), (byte) length }; + out.write(lengthBytes, 0, 4); + out.write(b, 0, b.length); + } + + /** + * <p>Encodes an MPI into the message.</p> + * + * @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); + } + + /** + * <p>Encodes a string into the message.</p> + * + * @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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java b/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java new file mode 100644 index 000000000..c0ff82bea --- /dev/null +++ b/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java @@ -0,0 +1,370 @@ +/* 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; + +/** + * <p>An object that implements the {@link IKeyPairCodec} operations for the + * <i>Raw</i> format to use with Diffie-Hellman keypairs.</p> + */ +public class DHKeyPairRawCodec implements IKeyPairCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments ctor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairCodec interface implementation ------------------- + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * <p>Returns the encoded form of the designated Diffie-Hellman public key + * according to the <i>Raw</i> format supported by this library.</p> + * + * <p>The <i>Raw</i> format for a DH public key, 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_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); + } + + /** + * <p>Returns the encoded form of the designated Diffie-Hellman private key + * according to the <i>Raw</i> format supported by this library.</p> + * + * <p>The <i>Raw</i> format for a DH private key, 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_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); + } +} diff --git a/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java b/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java new file mode 100644 index 000000000..5b1caa7d1 --- /dev/null +++ b/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java @@ -0,0 +1,134 @@ +/* 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; + +/** + * <p>The basic version of the Diffie-Hellman key agreement is described in the + * Handbook of Applied Cryptography [HAC] as follows:</p> + * <ul> + * <li>An appropriate prime p and generator g of Z<sub>p</sub><sup>*</sup> + * (2 <= g <= 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 <= x <= p-2, and sends B message + * (1) which is g^x mod p.</li> + * <li>B chooses a random secret y, 1 <= y <= 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:</p> + * <pre> + * "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." + * </pre> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected DiffieHellmanKeyAgreement() + { + super(Registry.DH_KA); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of common abstract methods in BaseKeyAGreementParty ------ + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ownerKey = null; + ZZ = null; + } +} diff --git a/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java b/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java new file mode 100644 index 000000000..4a3664d6a --- /dev/null +++ b/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java @@ -0,0 +1,147 @@ +/* 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; + +/** + * <p>This implementation is the receiver's part of the basic version of the + * Diffie-Hellman key agreement exchange (B in [HAC]).</p> + * + * @see DiffieHellmanKeyAgreement + */ +public class DiffieHellmanReceiver extends DiffieHellmanKeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private BigInteger y; // the receiver's random secret + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + 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"); + } + } + + // own methods ------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/dh/DiffieHellmanSender.java b/gnu/javax/crypto/key/dh/DiffieHellmanSender.java new file mode 100644 index 000000000..6b9cf70b6 --- /dev/null +++ b/gnu/javax/crypto/key/dh/DiffieHellmanSender.java @@ -0,0 +1,156 @@ +/* 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; + +/** + * <p>This implementation is the sender's part of the basic version of the + * Diffie-Hellman key agreement exchange (A in [HAC]).</p> + * + * @see DiffieHellmanKeyAgreement + * @version $Revision: 1.1 $ + */ +public class DiffieHellmanSender extends DiffieHellmanKeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private BigInteger x; // the sender's random secret + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + 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"); + } + } + + // own methods ------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java b/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java new file mode 100644 index 000000000..1c4e11ce2 --- /dev/null +++ b/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java @@ -0,0 +1,130 @@ +/* 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; + +/** + * <p>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:</p> + * <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 <= x <= 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:</p> + * <pre> + * "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." + * </pre> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected ElGamalKeyAgreement() + { + super(Registry.ELGAMAL_KA); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of common abstract methods in BaseKeyAGreementParty ------ + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ZZ = null; + } +} diff --git a/gnu/javax/crypto/key/dh/ElGamalReceiver.java b/gnu/javax/crypto/key/dh/ElGamalReceiver.java new file mode 100644 index 000000000..24776cba1 --- /dev/null +++ b/gnu/javax/crypto/key/dh/ElGamalReceiver.java @@ -0,0 +1,121 @@ +/* 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; + +/** + * <p>This implementation is the receiver's part of the ElGamal key agreement + * exchange (B in [HAC]).</p> + * + * @see ElGamalKeyAgreement + */ +public class ElGamalReceiver extends ElGamalKeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The recipient's private key. */ + private DHPrivateKey B; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + 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"); + } + } + + // own methods ------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/dh/ElGamalSender.java b/gnu/javax/crypto/key/dh/ElGamalSender.java new file mode 100644 index 000000000..a2de80a67 --- /dev/null +++ b/gnu/javax/crypto/key/dh/ElGamalSender.java @@ -0,0 +1,134 @@ +/* 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; + +/** + * <p>This implementation is the sender's part of the ElGamal key agreement + * exchange (A in [HAC]).</p> + * + * @see ElGamalKeyAgreement + */ +public class ElGamalSender extends ElGamalKeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The recipient's public key. */ + private DHPublicKey B; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + 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"); + } + } + + // own methods ------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/dh/GnuDHKey.java b/gnu/javax/crypto/key/dh/GnuDHKey.java new file mode 100644 index 000000000..e6806684e --- /dev/null +++ b/gnu/javax/crypto/key/dh/GnuDHKey.java @@ -0,0 +1,163 @@ +/* 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 java.math.BigInteger; +import java.security.Key; + +import javax.crypto.interfaces.DHKey; +import javax.crypto.spec.DHParameterSpec; + +/** + * <p>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> + * + * <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> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial protected constructor.</p> + * + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + */ + protected GnuDHKey(BigInteger q, BigInteger p, BigInteger g) + { + super(); + + this.q = q; + this.p = p; + this.g = g; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // javax.crypto.interfaces.DHKey interface implementation ------------------ + + public DHParameterSpec getParams() + { + if (q == null) + { + return new DHParameterSpec(p, g); + } + else + { + return new DHParameterSpec(p, g, q.bitLength()); + } + } + + // java.security.Key interface implementation ------------------------------ + + public String getAlgorithm() + { + return Registry.DH_KPG; + } + + public String getFormat() + { + return null; + } + + // Other instance methods -------------------------------------------------- + + public BigInteger getQ() + { + return q; + } + + /** + * <p>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.</p> + * + * @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()); + } +} diff --git a/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java b/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java new file mode 100644 index 000000000..5502fa7bf --- /dev/null +++ b/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java @@ -0,0 +1,254 @@ +/* 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.Registry; +import gnu.java.security.hash.Sha160; +import gnu.java.security.key.IKeyPairGenerator; + +import java.io.PrintWriter; +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 javax.crypto.spec.DHGenParameterSpec; + +/** + * <p>An implementation of a Diffie-Hellman keypair generator.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "dh"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * 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} 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"; + + /** Default value for the size in bits of the public prime (p). */ + // private static final int DEFAULT_PRIME_SIZE = 1024; + private static final int DEFAULT_PRIME_SIZE = 512; + + /** Default value for the size in bits of the private exponent (x). */ + private static final int DEFAULT_EXPONENT_SIZE = 160; + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairGenerator interface implementation --------------- + + 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? + DHGenParameterSpec params = (DHGenParameterSpec) attributes.get(DH_PARAMETERS); + + // find out the desired sizes + if (params != null) + { + l = params.getPrimeSize(); + m = params.getExponentSize(); + } + 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 < 1024) { + 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"); + } + } + + 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 (DEBUG && debuglevel > 0) + { + debug("seed: 0x" + seed.toString(16)); + debug("counter: " + counter.intValue()); + debug("q: 0x" + q.toString(16)); + debug("p: 0x" + p.toString(16)); + debug("j: 0x" + j.toString(16)); + debug("g: 0x" + g.toString(16)); + } + } + + // generate a private number x of length m such as: 1 < x < q - 1 + BigInteger q_minus_1 = q.subtract(BigInteger.ONE); + 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 + && x.compareTo(q_minus_1) < 0) + { + break; + } + } + BigInteger y = g.modPow(x, p); + + PrivateKey secK = new GnuDHPrivateKey(q, p, g, x); + PublicKey pubK = new GnuDHPublicKey(q, p, g, y); + + return new KeyPair(pubK, secK); + } + + // other methods ----------------------------------------------------------- + + /** + * <p>Fills the designated byte array with random data.</p> + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + { + new SecureRandom ().nextBytes(buffer); + } + } +} diff --git a/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java b/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java new file mode 100644 index 000000000..8b11f2c63 --- /dev/null +++ b/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java @@ -0,0 +1,155 @@ +/* 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.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import javax.crypto.interfaces.DHPrivateKey; + +/** + * <p>An implementation of the Diffie-Hellman private key.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The private exponent. */ + private final BigInteger x; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public GnuDHPrivateKey(BigInteger q, BigInteger p, BigInteger g, BigInteger x) + { + super(q, p, g); + + this.x = x; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @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) + { + // 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_DH_PRIVATE_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new DHKeyPairRawCodec(); + return (GnuDHPrivateKey) codec.decodePrivateKey(k); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.Key interface implementation ------------------------------ + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(IKeyPairCodec.RAW_FORMAT); + } + + // javax.crypto.interfaces.DHPrivateKey interface implementation ----------- + + public BigInteger getX() + { + return x; + } + + // other methods ----------------------------------------------------------- + + /** + * <p>Returns the encoded form of this private key according to the + * designated format.</p> + * + * @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 gnu.crypto.key.dh.DHKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DHKeyPairRawCodec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("format"); + } + return result; + } +} diff --git a/gnu/javax/crypto/key/dh/GnuDHPublicKey.java b/gnu/javax/crypto/key/dh/GnuDHPublicKey.java new file mode 100644 index 000000000..5166914eb --- /dev/null +++ b/gnu/javax/crypto/key/dh/GnuDHPublicKey.java @@ -0,0 +1,155 @@ +/* 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.key.IKeyPairCodec; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPublicKey; + +/** + * <p>An implementation of the Diffie-Hellman public key.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private BigInteger y; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public GnuDHPublicKey(BigInteger q, BigInteger p, BigInteger g, BigInteger y) + { + super(q, p, g); + + this.y = y; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @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) + { + // 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_DH_PUBLIC_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new DHKeyPairRawCodec(); + return (GnuDHPublicKey) codec.decodePublicKey(k); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.Key interface implementation ------------------------------ + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(IKeyPairCodec.RAW_FORMAT); + } + + // javax.crypto.interfaces.DHPublicKey interface implementation ------------ + + public BigInteger getY() + { + return y; + } + + // other methods ----------------------------------------------------------- + + /** + * <p>Returns the encoded form of this public key according to the designated + * format.</p> + * + * @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 gnu.crypto.key.dh.DHKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DHKeyPairRawCodec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("format"); + } + return result; + } +} diff --git a/gnu/javax/crypto/key/dh/RFC2631.java b/gnu/javax/crypto/key/dh/RFC2631.java new file mode 100644 index 000000000..656253de1 --- /dev/null +++ b/gnu/javax/crypto/key/dh/RFC2631.java @@ -0,0 +1,245 @@ +/* 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.Prime2; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * <p>An implementation of the Diffie-Hellman parameter generation as defined in + * RFC-2631.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RFC2631(int m, int L, SecureRandom rnd) + { + super(); + + this.m = m; + this.L = L; + this.rnd = rnd; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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 (Prime2.isProbablePrime(q)) + { + 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 (Prime2.isProbablePrime(p)) + { + 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 }; + } + + // helper methods ---------------------------------------------------------- + + /** + * <p>Fills the designated byte array with random data.</p> + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + { + new SecureRandom ().nextBytes(buffer); + } + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6Host.java b/gnu/javax/crypto/key/srp6/SRP6Host.java new file mode 100644 index 000000000..192e877b7 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6Host.java @@ -0,0 +1,213 @@ +/* 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; + +/** + * <p>The implementation of the Host in the SRP-6 key agreement protocol.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + 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 || "".equals(md.trim())) + { + 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(); + } + + // own methods ------------------------------------------------------------- + + 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))); + + // Map configuration = null; + // try { + // String mode = (String) credentials.get(SRPRegistry.CONFIG_NDX_FIELD); + // configuration = passwordDB.getConfiguration(mode); + // } catch (IOException x) { + // throw new KeyAgreementException("computeSharedSecret()", x); + // } + // + // BigInteger N = new BigInteger(1, Util.fromBase64( + // (String) configuration.get(SRPRegistry.SHARED_MODULUS))); + // BigInteger g = new BigInteger(1, Util.fromBase64( + // (String) configuration.get(SRPRegistry.FIELD_GENERATOR))); + // ---------------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java b/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java new file mode 100644 index 000000000..63c981d80 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java @@ -0,0 +1,172 @@ +/* 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; + +/** + * <p>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:</p> + * + * <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 + * ^ (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 ":" p)) (s is chosen randomly) + * v = g^x (computes password verifier) + * + * The host then keeps {I, s, v} in its password database. + * + * The authentication protocol itself goes as follows: + * User -> Host: I, A = g^a (identifies self, a = random number) + * Host -> User: s, B = 3v + g^b (sends salt, b = random number) + * + * Both: u = H(A, B) + * + * User: x = H(s, p) (user enters password) + * User: S = (B - 3g^x) ^ (a + ux) (computes session key) + * User: K = H(S) + * + * Host: S = (Av^u) ^ b (computes session key) + * Host: K = H(S) + * </pre> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected SRP6KeyAgreement() + { + super(Registry.SRP6_KA); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of common abstract methods in BaseKeyAGreementParty ------ + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(K); + } + + protected void engineReset() + { + // mda = null; + srp = null; + N = null; + g = null; + K = null; + } + + // helper methods ---------------------------------------------------------- + + protected BigInteger uValue(final BigInteger A, final BigInteger B) + { + // IMessageDigest hash = (IMessageDigest) mda.clone(); + 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()); + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6SaslClient.java b/gnu/javax/crypto/key/srp6/SRP6SaslClient.java new file mode 100644 index 000000000..ef460b13b --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6SaslClient.java @@ -0,0 +1,101 @@ +/* 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; + +/** + * <p>A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for + * the User (client side).</p> + * + * <p>In this alternative, the exchange goes as follows:</p> + * <pre> + * C -> S: I (identifies self) + * S -> C: N, g, s, B = 3v + g^b (sends salt, b = random number) + * C -> S: A = g^a (a = random number) + * </pre> + * + * <p>All elements are computed the same way as in the standard version.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6SaslServer.java b/gnu/javax/crypto/key/srp6/SRP6SaslServer.java new file mode 100644 index 000000000..5e759964e --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6SaslServer.java @@ -0,0 +1,101 @@ +/* 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; + +/** + * <p>A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for + * the Host (server side).</p> + * + * <p>In this alternative, the exchange goes as follows:</p> + * <pre> + * C -> S: I (identifies self) + * S -> C: N, g, s, B = 3v + g^b (sends salt, b = random number) + * C -> S: A = g^a (a = random number) + * </pre> + * + * <p>All elements are computed the same way as in the standard version.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6TLSClient.java b/gnu/javax/crypto/key/srp6/SRP6TLSClient.java new file mode 100644 index 000000000..5474a1e8e --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6TLSClient.java @@ -0,0 +1,191 @@ +/* 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; + +/** + * <p>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>.</p> + */ +public class SRP6TLSClient extends SRP6KeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The user's identity. */ + private String I; + + /** The user's cleartext password. */ + private byte[] p; + + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + 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 || "".equals(md.trim())) + { + 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(); + } + + // own methods ------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6TLSServer.java b/gnu/javax/crypto/key/srp6/SRP6TLSServer.java new file mode 100644 index 000000000..23e444077 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6TLSServer.java @@ -0,0 +1,220 @@ +/* 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; + +/** + * <p>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>.</p> + * + * @version $Revision: 1.1 $ + */ +public class SRP6TLSServer extends SRP6KeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + 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 || "".equals(md.trim())) + { + 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(); + } + + // own methods ------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6User.java b/gnu/javax/crypto/key/srp6/SRP6User.java new file mode 100644 index 000000000..d300d6f76 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6User.java @@ -0,0 +1,203 @@ +/* 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; + +/** + * <p>The implementation of the User in the SRP-6 protocol.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The user's identity. */ + private String I; + + /** The user's cleartext password. */ + private byte[] p; + + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + 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 || "".equals(md.trim())) + { + 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(); + } + + // own methods ------------------------------------------------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRPAlgorithm.java b/gnu/javax/crypto/key/srp6/SRPAlgorithm.java new file mode 100644 index 000000000..b068863ed --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPAlgorithm.java @@ -0,0 +1,175 @@ +/* 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.java.security.util.Prime2; +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.math.BigInteger; + +/** + * <p>Utilities for use with SRP-6 based methods and protocols.</p> + * + * <p>Reference:</p> + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRPAlgorithm +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // 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); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce usage through class methods. */ + private SRPAlgorithm() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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 (!Prime2.passEulerCriterion(N)) + { + 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 (!Prime2.passEulerCriterion(q)) + { + 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"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/javax/crypto/key/srp6/SRPKey.java b/gnu/javax/crypto/key/srp6/SRPKey.java new file mode 100644 index 000000000..79f4f07bc --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPKey.java @@ -0,0 +1,170 @@ +/* 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; + +/** + * <p>An abstract representation of a base SRP ephemeral key.</p> + * + * <p>This object encapsulates the two numbers:</p> + * <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> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The public, Germaine prime, shared modulus. */ + protected final BigInteger N; + + /** The generator. */ + protected final BigInteger g; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected SRPKey(BigInteger N, BigInteger g) + { + super(); + + this.N = N; + this.g = g; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.Key interface implementation ------------------------------ + + /** + * <p>Returns the standard algorithm name for this key.</p> + * + * @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); + } + + /** + * <p>Returns <code>null</code> since this implementation does not encode SRP + * keys.</p> + * + * @return null since this implementation does not encode SRP keys. + */ + public String getFormat() + { + return null; + } + + // other methods ----------------------------------------------------------- + + /** + * <p>Returns the public shared modulus.</p> + * + * @return <code>N</code>. + */ + public BigInteger getN() + { + return N; + } + + /** + * <p>Returns the generator.</p> + * + * @return <code>g</code>. + */ + public BigInteger getG() + { + return g; + } + + /** + * <p>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.</p> + * + * @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()); + } + + // abstract methods to be implemented by subclasses ------------------------ + + public abstract byte[] getEncoded(int format); +} diff --git a/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java b/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java new file mode 100644 index 000000000..3c8baaa7a --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java @@ -0,0 +1,341 @@ +/* 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.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.Prime2; + +import java.io.PrintWriter; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.Map; + +/** + * + * + * <p>Reference:</p> + * <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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "srp"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.key.IKeyPairGenerator interface implementation --------------- + + 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 (DEBUG && debuglevel > 0) + { + debug("q: " + q.toString(16)); + debug("N: " + N.toString(16)); + debug("g: " + g.toString(16)); + } + } + + return (v != null ? hostKeyPair() : userKeyPair()); + } + + // helper methods ---------------------------------------------------------- + + 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 (!Prime2.isProbablePrime(q)); + p = q.multiply(TWO).add(ONE); + } + while (p.bitLength() != l || !Prime2.isProbablePrime(p)); + + // 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 + { + new SecureRandom ().nextBytes(buffer); + } + } +} diff --git a/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java b/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java new file mode 100644 index 000000000..39234b627 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java @@ -0,0 +1,380 @@ +/* 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; + +/** + * <p>An object that implements the {@link IKeyPairCodec} operations for the + * <i>Raw</i> format to use with SRP keypairs.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairCodec interface implementation ------------------ + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * <p>Returns the encoded form of the designated SRP public key according to + * the <i>Raw</i> format supported by this library.</p> + * + * <p>The <i>Raw</i> format for an SRP public key, 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_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); + } + + /** + * <p>Returns the encoded form of the designated SRP private key according to + * the <i>Raw</i> format supported by this library.</p> + * + * <p>The <i>Raw</i> format for an SRP private key, 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_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); + } + else + { + return new SRPPrivateKey(N, g, x); + } + } +} diff --git a/gnu/javax/crypto/key/srp6/SRPPrivateKey.java b/gnu/javax/crypto/key/srp6/SRPPrivateKey.java new file mode 100644 index 000000000..d9f7a19a6 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPPrivateKey.java @@ -0,0 +1,250 @@ +/* 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; + +/** + * <p>A representation of an SRP ephemeral private key.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Public constructor for use from outside this package.</p> + * + * @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); + } + + /** + * <p>Public constructor for use from outside this package.</p> + * + * @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; + } + + /** + * <p>Default constructor. Assumes N and g are already validated.</p> + * + * @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"); + } + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @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); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the private exponent of the key as a {@link BigInteger}.</p> + * + * @return the private exponent of the key as a {@link BigInteger}. + */ + public BigInteger getX() + { + return X; + } + + /** + * <p>Returns the user's verifier as a {@link BigInteger}.</p> + * + * @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; + } + + // Other instance methods -------------------------------------------------- + + /** + * <p>Returns the encoded form of this private key according to the + * designated format.</p> + * + * @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; + } + + /** + * <p>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.</p> + * + * @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; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRPPublicKey.java b/gnu/javax/crypto/key/srp6/SRPPublicKey.java new file mode 100644 index 000000000..7283fd3da --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPPublicKey.java @@ -0,0 +1,194 @@ +/* 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; + +/** + * <p>A representation of an SRP ephemeral public key.</p> + * + * <p>Reference:</p> + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * The public exponent for either the server or the client engaged in the + * SRP protocol exchange. + */ + private final BigInteger Y; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Public constructor for use from outside this package.</p> + * + * @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; + } + + /** + * <p>Default constructor. Assumes that N and g are already validated.</p> + * + * @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]; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @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); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the public exponent of the key as a {@link BigInteger}.</p> + * + * @return the public exponent of the key as a {@link BigInteger}. + */ + public BigInteger getY() + { + return Y; + } + + // Other instance methods -------------------------------------------------- + + /** + * <p>Returns the encoded form of this public key according to the designated + * format.</p> + * + * @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; + } + + /** + * <p>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. + * </p> + * + * @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()); + } +} diff --git a/gnu/javax/crypto/keyring/AuthenticatedEntry.java b/gnu/javax/crypto/keyring/AuthenticatedEntry.java new file mode 100644 index 000000000..22b42b3ea --- /dev/null +++ b/gnu/javax/crypto/keyring/AuthenticatedEntry.java @@ -0,0 +1,222 @@ +/* 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 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.Date; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacInputStream; +import gnu.javax.crypto.mac.MacOutputStream; + +public final class AuthenticatedEntry extends MaskableEnvelopeEntry implements + Registry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 2; + + // Constructor. + // ------------------------------------------------------------------------ + + 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); + } + + // Class methods. + // ------------------------------------------------------------------------ + + 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; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * 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 + { + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + payload, + 0, + payload.length + - m.macSize())); + 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"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + 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, new Integer(maclen)); + mac.init(macAttr); + return mac; + } +} diff --git a/gnu/javax/crypto/keyring/BaseKeyring.java b/gnu/javax/crypto/keyring/BaseKeyring.java new file mode 100644 index 000000000..5fe7dbf4d --- /dev/null +++ b/gnu/javax/crypto/keyring/BaseKeyring.java @@ -0,0 +1,198 @@ +/* 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 java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import gnu.java.security.Registry; + +public abstract class BaseKeyring implements IKeyring +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** + * The top-level keyring data. + */ + protected PasswordAuthenticatedEntry keyring; + + protected CompressedEntry keyring2; + + // Constructors. + // ------------------------------------------------------------------------ + + public BaseKeyring() + { + } + + // Instance methods. + // ------------------------------------------------------------------------ + + 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; +} diff --git a/gnu/javax/crypto/keyring/BinaryDataEntry.java b/gnu/javax/crypto/keyring/BinaryDataEntry.java new file mode 100644 index 000000000..2dcd5454f --- /dev/null +++ b/gnu/javax/crypto/keyring/BinaryDataEntry.java @@ -0,0 +1,128 @@ +/* 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 +{ + + // Fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 9; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * 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); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static BinaryDataEntry decode(DataInputStream in) throws IOException + { + BinaryDataEntry entry = new BinaryDataEntry(); + entry.defaultDecode(in); + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * 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. + } +} diff --git a/gnu/javax/crypto/keyring/CertPathEntry.java b/gnu/javax/crypto/keyring/CertPathEntry.java new file mode 100644 index 000000000..ef62347ec --- /dev/null +++ b/gnu/javax/crypto/keyring/CertPathEntry.java @@ -0,0 +1,133 @@ +/* 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.DataOutputStream; +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 +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 8; + + private Certificate[] path; + + // Constructor. + // ------------------------------------------------------------------------ + + 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); + } + + // Class method. + // ------------------------------------------------------------------------ + + 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; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + 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(); + } +} diff --git a/gnu/javax/crypto/keyring/CertificateEntry.java b/gnu/javax/crypto/keyring/CertificateEntry.java new file mode 100644 index 000000000..95a708ac5 --- /dev/null +++ b/gnu/javax/crypto/keyring/CertificateEntry.java @@ -0,0 +1,150 @@ +/* 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.DataOutputStream; +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.security.cert.X509Certificate; +import java.util.Date; + +/** + * <p>An immutable class representing a trusted certificate entry.</p> + */ +public final class CertificateEntry extends PrimitiveEntry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int TYPE = 5; + + /** The certificate. */ + private Certificate certificate; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * 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); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * 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()); + } + } +} diff --git a/gnu/javax/crypto/keyring/CompressedEntry.java b/gnu/javax/crypto/keyring/CompressedEntry.java new file mode 100644 index 000000000..cce930d73 --- /dev/null +++ b/gnu/javax/crypto/keyring/CompressedEntry.java @@ -0,0 +1,113 @@ +/* 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 +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 4; + + // Constructor. + // ------------------------------------------------------------------------ + + public CompressedEntry(Properties properties) + { + super(TYPE, properties); + this.properties.put("algorithm", "DEFLATE"); + } + + private CompressedEntry() + { + this(new Properties()); + } + + // Class methods. + // ------------------------------------------------------------------------ + + 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; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + 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(); + } +} diff --git a/gnu/javax/crypto/keyring/EncryptedEntry.java b/gnu/javax/crypto/keyring/EncryptedEntry.java new file mode 100644 index 000000000..fad5f54b2 --- /dev/null +++ b/gnu/javax/crypto/keyring/EncryptedEntry.java @@ -0,0 +1,235 @@ +/* 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 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.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; + +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; + +public class EncryptedEntry extends MaskableEnvelopeEntry implements Registry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 0; + + // Constructor. + // ------------------------------------------------------------------------ + + 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); + } + + // Class methods. + // ------------------------------------------------------------------------ + + 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; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + 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); + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + buf, + 0, + buf.length + - padlen)); + 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"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + 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, new Integer(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/gnu/javax/crypto/keyring/Entry.java b/gnu/javax/crypto/keyring/Entry.java new file mode 100644 index 000000000..fa7f49679 --- /dev/null +++ b/gnu/javax/crypto/keyring/Entry.java @@ -0,0 +1,178 @@ +/* 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 java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * An immutable class representing a single entry in a keyring. + */ +public abstract class Entry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** This entry's type identifier. */ + protected int type; + + /** This entry's property set. */ + protected Properties properties; + + /** This entry's payload. */ + protected byte[] payload; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * 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(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * 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); + } + + /** + * 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"); + } + payload = new byte[len]; + in.readFully(payload); + } + + // Abstract methods. + // ------------------------------------------------------------------------ + + /** + * 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; +} diff --git a/gnu/javax/crypto/keyring/EnvelopeEntry.java b/gnu/javax/crypto/keyring/EnvelopeEntry.java new file mode 100644 index 000000000..25b1dc2a0 --- /dev/null +++ b/gnu/javax/crypto/keyring/EnvelopeEntry.java @@ -0,0 +1,398 @@ +/* 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 java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +/** + * An envelope entry is a generic container for some number of primitive + * and other envelope entries. + */ +public abstract class EnvelopeEntry extends Entry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The envelope that contains this one (if any). */ + protected EnvelopeEntry containingEnvelope; + + /** The contained entries. */ + protected List entries; + + // Constructor. + // ------------------------------------------------------------------------ + + 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(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Adds an entry to this envelope. + * + * @param entry The entry to add. + */ + public void add(Entry entry) + { + if (!containsEntry(entry)) + { + if (entry instanceof EnvelopeEntry) + { + ((EnvelopeEntry) entry).setContainingEnvelope(this); + } + entries.add(entry); + payload = null; + makeAliasList(); + } + } + + /** + * 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) + { + String aliases = getAliasList(); + if (aliases == null) + { + return false; + } + StringTokenizer tok = new StringTokenizer(aliases, ";"); + while (tok.hasMoreTokens()) + { + if (tok.nextToken().equals(alias)) + { + return true; + } + } + return false; + } + + /** + * 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); + } + else 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) + { + List result = new LinkedList(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + if (!((EnvelopeEntry) e).containsAlias(alias)) + { + continue; + } + if (e instanceof MaskableEnvelopeEntry) + { + if (((MaskableEnvelopeEntry) e).isMasked()) + { + result.add(e); + continue; + } + } + result.addAll(((EnvelopeEntry) e).get(alias)); + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).getAlias().equals(alias)) + { + result.add(e); + } + } + } + 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) + { + 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) + { + payload = null; + makeAliasList(); + } + return ret; + } + + /** + * Removes all primitive entries that have the specified alias. + * + * @param alias The alias of the entries to remove. + */ + public void remove(String alias) + { + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + ((EnvelopeEntry) e).remove(alias); + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).getAlias().equals(alias)) + { + it.remove(); + } + } + } + payload = null; + makeAliasList(); + } + + // 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 + { + 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); + } + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private void makeAliasList() + { + if (entries.isEmpty()) + return; + StringBuffer buf = new StringBuffer(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + if (entry instanceof EnvelopeEntry) + { + buf.append(((EnvelopeEntry) entry).getAliasList()); + } + else if (entry instanceof PrimitiveEntry) + { + buf.append(((PrimitiveEntry) entry).getAlias()); + } + if (it.hasNext()) + buf.append(';'); + } + properties.put("alias-list", buf.toString()); + if (containingEnvelope != null) + { + containingEnvelope.makeAliasList(); + } + } +} diff --git a/gnu/javax/crypto/keyring/GnuPrivateKeyring.java b/gnu/javax/crypto/keyring/GnuPrivateKeyring.java new file mode 100644 index 000000000..d49bd0963 --- /dev/null +++ b/gnu/javax/crypto/keyring/GnuPrivateKeyring.java @@ -0,0 +1,328 @@ +/* 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.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.IOException; +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.List; + +/** + * <p>.</p> + */ +public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + 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); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public boolean containsPrivateKey(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof PasswordAuthenticatedEntry) + { + return true; + } + } + return false; + } + + public Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + PasswordAuthenticatedEntry e1 = null; + PasswordEncryptedEntry e2 = null; + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordAuthenticatedEntry) + { + e1 = (PasswordAuthenticatedEntry) e; + break; + } + } + if (e1 == null) + { + return null; + } + try + { + e1.verify(password); + } + catch (Exception e) + { + throw new UnrecoverableKeyException("authentication failed"); + } + for (Iterator it = e1.getEntries().iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordEncryptedEntry) + { + e2 = (PasswordEncryptedEntry) e; + break; + } + } + if (e2 == null) + { + return null; + } + try + { + e2.decrypt(password); + } + catch (Exception e) + { + throw new UnrecoverableKeyException("decryption failed"); + } + for (Iterator it = e2.get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PrivateKeyEntry) + { + return ((PrivateKeyEntry) e).getKey(); + } + } + return null; + } + + public void putPrivateKey(String alias, Key key, char[] password) + { + if (containsPrivateKey(alias)) + { + return; + } + alias = fixAlias(alias); + Properties p = new Properties(); + p.put("alias", alias); + PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p); + PasswordEncryptedEntry enc = new PasswordEncryptedEntry(cipher, mode, + keylen, + new Properties()); + PasswordAuthenticatedEntry auth = new PasswordAuthenticatedEntry( + mac, + maclen, + new Properties()); + enc.add(pke); + auth.add(enc); + try + { + enc.encode(null, password); + auth.encode(null, password); + } + catch (IOException ioe) + { + throw new IllegalArgumentException(ioe.toString()); + } + keyring.add(auth); + } + + public boolean containsPublicKey(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof PublicKeyEntry) + { + return true; + } + } + return false; + } + + public PublicKey getPublicKey(String alias) + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PublicKeyEntry) + { + return ((PublicKeyEntry) e).getKey(); + } + } + return null; + } + + public void putPublicKey(String alias, PublicKey key) + { + if (containsPublicKey(alias)) + { + return; + } + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new PublicKeyEntry(key, new Date(), p)); + } + + public boolean containsCertPath(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof CertPathEntry) + { + return true; + } + } + return false; + } + + public Certificate[] getCertPath(String alias) + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertPathEntry) + { + return ((CertPathEntry) e).getCertPath(); + } + } + return null; + } + + public void putCertPath(String alias, Certificate[] path) + { + if (containsCertPath(alias)) + { + return; + } + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertPathEntry(path, new Date(), p)); + } + + protected void load(InputStream in, char[] password) throws IOException + { + 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); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + } +} diff --git a/gnu/javax/crypto/keyring/GnuPublicKeyring.java b/gnu/javax/crypto/keyring/GnuPublicKeyring.java new file mode 100644 index 000000000..318eb036f --- /dev/null +++ b/gnu/javax/crypto/keyring/GnuPublicKeyring.java @@ -0,0 +1,146 @@ +/* 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 java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import java.security.cert.Certificate; + +import gnu.java.security.Registry; + +public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring +{ + + // Fields. + // ------------------------------------------------------------------------ + + public static final int USAGE = Registry.GKR_CERTIFICATES; + + // Constructors. + // ------------------------------------------------------------------------ + + public GnuPublicKeyring(String mac, int macLen) + { + keyring = new PasswordAuthenticatedEntry(mac, macLen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + } + + public GnuPublicKeyring() + { + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public boolean containsCertificate(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof CertificateEntry) + { + return true; + } + } + return false; + } + + public Certificate getCertificate(String alias) + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertificateEntry) + { + return ((CertificateEntry) e).getCertificate(); + } + } + return null; + } + + public void putCertificate(String alias, Certificate cert) + { + if (containsCertificate(alias)) + { + return; + } + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertificateEntry(cert, new Date(), p)); + } + + protected void load(InputStream in, char[] password) throws IOException + { + 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); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + } +} diff --git a/gnu/javax/crypto/keyring/IKeyring.java b/gnu/javax/crypto/keyring/IKeyring.java new file mode 100644 index 000000000..56f467df2 --- /dev/null +++ b/gnu/javax/crypto/keyring/IKeyring.java @@ -0,0 +1,164 @@ +/* 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; + +/** + * <p>The top-level interface to a <i>keyring:</i> a file that is used to + * store and protect public and private cryptographic keys.</p> + * + * <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> + * + * <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.</p> + */ +public interface IKeyring +{ + + /** + * <p>Property name for the source of data to load the keyring from. The + * value mapped must be a {@link java.io.InputStream}.</p> + */ + public static final String KEYRING_DATA_IN = "gnu.crypto.keyring.data.in"; + + /** + * <p>Property name for the data sink to store the keyring to. The value + * mapped must be a {@link java.io.OutputStream}.</p> + */ + public static final String KEYRING_DATA_OUT = "gun.crypto.keyring.data.out"; + + /** + * <p>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.</p> + */ + public static final String KEYRING_PASSWORD = "gnu.crypto.keyring.password"; + + /** + * <p>Loads a keyring into memory.</p> + * + * <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?</p> + * + * @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; + + /** + * <p>Stores the contents of this keyring to persistent storage as specified + * by the designated <code>attributes</code>.</p> + * + * @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; + + /** + * <p>Resets this keyring, clearing all sensitive data. This method always + * suceeds.</p> + */ + void reset(); + + /** + * <p>Returns the number of entries in this keyring.</p> + * + * @return The number of current entries in this keyring. + */ + int size(); + + /** + * <p>Returns an {@link Enumeration} of all aliases (instances of + * {@link String}) in this keyring.</p> + * + * @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); + + /** + * <p>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.</p> + * + * @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); + + /** + * <p>Adds a designated {@link Entry} to this keyring.</p> + * + * <p>What happens if there is already an entry with the same alias?</p> + * + * @param entry The entry to put in this keyring. + */ + void add(Entry entry); + + /** + * <p>Removes an entry with the designated <code>alias</code> from this + * keyring. Does nothing if there was no such entry.</p> + * + * <p>What happens if there are more than one?</p> + * + * @param alias The alias of the entry to remove. + */ + void remove(String alias); +} diff --git a/gnu/javax/crypto/keyring/IPrivateKeyring.java b/gnu/javax/crypto/keyring/IPrivateKeyring.java new file mode 100644 index 000000000..66bbd84f5 --- /dev/null +++ b/gnu/javax/crypto/keyring/IPrivateKeyring.java @@ -0,0 +1,142 @@ +/* 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; + +/** + * <p>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> + * + * <p>What about public keys? and certificate-path?</p> + */ +public interface IPrivateKeyring extends IKeyring +{ + + /** + * <p>Tests if this keyring contains a private key entry with the given + * <code>alias</code>.</p> + * + * @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.</p> + */ + boolean containsPrivateKey(String alias); + + /** + * <p>Returns the private key with the given <code>alias</code>.</p> + * + * @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; + + /** + * <p>Adds a private key to this keyring.</p> + * + * @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); + + /** + * <p>Checks if this keyring contains a public key with the given + * <code>alias</code>.</p> + * + * @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); + + /** + * <p>Returns the public key with the given <code>alias</code>, or + * <code>null</code> if there is no such entry.</p> + * + * @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); + + /** + * <p>Sets a public key entry.</p> + * + * @param alias The alias for this public key. + * @param key The public key. + */ + void putPublicKey(String alias, PublicKey key); + + /** + * <p>Checks if this keyring contains a certificate path with the given + * <code>alias</code>.</p> + * + * @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); + + /** + * <p>Returns the certificate path with the given <code>alias</code>, or + * <code>null</code> if there is no such entry.</p> + * + * @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); + + /** + * <p>Sets a certificate path entry.</p> + * + * @param alias The alias for this certificate path. + * @param path The certificate path. + */ + void putCertPath(String alias, Certificate[] path); +} diff --git a/gnu/javax/crypto/keyring/IPublicKeyring.java b/gnu/javax/crypto/keyring/IPublicKeyring.java new file mode 100644 index 000000000..ccf9ca73b --- /dev/null +++ b/gnu/javax/crypto/keyring/IPublicKeyring.java @@ -0,0 +1,81 @@ +/* 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; + +/** + * <p>An interface for keyrings that contain trusted (by the owner) public + * credentials (incl. certificates).</p> + * + * @see IKeyring + */ +public interface IPublicKeyring extends IKeyring +{ + + /** + * <p>Tests if this keyring contains a certificate entry with the specified + * <code>alias</code>.</p> + * + * @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); + + /** + * <p>Returns a certificate that has the given <code>alias</code>, or + * <code>null</code> if this keyring has no such entry.</p> + * + * @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); + + /** + * <p>Adds a certificate in this keyring, with the given <code>alias</code>.</p> + * + * <p>What happens if there is already a certificate entry with this alias?</p> + * + * @param alias The alias of this certificate entry. + * @param cert The certificate. + */ + void putCertificate(String alias, Certificate cert); +} diff --git a/gnu/javax/crypto/keyring/MalformedKeyringException.java b/gnu/javax/crypto/keyring/MalformedKeyringException.java new file mode 100644 index 000000000..44c953946 --- /dev/null +++ b/gnu/javax/crypto/keyring/MalformedKeyringException.java @@ -0,0 +1,58 @@ +/* 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 +{ + + // Constructors. + // ------------------------------------------------------------------------ + + public MalformedKeyringException() + { + super(); + } + + public MalformedKeyringException(String msg) + { + super(msg); + } +} diff --git a/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java b/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java new file mode 100644 index 000000000..7fed7c40c --- /dev/null +++ b/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java @@ -0,0 +1,148 @@ +/* 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 +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The masked state. */ + protected boolean masked; + + // Constructors. + // ------------------------------------------------------------------------ + + public MaskableEnvelopeEntry(int type, Properties properties) + { + super(type, properties); + } + + protected MaskableEnvelopeEntry(int type) + { + super(type); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * 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 void remove(String alias) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + super.remove(alias); + } +} diff --git a/gnu/javax/crypto/keyring/MeteredInputStream.java b/gnu/javax/crypto/keyring/MeteredInputStream.java new file mode 100644 index 000000000..fcf2be746 --- /dev/null +++ b/gnu/javax/crypto/keyring/MeteredInputStream.java @@ -0,0 +1,137 @@ +/* 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.InputStream; +import java.io.IOException; + +final class MeteredInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------ + + private int count; + + private final int limit; + + // Constructor. + // ------------------------------------------------------------------------ + + MeteredInputStream(InputStream in, int limit) + { + super(in); + if (limit < 0) + throw new IllegalArgumentException("limit must be nonnegative"); + this.limit = limit; + count = 0; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * 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; + } +} diff --git a/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java b/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java new file mode 100644 index 000000000..2e3a0d145 --- /dev/null +++ b/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java @@ -0,0 +1,285 @@ +/* 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.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +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.security.SecureRandom; +import java.util.Arrays; +import java.util.Iterator; +import java.util.HashMap; + +/** + * <p>An entry authenticated with a password-based MAC.</p> + */ +public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int TYPE = 3; + + // Constructor(s) + // ------------------------------------------------------------------------- + + 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); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + public void verify(char[] password) + { + if (!isMasked() || payload == null) + { + return; + } + IMac m = null; + try + { + m = getMac(password); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.toString()); + } + + 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 + { + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + payload, + 0, + payload.length + - m.macSize())); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + setMasked(false); + payload = null; + } + + public void authenticate(char[] password) throws IOException + { + if (isMasked()) + { + throw new IllegalStateException("entry is masked"); + } + byte[] salt = new byte[8]; + new SecureRandom ().nextBytes (salt); + 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(); + entry.encode(out2); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + authenticate(password); + encode(out); + } + + protected void encodePayload(DataOutputStream out) throws IOException + { + if (payload == null) + { + throw new IllegalStateException("mac not computed"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private IMac getMac(char[] password) throws MalformedKeyringException + { + if (!properties.containsKey("salt")) + { + throw new MalformedKeyringException("no salt"); + } + byte[] salt = Util.toBytesFromString(properties.get("salt")); + IMac mac = MacFactory.getInstance(properties.get("mac")); + if (mac == null) + { + throw new MalformedKeyringException("no such mac: " + + properties.get("mac")); + } + int keylen = mac.macSize(); + int maclen = 0; + if (!properties.containsKey("maclen")) + { + throw new MalformedKeyringException("no MAC length"); + } + try + { + maclen = Integer.parseInt(properties.get("maclen")); + } + 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); + + 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, new Integer(maclen)); + try + { + mac.init(macAttr); + } + catch (InvalidKeyException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + return mac; + } +} diff --git a/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java b/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java new file mode 100644 index 000000000..26b4032bd --- /dev/null +++ b/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java @@ -0,0 +1,301 @@ +/* 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.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.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.security.SecureRandom; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; + +/** + * An envelope that is encrypted with a password-derived key. + */ +public class PasswordEncryptedEntry extends MaskableEnvelopeEntry implements + PasswordProtectedEntry, Registry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 1; + + // Constructors. + // ------------------------------------------------------------------------ + + 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); + } + + // Class methods. + // ------------------------------------------------------------------------ + + 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; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public void decrypt(char[] password) throws IllegalArgumentException, + WrongPaddingException + { + if (!isMasked() || payload == null) + { + return; + } + IMode mode = getMode(password, IMode.DECRYPTION); + IPad 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); + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + buf, + 0, + buf.length + - padlen)); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + setMasked(false); + payload = null; + } + + public void encrypt(char[] password) throws IOException + { + byte[] salt = new byte[8]; + new SecureRandom ().nextBytes (salt); + 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(); + 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 encode(DataOutputStream out, char[] password) throws IOException + { + encrypt(password); + encode(out); + } + + protected void encodePayload() throws IOException + { + if (payload == null) + { + throw new IllegalStateException("not encrypted"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + 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()); + } + } + IMode mode = ModeFactory.getInstance(properties.get("mode"), cipher, + blockSize); + if (mode == null) + { + throw new IllegalArgumentException("no such mode: " + + properties.get("mode")); + } + + 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, new Integer(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/gnu/javax/crypto/keyring/PasswordProtectedEntry.java b/gnu/javax/crypto/keyring/PasswordProtectedEntry.java new file mode 100644 index 000000000..0dcf73eb8 --- /dev/null +++ b/gnu/javax/crypto/keyring/PasswordProtectedEntry.java @@ -0,0 +1,66 @@ +/* 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 +{ + + // Constant. + // ------------------------------------------------------------------------ + + /** + * The iteration count for password-based KDFs. + */ + Integer ITERATION_COUNT = new Integer(1000); + + // Method. + // ------------------------------------------------------------------------ + + /** + * 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; +} diff --git a/gnu/javax/crypto/keyring/PrimitiveEntry.java b/gnu/javax/crypto/keyring/PrimitiveEntry.java new file mode 100644 index 000000000..4c9ff0ff1 --- /dev/null +++ b/gnu/javax/crypto/keyring/PrimitiveEntry.java @@ -0,0 +1,129 @@ +/* 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 +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The creation date. */ + protected Date creationDate; + + // Constructor. + // ------------------------------------------------------------------------ + + 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(creationDate.getTime())); + } + + protected PrimitiveEntry(int type) + { + super(type); + } + + // Instance method. + // ------------------------------------------------------------------------ + + /** + * 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"); + } + } +} diff --git a/gnu/javax/crypto/keyring/PrivateKeyEntry.java b/gnu/javax/crypto/keyring/PrivateKeyEntry.java new file mode 100644 index 000000000..306349915 --- /dev/null +++ b/gnu/javax/crypto/keyring/PrivateKeyEntry.java @@ -0,0 +1,221 @@ +/* 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.DataOutputStream; +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; + +/** + * <p>An immutable class representing a private or secret key entry.</p> + * + * @version $Revision: 1.1 $ + */ +public final class PrivateKeyEntry extends PrimitiveEntry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int TYPE = 7; + + /** The key. */ + private Key key; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Creates a new key entry.</p> + * + * @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); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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"); + entry.key = kf.generatePrivate(new PKCS8EncodedKeySpec( + entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + entry.key = kf.generatePrivate(new PKCS8EncodedKeySpec( + entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + throw new MalformedKeyringException( + "could not decode PKCS#8 key"); + } + } + } + else + { + throw new MalformedKeyringException("unsupported key type " + type); + } + return entry; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns this entry's key.</p> + * + * @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"); + } + } +} diff --git a/gnu/javax/crypto/keyring/Properties.java b/gnu/javax/crypto/keyring/Properties.java new file mode 100644 index 000000000..646b5711d --- /dev/null +++ b/gnu/javax/crypto/keyring/Properties.java @@ -0,0 +1,227 @@ +/* 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 => 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 +{ + + // Field. + // ------------------------------------------------------------------------ + + private HashMap props; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new properties object. + */ + public Properties() + { + props = new HashMap(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * 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(); + } + + // Own methods. + // ------------------------------------------------------------------------ + + private String canonicalize(String key) + { + return key.toLowerCase(); + } +} diff --git a/gnu/javax/crypto/keyring/PublicKeyEntry.java b/gnu/javax/crypto/keyring/PublicKeyEntry.java new file mode 100644 index 000000000..528e70cc6 --- /dev/null +++ b/gnu/javax/crypto/keyring/PublicKeyEntry.java @@ -0,0 +1,192 @@ +/* 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 java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.PublicKey; +import java.security.KeyFactory; +import java.security.spec.X509EncodedKeySpec; + +import java.util.Date; + +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; + +public final class PublicKeyEntry extends PrimitiveEntry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 6; + + private PublicKey key; + + // Constructor. + // ------------------------------------------------------------------------ + + 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); + } + + // Class method. + // ------------------------------------------------------------------------ + + 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; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * 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"); + } + } +} diff --git a/gnu/javax/crypto/mac/BaseMac.java b/gnu/javax/crypto/mac/BaseMac.java new file mode 100644 index 000000000..e5b47a937 --- /dev/null +++ b/gnu/javax/crypto/mac/BaseMac.java @@ -0,0 +1,144 @@ +/* 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.util.Map; +import java.security.InvalidKeyException; + +/** + * <p>A base abstract class to facilitate <i>MAC</i> (Message Authentication + * Code) implementations.</p> + */ +public abstract class BaseMac implements IMac +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + /** The authentication key for this instance. */ + // protected transient byte[] K; + // Constructor(s) + // ------------------------------------------------------------------------- + /** + * <p>Trivial constructor for use by concrete subclasses.</p> + * + * @param name the canonical name of this instance. + */ + protected BaseMac(String name) + { + super(); + + this.name = name; + } + + /** + * <p>Trivial constructor for use by concrete subclasses.</p> + * + * @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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.mac.IMac interface implementation ---------------------------- + + 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 + { + return super.clone(); + } + + // methods to be implemented by concrete subclasses ------------------------ + + public abstract void init(Map attributes) throws InvalidKeyException, + IllegalStateException; + + public abstract byte[] digest(); + + public abstract boolean selfTest(); +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/HMac.java b/gnu/javax/crypto/mac/HMac.java new file mode 100644 index 000000000..f8f2e317d --- /dev/null +++ b/gnu/javax/crypto/mac/HMac.java @@ -0,0 +1,313 @@ +/* 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; + +/** + * <p>The implementation of the <i>HMAC</i> (Keyed-Hash Message Authentication + * Code).</p> + * + * <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</p> + * + * <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:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial constructor for use by concrete subclasses.</p> + * + * @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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in BaseMac --------------------------- + + 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++) + { + // underlyingHash.update((byte)(K[i] ^ IPAD_BYTE)); + 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(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/HMacFactory.java b/gnu/javax/crypto/mac/HMacFactory.java new file mode 100644 index 000000000..156e6ced5 --- /dev/null +++ b/gnu/javax/crypto/mac/HMacFactory.java @@ -0,0 +1,128 @@ +/* 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; + +/** + * <p>A <i>Factory</i> to instantiate Keyed-Hash Message Authentication Code + * (HMAC) algorithm instances.</p> + */ +public class HMacFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + private HMacFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>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}.</p> + * + * @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); + } + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/IMac.java b/gnu/javax/crypto/mac/IMac.java new file mode 100644 index 000000000..c4170c42c --- /dev/null +++ b/gnu/javax/crypto/mac/IMac.java @@ -0,0 +1,197 @@ +/* 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.util.Map; +import java.security.InvalidKeyException; + +/** + * <p>The basic visible methods of any MAC (Message Authentication Code) + * algorithm.</p> + * + * <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> + * + * <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> + * + * <p>With <i>UMAC</i>s, the sender and receiver share a common secret key (the + * <i>MAC</i> key) which determines:</p> + * + * <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:</p> + * + * <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 +{ + + // Constants + // ------------------------------------------------------------------------- + + /** + * 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"; + + /** + * <p>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> + * + * <p>This implementation, follows the recommendation of the <i>RFC 2104</i> + * authors; specifically:</p> + * + * <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"; + + // Methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the canonical name of this algorithm.</p> + * + * @return the canonical name of this algorithm. + */ + String name(); + + /** + * <p>Returns the output length in bytes of this <i>MAC</i> algorithm.</p> + * + * @return the output length in bytes of this <i>MAC</i> algorithm. + */ + int macSize(); + + /** + * <p>Initialises the algorithm with designated attributes. Permissible names + * and values are described in the class documentation above.</p> + * + * @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; + + /** + * <p>Continues a <i>MAC</i> operation using the input byte.</p> + * + * @param b the input byte to digest. + */ + void update(byte b); + + /** + * <p>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.</p> + * + * @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); + + /** + * <p>Completes the <i>MAC</i> by performing final operations such as + * padding and resetting the instance.</p> + * + * @return the array of bytes representing the <i>MAC</i> value. + */ + byte[] digest(); + + /** + * <p>Resets the algorithm instance for re-initialisation and use with other + * characteristics. This method always succeeds.</p> + */ + void reset(); + + /** + * <p>A basic test. Ensures that the MAC of a pre-determined message is equal + * to a known pre-computed value.</p> + * + * @return <code>true</code> if the implementation passes a basic self-test. + * Returns <code>false</code> otherwise. + */ + boolean selfTest(); + + /** + * <p>Returns a clone copy of this instance.</p> + * + * @return a clone copy of this instance. + */ + Object clone() throws CloneNotSupportedException; +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/MacFactory.java b/gnu/javax/crypto/mac/MacFactory.java new file mode 100644 index 000000000..d8f8bcfce --- /dev/null +++ b/gnu/javax/crypto/mac/MacFactory.java @@ -0,0 +1,164 @@ +/* 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; + +/** + * <p>A <i>Factory</i> that instantiates instances of every supported Message + * Authentication Code algorithms, including all <i>HMAC</i> algorithms.</p> + */ +public class MacFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + private MacFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a <i>MAC</i> algorithm given its name.</p> + * + * @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(); + } + // else if (name.equalsIgnoreCase(TMMH32)) { + // result = new TMMH32(); + // } + + if (result != null && !result.selfTest()) + { + throw new InternalError(result.name()); + } + + return result; + } + + /** + * <p>Returns a {@link java.util.Set} of names of <i>MAC</i> algorithms + * supported by this <i>Factory</i>.</p> + * + * @return a {@link java.util.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); + // hs.add(TMMH32); + + for (Iterator it = CipherFactory.getNames().iterator(); it.hasNext();) + { + hs.add(OMAC_PREFIX + it.next()); + } + + names = Collections.unmodifiableSet(hs); + } + } + return names; + } + + private static Set names; + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/MacInputStream.java b/gnu/javax/crypto/mac/MacInputStream.java new file mode 100644 index 000000000..9acd18b19 --- /dev/null +++ b/gnu/javax/crypto/mac/MacInputStream.java @@ -0,0 +1,138 @@ +/* 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 +{ + + // Field. + // ------------------------------------------------------------------------ + + /** + * The digesting state. The MAC is updated only if this flag is true. + */ + private boolean digesting; + + /** + * The MAC being updated. + */ + private IMac mac; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * 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; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/MacOutputStream.java b/gnu/javax/crypto/mac/MacOutputStream.java new file mode 100644 index 000000000..a48d25ba3 --- /dev/null +++ b/gnu/javax/crypto/mac/MacOutputStream.java @@ -0,0 +1,140 @@ +/* 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; + +/** + * <p>A filtering output stream that computes a MAC (message authentication + * code) over all data written to the stream.</p> + */ +public class MacOutputStream extends FilterOutputStream +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The digesting state. The MAC is updated only if this flag is true. */ + private boolean digesting; + + /** The MAC being updated. */ + private IMac mac; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the MAC this stream is updating.</p> + * + * @return The MAC. + */ + public IMac getMac() + { + return mac; + } + + /** + * <p>Sets the MAC this stream is updating, which must have already been + * initialized. The argument is not cloned by this method.</p> + * + * @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; + } + + /** + * <p>Turns the digesting state on or off. When off, the MAC will not be + * updated when data is written to the stream.</p> + * + * @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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/OMAC.java b/gnu/javax/crypto/mac/OMAC.java new file mode 100644 index 000000000..c83320a1b --- /dev/null +++ b/gnu/javax/crypto/mac/OMAC.java @@ -0,0 +1,402 @@ +/* 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.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 gnu.javax.crypto.mode.ModeFactory; + +import java.security.InvalidKeyException; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * <p>The One-Key CBC MAC, OMAC. This message authentication code is based on + * a block cipher in CBC mode.</p> + * + * <p>References:</p> + * <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 +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + private static final boolean DEBUG = false; + + private static void debug(String msg) + { + System.out.print(">>> OMAC: "); + System.out.println(msg); + } + + 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; + + // Constructor. + // ------------------------------------------------------------------------ + + public OMAC(IBlockCipher cipher) + { + this.cipher = cipher; + this.name = "OMAC-" + cipher.name(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + 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 (DEBUG) + { + debug("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 (DEBUG) + { + debug("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 (DEBUG) + { + debug("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); + } + + // Own methods. + // ------------------------------------------------------------------------ + + private void process() + { + for (int i = 0; i < blockSize; i++) + { + M[i] = (byte) (M[i] ^ Y[i]); + } + cipher.encryptBlock(M, 0, Y, 0); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/TMMH16.java b/gnu/javax/crypto/mac/TMMH16.java new file mode 100644 index 000000000..82de3aac9 --- /dev/null +++ b/gnu/javax/crypto/mac/TMMH16.java @@ -0,0 +1,378 @@ +/* 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; + +/** + * <p><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> + * + * <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> + * + * <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> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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 + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public TMMH16() + { + super(Registry.TMMH16); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.mac.IMac interface implementation ---------------------------- + + 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(); + } + + // own methods ------------------------------------------------------------- + + /** + * <p>Similar to the same method with one argument, but uses the designated + * random number generator to compute needed keying material.</p> + * + * @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 + } + } + + /** + * <p>Similar to the same method with three arguments, but uses the + * designated random number generator to compute needed keying material.</p> + * + * @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); + } + } + + /** + * <p>Similar to the same method with no arguments, but uses the designated + * random number generator to compute needed keying material.</p> + * + * @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; + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/UHash32.java b/gnu/javax/crypto/mac/UHash32.java new file mode 100644 index 000000000..8abb0255e --- /dev/null +++ b/gnu/javax/crypto/mac/UHash32.java @@ -0,0 +1,957 @@ +/* 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; + +/** + * <p><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> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public UHash32() + { + super("uhash32"); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @param that the instance to clone. + */ + private UHash32(UHash32 that) + { + this(); + + this.streams = that.streams; + if (that.l1hash != null) + { + // this.l1hash = new L1Hash32[that.l1hash.length]; + this.l1hash = new L1Hash32[that.streams]; + // for (int i = 0; i < that.l1hash.length; i++) { + for (int i = 0; i < that.streams; i++) + { + if (that.l1hash[i] != null) + { + this.l1hash[i] = (L1Hash32) that.l1hash[i].clone(); + } + } + } + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>The prime numbers used in UMAC are:</p> + * <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) + ")"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new UHash32(this); + } + + // gnu.crypto.mac.IMac interface implementation ---------------------------- + + 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, new Integer(0)); + kdf1.init(map); + map.put(UMacGenerator.INDEX, new Integer(1)); + kdf2.init(map); + map.put(UMacGenerator.INDEX, new Integer(2)); + kdf3.init(map); + map.put(UMacGenerator.INDEX, new Integer(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; + } + + // helper methods ---------------------------------------------------------- + + // Inner classes + // ========================================================================= + + /** + * First hash stage of the UHash32 algorithm. + */ + class L1Hash32 implements Cloneable + { + + // Constants and variables + // ---------------------------------------------------------------------- + + 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 byte[] y; + private long totalCount; + + private L2Hash32 l2hash; + + private L3Hash32 l3hash; + + // Constructor(s) + // ---------------------------------------------------------------------- + + /** 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; + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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(); + } + } + + // Class methods + // ---------------------------------------------------------------------- + + // Instance methods + // ---------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ------------------------- + + public Object clone() + { + return new L1Hash32(this); + } + + // other instance methods ----------------------------------------------- + + 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(); + } + } + + // helper methods ------------------------------------------------------- + + /** + * 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 }; + } + } + + // ========================================================================= + + /** + * <p>Second hash stage of the UHash32 algorithm.</p> + * + * 5.4 L2-HASH-32: Second-layer hash.<p> + * <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 + { + + // Constants and variables + // ---------------------------------------------------------------------- + + private BigInteger k64, k128; + + private BigInteger y; + + private boolean highBound; + + private long bytesSoFar; + + private ByteArrayOutputStream buffer; + + // Constructor(s) + // ---------------------------------------------------------------------- + + 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); + } + } + + // Class methods + // ---------------------------------------------------------------------- + + // Instance methods + // ---------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ------------------------- + + public Object clone() + { + return new L2Hash32(this); + } + + // other instance methods ----------------------------------------------- + + // 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(); + } + } + + // helper methods ------------------------------------------------------- + + 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 + // int wordbytes = wordbits / 8; + + 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; + } + // } + + // return y; + } + } + + // ========================================================================= + + /** + * Third hash stage of the UHash32 algorithm. + * + * Input: + * K1 string of length 64 bytes. + * K2 string of length 4 bytes. + * M string of length 16 bytes. + * Returns: + * Y, string of length 4 bytes. + */ + class L3Hash32 implements Cloneable + { + + // Constants and variables + // ---------------------------------------------------------------------- + + private static final long PRIME_36 = 0x0000000FFFFFFFFBL; + + private int[] k = new int[9]; + + // Constructor(s) + // ---------------------------------------------------------------------- + + /** + * + * @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 + // int i = 0; + // for (int j = 0; i < 8; ) { + 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[i] = (int) (kk % PRIME_36); + } + // k[i] = K2[0] << 24 | (K2[1] & 0xFF) << 16 | (K2[2] & 0xFF) << 8 | (K2[3] & 0xFF); + k[8] = K2[0] << 24 | (K2[1] & 0xFF) << 16 | (K2[2] & 0xFF) << 8 + | (K2[3] & 0xFF); + } + + private L3Hash32(int[] k) + { + super(); + + this.k = k; + } + + // Class methods + // ---------------------------------------------------------------------- + + // Instance methods + // ---------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ------------------------- + + public Object clone() + { + return new L3Hash32((int[]) k.clone()); + } + + // other instance methods ----------------------------------------------- + + /** + * @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 }; + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mac/UMac32.java b/gnu/javax/crypto/mac/UMac32.java new file mode 100644 index 000000000..d20d4f4a9 --- /dev/null +++ b/gnu/javax/crypto/mac/UMac32.java @@ -0,0 +1,491 @@ +/* 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; + +/** + * <p>The implementation of the <i>UMAC</i> (Universal Message Authentication + * Code).</p> + * + * <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> + * + * <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> + * + * <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</p> + * + * <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> + * + * <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> + * + * <p>For the pseudorandom function we use the block cipher of the <i>Advanced + * Encryption Standard</i> (AES).</p> + * + * <p>The UMAC32 parameters, considered in this implementation are:</p> + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public UMac32() + { + super("umac32"); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new UMac32(this); + } + + // gnu.crypto.mac.IMac interface implementation ---------------------------- + + public int macSize() + { + return OUTPUT_LEN; + } + + /** + * <p>Initialising a <i>UMAC</i> instance consists of defining values for + * the following parameters:</p> + * + * <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.</p> + * + * <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.</p> + * + * @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(); + // System.out.println("UMAC test vector: "+Util.toString(result)); + valid = new Boolean(TV1.equals(Util.toString(result))); + } + return valid.booleanValue(); + } + + // helper methods ---------------------------------------------------------- + + /** + * + * @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(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(128/8)); + map.put(UMacGenerator.INDEX, new Integer(128)); + // map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/BaseMode.java b/gnu/javax/crypto/mode/BaseMode.java new file mode 100644 index 000000000..0a9ab2dab --- /dev/null +++ b/gnu/javax/crypto/mode/BaseMode.java @@ -0,0 +1,352 @@ +/* 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; + +/** + * <p>A basic abstract class to facilitate implementing block cipher modes of + * operations.</p> + */ +public abstract class BaseMode implements IMode +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial constructor for use by concrete subclasses.</p> + * + * @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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IMode interface implementation ------------------------------------------ + + 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(); + } + } + } + + // IBlockCipher interface implementation ----------------------------------- + + public String name() + { + return new StringBuffer().append(name).append('(').append(cipher.name()).append( + ')').toString(); + } + + /** + * <p>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.</p> + * + * @return the default value, in bytes, of the mode's block size. + * @see gnu.crypto.mode.ModeFactory + */ + public int defaultBlockSize() + { + return cipherBlockSize; + } + + /** + * <p>Returns the default value, in bytes, of the underlying block cipher + * key size.</p> + * + * @return the default value, in bytes, of the underlying cipher's key size. + */ + public int defaultKeySize() + { + return cipher.defaultKeySize(); + } + + /** + * <p>Returns an {@link Iterator} over the supported block sizes. Each + * element returned by this object is an {@link Integer}.</p> + * + * <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.</p> + * + * @return an {@link Iterator} over the supported block sizes. + */ + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(cipherBlockSize)); + + return Collections.unmodifiableList(al).iterator(); + } + + /** + * <p>Returns an {@link Iterator} over the supported underlying block cipher + * key sizes. Each element returned by this object is an instance of + * {@link Integer}.</p> + * + * @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; + } + + // methods to be implemented by concrete subclasses ------------------------ + + 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); + + // own methods ------------------------------------------------------------- + + 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, new Integer(cipherBlockSize)); + map.put(STATE, new Integer(ENCRYPTION)); + map.put(IV, iv); + map.put(MODE_BLOCK_SIZE, new Integer(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, new Integer(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; + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/CBC.java b/gnu/javax/crypto/mode/CBC.java new file mode 100644 index 000000000..10578a6ef --- /dev/null +++ b/gnu/javax/crypto/mode/CBC.java @@ -0,0 +1,143 @@ +/* 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:</p> + * + * <blockquote><p>C<sub>i</sub> = E<sub>K</sub>(P<sub>i</sub> ^ + * C<sub>i-1</sub></p></blockquote> + * + * <p>Similarly, decrypting is:</p> + * + * <blockquote><p>P<sub>i</sub> = C<sub>i-1</sub> ^ + * D<sub>K</sub>(C<sub>i</sub>)</p></blockquote> + */ +public class CBC extends BaseMode implements Cloneable +{ + + // Constants and Variables + //------------------------------------------------------------------ + + /** The last (de|en)crypted block */ + private byte[] lastBlock; + + /** An intermediate buffer. */ + private byte[] scratch; + + // Constructors + // ----------------------------------------------------------------- + + /** + * 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); + } + + // Cloneable interface implementation + // ----------------------------------------------------------------- + + public Object clone() + { + return new CBC(this); + } + + // Implementation of abstract methods in BaseMode + // ----------------------------------------------------------------- + + 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/CFB.java b/gnu/javax/crypto/mode/CFB.java new file mode 100644 index 000000000..fef2b634c --- /dev/null +++ b/gnu/javax/crypto/mode/CFB.java @@ -0,0 +1,175 @@ +/* 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 <= <i>s</i> <= <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] ^ MSB(s, O[j]) for j = 1,2...n + </pre> + * + * <p>And decryption is:</p> + * + <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] ^ MSB(s, O[j]) for j = 1,2...n + </pre> + * + * <p>CFB mode requires an initialization vector, which need not be kept + * secret.</p> + * + * <p>References:</p> + * <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 +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** The shift register, the input block to the block cipher. */ + private byte[] shiftRegister; + + /** The output block from the block cipher. */ + private byte[] scratch; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * 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); + } + + // Instance methods implementing BaseMode. + // ----------------------------------------------------------------------- + + 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/CTR.java b/gnu/javax/crypto/mode/CTR.java new file mode 100644 index 000000000..49f4b9f3c --- /dev/null +++ b/gnu/javax/crypto/mode/CTR.java @@ -0,0 +1,221 @@ +/* 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.math.BigInteger; +import java.util.Arrays; +import java.util.Iterator; + +/** + * <p>The implementation of the Counter Mode.</p> + * + * <p>The algorithm steps are formally described as follows:</p> + * + * <pre> + * CTR Encryption: O[j] = E(K)(T[j]); for j = 1, 2...n; + * C[j] = P[j] ^ O[j]; for j = 1, 2...n. + * CTR Decryption: O[j] = E(K)(T[j]); for j = 1, 2...n; + * P[j] = C[j] ^ 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> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The current counter. */ + // private BigInteger T; + private int off; + + private byte[] counter, enc; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial package-private constructor for use by the Factory class.</p> + * + * @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); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @param that the instance to clone. + */ + private CTR(CTR that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation + // ------------------------------------------------------------------------- + + public Object clone() + { + return new CTR(this); + } + + // Implementation of abstract methods in BaseMode + // ------------------------------------------------------------------------- + + 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); + // if (modeBlockSize != cipherBlockSize) { + // throw new IllegalArgumentException(); + // } + + // byte[] tBytes = new byte[modeBlockSize+1]; + // tBytes[0] = (byte) 0x80; + // for (int i = 0; i < modeBlockSize; i++) { + // tBytes[i+1] = (byte)(256 - modeBlockSize + i); + // } + + // T = new BigInteger(1, tBytes); + } + + public void teardown() + { + if (counter != null) + { + Arrays.fill(counter, (byte) 0); + } + if (enc != null) + { + Arrays.fill(enc, (byte) 0); + } + // T = null; + } + + 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(); + } + + // own methods + // ------------------------------------------------------------------------- + + private void ctr(byte[] in, int inOffset, byte[] out, int outOffset) + { + // T = T.add(BigInteger.ONE); + // byte[] O = T.toByteArray(); + // int ndx = O.length - modeBlockSize; + // cipher.encryptBlock(O, ndx, O, ndx); + // for (int i = 0; i < modeBlockSize; i++) { + // out[outOffset++] = (byte)(in[inOffset++] ^ O[ndx++]); + // } + 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); + } + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/EAX.java b/gnu/javax/crypto/mode/EAX.java new file mode 100644 index 000000000..bf2609898 --- /dev/null +++ b/gnu/javax/crypto/mode/EAX.java @@ -0,0 +1,352 @@ +/* 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; + +/** + * <p>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:</p> + * <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 +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** 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; + + // Constructor. + // ------------------------------------------------------------------------ + + 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; + } + + // IMode instance methods. + // ------------------------------------------------------------------------ + + 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 = new Integer(cipherBlockSize); + } + HashMap ctrAttr = new HashMap(); + ctrAttr.put(KEY_MATERIAL, key); + ctrAttr.put(IV, N); + ctrAttr.put(STATE, new Integer(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 + } + + // IMac instance methods. + // ------------------------------------------------------------------------ + + 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/ECB.java b/gnu/javax/crypto/mode/ECB.java new file mode 100644 index 000000000..3b33a1848 --- /dev/null +++ b/gnu/javax/crypto/mode/ECB.java @@ -0,0 +1,137 @@ +/* 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; + +/** + * <p>The implementation of the Electronic Codebook mode.</p> + * + * <p>The Electronic Codebook (ECB) mode is a confidentiality mode that is + * defined as follows:</p> + * + * <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> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial package-private constructor for use by the Factory class.</p> + * + * @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); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @param that the mode to clone. + */ + private ECB(ECB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new ECB(this); + } + + // Implementation of abstract methods in BaseMode -------------------------- + + 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/IAuthenticatedMode.java b/gnu/javax/crypto/mode/IAuthenticatedMode.java new file mode 100644 index 000000000..d89c0016d --- /dev/null +++ b/gnu/javax/crypto/mode/IAuthenticatedMode.java @@ -0,0 +1,60 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +public interface IAuthenticatedMode extends IMode, IMac +{ + + // Trivial conjunction of IMode and IMac. +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/ICM.java b/gnu/javax/crypto/mode/ICM.java new file mode 100644 index 000000000..d37908b5d --- /dev/null +++ b/gnu/javax/crypto/mode/ICM.java @@ -0,0 +1,228 @@ +/* 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; + +/** + * <p>An implementation of <i>David McGrew</i> Integer Counter Mode (ICM) as an + * {@link IMode}.</p> + * + * <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> + * + * <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> + * + * <p>For simplicity, this implementation, fixes these two values to the + * following:</p> + * + * <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> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial package-private constructor for use by the Factory class.</p> + * + * @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); + } + + /** + * <p>Private constructor for cloning purposes.<p> + * + * @param that the instance to clone. + */ + private ICM(ICM that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation + // ------------------------------------------------------------------------- + + public Object clone() + { + return new ICM(this); + } + + // Implementation of abstract methods in BaseMode + // ------------------------------------------------------------------------- + + 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); + } + + // Instance methods + // ------------------------------------------------------------------------- + + private void icm(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (blockNdx.compareTo(maxBlocksPerSegment) >= 0) + throw new RuntimeException("Maximum blocks for segment reached"); + + // 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); + byte[] result = Ci.toByteArray(); + int limit = result.length; + // if (limit < cipherBlockSize) { + // byte[] data = new byte[cipherBlockSize]; + // System.arraycopy(result, 0, data, cipherBlockSize-limit, limit); + // result = data; + // } else if (limit > cipherBlockSize) { + // byte[] data = new byte[cipherBlockSize]; + // System.arraycopy(result, limit-cipherBlockSize, data, 0, cipherBlockSize); + // result = data; + // } + // + // cipher.encryptBlock(result, 0, result, 0); + // blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx + // for (int i = 0; i < modeBlockSize; ) { // xor result with input block + // out[outOffset++] = (byte)(in[inOffset++] ^ result[i++]); + // } + 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++]); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/IMode.java b/gnu/javax/crypto/mode/IMode.java new file mode 100644 index 000000000..4cb6ca64b --- /dev/null +++ b/gnu/javax/crypto/mode/IMode.java @@ -0,0 +1,145 @@ +/* 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; + +/** + * <p>The basic visible methods of any block cipher mode.</p> + * + * <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> + * + * <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:</p> + * + * <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:</p> + * + * <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 +{ + + // Constants + // ------------------------------------------------------------------------- + + /** + * <p>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>.</p> + */ + String STATE = "gnu.crypto.mode.state"; + + /** + * <p>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.</p> + */ + String MODE_BLOCK_SIZE = "gnu.crypto.mode.block.size"; + + /** + * <p>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.</p> + */ + String IV = "gnu.crypto.mode.iv"; + + /** + * <p>Constant indicating the instance is being used for <i>encryption</i>.</p> + */ + int ENCRYPTION = 1; + + /** + * <p>Constant indicating the instance is being used for <i>decryption</i>.</p> + */ + int DECRYPTION = 2; + + // Methods + // ------------------------------------------------------------------------- + + /** + * <p>A convenience method. Effectively invokes the <code>encryptBlock()</code> + * or <code>decryptBlock()</code> method depending on the operational state + * of the instance.</p> + * + * @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; +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/ModeFactory.java b/gnu/javax/crypto/mode/ModeFactory.java new file mode 100644 index 000000000..0e949ed9e --- /dev/null +++ b/gnu/javax/crypto/mode/ModeFactory.java @@ -0,0 +1,192 @@ +/* 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; + +/** + * <p>A <i>Factory</i> to instantiate block cipher modes of operations.</p> + */ +public class ModeFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private ModeFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a block cipher mode of operations given its name + * and characteristics of the underlying block cipher.</p> + * + * @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; + } + + /** + * <p>Returns a {@link java.util.Set} of names of mode supported by this + * <i>Factory</i>.</p> + * + * @return a {@link java.util.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; + } + + private static Set names; + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/mode/OFB.java b/gnu/javax/crypto/mode/OFB.java new file mode 100644 index 000000000..68065d10b --- /dev/null +++ b/gnu/javax/crypto/mode/OFB.java @@ -0,0 +1,194 @@ +/* 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; + +/** + * <p>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:</p> + * + * <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> + * + * <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> + * + * <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> + * + * <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> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private byte[] outputBlock; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial package-private constructor for use by the Factory class.</p> + * + * @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); + } + + /** + * <p>Private constructor for cloning purposes.</p> + * + * @param that the mode to clone. + */ + private OFB(OFB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new OFB(this); + } + + // Implementation of abstract methods in BaseMode -------------------------- + + 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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/pad/BasePad.java b/gnu/javax/crypto/pad/BasePad.java new file mode 100644 index 000000000..49c5d050a --- /dev/null +++ b/gnu/javax/crypto/pad/BasePad.java @@ -0,0 +1,153 @@ +/* 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; + +/** + * <p>An abstract class to facilitate implementing padding algorithms.</p> + */ +public abstract class BasePad implements IPad +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name prefix of the padding algorithm. */ + protected String name; + + /** The block size, in bytes, for this instance. */ + protected int blockSize; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor for use by concrete subclasses. */ + protected BasePad(final String name) + { + super(); + + this.name = name; + blockSize = -1; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IPad interface implementation ------------------------------------------- + + 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(); + } + + public void reset() + { + blockSize = -1; + } + + public boolean selfTest() + { + byte[] padBytes; + final int offset = 5; + final int limit = 1024; + final byte[] in = new byte[limit]; + for (int bs = 2; bs < 256; bs++) + { + this.init(bs); + for (int i = 0; i < limit - offset - blockSize; i++) + { + padBytes = pad(in, offset, i); + if (((i + padBytes.length) % blockSize) != 0) + { + new RuntimeException(name()).printStackTrace(System.err); + return false; + } + + System.arraycopy(padBytes, 0, in, offset + i, padBytes.length); + try + { + if (padBytes.length != unpad(in, offset, i + padBytes.length)) + { + new RuntimeException(name()).printStackTrace(System.err); + return false; + } + } + catch (WrongPaddingException x) + { + x.printStackTrace(System.err); + return false; + } + } + this.reset(); + } + + return true; + } + + // abstract methods to implement by subclasses ----------------------------- + + /** + * <p>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.</p> + */ + 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; +}
\ No newline at end of file diff --git a/gnu/javax/crypto/pad/IPad.java b/gnu/javax/crypto/pad/IPad.java new file mode 100644 index 000000000..4b4c925e6 --- /dev/null +++ b/gnu/javax/crypto/pad/IPad.java @@ -0,0 +1,110 @@ +/* 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; + +/** + * <p>The basic visible methods of any padding algorithm.</p> + * + * <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.crypto.mode.IMode} and/or {@link gnu.crypto.cipher.IBlockCipher}.</p> + */ +public interface IPad +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** @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; + + /** + * 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 + * <tt>offset + length</tt> in <i>in</i>. In other words, if the return + * value of a successful invocation of this method is <tt>result</tt>, then + * the unpadded byte sequence will be <tt>offset + length - result</tt> bytes + * in <i>in</i>, starting from index position <tt>offset</tt>. + * @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 <tt>true</tt> if the implementation passes a basic symmetric + * self-test. Returns <tt>false</tt> otherwise. + */ + boolean selfTest(); +}
\ No newline at end of file diff --git a/gnu/javax/crypto/pad/PKCS1_V1_5.java b/gnu/javax/crypto/pad/PKCS1_V1_5.java new file mode 100644 index 000000000..5b4f7b850 --- /dev/null +++ b/gnu/javax/crypto/pad/PKCS1_V1_5.java @@ -0,0 +1,184 @@ +/* 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.Registry; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; +import gnu.java.security.util.Util; + +import java.io.PrintWriter; +import java.util.Random; + +/** + * <p>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> + * + * <p>References:</p> + * <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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = Registry.EME_PKCS1_V1_5_PAD; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(final String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private EME_PKCS1_V1_5 codec; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Trivial package-private constructor for use by the <i>Factory</i> class. + * </p> + * + * @see gnu.crypto.pad.PadFactory + */ + PKCS1_V1_5() + { + super(Registry.EME_PKCS1_V1_5_PAD); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePad + // ------------------------------------------------------------------------- + + 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 (DEBUG && debuglevel > 8) + { + debug("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 (DEBUG && debuglevel > 8) + { + debug("padding length: " + String.valueOf(result)); + } + return result; + } + + // overloaded methods ------------------------------------------------------ + + public boolean selfTest() + { + final int[] mLen = new int[] { 16, 20, 32, 48, 64 }; + final byte[] M = new byte[mLen[mLen.length - 1]]; + new Random ().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) + { + new RuntimeException(name()).printStackTrace(System.err); + 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)) + { + new RuntimeException(name()).printStackTrace(System.err); + return false; + } + } + catch (WrongPaddingException x) + { + x.printStackTrace(System.err); + return false; + } + } + reset(); + } + + return true; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/pad/PKCS7.java b/gnu/javax/crypto/pad/PKCS7.java new file mode 100644 index 000000000..5697aff27 --- /dev/null +++ b/gnu/javax/crypto/pad/PKCS7.java @@ -0,0 +1,149 @@ +/* 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.Registry; +import gnu.java.security.util.Util; + +import java.io.PrintWriter; + +/** + * <p>The implementation of the PKCS7 padding algorithm.</p> + * + * <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:<br> + * <a href="http://www.ietf.org/rfc/rfc1423.txt">RFC-1423</a>: Privacy + * Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and + * Identifiers.<br> + * <a href="http://www.ietf.org/">IETF</a>. + * <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-7/">[PKCS-7]</a>PKCS #7: + * Cryptographic Message Syntax Standard - An RSA Laboratories Technical Note.<br> + * <a href="http://www.rsasecurity.com/">RSA Security</a>.<p> + */ +public final class PKCS7 extends BasePad +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "pkcs7"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial package-private constructor for use by the <i>Factory</i> class.<p> + * + * @see gnu.crypto.pad.PadFactory + */ + PKCS7() + { + super(Registry.PKCS7_PAD); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePad + // ------------------------------------------------------------------------- + + 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 (DEBUG && debuglevel > 8) + { + debug("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 - 1] & 0xFF; + for (int i = 0; i < result; i++) + { + if (result != (in[--limit] & 0xFF)) + { + throw new WrongPaddingException(); + } + } + + if (DEBUG && debuglevel > 8) + { + debug("padding length: " + String.valueOf(result)); + } + return result; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/pad/PadFactory.java b/gnu/javax/crypto/pad/PadFactory.java new file mode 100644 index 000000000..e122719b6 --- /dev/null +++ b/gnu/javax/crypto/pad/PadFactory.java @@ -0,0 +1,136 @@ +/* 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; + +/** + * <p>A Factory to instantiate padding schemes.</p> + */ +public class PadFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private PadFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a padding algorithm given its name.</p> + * + * @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)) + { + 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(); + } + + if (result != null && !result.selfTest()) + { + throw new InternalError(result.name()); + } + + return result; + } + + /** + * <p>Returns a {@link java.util.Set} of names of padding algorithms + * supported by this <i>Factory</i>.</p> + * + * @return a {@link Set} of padding algorithm names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(PKCS7_PAD); + hs.add(TBC_PAD); + hs.add(EME_PKCS1_V1_5_PAD); + hs.add(SSL3_PAD); + hs.add(TLS1_PAD); + + return Collections.unmodifiableSet(hs); + } + + // Instance methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/pad/SSL3.java b/gnu/javax/crypto/pad/SSL3.java new file mode 100644 index 000000000..25aeefa13 --- /dev/null +++ b/gnu/javax/crypto/pad/SSL3.java @@ -0,0 +1,98 @@ +/* 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.</p> + */ +public class SSL3 extends BasePad +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public SSL3() + { + super("ssl3"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/pad/TBC.java b/gnu/javax/crypto/pad/TBC.java new file mode 100644 index 000000000..25c3e4286 --- /dev/null +++ b/gnu/javax/crypto/pad/TBC.java @@ -0,0 +1,156 @@ +/* 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.Registry; +import gnu.java.security.util.Util; + +import java.io.PrintWriter; + +/** + * <p>The implementation of the Trailing Bit Complement (TBC) padding algorithm.</p> + * + * <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:<br> + * <a href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf"> + * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>, + * Morris Dworkin.<p> + */ +public final class TBC extends BasePad +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "tbc"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial package-private constructor for use by the <i>Factory</i> class.<p> + * + * @see gnu.crypto.pad.PadFactory + */ + TBC() + { + super(Registry.TBC_PAD); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePad + // ------------------------------------------------------------------------- + + 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 (DEBUG && debuglevel > 8) + { + debug("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 (DEBUG && debuglevel > 8) + { + debug("padding length: " + String.valueOf(result)); + } + return result; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/pad/TLS1.java b/gnu/javax/crypto/pad/TLS1.java new file mode 100644 index 000000000..00a538f88 --- /dev/null +++ b/gnu/javax/crypto/pad/TLS1.java @@ -0,0 +1,105 @@ +/* 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; + +import gnu.java.security.util.Util; + +/** + * 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>.</p> + */ +public class TLS1 extends BasePad +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public TLS1() + { + super("tls1"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/pad/WrongPaddingException.java b/gnu/javax/crypto/pad/WrongPaddingException.java new file mode 100644 index 000000000..cc74dfb26 --- /dev/null +++ b/gnu/javax/crypto/pad/WrongPaddingException.java @@ -0,0 +1,63 @@ +/* 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; + +/** + * <p>A checked exception that indicates that a padding algorithm did not find the + * expected padding bytes when unpadding some data.</p> + * + * @version $Revision: 1.1 $ + */ +public class WrongPaddingException extends Exception +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instant methods + // ------------------------------------------------------------------------- +}
\ No newline at end of file diff --git a/gnu/javax/crypto/prng/ARCFour.java b/gnu/javax/crypto/prng/ARCFour.java new file mode 100644 index 000000000..22316ec8b --- /dev/null +++ b/gnu/javax/crypto/prng/ARCFour.java @@ -0,0 +1,161 @@ +/* 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:</p> + * + * <pre> out = in ^ arcfour.nextByte();</pre> + * + * <p>This operation works for encryption and decryption.</p> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** 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; + + // Constructors. + // ----------------------------------------------------------------------- + + /** Default 0-arguments constructor. */ + public ARCFour() + { + super(Registry.ARCFOUR_PRNG); + } + + // Methods implementing BasePRNG. + // ----------------------------------------------------------------------- + + 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]; + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/prng/CSPRNG.java b/gnu/javax/crypto/prng/CSPRNG.java new file mode 100644 index 000000000..197009232 --- /dev/null +++ b/gnu/javax/crypto/prng/CSPRNG.java @@ -0,0 +1,1268 @@ +/* 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.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.ArrayList; +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; + +/** + * <p>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> + * + * <p>The basic properties of this generator are:</p> + * + * <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 +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + + private static void debug(String msg) + { + System.err.print(">>> CSPRNG: "); + System.err.println(msg); + } + + /** + * 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.crypto.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; + + // Constructor. + // ------------------------------------------------------------------------- + + 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(); + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * <p>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> + * + * <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> + * + * <p>The following vales for <i>name</i> are used here:</p> + * + * <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> + * + * <p>An example of valid properties would be:</p> + * + * <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, new Boolean(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); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + return new CSPRNG(); + } + + public void setup(Map attrib) + { + List list = null; + + if (DEBUG) + { + debug(String.valueOf(attrib)); + } + try + { + list = (List) attrib.get(FILE_SOURCES); + if (DEBUG) + { + debug(String.valueOf(list)); + } + if (list != null) + { + files.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (DEBUG) + { + debug("l=" + l); + } + if (l.size() != 4) + { + if (DEBUG) + { + debug("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 (DEBUG) + { + debug("bad file list: " + cce.getMessage()); + cce.printStackTrace(); + } + throw new IllegalArgumentException("invalid file list"); + } + + try + { + list = (List) attrib.get(URL_SOURCES); + if (DEBUG) + { + debug(String.valueOf(list)); + } + if (list != null) + { + urls.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (DEBUG) + { + debug("l=" + l); + } + if (l.size() != 4) + { + if (DEBUG) + { + debug("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 (DEBUG) + { + debug("bad URL list: " + cce.getMessage()); + cce.printStackTrace(); + } + throw new IllegalArgumentException("invalid URL list"); + } + + try + { + list = (List) attrib.get(PROGRAM_SOURCES); + if (DEBUG) + { + debug(String.valueOf(list)); + } + if (list != null) + { + progs.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (DEBUG) + { + debug("l=" + l); + } + if (l.size() != 4) + { + if (DEBUG) + { + debug("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 (DEBUG) + { + debug("bad program list: " + cce.getMessage()); + cce.printStackTrace(); + } + throw new IllegalArgumentException("invalid program list"); + } + + try + { + list = (List) attrib.get(OTHER_SOURCES); + if (DEBUG) + { + debug(String.valueOf(list)); + } + if (list != null) + { + other.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + EntropySource src = (EntropySource) it.next(); + if (DEBUG) + { + debug("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 (DEBUG) + { + debug("fillBlock"); + } + if (getQuality() < 100.0) + { + if (DEBUG) + { + debug("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 (DEBUG) + { + debug("adding random bytes:"); + debug(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 (DEBUG) + { + debug("adding byte " + Integer.toHexString(b)); + } + pool[index++] ^= b; + if (index >= pool.length) + { + mixRandomPool(); + index = 0; + } + } + + // Package methods. + // ------------------------------------------------------------------------- + + synchronized void addQuality(double quality) + { + if (DEBUG) + { + debug("adding quality " + quality); + } + if (this.quality < 100) + { + this.quality += quality; + } + if (DEBUG) + { + debug("quality now " + this.quality); + } + } + + synchronized double getQuality() + { + return quality; + } + + // Own methods. + // ------------------------------------------------------------------------- + + /** + * 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 (DEBUG) + { + debug("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 (DEBUG) + { + debug("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); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * 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 + { + + // Field. + // ----------------------------------------------------------------------- + + private byte counter; + + // Constructor. + // ----------------------------------------------------------------------- + + private Spinner() + { + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void run() + { + while (true) + { + counter++; + try + { + Thread.sleep(100); + } + catch (InterruptedException ie) + { + } + } + } + } + + private final class Poller implements Runnable + { + + // Fields. + // ----------------------------------------------------------------------- + + private final List files; + + private final List urls; + + private final List progs; + + private final List other; + + private final CSPRNG pool; + + private boolean running; + + // Constructor. + // ----------------------------------------------------------------------- + + 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; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void run() + { + running = true; + if (DEBUG) + { + debug("files: " + files); + debug("URLs: " + urls); + debug("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 (DEBUG) + { + debug(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 (DEBUG) + { + debug("got " + len + " bytes from " + src); + } + } + catch (Exception x) + { + if (DEBUG) + { + debug(x.toString()); + x.printStackTrace(); + } + } + } + + if (pool.getQuality() >= 100.0 || !running) + { + return; + } + + if (urls_it.hasNext()) + { + try + { + List l = (List) urls_it.next(); + if (DEBUG) + { + debug(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 (DEBUG) + { + debug("got " + len + " bytes from " + src); + } + } + catch (Exception x) + { + if (DEBUG) + { + debug(x.toString()); + x.printStackTrace(); + } + } + } + + if (pool.getQuality() >= 100.0 || !running) + { + return; + } + + Process proc = null; + if (prog_it.hasNext()) + { + try + { + List l = (List) prog_it.next(); + if (DEBUG) + { + debug(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 (DEBUG) + { + debug("got " + len + " bytes from " + src); + } + } + catch (Exception x) + { + if (DEBUG) + { + debug(x.toString()); + x.printStackTrace(); + } + 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 (DEBUG) + { + debug("got " + buf.length + " bytes from " + src); + } + } + catch (Exception x) + { + if (DEBUG) + { + debug(x.toString()); + x.printStackTrace(); + } + } + } + } + } + + public void stopUpdating() + { + running = false; + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/prng/Fortuna.java b/gnu/javax/crypto/prng/Fortuna.java new file mode 100644 index 000000000..6453a9d02 --- /dev/null +++ b/gnu/javax/crypto/prng/Fortuna.java @@ -0,0 +1,366 @@ +/* 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></p> + * + * <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); + } + + 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); + } + + /** + * 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; + } + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/prng/ICMGenerator.java b/gnu/javax/crypto/prng/ICMGenerator.java new file mode 100644 index 000000000..0de38e256 --- /dev/null +++ b/gnu/javax/crypto/prng/ICMGenerator.java @@ -0,0 +1,379 @@ +/* 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.IBlockCipher; +import gnu.javax.crypto.cipher.CipherFactory; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + * <p>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> + * + * <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> + * + * <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> + * + * <p>The practical limits and constraints of such generator are:</p> + * <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> + * + * <p>References:</p> + * + * <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> + * + * @version $Revision: 1.1 $ + */ +public class ICMGenerator extends BasePRNG implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public ICMGenerator() + { + super(Registry.ICM_PRNG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePRNG -------------------------- + + // 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, new Integer(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 + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/prng/IPBE.java b/gnu/javax/crypto/prng/IPBE.java new file mode 100644 index 000000000..531e7ead8 --- /dev/null +++ b/gnu/javax/crypto/prng/IPBE.java @@ -0,0 +1,69 @@ +/* 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; + +/** + * <p>Trivial interface to group Password-based encryption property names.</p> + * + * @version $Revision: 1.1 $ + */ +public interface IPBE +{ + + // Constants + // ------------------------------------------------------------------------- + + /** + * Property name for the iteration count in a PBE algorithm. The property + * associated with this is expected to be an {@link Integer}. + */ + public static final 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. + */ + public static final String PASSWORD = "gnu.crypto.pbe.password"; + + /** + * Property name for the salt in a PBE algorithm. The property associated + * with this is expected to be a byte array. + */ + public static final String SALT = "gnu.crypto.pbe.salt"; +}
\ No newline at end of file diff --git a/gnu/javax/crypto/prng/PBKDF2.java b/gnu/javax/crypto/prng/PBKDF2.java new file mode 100644 index 000000000..5146bd4b9 --- /dev/null +++ b/gnu/javax/crypto/prng/PBKDF2.java @@ -0,0 +1,216 @@ +/* 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; + +/** + * <p>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> + * + * <p>This version uses a MAC as its pseudo-random function, and the password is + * used as the key.</p> + * + * <p>References:</p> + * <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> + * + * @version $Revision: 1.1 $ + */ +public class PBKDF2 extends BasePRNG implements Cloneable +{ + + // Contstants and variables + // ------------------------------------------------------------------------- + + /** + * 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>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.</p> + * + * @param mac The pseudo-random function. + */ + public PBKDF2(IMac mac) + { + super("PBKDF2-" + mac.name()); + this.mac = mac; + iterationCount = -1; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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; + } + + char[] password = (char[]) attributes.get(IPBE.PASSWORD); + if (password != null) + { + try + { + macAttrib.put(IMac.MAC_KEY_MATERIAL, + new String(password).getBytes("UTF-8")); + } + catch (UnsupportedEncodingException uee) + { + throw new Error(uee.getMessage()); + } + } + else if (!initialised) + { + throw new IllegalArgumentException("no password specified"); + } // otherwise re-use previous password. + + 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 (Exception x) { + } + catch (LimitReachedException x) + { + // x.printStackTrace(System.err); + throw new Error(x.getMessage()); + } + } + + public void fillBlock() throws LimitReachedException + { + if (++count > ((1L << 32) - 1)) + { + throw new LimitReachedException(); + } + // for (int i = 0; i < buffer.length; i++) { + // buffer[i] = 0; + // } + Arrays.fill(buffer, (byte) 0x00); + int limit = salt.length; + // in = new byte[salt.length + 4]; + in = new byte[limit + 4]; + System.arraycopy(salt, 0, in, 0, salt.length); + // in[salt.length ] = (byte)(count >>> 24); + // in[salt.length+1] = (byte)(count >>> 16); + // in[salt.length+2] = (byte)(count >>> 8); + // in[salt.length+3] = (byte) count; + 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]; + } + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/prng/PRNGFactory.java b/gnu/javax/crypto/prng/PRNGFactory.java new file mode 100644 index 000000000..9ff6558b0 --- /dev/null +++ b/gnu/javax/crypto/prng/PRNGFactory.java @@ -0,0 +1,143 @@ +/* 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.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.HMacFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * <p>A Factory to instantiate pseudo random number generators.</p> + */ +public class PRNGFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + private PRNGFactory() + { + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a padding algorithm given its name.</p> + * + * @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); + } + + /** + * <p>Returns a {@link Set} of names of padding algorithms supported by this + * <i>Factory</i>.</p> + * + * @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); + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/javax/crypto/prng/UMacGenerator.java b/gnu/javax/crypto/prng/UMacGenerator.java new file mode 100644 index 000000000..0e3725ce9 --- /dev/null +++ b/gnu/javax/crypto/prng/UMacGenerator.java @@ -0,0 +1,228 @@ +/* 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; + +/** + * <p><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> + * + * <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 java.lang.Integer} with a value between + * <code>0</code> and <code>255</code>). Using the same key, but different + * indices, generates different pseudorandom outputs.</p> + * + * <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 java.lang.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 + * 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> + * + * <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> + * + * <p>References:</p> + * + * <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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * <p>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>.</p> + */ + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public UMacGenerator() + { + super(Registry.UMAC_PRNG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePRNG -------------------------- + + 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, new Integer(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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/AuthInfo.java b/gnu/javax/crypto/sasl/AuthInfo.java new file mode 100644 index 000000000..1e942559d --- /dev/null +++ b/gnu/javax/crypto/sasl/AuthInfo.java @@ -0,0 +1,143 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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(); + if (!"gnu.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); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private AuthInfo() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * 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; + } +} diff --git a/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java b/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java new file mode 100644 index 000000000..6ba5fc562 --- /dev/null +++ b/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java @@ -0,0 +1,89 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-args constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IAuthInfoProviderFactory interface implementation ----------------------- + + 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; + } +} diff --git a/gnu/javax/crypto/sasl/ClientFactory.java b/gnu/javax/crypto/sasl/ClientFactory.java new file mode 100644 index 000000000..ef184632c --- /dev/null +++ b/gnu/javax/crypto/sasl/ClientFactory.java @@ -0,0 +1,210 @@ +/* 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.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.HashMap; + +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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + 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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + 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))); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/ClientMechanism.java b/gnu/javax/crypto/sasl/ClientMechanism.java new file mode 100644 index 000000000..45873ae6b --- /dev/null +++ b/gnu/javax/crypto/sasl/ClientMechanism.java @@ -0,0 +1,365 @@ +/* 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; + +/** + * <p>A base class to facilitate implementing SASL client-side mechanisms.</p> + */ +public abstract class ClientMechanism implements SaslClient +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected ClientMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.state = -1; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods to be implemented by concrete subclasses --------------- + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + // javax.security.sasl.SaslClient interface implementation ----------------- + + 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 + { + } + + // other Instance methods -------------------------------------------------- + + 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; + } + + /** + * <p>Initialises the mechanism with designated attributes. Permissible names + * and values are mechanism specific.</p> + * + * @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; + } + + /** + * <p>Resets the mechanism instance for re-initialisation and use with other + * characteristics.</p> + * + * @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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/ConfidentialityException.java b/gnu/javax/crypto/sasl/ConfidentialityException.java new file mode 100644 index 000000000..561827d8d --- /dev/null +++ b/gnu/javax/crypto/sasl/ConfidentialityException.java @@ -0,0 +1,84 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/IAuthInfoProvider.java b/gnu/javax/crypto/sasl/IAuthInfoProvider.java new file mode 100644 index 000000000..2b913a137 --- /dev/null +++ b/gnu/javax/crypto/sasl/IAuthInfoProvider.java @@ -0,0 +1,117 @@ +/* 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 +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * 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; +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java b/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java new file mode 100644 index 000000000..e630b8da1 --- /dev/null +++ b/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java @@ -0,0 +1,62 @@ +/* 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 +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * 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); +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/IllegalMechanismStateException.java b/gnu/javax/crypto/sasl/IllegalMechanismStateException.java new file mode 100644 index 000000000..94d9269a1 --- /dev/null +++ b/gnu/javax/crypto/sasl/IllegalMechanismStateException.java @@ -0,0 +1,86 @@ +/* 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. + * + * @version $Revision: 1.1 $ + */ +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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/InputBuffer.java b/gnu/javax/crypto/sasl/InputBuffer.java new file mode 100644 index 000000000..a64ea3e0e --- /dev/null +++ b/gnu/javax/crypto/sasl/InputBuffer.java @@ -0,0 +1,339 @@ +/* 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; + +/** + * <p>The implementation of an incoming SASL buffer.</p> + * + * <p>The data elements this class caters for are described in [1].</p> + * + * <p>References:</p> + * <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ïf S. Naffah</a>.</li> + * </ol> + */ +public class InputBuffer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The internal buffer stream containing the buffer's contents. */ + protected ByteArrayInputStream in; + + /** The length of the buffer, according to its header. */ + protected int length; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Constructs a SASL buffer given the buffer's encoded form, including its + * header bytes.</p> + * + * @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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a SASL buffer given the buffer's encoded contents, + * excluding the buffer's header bytes.</p> + * + * <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); + } + + /** + * <p>Returns an instance of a SASL buffer given the buffer's encoded + * contents, excluding the buffer's header bytes.</p> + * + * @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; + } + + /** + * <p>Converts four octets into the number that they represent.</p> + * + * @param b the four octets. + * @return the length. + */ + // public static int fourBytesToLength(byte[] b) throws SaslEncodingException { + // 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 SaslEncodingException("SASL EOS size limit exceeded"); + // } + // return result; + // } + /** + * <p>Converts two octets into the number that they represent.</p> + * + * @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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + public boolean hasMoreElements() + { + return (in.available() > 0); + } + + /** + * <p>Decodes a SASL scalar quantity, <code>count</code>-octet long, from the + * current buffer.</p> + * + * @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; + } + + /** + * <p>Decodes a SASL OS from the current buffer.</p> + * + * @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; + } + + /** + * <p>Decodes a SASL EOS from the current buffer.</p> + * + * @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; + } + + /** + * <p>Decodes a SASL MPI from the current buffer.</p> + * + * @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); + } + + /** + * <p>Decodes a SASL Text from the current buffer.</p> + * + * @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"); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/IntegrityException.java b/gnu/javax/crypto/sasl/IntegrityException.java new file mode 100644 index 000000000..4a56ca2d5 --- /dev/null +++ b/gnu/javax/crypto/sasl/IntegrityException.java @@ -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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/NoSuchMechanismException.java b/gnu/javax/crypto/sasl/NoSuchMechanismException.java new file mode 100644 index 000000000..65432082a --- /dev/null +++ b/gnu/javax/crypto/sasl/NoSuchMechanismException.java @@ -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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/NoSuchUserException.java b/gnu/javax/crypto/sasl/NoSuchUserException.java new file mode 100644 index 000000000..fe362c742 --- /dev/null +++ b/gnu/javax/crypto/sasl/NoSuchUserException.java @@ -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); + } +} diff --git a/gnu/javax/crypto/sasl/OutputBuffer.java b/gnu/javax/crypto/sasl/OutputBuffer.java new file mode 100644 index 000000000..d219e7e9f --- /dev/null +++ b/gnu/javax/crypto/sasl/OutputBuffer.java @@ -0,0 +1,225 @@ +/* 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; + +/** + * <p>The implementation of an outgoing SASL buffer.</p> + * + * <p>The data elements this class caters for are described in [1].</p> + * + * <p>References:</p> + * <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ïf S. Naffah</a>.</li> + * </ol> + */ +public class OutputBuffer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The internal output stream. */ + private ByteArrayOutputStream out; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public OutputBuffer() + { + super(); + + out = new ByteArrayOutputStream(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Encodes a SASL scalar quantity, <code>count</code>-octet long, to the + * current buffer.</p> + * + * @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); + } + + /** + * <p>Encodes a SASL OS to the current buffer.</p> + * + * @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); + } + + /** + * <p>Encodes a SASL EOS to the current buffer.</p> + * + * @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); + } + + /** + * <p>Encodes a SASL MPI to the current buffer.</p> + * + * @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); + } + + /** + * <p>Encodes a SASL Text to the current buffer.</p> + * + * @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); + } + + /** + * <p>Returns the encoded form of the current buffer including the 4-byte + * length header.</p> + * + * @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; + } + + /** + * <p>Returns the encoded form of the current buffer excluding the 4-byte + * length header.</p> + * + * @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(); + } +} diff --git a/gnu/javax/crypto/sasl/SaslEncodingException.java b/gnu/javax/crypto/sasl/SaslEncodingException.java new file mode 100644 index 000000000..9f4c59f1c --- /dev/null +++ b/gnu/javax/crypto/sasl/SaslEncodingException.java @@ -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); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/SaslInputStream.java b/gnu/javax/crypto/sasl/SaslInputStream.java new file mode 100644 index 000000000..57eb2b5c5 --- /dev/null +++ b/gnu/javax/crypto/sasl/SaslInputStream.java @@ -0,0 +1,459 @@ +/* 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.util.Util; + +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.IOException; +import java.io.PrintWriter; + +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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "SaslOutputStream"; + + private static final String ERROR = "ERROR"; + + private static final String WARN = " WARN"; + + // private static final String INFO = " INFO"; + private static final String TRACE = "DEBUG"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 3; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String level, Object obj) + { + err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj)); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private SaslClient client; + + private SaslServer server; + + private int maxRawSendSize; + + private InputStream source; + + private byte[] internalBuf; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public SaslInputStream(SaslClient client, InputStream source) + throws IOException + { + super(); + + this.client = client; + maxRawSendSize = Integer.parseInt((String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE)); + server = null; + this.source = source; + } + + public SaslInputStream(SaslServer server, InputStream source) + throws IOException + { + super(); + + this.server = server; + maxRawSendSize = Integer.parseInt((String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE)); + client = null; + this.source = source; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Overloaded java.io.InputStream methods ---------------------------------- + + public int available() throws IOException + { + return (internalBuf == null) ? 0 : internalBuf.length; + } + + public void close() throws IOException + { + source.close(); + } + + /** + * <p>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> + * + * <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.</p> + * + * @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, 0, tmp, 0, tmp.length); + 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; + } + + /** + * <p>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> + * + * <p>This method blocks until input data is available, end of file is + * detected, or an exception is thrown.</p> + * + * <p>If <code>b</code> is <code>null</code>, a {@link NullPointerException} is + * thrown.</p> + * + * <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> + * + * <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> + * + * <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> + * + * <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> + * + * <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> + * + * <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.</p> + * + * @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 (DEBUG && debuglevel > 8) + debug(TRACE, "==> read(b, " + String.valueOf(off) + ", " + + String.valueOf(len) + ")"); + + if (b == null) + { + throw new NullPointerException("b"); + } + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + { + throw new IndexOutOfBoundsException("off=" + String.valueOf(off) + + ", len=" + String.valueOf(len) + + ", b.length=" + + String.valueOf(b.length)); + } + if (len == 0) + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== read() --> 0"); + return 0; + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Available: " + String.valueOf(available())); + + int result = 0; + if (internalBuf == null || internalBuf.length < 1) + try + { + internalBuf = readSaslBuffer(); + if (internalBuf == null) + { + if (DEBUG && debuglevel > 4) + debug(WARN, "Underlying stream empty. Returning -1"); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== read() --> -1"); + return -1; + } + } + catch (InterruptedIOException x) + { + if (DEBUG && debuglevel > 6) + debug(TRACE, x); + if (DEBUG && debuglevel > 4) + debug(WARN, "Reading thread was interrupted. Returning -1"); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== read() --> -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 (DEBUG && debuglevel > 4) + debug(WARN, "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 (DEBUG && debuglevel > 4) + debug(WARN, + "Not enough bytes in source to read a buffer. Breaking..."); + break; + } + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Remaining: " + + (internalBuf == null ? 0 : internalBuf.length)); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== read() --> " + String.valueOf(result)); + return result; + } + + // other nstance methods --------------------------------------------------- + + /** + * 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 (DEBUG && debuglevel > 8) + debug(TRACE, "==> 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 (DEBUG && debuglevel > 8) + debug(TRACE, "<== readSaslBuffer() --> null"); + return null; + } + } + catch (IOException x) + { + if (DEBUG && debuglevel > 0) + debug(ERROR, x); + throw x; + } + + if (realLength != 4) + { + throw new IOException("Was expecting 4 but found " + + String.valueOf(realLength)); + } + int bufferLength = result[0] << 24 | (result[1] & 0xFF) << 16 + | (result[2] & 0xFF) << 8 | (result[3] & 0xFF); + + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 0) + debug(ERROR, x); + throw x; + } + + if (realLength != bufferLength) + throw new IOException("Was expecting " + String.valueOf(bufferLength) + + " but found " + String.valueOf(realLength)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (before security) (hex): " + + Util.dumpString(result)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (after security) (hex): " + + Util.dumpString(result)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (after security) (str): \"" + + new String(result) + "\""); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== readSaslBuffer()"); + return result; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/SaslOutputStream.java b/gnu/javax/crypto/sasl/SaslOutputStream.java new file mode 100644 index 000000000..699720137 --- /dev/null +++ b/gnu/javax/crypto/sasl/SaslOutputStream.java @@ -0,0 +1,218 @@ +/* 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.util.Util; + +import java.io.OutputStream; +import java.io.IOException; +import java.io.PrintWriter; + +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 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "SaslOutputStream"; + + // private static final String ERROR = "ERROR"; + // private static final String WARN = " WARN"; + // private static final String INFO = " INFO"; + private static final String TRACE = "DEBUG"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 3; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String level, Object obj) + { + err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj)); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private SaslClient client; + + private SaslServer server; + + private int maxRawSendSize; + + private OutputStream dest; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public SaslOutputStream(SaslClient client, OutputStream dest) + throws IOException + { + super(); + + this.client = client; + maxRawSendSize = Integer.parseInt((String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE)); + server = null; + this.dest = dest; + } + + public SaslOutputStream(SaslServer server, OutputStream dest) + throws IOException + { + super(); + + this.server = server; + maxRawSendSize = Integer.parseInt((String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE)); + client = null; + this.dest = dest; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Overloaded java.io.OutputStream methods + // ------------------------------------------------------------------------- + + 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 (b == null) + { + throw new NullPointerException("b"); + } + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + { + throw new IndexOutOfBoundsException("off=" + String.valueOf(off) + + ", len=" + String.valueOf(len) + + ", b.length=" + + String.valueOf(b.length)); + } + if (len == 0) + { + return; + } + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> write()"); + + int chunckSize, length, chunck = 1; + byte[] output = null, result; + if (DEBUG && debuglevel > 6) + debug(TRACE, "About to wrap " + String.valueOf(len) + " byte(s)..."); + while (len > 0) + { + chunckSize = (len > maxRawSendSize ? maxRawSendSize : len); + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Outgoing buffer (before security) (hex): " + + Util.dumpString(b, off, chunckSize)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Outgoing buffer (after security) (hex): " + + Util.dumpString(output)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Wrapped chunck #" + String.valueOf(chunck)); + chunck++; + } + + dest.flush(); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== write()"); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/SaslUtil.java b/gnu/javax/crypto/sasl/SaslUtil.java new file mode 100644 index 000000000..e70312c0d --- /dev/null +++ b/gnu/javax/crypto/sasl/SaslUtil.java @@ -0,0 +1,89 @@ +/* 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.math.BigInteger; +import java.security.MessageDigest; + +/** + * Utility methods for SASL-related classes. + */ +public class SaslUtil +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + private SaslUtil() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final boolean validEmailAddress(String address) + { + // need to do better than this + return (address.indexOf("@") != -1); + } + + // Visualisation methods + // ------------------------------------------------------------------------- + + /** 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/ServerFactory.java b/gnu/javax/crypto/sasl/ServerFactory.java new file mode 100644 index 000000000..e9b08dbd4 --- /dev/null +++ b/gnu/javax/crypto/sasl/ServerFactory.java @@ -0,0 +1,194 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + 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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + 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))); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/ServerMechanism.java b/gnu/javax/crypto/sasl/ServerMechanism.java new file mode 100644 index 000000000..f12a075d9 --- /dev/null +++ b/gnu/javax/crypto/sasl/ServerMechanism.java @@ -0,0 +1,371 @@ +/* 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.SaslServer; +import javax.security.sasl.SaslException; + +/** + * <p>A base class to facilitate implementing SASL server-side mechanisms.</p> + */ +public abstract class ServerMechanism implements SaslServer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected ServerMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.authenticator = AuthInfo.getProvider(mechanism); + this.state = -1; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods to be implemented by concrete subclasses --------------- + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + // javax.security.sasl.SaslServer interface implementation ----------------- + + 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(); + } + + // other Instance methods -------------------------------------------------- + + 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; + } + + /** + * <p>Initialises the mechanism with designated attributes. Permissible names + * and values are mechanism specific.</p> + * + * @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; + } + + /** + * <p>Resets the mechanism instance for re-initialisation and use with other + * characteristics.</p> + * + * @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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/UserAlreadyExistsException.java b/gnu/javax/crypto/sasl/UserAlreadyExistsException.java new file mode 100644 index 000000000..764a36df3 --- /dev/null +++ b/gnu/javax/crypto/sasl/UserAlreadyExistsException.java @@ -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); + } +} diff --git a/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java b/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java new file mode 100644 index 000000000..f5b1faab2 --- /dev/null +++ b/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java @@ -0,0 +1,120 @@ +/* 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.SaslClient; +import javax.security.sasl.SaslException; +import javax.security.sasl.AuthenticationException; + +/** + * <p>The ANONYMOUS client-side mechanism.</p> + */ +public class AnonymousClient extends ClientMechanism implements SaslClient +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public AnonymousClient() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslClient interface implementation ----------------- + + 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; + // return authorizationID.getBytes(); + final byte[] result; + try + { + result = authorizationID.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("response()", x); + } + return result; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java b/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java new file mode 100644 index 000000000..2c10f78a7 --- /dev/null +++ b/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java @@ -0,0 +1,107 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public AnonymousServer() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslServer interface implementation ----------------- + + 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"); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java b/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java new file mode 100644 index 000000000..99e95eaec --- /dev/null +++ b/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java @@ -0,0 +1,109 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial private constructor to enforce Singleton pattern. */ + private AnonymousUtil() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java b/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java new file mode 100644 index 000000000..cf73b6f98 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java @@ -0,0 +1,200 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private PasswordFile passwordFile = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-args constrcutor + + // Class methods + // ------------------------------------------------------------------------- + + // IAuthInfoProvider interface implementation + // ------------------------------------------------------------------------- + + 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()); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java b/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java new file mode 100644 index 000000000..094109ff9 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java @@ -0,0 +1,201 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public CramMD5Client() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslClient interface implementation ----------------- + + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java b/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java new file mode 100644 index 000000000..1c61cace4 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java @@ -0,0 +1,66 @@ +/* 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"; +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java b/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java new file mode 100644 index 000000000..d6622b6db --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java @@ -0,0 +1,185 @@ +/* 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; + +/** + * <p>The CRAM-MD5 SASL server-side mechanism.</p> + */ +public class CramMD5Server extends ServerMechanism implements SaslServer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private byte[] msgID; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public CramMD5Server() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslServer interface implementation ----------------- + + 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 = (new String(Util.toString(digest).toLowerCase())).getBytes("UTF-8"); + 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; + } + + // Other instance methods -------------------------------------------------- + + 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); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java b/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java new file mode 100644 index 000000000..6e7539349 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java @@ -0,0 +1,137 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + private CramMD5Util() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + static byte[] createMsgID() throws SaslException + { + // <process-ID.clock@hostname> + 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("<").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(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/PasswordFile.java b/gnu/javax/crypto/sasl/crammd5/PasswordFile.java new file mode 100644 index 000000000..081af4615 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/PasswordFile.java @@ -0,0 +1,301 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + 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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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)) + { // check if the entry exists + throw new NoSuchUserException(user); + } + + final 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(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(); + } + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PasswordFile.java b/gnu/javax/crypto/sasl/plain/PasswordFile.java new file mode 100644 index 000000000..4ef6b8541 --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PasswordFile.java @@ -0,0 +1,309 @@ +/* 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.classpath.SystemProperties; + +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.Enumeration; +import java.util.Hashtable; +import java.util.StringTokenizer; +import java.util.NoSuchElementException; + +/** + * A representation of a Plain password file. + */ +public class PasswordFile +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = SystemProperties.getProperty(PlainRegistry.PASSWORD_FILE, + PlainRegistry.DEFAULT_PASSWORD_FILE); + } + + private Hashtable entries; + + private File passwdFile; + + // private String[] last_params; + private long lastmod; + + // Constructor(s) + // ------------------------------------------------------------------------- + + 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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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(); + } + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java b/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java new file mode 100644 index 000000000..9882ce9bb --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java @@ -0,0 +1,206 @@ +/* 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 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private PasswordFile passwordFile = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-args constrcutor + + // Class methods + // ------------------------------------------------------------------------- + + // IAuthInfoProvider interface implementation + // ------------------------------------------------------------------------- + + 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; + } + else + { + 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; + } + else + { + throw new AuthenticationException("update()", x); + } + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + throw new AuthenticationException("", new UnsupportedOperationException()); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PlainClient.java b/gnu/javax/crypto/sasl/plain/PlainClient.java new file mode 100644 index 000000000..066db3770 --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PlainClient.java @@ -0,0 +1,193 @@ +/* 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; + +/** + * <p>The PLAIN SASL client-side mechanism.</p> + */ +public class PlainClient extends ClientMechanism implements SaslClient +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public PlainClient() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslClient interface implementation ----------------- + + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PlainRegistry.java b/gnu/javax/crypto/sasl/plain/PlainRegistry.java new file mode 100644 index 000000000..0b48c0ad3 --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PlainRegistry.java @@ -0,0 +1,67 @@ +/* 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 +{ + + // Constants + // ------------------------------------------------------------------------- + + /** 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"; +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PlainServer.java b/gnu/javax/crypto/sasl/plain/PlainServer.java new file mode 100644 index 000000000..205688473 --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PlainServer.java @@ -0,0 +1,196 @@ +/* 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; + +/** + * <p>The PLAIN SASL server-side mechanism.</p> + */ +public class PlainServer extends ServerMechanism implements SaslServer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public PlainServer() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslServer interface implementation ----------------- + + 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; + } + + // other methods ----------------------------------------------------------- + + 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); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/CALG.java b/gnu/javax/crypto/sasl/srp/CALG.java new file mode 100644 index 000000000..6215783d6 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/CALG.java @@ -0,0 +1,292 @@ +/* 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; + +/** + * <p>A Factory class that returns CALG (Confidentiality Algorithm) instances + * that operate as described in the draft-burdis-cat-sasl-srp-08.</p> + * + * <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> + * + * <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> + * + * <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> + * + * <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:</p> + * + * <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 < 256</code> octets, which is the case with + * symmetric key block ciphers today, and in the forseeable future.</p> + */ +public final class CALG +{ + + // Constants and variables + // -------------------------------------------------------------------------- + + 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). + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** 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; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a SASL-SRP CALG implementation.</p> + * + * @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(); + final Object modeNdx = ofbCipher.append(Stage.getInstance( + ModeFactory.getInstance( + Registry.OFB_MODE, + cipher, + blockSize), + Direction.FORWARD)); + final IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD); + // the passed IV may be longer that what we need. ensure correct length + // byte[] realIV = null; + // 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); + // } + // } + + // HashMap modeAttributes = new HashMap(); + // modeAttributes.put(IBlockCipher.KEY_MATERIAL, K.clone()); + // modeAttributes.put(IMode.IV, realIV); + + final Assembly asm = new Assembly(); + asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher)); + asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7)); + + // HashMap attributes = new HashMap(); + // attributes.put(Assembly.DIRECTION, dir); + // attributes.put(modeNdx, modeAttributes); + // try { + // asm.init(attributes); + // } catch (TransformerException x) { + // throw new SaslException("getInstance()", x); + // } + + return new CALG(blockSize, keySize, modeNdx, asm); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Initialises a SASL-SRP CALG implementation.</p> + * + * @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(byte[] K, byte[] iv, Direction dir) throws SaslException { + public void init(final KDF kdf, final byte[] iv, final Direction dir) + throws SaslException + { + // IBlockCipher cipher = CipherFactory.getInstance(algorithm); + // int blockSize = cipher.defaultBlockSize(); + // Cascade ofbCipher = new Cascade(); + // Object modeNdx = ofbCipher.append( + // Stage.getInstace( + // ModeFactory.getInstance(Registry.OFB_MODE, cipher, blockSize), + // Direction.FORWARD)); + // IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD); + // the passed IV may be longer that what we need. ensure correct length + 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(); + // modeAttributes.put(IBlockCipher.KEY_MATERIAL, K.clone()); + final byte[] sk = kdf.derive(keySize); + modeAttributes.put(IBlockCipher.KEY_MATERIAL, sk); + //System.out.println("**** Initialised CALG with: "+gnu.crypto.util.Util.dumpString(sk)); + modeAttributes.put(IMode.IV, realIV); + + // Assembly asm = new Assembly(); + // asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher)); + // asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7)); + + final HashMap attributes = new HashMap(); + attributes.put(Assembly.DIRECTION, dir); + attributes.put(modeNdx, modeAttributes); + try + { + // asm.init(attributes); + assembly.init(attributes); + } + catch (TransformerException x) + { + throw new SaslException("getInstance()", x); + } + + // return new CALG(asm); + } + + /** + * <p>Encrypts or decrypts, depending on the mode already set, a designated + * array of bytes and returns the result.</p> + * + * @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); + } + + /** + * <p>Encrypts or decrypts, depending on the mode already set, a designated + * array of bytes and returns the result.</p> + * + * @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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/ClientStore.java b/gnu/javax/crypto/sasl/srp/ClientStore.java new file mode 100644 index 000000000..ce16f4aa7 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/ClientStore.java @@ -0,0 +1,173 @@ +/* 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; + +/** + * <p>The client-side implementation of the SRP security context store.</p> + */ +public class ClientStore +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Private constructor to enforce Singleton pattern. */ + private ClientStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the classloader Singleton.</p> + * + * @return the classloader Singleton instance. + */ + static synchronized final ClientStore instance() + { + if (singleton == null) + { + singleton = new ClientStore(); + } + return singleton; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns a boolean flag indicating if the designated client's session is + * still alive or not.</p> + * + * @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; + } + + /** + * <p>Records a mapping between a client's unique identifier and its security + * context.</p> + * + * @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)); + } + } + + /** + * <p>Removes the mapping between the designated SRP client unique identifier + * and the its session security context (and other timing information).</p> + * + * @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); + } + } + + /** + * <p>Returns an SRP client's security context record mapped by that client's + * unique identifier.</p> + * + * @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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/IALG.java b/gnu/javax/crypto/sasl/srp/IALG.java new file mode 100644 index 000000000..cfaf22b1e --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/IALG.java @@ -0,0 +1,159 @@ +/* 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; + +/** + * <p>A Factory class that returns IALG (Integrity Algorithm) instances that + * operate as described in the draft-burdis-cat-sasl-srp-04 and later.</p> + * + * @version $Revision: 1.1 $ + */ +public final class IALG implements Cloneable +{ + + // Constants and variables + // -------------------------------------------------------------------------- + + private IMac hmac; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Private constructor to enforce instantiation through Factory method. */ + private IALG(final IMac hmac) + { + super(); + + this.hmac = hmac; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of a SASL-SRP IALG implementation.</p> + * + * @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)); + } + // try { + // byte[] sk = (byte[]) K.clone(); + // HashMap map = new HashMap(); + // map.put(IMac.MAC_KEY_MATERIAL, sk); + // hmac.init(map); + // } catch (InvalidKeyException x) { + // throw new SaslException("getInstance()", x); + // } + return new IALG(hmac); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation -------------------------------------- + + public Object clone() throws CloneNotSupportedException + { + return new IALG((IMac) hmac.clone()); + } + + // other methdds ----------------------------------------------------------- + + // public void init(final byte[] K) throws SaslException { + public void init(final KDF kdf) throws SaslException + { + try + { + // final byte[] sk = (byte[]) K.clone(); + final byte[] sk = kdf.derive(hmac.macSize()); + final HashMap map = new HashMap(); + map.put(IMac.MAC_KEY_MATERIAL, sk); + hmac.init(map); + //System.out.println("**** Initialised IALG with: "+gnu.crypto.util.Util.dumpString(sk)); + } + 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(); + } + + /** + * <p>Returns the length (in bytes) of this SASL SRP Integrity Algorithm.</p> + * + * @return the length, in bytes, of this integrity protection algorithm. + */ + public int length() + { + return hmac.macSize(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/KDF.java b/gnu/javax/crypto/sasl/srp/KDF.java new file mode 100644 index 000000000..161ec78b6 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/KDF.java @@ -0,0 +1,157 @@ +/* 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.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.util.HashMap; +import java.util.Random; + +/** + * <p>The SASL-SRP KDF implementation, which is also used, depending on how it + * was instantiated, as a secure Pseudo Random Number Generator.</p> + */ +public class KDF +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int AES_BLOCK_SIZE = 16; // default block size for the AES + + private static final int AES_KEY_SIZE = 16; // default key size for the AES + + /** The shared secret K to use. */ + // private byte[] keyMaterial; + /** The underlying UMAC Generator instance. */ + private UMacGenerator umac = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * <p>Constructs an instance of the <code>KDF</code> initialised with the + * designated shared secret bytes.</p> + * + * @param keyMaterial the SASL SRP shared secret (K) bytes. + */ + private KDF(final byte[] keyMaterial, final int ndx) + { + super(); + + // if (ndx != 0) { + // this.keyMaterial = (byte[]) keyMaterial.clone(); + // } + final HashMap map = new HashMap(); + map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + map.put(UMacGenerator.INDEX, new Integer(ndx)); + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(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); + //System.out.println("**** Initialised KDF with: "+gnu.crypto.util.Util.dumpString(key)); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>A Factory mehod that returns an instance of a <code>KDF</code> based on + * supplied seed data.</p> + * + * @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]; + ndx = new Random ().nextInt (256); // XXX does this need to be secure? + } + return new KDF(keyMaterial, ndx); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns a designated number of bytes suitable for use in the SASL SRP + * mechanism.</p> + * + * @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]; + // if (keyMaterial == null || length > keyMaterial.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); + } + // } else { + // System.arraycopy(keyMaterial, 0, result, 0, length); + // } + + return result; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/PasswordFile.java b/gnu/javax/crypto/sasl/srp/PasswordFile.java new file mode 100644 index 000000000..1628a4167 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/PasswordFile.java @@ -0,0 +1,699 @@ +/* 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.hash.IMessageDigest; +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.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +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; + +/** + * <p>The implementation of SRP password files.</p> + * + * <p>For SRP, there are three (3) files: + * <ol> + * <li>The password configuration file: tpasswd.conf. It contains the pairs + * <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> + * + * <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> + * + * <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> + * + * <p>Reference:</p> + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class PasswordFile +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // 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 }; + + // Constructor(s) + // ------------------------------------------------------------------------- + + 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(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns a string representing the decimal value of an integer + * identifying the message digest algorithm to use for the SRP computations. + * </p> + * + * @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"; + } + + // SRP password configuration file methods --------------------------------- + + /** + * <p>Checks if the current configuration file contains the <N, g> pair + * for the designated <code>index</code>.</p> + * + * @param index a string representing 1-digit identification of an <N, g> + * pair used. + * @return <code>true</code> if the designated <code>index</code> is that of + * a known <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); + } + + /** + * <p>Returns a pair of strings representing the pair of <code>N</code> and + * <code>g</code> MPIs for the designated <code>index</code>.</p> + * + * @param index a string representing 1-digit identification of an <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; + } + + // SRP base and extended password configuration files methods -------------- + + 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(); + } + + /** + * <p>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.</p> + * + * @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 }; + } + + // Other instance methods -------------------------------------------------- + + 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()); + } + } + + /** + * <p>Compute the new verifiers for the designated username and password.</p> + * + * <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> + * + * @param user the user's name. + * @param s the user's salt. + * @param password the user's password + * @param index the index of the <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().append(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().append(digestID).append(":").append( + user).append( + ":").append( + (String) verifiers.get(digestID)); + pw2.println(sb2.toString()); + } + } + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRP.java b/gnu/javax/crypto/sasl/srp/SRP.java new file mode 100644 index 000000000..d3eb596d4 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRP.java @@ -0,0 +1,285 @@ +/* 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; + +/** + * <p>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.</p> + */ +public final class SRP +{ + + // Constants and variables + // -------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Trivial private constructor to enforce Singleton pattern. */ + private SRP(final IMessageDigest mda) + { + super(); + + this.mda = mda; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns an instance of this object that uses the designated message + * digest algorithm as its digest function.</p> + * + * @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; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** @return the message digest algorithm name used by this instance. */ + public String getAlgorithm() + { + return mda.name(); + } + + // Message Digest algorithm related methods -------------------------------- + + /** + * <p>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.</p> + * + * @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(); + } + + /** + * <p>Convenience method to return the result of digesting the designated + * input with a new instance of the SRP message digest algorithm.</p> + * + * @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(); + } + + /** + * <p>Convenience method to return the result of digesting the designated + * input with a new instance of the SRP message digest algorithm.</p> + * + * @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")); + } + + // Other methods ----------------------------------------------------------- + + /** + * <p>Convenience method to XOR N bytes from two arrays; N being the output + * size of the SRP message digest algorithm.</p> + * + * @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(); + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java b/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java new file mode 100644 index 000000000..9ea21efb6 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java @@ -0,0 +1,218 @@ +/* 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; + +/** + * <p>The SRP mechanism authentication information provider implementation.</p> + */ +public class SRPAuthInfoProvider implements IAuthInfoProvider +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private PasswordFile passwordFile = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-args constrcutor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IAuthInfoProvider interface implementation ------------------------------ + + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRPClient.java b/gnu/javax/crypto/sasl/srp/SRPClient.java new file mode 100644 index 000000000..26a9e8aaf --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRPClient.java @@ -0,0 +1,1199 @@ +/* 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.Registry; +import gnu.java.security.hash.MD5; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +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.IOException; +import java.io.PrintWriter; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.HashMap; +import java.util.StringTokenizer; + +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.auth.DestroyFailedException; +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * <p>The SASL-SRP client-side mechanism.</p> + */ +public class SRPClient extends ClientMechanism implements SaslClient +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "SRPClient"; + + // private static final String ERROR = "ERROR"; + // private static final String WARN = " WARN"; + private static final String INFO = " INFO"; + + private static final String TRACE = "DEBUG"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 3; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(final String level, final Object obj) + { + err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj)); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + // private static final HashMap uid2ctx = new HashMap(); + + 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); + + // Constructor(s) + // ------------------------------------------------------------------------- + + public SRPClient() + { + super(Registry.SASL_SRP_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + 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; + } + + // javax.security.sasl.SaslClient interface implementation ----------------- + + 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 (DEBUG && debuglevel > 8) + debug(TRACE, "==> 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 + { + // final InputBuffer frameIn = InputBuffer.getInstance(incoming, offset, len); + // result = frameIn.getEOS(); + 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 = frameIn.getOS(); + final byte[] received_mac = new byte[macBytesCount]; + System.arraycopy(incoming, offset + payloadLength, received_mac, 0, + macBytesCount); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got C (received MAC): " + + Util.dumpString(received_mac)); + // inMac.update(result); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "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 + // if (inCipher != null) { + result = inCipher.doFinal(incoming, offset, len); + // } else { + // result = new byte[len]; + // System.arraycopy(incoming, offset, result, 0, len); + // } + } + // if (inCipher != null) { + // result = inCipher.doFinal(result); + // } + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("engineUnwrap()", x); + } + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== engineUnwrap()"); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> 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[] data = new byte[len]; + // System.arraycopy(outgoing, offset, data, 0, len); + byte[] result; + try + { + // OutputBuffer frameOut = new OutputBuffer(); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + // Process the data + if (outCipher != null) + { + // data = outCipher.doFinal(data); + result = outCipher.doFinal(outgoing, offset, len); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + + // frameOut.setEOS(data); + out.write(result); + + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "outCounter=" + String.valueOf(outCounter)); + outMac.update(new byte[] { (byte) (outCounter >>> 24), + (byte) (outCounter >>> 16), + (byte) (outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + // frameOut.setOS(C); + out.write(C); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding C (integrity checksum): " + + Util.dumpString(C)); + } // else confidentiality only; do nothing + } + else + { // no confidentiality; just integrity [+ replay detection] + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding p (plaintext): "+Util.dumpString(data)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + + // frameOut.setEOS(data); + out.write(outgoing, offset, len); + + // if (outMac != null) { + // outMac.update(data); + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "outCounter=" + String.valueOf(outCounter)); + outMac.update(new byte[] { (byte) (outCounter >>> 24), + (byte) (outCounter >>> 16), + (byte) (outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + // frameOut.setOS(C); + out.write(C); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding C (integrity checksum): " + + Util.dumpString(C)); + // } + } + + // frameOut.setEOS(data); + // + // if (outMac != null) { + // outMac.update(data); + // if (replayDetection) { + // outCounter++; + // if (DEBUG && debuglevel > 6) debug(TRACE, "outCounter="+String.valueOf(outCounter)); + // outMac.update(new byte[] { + // (byte)(outCounter >>> 24), + // (byte)(outCounter >>> 16), + // (byte)(outCounter >>> 8), + // (byte) outCounter }); + // } + // byte[] C = outMac.doFinal(); + // frameOut.setOS(C); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding C (integrity checksum): "+Util.dumpString(C)); + // } + + // result = frameOut.wrap(); + result = out.toByteArray(); + + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("engineWrap()", x); + } + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== engineWrap()"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + { + return Registry.QOP_AUTH_CONF; + } + else + { + return Registry.QOP_AUTH_INT; + } + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + { + return Registry.STRENGTH_HIGH; + } + else + { + return Registry.STRENGTH_MEDIUM; + } + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + // other methods ----------------------------------------------------------- + + private byte[] sendIdentities() throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> sendIdentities()"); + + // If necessary, prompt the client for the username and password + getUsernameAndPassword(); + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Password: \"" + new String(password.getPassword()) + "\""); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding U (username): \"" + U + "\""); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding I (userid): \"" + authorizationID + "\""); + + // if session re-use generate new 16-byte nonce + if (sid.length != 0) + { + cn = new SecureRandom ().generateSeed (16); + } + 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 (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendIdentities()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "C: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " U = " + U); + if (DEBUG && debuglevel > 2) + debug(INFO, " I = " + authorizationID); + if (DEBUG && debuglevel > 2) + debug(INFO, "sid = " + new String(sid)); + if (DEBUG && debuglevel > 2) + debug(INFO, " cn = " + Util.dumpString(cn)); + if (DEBUG && debuglevel > 2) + debug(INFO, "cCB = " + Util.dumpString(channelBinding)); + return result; + } + + private byte[] sendPublicKey(final byte[] input) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> sendPublicKey()"); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Got N (modulus): " + Util.dump(N)); + g = frameIn.getMPI(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got g (generator): " + Util.dump(g)); + s = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got s (salt): " + Util.dumpString(s)); + B = frameIn.getMPI(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got B (server ephermeral public key): " + + Util.dump(B)); + L = frameIn.getText(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got L (available options): \"" + L + "\""); + } + else if (ack == 0xFF) + { // session re-use + sn = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sn (server nonce): " + Util.dumpString(sn)); + sCB = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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.newDigest()); + 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 (DEBUG && debuglevel > 6) + debug(TRACE, "K: " + Util.dumpString(K)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding o (client chosen options): \"" + o + "\""); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendPublicKey()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "New session, or session re-use rejected..."); + if (DEBUG && debuglevel > 2) + debug(INFO, "C: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " A = 0x" + A.toString(16)); + if (DEBUG && debuglevel > 2) + debug(INFO, " M1 = " + Util.dumpString(M1)); + if (DEBUG && debuglevel > 2) + debug(INFO, " o = " + o); + if (DEBUG && debuglevel > 2) + debug(INFO, "cIV = " + Util.dumpString(cIV)); + + return result; + } + else + { // session re-use accepted ------------------------------------- + setupSecurityServices(true); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendPublicKey()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "Session re-use accepted..."); + return null; + } + } + + private byte[] receiveEvidence(byte[] input) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> receiveEvidence()"); + if (DEBUG && debuglevel > 6) + debug(TRACE, "S: " + Util.dumpString(input)); + + // Server send M2, sIV, sCB, sid, ttl + final InputBuffer frameIn = new InputBuffer(input); + try + { + M2 = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got M2 (server evidence): " + Util.dumpString(M2)); + sIV = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sIV (server IV): " + Util.dumpString(sIV)); + sid = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sid (session ID): " + new String(sid)); + ttl = (int) frameIn.getScalar(4); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got ttl (session time-to-live): " + ttl + "sec."); + sCB = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Expected: " + Util.dumpString(expected)); + if (!Arrays.equals(M2, expected)) + { + throw new AuthenticationException("M2 mismatch"); + } + + setupSecurityServices(false); + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== 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 (DEBUG && debuglevel > 8) + debug(TRACE, "==> 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 (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "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 + + "=" + + String.valueOf(maxBufferSize), + x); + } + } + } + + replayDetection = replaydetectionAvailable + && Boolean.valueOf( + (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION)).booleanValue(); + boolean integrity = integrityAvailable + && Boolean.valueOf( + (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION)).booleanValue(); + boolean confidentiality = confidentialityAvailable + && Boolean.valueOf( + (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY)).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]; + new SecureRandom ().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 (DEBUG && debuglevel > 8) + debug(TRACE, "<== 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 (DEBUG && debuglevel > 2) + debug(INFO, "Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (DEBUG && debuglevel > 2) + debug(INFO, "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 (DEBUG && debuglevel > 2) + debug(INFO, "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)); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRPRegistry.java b/gnu/javax/crypto/sasl/srp/SRPRegistry.java new file mode 100644 index 000000000..262cbcba3 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRPRegistry.java @@ -0,0 +1,219 @@ +/* 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; + +/** + * <p>A list of key names designating the values exchanged between the server + * and client in an SRP communication authentication phase.</p> + */ +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 gnu.crypto.sasl.srp.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 = MANDATORY_NONE; + String DEFAULT_MANDATORY = OPTION_REPLAY_DETECTION; + + // String DEFAULT_MANDATORY = OPTION_INTEGRITY; + // String DEFAULT_MANDATORY = OPTION_CONFIDENTIALITY; + + /** 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; +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRPServer.java b/gnu/javax/crypto/sasl/srp/SRPServer.java new file mode 100644 index 000000000..421da6e1b --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRPServer.java @@ -0,0 +1,1147 @@ +/* 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.Registry; +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.KeyAgreementFactory; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.IncomingMessage; +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.IOException; +import java.io.PrintWriter; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.HashMap; +import java.util.StringTokenizer; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * <p>The SASL-SRP server-side mechanism.</p> + * + * @version $Revision: 1.1 $ + */ +public class SRPServer extends ServerMechanism implements SaslServer +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "SRPServer"; + + // private static final String ERROR = "ERROR"; + private static final String WARN = " WARN"; + + private static final String INFO = " INFO"; + + private static final String TRACE = "DEBUG"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 3; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(final String level, final Object obj) + { + err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj)); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + 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); + + // Constructor(s) + // ------------------------------------------------------------------------- + + public SRPServer() + { + super(Registry.SASL_SRP_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + 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; + } + + // javax.security.sasl.SaslServer interface implementation ----------------- + + 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 (DEBUG && debuglevel > 8) debug(TRACE, "==> engineUnwrap()"); + // + // if (inMac == null && inCipher == null) { + // throw new IllegalStateException("connection is not protected"); + // } + // + // if (DEBUG && debuglevel > 6) debug(TRACE, "Incoming buffer (before security): "+Util.dumpString(incoming, offset, len)); + // + // byte[] data = null; + // try { + // InputBuffer frameIn = InputBuffer.getInstance(incoming, offset, len); + // data = frameIn.getEOS(); + // if (inMac != null) { + // byte[] received_mac = frameIn.getOS(); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Got C (received MAC): "+Util.dumpString(received_mac)); + // inMac.update(data); + // if (replayDetection) { + // inCounter++; + // if (DEBUG && debuglevel > 6) debug(TRACE, "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 (DEBUG && debuglevel > 6) debug(TRACE, "Computed MAC: "+Util.dumpString(computed_mac)); + // if (!Arrays.equals(received_mac, computed_mac)) + // throw new IntegrityException("engineUnwrap()"); + // } + // if (inCipher != null) { + // data = inCipher.doFinal(data); + // } + // } catch (IOException x) { + // if (x instanceof SaslException) { + // throw (SaslException) x; + // } + // throw new SaslException("engineUnwrap()", x); + // } + // + // if (DEBUG && debuglevel > 6) debug(TRACE, "Incoming buffer (after security): "+Util.dumpString(data)); + // if (DEBUG && debuglevel > 8) debug(TRACE, "<== engineUnwrap()"); + // return data; + + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> engineUnwrap()"); + + if (inMac == null && inCipher == null) + { + throw new IllegalStateException("connection is not protected"); + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Got C (received MAC): " + + Util.dumpString(received_mac)); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "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 + // if (inCipher != null) { + result = inCipher.doFinal(incoming, offset, len); + // } else { + // result = new byte[len]; + // System.arraycopy(incoming, offset, result, 0, len); + // } + } + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("engineUnwrap()", x); + } + if (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (after security): " + + Util.dumpString(result)); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== engineUnwrap()"); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + // if (DEBUG && debuglevel > 8) debug(TRACE, "==> engineWrap()"); + // + // if (outMac == null && outCipher == null) { + // throw new IllegalStateException("connection is not protected"); + // } + // + // byte[] data = new byte[len]; + // System.arraycopy(outgoing, offset, data, 0, len); + // + // if (DEBUG && debuglevel > 6) debug(TRACE, "Outgoing buffer (before security) (hex): "+Util.dumpString(data)); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Outgoing buffer (before security) (str): \""+new String(data)+"\""); + // + // final byte[] result; + // try { + // OutputBuffer frameOut = new OutputBuffer(); + // // Process the data + // if (outCipher != null) { + // data = outCipher.doFinal(data); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding c (encrypted plaintext): "+Util.dumpString(data)); + // } else { + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding p (plaintext): "+Util.dumpString(data)); + // } + // frameOut.setEOS(data); + // if (outMac != null) { + // outMac.update(data); + // if (replayDetection) { + // outCounter++; + // if (DEBUG && debuglevel > 6) debug(TRACE, "outCounter="+String.valueOf(outCounter)); + // outMac.update(new byte[] { + // (byte)(outCounter >>> 24), + // (byte)(outCounter >>> 16), + // (byte)(outCounter >>> 8), + // (byte) outCounter}); + // } + // byte[] C = outMac.doFinal(); + // frameOut.setOS(C); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding C (integrity checksum): "+Util.dumpString(C)); + // } + // result = frameOut.wrap(); + // + // } catch (IOException x) { + // if (x instanceof SaslException) { + // throw (SaslException) x; + // } + // throw new SaslException("engineWrap()", x); + // } + // + // if (DEBUG && debuglevel > 8) debug(TRACE, "<== engineWrap()"); + // return result; + + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> engineWrap()"); + + if (outMac == null && outCipher == null) + { + throw new IllegalStateException("connection is not protected"); + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Outgoing buffer (before security) (hex): " + + Util.dumpString(outgoing, offset, len)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + + out.write(result); + + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "outCounter=" + String.valueOf(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 (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding C (integrity checksum): " + + Util.dumpString(C)); + } // else ciphertext only; do nothing + } + else + { // no confidentiality; just integrity [+ replay detection] + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + + out.write(outgoing, offset, len); + + // if (outMac != null) { + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "outCounter=" + String.valueOf(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 (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding C (integrity checksum): " + + Util.dumpString(C)); + // } // else plaintext only; do nothing + } + + result = out.toByteArray(); + + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("engineWrap()", x); + } + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== engineWrap()"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + { + return Registry.QOP_AUTH_CONF; + } + else + { + return Registry.QOP_AUTH_INT; + } + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + { + return Registry.STRENGTH_HIGH; + } + else + { + return Registry.STRENGTH_MEDIUM; + } + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + // other methods ----------------------------------------------------------- + + private byte[] sendProtocolElements(final byte[] input) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> sendProtocolElements()"); + if (DEBUG && debuglevel > 6) + debug(TRACE, "C: " + Util.dumpString(input)); + + // Client send U, I, sid, cn + final InputBuffer frameIn = new InputBuffer(input); + try + { + U = frameIn.getText(); // Extract username + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got U (username): \"" + U + "\""); + authorizationID = frameIn.getText(); // Extract authorisation ID + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got I (userid): \"" + authorizationID + "\""); + sid = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sid (session ID): " + new String(sid)); + cn = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got cn (client nonce): " + Util.dumpString(cn)); + cCB = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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]; + } + new SecureRandom ().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 (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendProtocolElements()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "Old session..."); + if (DEBUG && debuglevel > 2) + debug(INFO, "S: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " sn = " + Util.dumpString(sn)); + if (DEBUG && debuglevel > 2) + debug(INFO, " sCB = " + Util.dumpString(channelBinding)); + return result; + } + else + { // new session + authenticator.activate(properties); + + // ------------------------------------------------------------------- + final HashMap mapB = new HashMap(); + // mapB.put(SRP6KeyAgreement.HASH_FUNCTION, srp.newDigest()); + 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 (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding N (modulus): " + Util.dump(N)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding g (generator): " + Util.dump(g)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding s (client's salt): " + Util.dumpString(s)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding L (available options): \"" + L + "\""); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendProtocolElements()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "New session..."); + if (DEBUG && debuglevel > 2) + debug(INFO, "S: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " N = 0x" + N.toString(16)); + if (DEBUG && debuglevel > 2) + debug(INFO, " g = 0x" + g.toString(16)); + if (DEBUG && debuglevel > 2) + debug(INFO, " s = " + Util.dumpString(s)); + if (DEBUG && debuglevel > 2) + debug(INFO, " B = 0x" + B.toString(16)); + if (DEBUG && debuglevel > 2) + debug(INFO, " L = " + L); + return result; + } + } + + private byte[] sendEvidence(final byte[] input) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> sendEvidence()"); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "Got A (client ephemeral public key): " + Util.dump(A)); + M1 = frameIn.getOS(); // Extract evidence + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got M1 (client evidence): " + Util.dumpString(M1)); + o = frameIn.getText(); // Extract client's options list + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got o (client chosen options): \"" + o + "\""); + cIV = frameIn.getOS(); // Extract client's IV + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 6) + debug(TRACE, "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 (DEBUG && debuglevel > 2) + debug(INFO, "S: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " M2 = " + Util.dumpString(M2)); + if (DEBUG && debuglevel > 2) + debug(INFO, " sIV = " + Util.dumpString(sIV)); + if (DEBUG && debuglevel > 2) + debug(INFO, " sid = " + new String(sid)); + if (DEBUG && debuglevel > 2) + debug(INFO, " ttl = " + ttl); + if (DEBUG && debuglevel > 2) + debug(INFO, " sCB = " + Util.dumpString(channelBinding)); + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendEvidence()"); + return result; + } + + private String createL() + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> 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 (DEBUG && debuglevel > 4) + debug(WARN, "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 (DEBUG && debuglevel > 8) + debug(TRACE, "<== 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 (DEBUG && debuglevel > 6) + debug(TRACE, "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"); + } + else + { + option = option.substring(option.indexOf('=') + 1); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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"); + } + else + { + option = option.substring(option.indexOf('=') + 1); + if (DEBUG && debuglevel > 6) + debug(TRACE, "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 + + "=" + + String.valueOf(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) + { + new SecureRandom ().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 (DEBUG && debuglevel > 2) + debug(INFO, "Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (DEBUG && debuglevel > 2) + debug(INFO, "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 (DEBUG && debuglevel > 2) + debug(INFO, "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)); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SecurityContext.java b/gnu/javax/crypto/sasl/srp/SecurityContext.java new file mode 100644 index 000000000..feca25cad --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SecurityContext.java @@ -0,0 +1,164 @@ +/* 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; + +/** + * <p>A package-private placeholder for an SRP security context.</p> + */ +class SecurityContext +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + 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; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + 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; + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/ServerStore.java b/gnu/javax/crypto/sasl/srp/ServerStore.java new file mode 100644 index 000000000..99bf96a94 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/ServerStore.java @@ -0,0 +1,196 @@ +/* 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; + +/** + * <p>The server-side implementation of the SRP security context store.</p> + */ +public class ServerStore +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** 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; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Private constructor to enforce Singleton pattern. */ + private ServerStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns the classloader Singleton.</p> + * + * @return the classloader Singleton instance. + */ + static synchronized final ServerStore instance() + { + if (singleton == null) + { + singleton = new ServerStore(); + } + return singleton; + } + + /** + * <p>Returns a legible new session identifier.</p> + * + * @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(); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns a boolean flag indicating if the designated session is still + * alive or not.</p> + * + * @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; + } + + /** + * <p>Records a mapping between a session identifier and the Security Context + * of the designated SRP server mechanism instance.</p> + * + * @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)); + } + } + + /** + * <p>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.</p> + * + * @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; + } + + /** + * <p>Removes all information related to the designated session ID.</p> + * + * @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); + } + } +}
\ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/StoreEntry.java b/gnu/javax/crypto/sasl/srp/StoreEntry.java new file mode 100644 index 000000000..c5041fa4b --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/StoreEntry.java @@ -0,0 +1,89 @@ +/* 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; + +/** + * <p>A simple timing-related object for use by SRP re-use code.</p> + */ +class StoreEntry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private boolean perenial; + + private long timeToDie; + + // Constructor(s) + // ------------------------------------------------------------------------- + + StoreEntry(int ttl) + { + super(); + + if (ttl == 0) + { + perenial = true; + timeToDie = 0L; + } + else + { + perenial = false; + timeToDie = System.currentTimeMillis() + (ttl & 0xFFFFFFFFL) * 1000L; + } + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * <p>Returns <code>true</code> if the Time-To_live period has not elapsed.</p> + * + * @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)); + } +}
\ No newline at end of file diff --git a/gnu/javax/net/ssl/Base64.java b/gnu/javax/net/ssl/Base64.java new file mode 100644 index 000000000..52989da69 --- /dev/null +++ b/gnu/javax/net/ssl/Base64.java @@ -0,0 +1,311 @@ +/* Base64.java -- Base64 encoding and decoding. + 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. + +-- +Base64 encoding derived from ISC's DHCP. Copyright notices from DHCP +follow. See http://www.isc.org/products/DHCP/. + +Copyright (c) 1996 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-- +Portions Copyright (c) 1995 by International Business Machines, Inc. + +International Business Machines, Inc. (hereinafter called IBM) grants +permission under its copyrights to use, copy, modify, and distribute +this Software with or without fee, provided that the above copyright +notice and all paragraphs of this notice appear in all copies, and +that the name of IBM not be used in connection with the marketing of +any product incorporating the Software or modifications thereof, +without specific, written prior permission. + +To the extent it has a right to do so, IBM grants an immunity from +suit under its patents, if any, for the use, sale or manufacture of +products to the extent that such products are used for performing +Domain Name System dynamic updates in TCP/IP networks by means of the +Software. No immunity is granted for any product per se or for any +other function of any product. + +THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, +DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE, EVEN IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH +DAMAGES. */ + + +package gnu.javax.net.ssl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public final class Base64 +{ + + // No constructor. + private Base64() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** Base-64 characters. */ + private static final String BASE_64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** Base-64 padding character. */ + private static final char BASE_64_PAD = '='; + + /** + * Base64 encode a byte array, returning the returning string. + * + * @param buf The byte array to encode. + * @param tw The total length of any line, 0 for unlimited. + * @return <tt>buf</tt> encoded in Base64. + */ + public static String encode(byte[] buf, int tw) + { + int srcLength = buf.length; + byte[] input = new byte[3]; + int[] output = new int[4]; + StringBuffer out = new StringBuffer(); + int i = 0; + int chars = 0; + + while (srcLength > 2) + { + input[0] = buf[i++]; + input[1] = buf[i++]; + input[2] = buf[i++]; + srcLength -= 3; + + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + output[3] = input[2] & 0x3f; + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[2])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[3])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + + if (srcLength != 0) + { + input[0] = input[1] = input[2] = 0; + for (int j = 0; j < srcLength; j++) + { + input[j] = buf[i+j]; + } + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + if (srcLength == 1) + { + out.append(BASE_64_PAD); + } + else + { + out.append(BASE_64.charAt(output[2])); + } + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64_PAD); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + if (tw > 0) + { + out.append("\n"); + } + + return out.toString(); + } + + /** + * Decode a Base-64 string into a byte array. + * + * @param b64 The Base-64 encoded string. + * @return The decoded bytes. + * @throws java.io.IOException If the argument is not a valid Base-64 + * encoding. + */ + public static byte[] decode(String b64) throws IOException + { + ByteArrayOutputStream result = new ByteArrayOutputStream(b64.length() / 3); + int state = 0, i; + byte temp = 0; + + for (i = 0; i < b64.length(); i++) + { + if (Character.isWhitespace(b64.charAt(i))) + { + continue; + } + if (b64.charAt(i) == BASE_64_PAD) + { + break; + } + + int pos = BASE_64.indexOf(b64.charAt(i)); + if (pos < 0) + { + throw new IOException("non-Base64 character " + b64.charAt(i)); + } + switch (state) + { + case 0: + temp = (byte) (pos - BASE_64.indexOf('A') << 2); + state = 1; + break; + + case 1: + temp |= (byte) (pos - BASE_64.indexOf('A') >>> 4); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x0f) << 4); + state = 2; + break; + + case 2: + temp |= (byte) ((pos - BASE_64.indexOf('A') & 0x7f) >>> 2); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x03) << 6); + state = 3; + break; + + case 3: + temp |= (byte) (pos - BASE_64.indexOf('A') & 0xff); + result.write(temp); + state = 0; + break; + + default: + throw new Error("this statement should be unreachable"); + } + } + + if (i < b64.length() && b64.charAt(i) == BASE_64_PAD) + { + switch (state) + { + case 0: + case 1: + throw new IOException("malformed Base64 sequence"); + + case 2: + for ( ; i < b64.length(); i++) + { + if (!Character.isWhitespace(b64.charAt(i))) + { + break; + } + } + // We must see a second pad character here. + if (b64.charAt(i) != BASE_64_PAD) + { + throw new IOException("malformed Base64 sequence"); + } + i++; + // Fall-through. + + case 3: + i++; + for ( ; i < b64.length(); i++) + { + // We should only see whitespace after this. + if (!Character.isWhitespace(b64.charAt(i))) + { + System.err.println(b64.charAt(i)); + throw new IOException("malformed Base64 sequence"); + } + } + } + } + else + { + if (state != 0) + { + throw new IOException("malformed Base64 sequence"); + } + } + + return result.toByteArray(); + } +} diff --git a/gnu/javax/net/ssl/EntropySource.java b/gnu/javax/net/ssl/EntropySource.java new file mode 100644 index 000000000..be840e5d6 --- /dev/null +++ b/gnu/javax/net/ssl/EntropySource.java @@ -0,0 +1,62 @@ +/* EntropySource.java -- a source of random bits. + 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.net.ssl; + +/** + * 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(); +} diff --git a/gnu/javax/net/ssl/NullManagerParameters.java b/gnu/javax/net/ssl/NullManagerParameters.java new file mode 100644 index 000000000..0e9337932 --- /dev/null +++ b/gnu/javax/net/ssl/NullManagerParameters.java @@ -0,0 +1,56 @@ +/* NullManagerParameters.java -- parameters for empty managers. + 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.net.ssl; + +import javax.net.ssl.ManagerFactoryParameters; + +/** + * This empty class can be used to initialize {@link + * javax.net.ssl.KeyManagerFactory} and {@link + * javax.net.ssl.TrustManagerFactory} instances for the ``JessieX509'' + * algorithm, for cases when no keys or trusted certificates are + * desired or needed. + * + * <p>This is the default manager parameters object used in {@link + * javax.net.ssl.KeyManagerFactory} instances if no key stores are + * specified through security properties. + */ +public final class NullManagerParameters implements ManagerFactoryParameters +{ +} diff --git a/gnu/javax/net/ssl/PrivateCredentials.java b/gnu/javax/net/ssl/PrivateCredentials.java new file mode 100644 index 000000000..f602f98ae --- /dev/null +++ b/gnu/javax/net/ssl/PrivateCredentials.java @@ -0,0 +1,360 @@ +/* PrivateCredentials.java -- private key/certificate pairs. + 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.net.ssl; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +import java.math.BigInteger; + +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; + +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +import gnu.javax.security.auth.callback.ConsoleCallbackHandler; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; + +/** + * An instance of a manager factory parameters for holding a single + * certificate/private key pair, encoded in PEM format. + */ +public class PrivateCredentials implements ManagerFactoryParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + public static final String BEGIN_DSA = "-----BEGIN DSA PRIVATE KEY"; + public static final String END_DSA = "-----END DSA PRIVATE KEY"; + public static final String BEGIN_RSA = "-----BEGIN RSA PRIVATE KEY"; + public static final String END_RSA = "-----END RSA PRIVATE KEY"; + + private List privateKeys; + private List certChains; + + // Constructor. + // ------------------------------------------------------------------------- + + public PrivateCredentials() + { + privateKeys = new LinkedList(); + certChains = new LinkedList(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void add(InputStream certChain, InputStream privateKey) + throws CertificateException, InvalidKeyException, InvalidKeySpecException, + IOException, NoSuchAlgorithmException, WrongPaddingException + { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Collection certs = cf.generateCertificates(certChain); + X509Certificate[] chain = (X509Certificate[]) certs.toArray(new X509Certificate[0]); + + String alg = null; + String line = readLine(privateKey); + String finalLine = null; + if (line.startsWith(BEGIN_DSA)) + { + alg = "DSA"; + finalLine = END_DSA; + } + else if (line.startsWith(BEGIN_RSA)) + { + alg = "RSA"; + finalLine = END_RSA; + } + else + throw new IOException("Unknown private key type."); + + boolean encrypted = false; + String cipher = null; + String salt = null; + StringBuffer base64 = new StringBuffer(); + while (true) + { + line = readLine(privateKey); + if (line == null) + throw new EOFException("premature end-of-file"); + else if (line.startsWith("Proc-Type: 4,ENCRYPTED")) + encrypted = true; + else if (line.startsWith("DEK-Info: ")) + { + int i = line.indexOf(','); + if (i < 0) + cipher = line.substring(10).trim(); + else + { + cipher = line.substring(10, i).trim(); + salt = line.substring(i + 1).trim(); + } + } + else if (line.startsWith(finalLine)) + break; + else if (line.length() > 0) + { + base64.append(line); + base64.append(System.getProperty("line.separator")); + } + } + + byte[] enckey = Base64.decode(base64.toString()); + if (encrypted) + { + enckey = decryptKey(enckey, cipher, toByteArray(salt)); + } + + DERReader der = new DERReader(enckey); + if (der.read().getTag() != DER.SEQUENCE) + throw new IOException("malformed DER sequence"); + der.read(); // version + + KeyFactory kf = KeyFactory.getInstance(alg); + KeySpec spec = null; + if (alg.equals("DSA")) + { + BigInteger p = (BigInteger) der.read().getValue(); + BigInteger q = (BigInteger) der.read().getValue(); + BigInteger g = (BigInteger) der.read().getValue(); + der.read(); // y + BigInteger x = (BigInteger) der.read().getValue(); + spec = new DSAPrivateKeySpec(x, p, q, g); + } + else + { + spec = new RSAPrivateCrtKeySpec( + (BigInteger) der.read().getValue(), // modulus + (BigInteger) der.read().getValue(), // pub exponent + (BigInteger) der.read().getValue(), // priv expenent + (BigInteger) der.read().getValue(), // prime p + (BigInteger) der.read().getValue(), // prime q + (BigInteger) der.read().getValue(), // d mod (p-1) + (BigInteger) der.read().getValue(), // d mod (q-1) + (BigInteger) der.read().getValue()); // coefficient + } + privateKeys.add(kf.generatePrivate(spec)); + certChains.add(chain); + } + + public List getPrivateKeys() + { + if (isDestroyed()) + { + throw new IllegalStateException("this object is destroyed"); + } + return privateKeys; + } + + public List getCertChains() + { + return certChains; + } + + public void destroy() + { + privateKeys.clear(); + privateKeys = null; + } + + public boolean isDestroyed() + { + return (privateKeys == null); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private String readLine(InputStream in) throws IOException + { + boolean eol_is_cr = System.getProperty("line.separator").equals("\r"); + StringBuffer str = new StringBuffer(); + while (true) + { + int i = in.read(); + if (i == -1) + { + if (str.length() > 0) + break; + else + return null; + } + else if (i == '\r') + { + if (eol_is_cr) + break; + } + else if (i == '\n') + break; + else + str.append((char) i); + } + return str.toString(); + } + + private byte[] decryptKey(byte[] ct, String cipher, byte[] salt) + throws IOException, InvalidKeyException, WrongPaddingException + { + byte[] pt = new byte[ct.length]; + IMode mode = null; + if (cipher.equals("DES-EDE3-CBC")) + { + mode = ModeFactory.getInstance("CBC", "TripleDES", 8); + HashMap attr = new HashMap(); + attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 24)); + attr.put(IMode.IV, salt); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + mode.init(attr); + } + else if (cipher.equals("DES-CBC")) + { + mode = ModeFactory.getInstance("CBC", "DES", 8); + HashMap attr = new HashMap(); + attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 8)); + attr.put(IMode.IV, salt); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + mode.init(attr); + } + else + throw new IllegalArgumentException("unknown cipher: " + cipher); + + for (int i = 0; i < ct.length; i += 8) + mode.update(ct, i, pt, i); + + int pad = pt[pt.length-1]; + if (pad < 1 || pad > 8) + throw new WrongPaddingException(); + for (int i = pt.length - pad; i < pt.length; i++) + { + if (pt[i] != pad) + throw new WrongPaddingException(); + } + + byte[] result = new byte[pt.length - pad]; + System.arraycopy(pt, 0, result, 0, result.length); + return result; + } + + private byte[] deriveKey(byte[] salt, int keylen) + throws IOException + { + CallbackHandler passwordHandler = new ConsoleCallbackHandler(); + try + { + Class c = Class.forName(Security.getProperty("jessie.password.handler")); + passwordHandler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + + PasswordCallback passwdCallback = + new PasswordCallback("Enter PEM passphrase: ", false); + try + { + passwordHandler.handle(new Callback[] { passwdCallback }); + } + catch (UnsupportedCallbackException uce) + { + throw new IOException("specified handler cannot handle passwords"); + } + char[] passwd = passwdCallback.getPassword(); + + IMessageDigest md5 = HashFactory.getInstance("MD5"); + byte[] key = new byte[keylen]; + int count = 0; + while (count < keylen) + { + for (int i = 0; i < passwd.length; i++) + md5.update((byte) passwd[i]); + md5.update(salt, 0, salt.length); + byte[] digest = md5.digest(); + int len = Math.min(digest.length, keylen - count); + System.arraycopy(digest, 0, key, count, len); + count += len; + if (count >= keylen) + break; + md5.reset(); + md5.update(digest, 0, digest.length); + } + passwdCallback.clearPassword(); + return key; + } + + private byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } +} diff --git a/gnu/javax/net/ssl/SRPManagerParameters.java b/gnu/javax/net/ssl/SRPManagerParameters.java new file mode 100644 index 000000000..a2a745e1b --- /dev/null +++ b/gnu/javax/net/ssl/SRPManagerParameters.java @@ -0,0 +1,81 @@ +/* SRPManagerParameters.java -- Wrapper for SRP PasswordFile. + 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.net.ssl; + +import javax.net.ssl.ManagerFactoryParameters; +import gnu.javax.crypto.sasl.srp.PasswordFile; + +/** + * Instances of this class are used to initialize {@link + * javax.net.ssl.TrustManagerFactory} instances for the ``SRP'' algorithm. + */ +public class SRPManagerParameters implements ManagerFactoryParameters +{ + + // Field. + // ------------------------------------------------------------------------- + + private final PasswordFile file; + + // Constructor. + // ------------------------------------------------------------------------- + + /** + * Initializes these parameters with the specified SRP password file. + * + * @param file The SRP password file object. + * @throws NullPointerException if <i>file</i> is <code>null</code>. + */ + public SRPManagerParameters(PasswordFile file) + { + if (file == null) + { + throw new NullPointerException(); + } + this.file = file; + } + + // Instance method. + // ------------------------------------------------------------------------- + + public PasswordFile getPasswordFile() + { + return file; + } +} diff --git a/gnu/javax/net/ssl/SRPTrustManager.java b/gnu/javax/net/ssl/SRPTrustManager.java new file mode 100644 index 000000000..664fa4cab --- /dev/null +++ b/gnu/javax/net/ssl/SRPTrustManager.java @@ -0,0 +1,99 @@ +/* SRPTrustManager.java -- interface to SRP trust managers. + 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.net.ssl; + +import gnu.javax.crypto.sasl.srp.PasswordFile; + +import java.math.BigInteger; +import java.security.KeyPair; +import javax.net.ssl.TrustManager; + +/** + * A trust manager for secure remote password (SRP) key exchange cipher + * suites. This is a read-only interface to the {@link + * gnu.crypto.sasl.srp.PasswordFile} class, with convenience methods to + * generate session key pairs. + */ +public interface SRPTrustManager extends TrustManager +{ + + // Methods. + // ------------------------------------------------------------------------- + + /** + * Tests if the configured password file contains the specified user name. + * + * @param user The user name. + * @return True if the password file has an entry for <i>user</i> + */ + boolean contains(String user); + + /** + * Create and return a session SRP key pair for the given user name. + * + * @param user The user name to generate the key pair for. + * @return The session key pair, or <code>null</code> if there is no + * entry for <i>user</i>. + */ + KeyPair getKeyPair(String user); + + /** + * Returns the salt value for the given user. + * + * @param user The user name. + * @return The salt for <i>user</i>'s entry, or <code>null</code>. + */ + byte[] getSalt(String user); + + /** + * Returns the password verifier for the given user. + * + * @param user The user name. + * @return <i>user</i>'s password verifier, or <code>null</code>. + */ + BigInteger getVerifier(String user); + + /** + * Returns a reference to the SRP {@link PasswordFile} used by this + * {@link TrustManager}. + * + * @return a reference to the SRP password file in use. + */ + PasswordFile getPasswordFile(); +} diff --git a/gnu/javax/net/ssl/StaticTrustAnchors.java b/gnu/javax/net/ssl/StaticTrustAnchors.java new file mode 100644 index 000000000..0c2c3cca8 --- /dev/null +++ b/gnu/javax/net/ssl/StaticTrustAnchors.java @@ -0,0 +1,1942 @@ +/* StaticTrustAnchors.java -- static list of CA certificates. + 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.net.ssl; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import java.util.LinkedList; + +import javax.net.ssl.ManagerFactoryParameters; + +/** + * This class implements a simple set of trust anchors suitable for + * initializing a TrustManagerFactory for the "JessieX509" algorithm. + * + * <p>The important field of this class is the {@link #CA_CERTS} + * constant, which contains an array of commonly accepted CA + * certificates. + */ +public class StaticTrustAnchors implements ManagerFactoryParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private X509Certificate[] certs; + + // Constructor. + // ------------------------------------------------------------------------- + + public StaticTrustAnchors(X509Certificate[] certs) + { + this.certs = (X509Certificate[]) certs.clone(); + } + + // Class method. + // ------------------------------------------------------------------------- + + public static X509Certificate generate(CertificateFactory factory, + String encoded) + { + try + { + ByteArrayInputStream in = + new ByteArrayInputStream(encoded.getBytes("UTF-8")); + return (X509Certificate) factory.generateCertificate(in); + } + catch (Exception x) + { + return null; + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public X509Certificate[] getCertificates() + { + return (X509Certificate[]) certs.clone(); + } + + // Constant. + // ------------------------------------------------------------------------- + + /** + * A list of known certificate authority certificates. This set of + * certificates is the same as the default CA certificates used by + * Mozilla. + */ + public static final StaticTrustAnchors CA_CERTS; + + // Static initializer. + // ------------------------------------------------------------------------- + + static + { + LinkedList certs = new LinkedList(); + CertificateFactory factory = null; + + try + { + factory = CertificateFactory.getInstance("X.509"); + } + catch (CertificateException ce) + { + throw new Error(ce.toString()); + } + + X509Certificate cert = generate(factory, + // ABAecom_=sub.__Am._Bankers_Assn.=_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEF\n" + + "BQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2Fz\n" + + "aGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFC\n" + + "QS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3Ry\n" + + "dXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQsw\n" + + "CQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24x\n" + + "FzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBS\n" + + "b290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20w\n" + + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVC\n" + + "AOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQK\n" + + "pSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV\n" + + "6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665Wc\n" + + "OQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJV\n" + + "jO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9\n" + + "cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8C\n" + + "AQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k\n" + + "qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvT\n" + + "ZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHeg\n" + + "TYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm\n" + + "/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgx\n" + + "fexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJ\n" + + "TzFxiNmIf1Q=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AOL_Time_Warner_Root_Certification_Authority_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" + + "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" + + "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" + + "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAw\n" + + "MFoXDTM3MTEyMDE1MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" + + "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" + + "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" + + "dGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" + + "ggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U0pPlLYnKhHw/EEMbjIt8hFj4JHxI\n" + + "zyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItITuLCxFlpMGK2MKKMCxGZYTVt\n" + + "fu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAfRC+iYkGzuxgh28pxPIzs\n" + + "trkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqFzQ6axOAAsNUl6twr\n" + + "5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqhBC4aMqiaILGc\n" + + "LCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEAAaNjMGEw\n" + + "DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jYPXy+\n" + + "XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/\n" + + "BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNM\n" + + "eUWn9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7\n" + + "CegCgTXTCt8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77Bf\n" + + "WgDrvq2g+EQFZ7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oT\n" + + "LW4jYYehY0KswsuXn2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCz\n" + + "vhGbRWeDhhmH05i9CBoWH1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmw\n" + + "X7A5KGgOc90lmt4S\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AOL_Time_Warner_Root_Certification_Authority_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" + + "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" + + "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" + + "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw\n" + + "MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" + + "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" + + "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" + + "dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\n" + + "ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs\n" + + "RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs\n" + + "i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg\n" + + "/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ\n" + + "2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0\n" + + "ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X\n" + + "+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml\n" + + "J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh\n" + + "EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo\n" + + "Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ\n" + + "Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex\n" + + "MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB\n" + + "Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA\n" + + "FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG\n" + + "9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0\n" + + "cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF\n" + + "ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY\n" + + "vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/\n" + + "drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la\n" + + "5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks\n" + + "mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5\n" + + "O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD\n" + + "062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41\n" + + "xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H\n" + + "hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL\n" + + "Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_External_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4\n" + + "dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h\n" + + "bCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzEL\n" + + "MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1B\n" + + "ZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1\n" + + "c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n" + + "AQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8\n" + + "k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50\n" + + "ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504\n" + + "B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDez\n" + + "eWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5\n" + + "aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB\n" + + "3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQD\n" + + "AgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6\n" + + "xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\n" + + "cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdv\n" + + "cmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ\n" + + "KoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl\n" + + "j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5R\n" + + "xNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjT\n" + + "K3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1\n" + + "n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHx\n" + + "REzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O\n" + + "hgQ=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Low-Value_Services_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" + + "HhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" + + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwze\n" + + "xODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGI\n" + + "gb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0O\n" + + "M3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1Lc\n" + + "sRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5\n" + + "mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG\n" + + "9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCU\n" + + "tr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/\n" + + "MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQsw\n" + + "CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk\n" + + "ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAx\n" + + "IENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0\n" + + "MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph\n" + + "iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9\n" + + "tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL\n" + + "/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlV\n" + + "g3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6\n" + + "tkD9xOQ14R0WHNC8K47Wcdk=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Public_Services_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAe\n" + + "Fw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNF\n" + + "MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ\n" + + "IE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB\n" + + "IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+\n" + + "A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c\n" + + "+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2\n" + + "P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKX\n" + + "C1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8R\n" + + "s3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9\n" + + "BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAf\n" + + "d59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCB\n" + + "jgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkG\n" + + "A1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU\n" + + "cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENB\n" + + "IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu\n" + + "G7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL\n" + + "+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbj\n" + + "PGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bY\n" + + "GozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6\n" + + "NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362Kqx\n" + + "My3ZdvJOOjMMK7MtkAY=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Qualified_Certificates_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9v\n" + + "dDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYT\n" + + "AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg\n" + + "VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS\n" + + "b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoek\n" + + "n0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKk\n" + + "IhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6z\n" + + "sLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1t\n" + + "UvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R\n" + + "+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES\n" + + "a0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5\n" + + "lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw\n" + + "AwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkw\n" + + "ZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL\n" + + "ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVh\n" + + "bGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh\n" + + "lRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG\n" + + "GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx9\n" + + "5dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKF\n" + + "Yqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVA\n" + + "wRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQw\n" + + "dOUeqN48Jzd/g66ed8/wMLH/S5noxqE=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // America_Online_Root_Certification_Authority_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" + + "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4X\n" + + "DTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMx\n" + + "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" + + "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw\n" + + "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCa\n" + + "xlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXl\n" + + "GbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7n\n" + + "BzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145Lcx\n" + + "VR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiE\n" + + "mf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu\n" + + "JKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n" + + "HQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z5\n" + + "9m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUA\n" + + "A4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF\n" + + "Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOM\n" + + "IOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI\n" + + "dGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g\n" + + "Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j\n" + + "8uB9Gr784N/Xx6dssPmuujz9dLQR6FgNgLzTqIA6me11zEZ7\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // America_Online_Root_Certification_Authority_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" + + "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4X\n" + + "DTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMx\n" + + "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" + + "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw\n" + + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssN\n" + + "t79Hc9PwVU3dxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/\n" + + "DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7x\n" + + "uhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE\n" + + "18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxr\n" + + "kJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD\n" + + "bi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcX\n" + + "uVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVu\n" + + "Y8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9\n" + + "W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ\n" + + "o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48\n" + + "ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn\n" + + "AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op\n" + + "aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNee\n" + + "MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypL\n" + + "M7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qf\n" + + "tIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjR\n" + + "Ywu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R\n" + + "+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr\n" + + "+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVM\n" + + "nNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOt\n" + + "d+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh1NolNscI\n" + + "WC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZ\n" + + "ZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y\n" + + "3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz\n" + + "2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw\n" + + "RY8mkaKO/qk=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Code_Signing_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDpjCCAo6gAwIBAgIEAgAAvzANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MS8wLQYDVQQDEyZCYWx0aW1vcmUgQ3liZXJUcnVzdCBDb2RlIFNpZ25pbmcg\n" + + "Um9vdDAeFw0wMDA1MTcxNDAxMDBaFw0yNTA1MTcyMzU5MDBaMGcxCzAJBgNV\n" + + "BAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1\n" + + "c3QxLzAtBgNVBAMTJkJhbHRpbW9yZSBDeWJlclRydXN0IENvZGUgU2lnbmlu\n" + + "ZyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHGaGBKO\n" + + "etv5mvxBr9jy9AmOrT/+Zzc82skmULGxPsvoTnMA8rLc88VG+wnvGJbOp+Cc\n" + + "hF0gDnqgqjaL+ii2eC6z7OhH8wTwkCO06q/lU7gF90ddK4bxp6TGOzW20g1S\n" + + "Qdf0knXhogpQVoe+lwt7M4UQuSgY7jPqSBHXW5FHdiLU7s9d56hOHJ2Wkd2c\n" + + "vXQJqHJhqrAhOvE9LANWCdLB3MO1x1Q3q+YmorJGcXPKEYjuvOdk99ARGnNA\n" + + "WshJLA+375B/aIAEOAsbDzvU9aCzwo7hNLSAmW2edtSSKUCxldI3pGcSf+Bi\n" + + "u641xZk2gkS45ngYM2Fxk1stjZ94lYLrbQIDAQABo1owWDATBgNVHSUEDDAK\n" + + "BggrBgEFBQcDAzAdBgNVHQ4EFgQUyEE0XBUVBOVA8tGrmm8kknqHQlowEgYD\n" + + "VR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEF\n" + + "BQADggEBAFJ0qpVLIozHPZak/l36L7W86/AL6VY4HdFtDaG8aIvwxYClJDT9\n" + + "8pYYEYahNvU351RA1WQfw19wQmstOceeUgXO52py0o1yP0dQg6vHjSXJsOOn\n" + + "UxaVpmpT6hidj3ipd3ca+bSXR1mIJyi1yuEu1z4Oog24IkQD49FjsEE6ofWk\n" + + "Lfd2HgRUmXgyQNcrfE26ppyweW4Hvozs7tc4aVvBDFZon/7r0eHIiPnyzX++\n" + + "hbREZwBQPvQmA2Tqd33oXj4cN0fI1uqk8zY8l8I5cgWUGSXD1zdBD8Efh4r9\n" + + "qr7psWRX5NuSoc/hSeg7H5ETWsOP2SVYSYBHD8YDrqzjv7fAqio=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Mobile_Commerce_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICfTCCAeagAwIBAgIEAgAAuDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MSkwJwYDVQQDEyBCYWx0aW1vcmUgQ3liZXJUcnVzdCBNb2JpbGUgUm9vdDAe\n" + + "Fw0wMDA1MTIxODIwMDBaFw0yMDA1MTIyMzU5MDBaMGExCzAJBgNVBAYTAklF\n" + + "MRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxKTAn\n" + + "BgNVBAMTIEJhbHRpbW9yZSBDeWJlclRydXN0IE1vYmlsZSBSb290MIGfMA0G\n" + + "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjbbE4Vqz8tVYh3sCQXSZHgsZ9jx+g\n" + + "hY8vu9ThHB3yJB8osC+5pKVvoiIgZP6ERzx+K2xparjUwJaOjFINzW9B1L8E\n" + + "rqeBLy2YSNLBlKO1GV1dUWT0jkGwm8AtIqBexthaEmO8EUpeJhId4iYF5g9f\n" + + "Ih96X3aUrs9aKA6rRdoiMQIDAQABo0IwQDAdBgNVHQ4EFgQUyeKPwAImWrbA\n" + + "B+N/lAcY2y6lmnAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAUwgLJgl4QnPU7Hp3Rw3jCzNx764zFE37+v0a\n" + + "t1H15JkcBnHXKRnX5hUgUVFGbU/eGEmY0Ph4u3HojQEG1ddkj5TfR/6ghWk2\n" + + "qS9CemhKEtaLC3BECqQE7yaIwTVxOF0bW0hC8OeUHHCVNKir9avieK318FL9\n" + + "m+pCDOjYVL5TZvU=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUx\n" + + "MjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNV\n" + + "BAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZ\n" + + "QmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD\n" + + "ggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+h\n" + + "Xe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gR\n" + + "QKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP\n" + + "wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1\n" + + "pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNT\n" + + "Px8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC\n" + + "AwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1Ud\n" + + "EwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA\n" + + "A4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkT\n" + + "I7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n" + + "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/\n" + + "oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67\n" + + "G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H\n" + + "RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" + + "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" + + "DwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQw\n" + + "MjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" + + "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEB\n" + + "AQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR\n" + + "EmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth\n" + + "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0\n" + + "dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" + + "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" + + "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx\n" + + "MDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3\n" + + "pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNV\n" + + "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" + + "DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN\n" + + "QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomA\n" + + "sH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6\n" + + "w4pl\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGp\n" + + "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" + + "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" + + "LjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx\n" + + "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDEx\n" + + "ODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" + + "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" + + "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx\n" + + "FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" + + "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" + + "ANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3U\n" + + "q4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEF\n" + + "koPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXh\n" + + "TizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4Wd\n" + + "lGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn\n" + + "7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG\n" + + "9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+\n" + + "LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvV\n" + + "WlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX\n" + + "8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn8\n" + + "6Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsT\n" + + "F7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" + + "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" + + "DwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3\n" + + "MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" + + "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEB\n" + + "AQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB\n" + + "w18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e\n" + + "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd\n" + + "55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" + + "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" + + "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw\n" + + "OTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6s\n" + + "NS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNV\n" + + "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" + + "DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR\n" + + "xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLb\n" + + "dHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih\n" + + "w6ID\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_4.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGp\n" + + "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" + + "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" + + "LjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx\n" + + "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAy\n" + + "MjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" + + "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" + + "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx\n" + + "FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" + + "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" + + "ANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6\n" + + "ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5\n" + + "/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9\n" + + "MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ih\n" + + "YqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCv\n" + + "bK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG\n" + + "9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWog\n" + + "WxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6\n" + + "HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV\n" + + "6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8\n" + + "PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30\n" + + "sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Global_Secure_Personal_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB\n" + + "X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" + + "HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" + + "c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy\n" + + "MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" + + "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y\n" + + "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg\n" + + "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp\n" + + "ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA\n" + + "A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU\n" + + "rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB\n" + + "3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y\n" + + "NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E\n" + + "gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw\n" + + "PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy\n" + + "ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0\n" + + "Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy\n" + + "dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw\n" + + "IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD\n" + + "AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW\n" + + "BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2\n" + + "fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA\n" + + "O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L\n" + + "a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l\n" + + "TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Global_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf\n" + + "Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc\n" + + "KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz\n" + + "dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe\n" + + "Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF\n" + + "bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg\n" + + "aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg\n" + + "MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l\n" + + "dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G\n" + + "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw\n" + + "tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK\n" + + "wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI\n" + + "XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD\n" + + "AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu\n" + + "dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp\n" + + "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy\n" + + "MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0\n" + + "IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw\n" + + "NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc\n" + + "/vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV\n" + + "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq\n" + + "hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv\n" + + "yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp\n" + + "bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/\n" + + "bIkz8OwVDw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Premium_2048_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf\n" + + "MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" + + "HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" + + "c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy\n" + + "MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" + + "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y\n" + + "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg\n" + + "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy\n" + + "dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF\n" + + "AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4\n" + + "QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC\n" + + "DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj\n" + + "/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP\n" + + "KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd\n" + + "enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\n" + + "4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB\n" + + "0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ\n" + + "FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh\n" + + "fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU\n" + + "KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho\n" + + "wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2\n" + + "+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888\n" + + "6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Secure_Personal_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE\n" + + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50\n" + + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs\n" + + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp\n" + + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0\n" + + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa\n" + + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV\n" + + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw\n" + + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50\n" + + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50\n" + + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL\n" + + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv\n" + + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV\n" + + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173\n" + + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw\n" + + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50\n" + + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff\n" + + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE\n" + + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50\n" + + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD\n" + + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D\n" + + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx\n" + + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW\n" + + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG\n" + + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI\n" + + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ\n" + + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU\n" + + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE\n" + + "PHayXOw=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE\n" + + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50\n" + + "cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl\n" + + "MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE\n" + + "AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw\n" + + "CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3\n" + + "dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh\n" + + "Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow\n" + + "OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp\n" + + "b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0\n" + + "VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN\n" + + "iC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHk\n" + + "mGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHT\n" + + "MBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHY\n" + + "pIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5\n" + + "BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChs\n" + + "aW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM\n" + + "aW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl\n" + + "cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNo\n" + + "dHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAi\n" + + "gA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMC\n" + + "AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYE\n" + + "FPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9\n" + + "B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKn\n" + + "CqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2Zcgx\n" + + "xufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6\n" + + "rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" + + "EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1\n" + + "cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4\n" + + "MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgx\n" + + "LTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0\n" + + "eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R\n" + + "FGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO\n" + + "/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuv\n" + + "K9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" + + "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEt\n" + + "MCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5\n" + + "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL\n" + + "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9Qw\n" + + "HQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8w\n" + + "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" + + "AFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n" + + "7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2u\n" + + "FHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_Global_eBusiness_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1\n" + + "aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0\n" + + "MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoT\n" + + "E0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJl\n" + + "IEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" + + "gYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQy\n" + + "td4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORR\n" + + "OhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2EC\n" + + "AwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "HwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6o\n" + + "oHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf\n" + + "2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxa\n" + + "z2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1\n" + + "pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_eBusiness_CA_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1\n" + + "aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcN\n" + + "MjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZh\n" + + "eCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu\n" + + "ZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe\n" + + "k6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5\n" + + "/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXW\n" + + "HXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCG\n" + + "SAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4\n" + + "MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBq\n" + + "R3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm\n" + + "JXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1\n" + + "tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYr\n" + + "tWKmpj29f5JZzVoqgrI3eQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_eBusiness_CA_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" + + "EwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlm\n" + + "YXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5\n" + + "MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXgg\n" + + "U2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0Et\n" + + "MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF\n" + + "7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKD\n" + + "pkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HM\n" + + "HMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" + + "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBT\n" + + "ZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y\n" + + "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL\n" + + "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYw\n" + + "HQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8w\n" + + "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" + + "AAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy\n" + + "0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkt\n" + + "y3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GTE_CyberTrust_Global_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw\n" + + "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy\n" + + "dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg\n" + + "R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1\n" + + "MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD\n" + + "VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT\n" + + "GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA\n" + + "A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4\n" + + "ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn\n" + + "ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F\n" + + "LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3\n" + + "46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq\n" + + "81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d\n" + + "XIVtx6quTx8itc2VrbqnzPmrC3p/\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GTE_CyberTrust_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw\n" + + "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy\n" + + "dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw\n" + + "CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD\n" + + "ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n" + + "iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K\n" + + "DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw\n" + + "KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID\n" + + "AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD\n" + + "+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv\n" + + "U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e\n" + + "6bR64eVaH4QwnNOfpSXY\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GeoTrust_Global_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYT\n" + + "AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz\n" + + "dCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBC\n" + + "MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE\n" + + "AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + + "MIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH\n" + + "CIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlC\n" + + "GDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7\n" + + "csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAj\n" + + "Nvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdRe\n" + + "JivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQAB\n" + + "o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9\n" + + "qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkq\n" + + "hkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Qzxpe\n" + + "R+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWV\n" + + "Yrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n" + + "PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot\n" + + "2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX\n" + + "xx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm\n" + + "Mw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GlobalSign_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzEL\n" + + "MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNV\n" + + "BAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05\n" + + "ODA5MDExMjAwMDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkw\n" + + "FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRsw\n" + + "GQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR\n" + + "4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc\n" + + "71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4\n" + + "bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgK\n" + + "OOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMW\n" + + "ea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP\n" + + "AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQUYHtmGkUNl8qJ\n" + + "UC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOC\n" + + "AQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq75bCd\n" + + "PTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q\n" + + "gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT\n" + + "2iHRrH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlD\n" + + "NPYPhyk7ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBg\n" + + "Hcl5JLL2bP2oZg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Root_Certificate_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f\n" + + "NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM\n" + + "MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34\n" + + "t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b\n" + + "e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu\n" + + "PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A\n" + + "PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Security_1024_v3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF\n" + + "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" + + "U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx\n" + + "NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" + + "QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + + "gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY\n" + + "rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt\n" + + "bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB\n" + + "o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME\n" + + "GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N\n" + + "AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy\n" + + "HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9\n" + + "am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B\n" + + "qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Security_2048_v3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF\n" + + "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" + + "U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5\n" + + "MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" + + "QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + + "CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37\n" + + "RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E\n" + + "0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J\n" + + "6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq\n" + + "s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD\n" + + "uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw\n" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW\n" + + "gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6\n" + + "/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V\n" + + "EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g\n" + + "EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+\n" + + "f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq\n" + + "aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk\n" + + "llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA\n" + + "pKnXwiJPZ9d37CAFYd4=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // TC_TrustCenter__Germany__Class_2_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" + + "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" + + "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" + + "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB\n" + + "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" + + "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" + + "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" + + "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" + + "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEp\n" + + "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" + + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmk\n" + + "qYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJO\n" + + "gtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7\n" + + "zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" + + "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" + + "CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+W\n" + + "LDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xR\n" + + "T3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac\n" + + "ASZ4smZHcFFk\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // TC_TrustCenter__Germany__Class_3_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" + + "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" + + "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" + + "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENB\n" + + "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" + + "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" + + "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" + + "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" + + "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEp\n" + + "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" + + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQ\n" + + "GwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYn\n" + + "v68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvA\n" + + "o+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" + + "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" + + "CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4\n" + + "iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yC\n" + + "GdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS\n" + + "CdS7kjXvD9s0\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Basic_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl\n" + + "cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp\n" + + "Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow\n" + + "gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV\n" + + "BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm\n" + + "BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV\n" + + "BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ\n" + + "cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB\n" + + "jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK\n" + + "P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ\n" + + "fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j\n" + + "kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB\n" + + "gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7\n" + + "c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95\n" + + "B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Freemail_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl\n" + + "cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m\n" + + "cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz\n" + + "NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx\n" + + "EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp\n" + + "bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" + + "JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG\n" + + "SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq\n" + + "hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N\n" + + "j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef\n" + + "QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY\n" + + "x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq\n" + + "hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP\n" + + "MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC\n" + + "neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr\n" + + "5PjRzneigQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Premium_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl\n" + + "cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy\n" + + "ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5\n" + + "NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw\n" + + "EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n\n" + + "MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw\n" + + "IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3\n" + + "DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7\n" + + "7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j\n" + + "Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq\n" + + "W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\n" + + "DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH\n" + + "b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx\n" + + "eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1\n" + + "KzGJ\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Premium_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" + + "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl\n" + + "IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl\n" + + "cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1\n" + + "OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ\n" + + "BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg\n" + + "Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" + + "ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3\n" + + "DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B\n" + + "AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI\n" + + "NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL\n" + + "lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN\n" + + "9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B\n" + + "AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI\n" + + "hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ\n" + + "a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU\n" + + "Qg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" + + "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl\n" + + "IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0\n" + + "ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG\n" + + "A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw\n" + + "ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE\n" + + "CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ\n" + + "VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz\n" + + "QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I\n" + + "/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC\n" + + "6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX\n" + + "TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD\n" + + "TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e\n" + + "QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni\n" + + "TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Time_Stamping_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls\n" + + "bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj\n" + + "YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw\n" + + "MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT\n" + + "BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN\n" + + "BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x\n" + + "HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN\n" + + "AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8\n" + + "WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR\n" + + "5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7\n" + + "X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN\n" + + "AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK\n" + + "0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8\n" + + "zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ\n" + + "SdM=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // UTN-USER_First-Network_Applications.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUF\n" + + "ADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0\n" + + "IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw\n" + + "HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVU\n" + + "Ti1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0\n" + + "ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT\n" + + "AlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVT\n" + + "RVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz\n" + + "dC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNh\n" + + "dGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZV\n" + + "hawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAb\n" + + "GHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZ\n" + + "NaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4\n" + + "xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv\n" + + "/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7i\n" + + "gEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD\n" + + "AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf\n" + + "8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0\n" + + "LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G\n" + + "CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXh\n" + + "i6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUq\n" + + "f9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAf\n" + + "hZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvP\n" + + "NximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+\n" + + "FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjis\n" + + "H8SE\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_Class_1_VA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw\n" + + "8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m\n" + + "+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSN\n" + + "dnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+V\n" + + "YH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8so\n" + + "gTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw\n" + + "nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_Class_2_VA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc\n" + + "65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ\n" + + "b7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcn\n" + + "wbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4\n" + + "OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZ\n" + + "oDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n" + + "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDSDCCArGgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjEkMCIGA1UEBxMb\n" + + "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2Vy\n" + + "dCwgSW5jLjEsMCoGA1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0\n" + + "eSAtIE9DU1AxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEg\n" + + "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb20wHhcNMDAwMjEyMTE1\n" + + "MDA1WhcNMDUwMjEwMTE1MDA1WjCBsjEkMCIGA1UEBxMbVmFsaUNlcnQgVmFs\n" + + "aWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjEsMCoG\n" + + "A1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0eSAtIE9DU1AxITAf\n" + + "BgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEgMB4GCSqGSIb3DQEJ\n" + + "ARYRaW5mb0B2YWxpY2VydC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ\n" + + "AoGBAMeML6fDQIc7PdfEmlgUZArDCDliGs/S66nxaXSKyg5adsyiUk7Q88R6\n" + + "tfimHLujp6RTh1uNwAC71WYk53TGFsivyANi1TKHolKRRJSVqEdDbaVInPZM\n" + + "ddVPYufJ/3v0JIynvCh2tTKgJXO3Ry94+Eb5hxTwd/wKd+hP/Ywf+mLZAgMB\n" + + "AAGjbDBqMA8GCSsGAQUFBzABBQQCBQAwEwYDVR0lBAwwCgYIKwYBBQUHAwkw\n" + + "CwYDVR0PBAQDAgGGMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0\n" + + "cDovL29jc3AyLnZhbGljZXJ0Lm5ldDANBgkqhkiG9w0BAQUFAAOBgQAVxeC4\n" + + "NHISBiCoYpWT0byTupCr3E6Njo2YTOMy9Ss/s5f7qqKtQJetaL1crVMO0Kaz\n" + + "DawamY2qMB7PDnD/ArB3ZYPN2gdcUs1Zu6LI4rQWg4/UlXmTLei/RJMxkjDT\n" + + "NDTxEPshrC70w11kY3qZ4ZqrQh1IZqZ3N7hVPK3+ZbBi6Q==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8x\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE\n" + + "CxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNV\n" + + "BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh\n" + + "c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCB\n" + + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3\n" + + "noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B\n" + + "9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg\n" + + "1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBM\n" + + "P7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P\n" + + "/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjj\n" + + "t/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq\n" + + "0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9\n" + + "Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6c\n" + + "PvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9Zr\n" + + "bWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul\n" + + "uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4i\n" + + "P/68DzFc6PLZ\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRR\n" + + "ZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6j\n" + + "Rx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKsh\n" + + "JlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7P\n" + + "oBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2\n" + + "6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHh\n" + + "v2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQ\n" + + "BfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N\n" + + "y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUf\n" + + "xJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFM\n" + + "DSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5\n" + + "SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXV\n" + + "OBRgmaNL3gaWcSzy27YfpO8/7g==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAx\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC57V56Ondfzl86UvzNZPdxtW9qlsZZklWUXS9bLsER\n" + + "6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQDalbBgyzhb1upVFAkSsYuekyh\n" + + "WzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4S8co5GYjhFHvRreT2IEz\n" + + "y+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" + + "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" + + "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" + + "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" + + "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMX\n" + + "fH8C6dX3i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4\n" + + "KY2kpXeH9fErJq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z\n" + + "6k/BEVmXarIrE7HarZehs7GgIFvKMquNzxPwHynD\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" + + "Ey5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" + + "cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" + + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZM\n" + + "JaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvE\n" + + "erf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCC\n" + + "JkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIob\n" + + "K/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxg\n" + + "MxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3\n" + + "Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHB\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNV\n" + + "BAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo\n" + + "b3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4g\n" + + "LSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24g\n" + + "VHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTla\n" + + "MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6\n" + + "BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIElu\n" + + "Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNp\n" + + "Z24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + + "p4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkf\n" + + "rbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+Z\n" + + "Jwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATAN\n" + + "BgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/\n" + + "7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX\n" + + "rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6x\n" + + "RnInjBJ7xUS0rg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcox\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UE\n" + + "CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkg\n" + + "VmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMG\n" + + "A1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp\n" + + "Y2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcx\n" + + "NjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg\n" + + "SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UE\n" + + "CxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1\n" + + "c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJp\n" + + "bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG\n" + + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY8\n" + + "1nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT\n" + + "2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UT\n" + + "AJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQ\n" + + "HgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN\n" + + "qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVC\n" + + "YQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekh\n" + + "ktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf\n" + + "0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydE\n" + + "p85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377B\n" + + "MnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab\n" + + "5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPX\n" + + "p/naOlXJWBD5qu9ats9LS98q\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAy\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQDQymMxYX9ENHwFfQs9apDLeUt3Cj9LxyPlwGItfpx+\n" + + "PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDiWr3I3bR45qVCkwhnAcAgTddc\n" + + "9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ/wtVqxXd+5rBuR10DbKM\n" + + "RF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" + + "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" + + "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" + + "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" + + "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUE\n" + + "nPMmm+M5bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1Vs\n" + + "WJsswrQ0LHozQsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+\n" + + "It3jl6jhvCJDwt1N2/aBnpIUnjkPE1TegtjAXjSN\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" + + "Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" + + "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" + + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q\n" + + "RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In\n" + + "zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a\n" + + "/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM\n" + + "EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw\n" + + "TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk\n" + + "uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM\n" + + "XtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX\n" + + "wc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GV\n" + + "j0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01U\n" + + "bSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i\n" + + "F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo\n" + + "1KpYoJ2daZH9\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2\n" + + "R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDo\n" + + "vFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwg\n" + + "TS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+V\n" + + "k7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ\n" + + "Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJ\n" + + "OxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my\n" + + "/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f\n" + + "j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoA\n" + + "Wii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8S\n" + + "GhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbb\n" + + "o27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh\n" + + "/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAz\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQDx5AgOg7t140jluNum8Lmr6Txix141W9ACVBHYydFW\n" + + "uXZLuat65s269gwE1n7WsAplrE454/H3LaMlOe+wi8++2wxdbnD0B81w9zrA\n" + + "PjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4KC8/BdsEIb/hRWb+PLeC\n" + + "7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCTBCBggr\n" + + "BgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVyaXNp\n" + + "Z24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw\n" + + "KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJ\n" + + "BgNVHRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNj\n" + + "wKke8tCLMzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJU\n" + + "LBMK03cjzzf8Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnE\n" + + "KMLL/J6oia5bPY4S6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_4_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6\n" + + "8OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTK\n" + + "QWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VX\n" + + "xbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGI\n" + + "L4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y\n" + + "cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckzt\n" + + "ImRPT8qAkbYp\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_4_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl\n" + + "S+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXC\n" + + "KtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDc\n" + + "VHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdL\n" + + "MEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY\n" + + "ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDD\n" + + "Zq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr\n" + + "IhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt\n" + + "mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csK\n" + + "vE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluP\n" + + "QSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kP\n" + + "mF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr\n" + + "9Xgn2uf3ZkPznoM+IKrDNWCRzg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_RSA_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu\n" + + "MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD\n" + + "VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb\n" + + "MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O\n" + + "LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs\n" + + "iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC\n" + + "sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw\n" + + "4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr\n" + + "l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1\n" + + "g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Secure_Server_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEF\n" + + "BQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5\n" + + "LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24g\n" + + "QXV0aG9yaXR5MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4x\n" + + "FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6\n" + + "Ly93d3cudmVyaXNpZ24uY29tL1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJl\n" + + "IFNlcnZlciBPQ1NQIFJlc3BvbmRlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" + + "gYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8oXiMM+6f9L452psPTUepjyDoS0S9\n" + + "zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSuzOLDB4Nqo3IQASdiIqY1Jjkt\n" + + "ns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnXOZXYHTWewr2zXcEMSx8C\n" + + "AwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYDVQQDEwhPQ1NQIDEt\n" + + "NDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlzaWduLmNvbS9S\n" + + "U0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwkwQgYI\n" + + "KwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZlcmlz\n" + + "aWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEB\n" + + "MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEw\n" + + "CQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBT\n" + + "ZpxJky4xoAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+\n" + + "TtvOzLqGuBjOsRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8Y\n" + + "dZqfFzP9qSa44+LewqjEWop/mNYHBmvMVp6GcM7U7w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Time_Stamping_Authority_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUF\n" + + "ADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTww\n" + + "OgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24g\n" + + "QXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJ\n" + + "bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlT\n" + + "aWduIFRydXN0IE5ldHdvcmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1\n" + + "OTU5WjCBpTEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\n" + + "cmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh\n" + + "dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTAwMSwwKgYDVQQD\n" + + "EyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1dGhvcml0eSBDQTCBnzANBgkq\n" + + "hkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVlizrQJIkRpivglWtvtDbc2\n" + + "fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU/OB4naCTuQk9I1F/\n" + + "RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11S7zi6ESHzeZB\n" + + "CiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/AgEAMEUG\n" + + "A1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0dHBz\n" + + "Oi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0\n" + + "cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIG\n" + + "CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJp\n" + + "c2lnbi5jb20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2\n" + + "DcIBcBlK0lRWHqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQn\n" + + "Keg3S/LvRJdrF1Eaw1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937n\n" + + "tag+RaypJXUie28/sJyU58dzq6wf7iWbwBbtt8pb8BQ=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Visa_International_Global_Root_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMC\n" + + "VVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25h\n" + + "bCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcN\n" + + "MDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl\n" + + "cnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJ\n" + + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZ\n" + + "DK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJ\n" + + "XLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWl\n" + + "Ahr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm\n" + + "7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTa\n" + + "xhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3e\n" + + "QbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDO\n" + + "qU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqG\n" + + "SIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdp\n" + + "NSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ\n" + + "kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoL\n" + + "axhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/Rt\n" + + "Ldh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8\n" + + "ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Visa_eCommerce_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUF\n" + + "ADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlz\n" + + "YSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMT\n" + + "E1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0\n" + + "MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UE\n" + + "CxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa\n" + + "BgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh\n" + + "28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362\n" + + "rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81\n" + + "q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtF\n" + + "Wsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0\n" + + "lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4t\n" + + "AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\n" + + "A1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOC\n" + + "AQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR\n" + + "zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKht\n" + + "cbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI\n" + + "xHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu\n" + + "YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/\n" + + "hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA-Baltimore_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" + + "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" + + "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0\n" + + "aW9uMB4XDTAyMDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UE\n" + + "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" + + "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRh\n" + + "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALx+xDmcjOPW\n" + + "HIb/ymKt4H8wRXqOGrO4x/nRNv8i805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R\n" + + "9U+jK7wYFuK13XneIviCfsuBH/0nLI/6l2Qijvj/YaOcGx6Sj8CoCd8JEey3\n" + + "fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92BFODEPM2dMPgwqZfT7syj0B9f\n" + + "HBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+YmpkbIq2eszh+6l/ePazIjm\n" + + "iSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7eHgZFLL8kFKJOGJg\n" + + "B7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIaMA8GA1UdEwEB\n" + + "/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4AAAEJKIOR\n" + + "MTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3IgdXNl\n" + + "IG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu\n" + + "dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5k\n" + + "YXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmlj\n" + + "YXRpb24gUHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0\n" + + "eSBBZ3JlZW1lbnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVT\n" + + "VGVkIHdlYiBzaXRlLCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVj\n" + + "dHNfc2VydmljZXMvaW5kZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3\n" + + "dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWww\n" + + "HQYDVR0OBBYEFEU9w6nR3D8kVpgccxiIav+DR+22MB8GA1UdIwQYMBaAFEU9\n" + + "w6nR3D8kVpgccxiIav+DR+22MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCAWXf82n+0S9/DZEtqTg6t8n1Z\n" + + "dwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu67RMdmgduyzFiEuhjA6p9\n" + + "beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AYgkHNZTfqjjJ+vWuZ\n" + + "XTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb4cV97yHgjQ5d\n" + + "UX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9CReJf8Py\n" + + "05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" + + "EwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQg\n" + + "Um9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYy\n" + + "MDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNV\n" + + "BAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRow\n" + + "GAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n" + + "ggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4\n" + + "SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3\n" + + "o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8V\n" + + "cr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3k\n" + + "bWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8\n" + + "tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUC\n" + + "AwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIB\n" + + "TDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxp\n" + + "YW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz\n" + + "IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0\n" + + "ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9u\n" + + "IHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJl\n" + + "VFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29t\n" + + "L3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNU\n" + + "ZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYD\n" + + "VQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub\n" + + "2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxir\n" + + "ZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax\n" + + "6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxl\n" + + "pE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE\n" + + "/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoA\n" + + "AEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH\n" + + "0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpG\n" + + "EK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA_-_Entrust_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" + + "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" + + "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0\n" + + "aW9uMB4XDTAyMDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UE\n" + + "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" + + "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRh\n" + + "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1\n" + + "Q+xVkrYwfTVXDNvzDSduTPdQqJtOK2/b9a0cS12zqcH+e0TrW6MFDR/FNCsw\n" + + "ACnxeECypP869AGIF37m1CbTukzqMvtDd5eHI8XbQ6P1KqNRXuE70mVpflUV\n" + + "m3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdjDheT389Lrm5zdeDzqrmkwAkb\n" + + "hepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCeyv78IZTuEyhL11xeDGbu\n" + + "6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCktVjMFu5dZfsZJT4nX\n" + + "LySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMBMIIBtwYDVR0g\n" + + "BIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYIKwYBBQUH\n" + + "AgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRpZmlj\n" + + "YXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug\n" + + "b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29u\n" + + "ZGl0aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0\n" + + "YXRlbWVudCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGlj\n" + + "aCBjYW4gYmUgZm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0\n" + + "cHM6Ly93d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRl\n" + + "eC5odG1sMEIGCCsGAQUFBwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29t\n" + + "L3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQD\n" + + "AgAHMIGJBgNVHR8EgYEwfzB9oHugeaR3MHUxEjAQBgNVBAoTCWJlVFJVU1Rl\n" + + "ZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYDVQQDEypiZVRS\n" + + "VVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24xDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEwODI0MjdagQ8yMDIyMDQx\n" + + "MTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFH1w5a44iwY/qhwa\n" + + "j/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQwqoSEFjAMBgNV\n" + + "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkq\n" + + "hkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ5V04\n" + + "ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB\n" + + "evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220\n" + + "Y/ozADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2\n" + + "KjiS2d2kXgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFi\n" + + "aDrmLzfzgYYhxKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep\n" + + "9w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA_-_RSA_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUF\n" + + "ADBiMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBS\n" + + "b290IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1w\n" + + "bGVtZW50YXRpb24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBi\n" + + "MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290\n" + + "IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVt\n" + + "ZW50YXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQw\n" + + "CY5X0LkGLG9uJIAiv11DpvpPrILnHGhwhRujbrWqeNluB0s/6d/16uhUoWGK\n" + + "Di9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I1DpAa5LxmZZk3tv/ePTulh1HiXzU\n" + + "vrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPktPDgaTuID0GQ+NRxQyTBjyZL\n" + + "O1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnUGxlkVgoZ98zh/4avflhe\n" + + "rHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8ercmsl9fNTGwxMLvF1\n" + + "S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIYMIICFDAMBgNV\n" + + "HRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+AAADCSiD\n" + + "kTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20v\n" + + "cHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB\n" + + "OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj\n" + + "cmVhdGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRo\n" + + "ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlv\n" + + "bnMgb2YgdXNlLCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l\n" + + "bnQgYW5kIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2Fu\n" + + "IGJlIGZvdW5kIGF0IHRoZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93\n" + + "d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1s\n" + + "MAsGA1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSp7BR++dlDzFMrFK3P9/BZiUHN\n" + + "GTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxStz/fwWYlBzRkwDQYJKoZIhvcNAQEF\n" + + "BQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g6IHHtt9DwSwddUvUQo3neqh0\n" + + "3GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuKmET7m9cqg5c0Lcd9NUwt\n" + + "NLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbdLrML3kqNWz2rDcI1\n" + + "UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28BbJ1zTcwfBwvNM\n" + + "m2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3SK41ty8y\n" + + "mmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=\n" + + "-----END CERTIFICATE-----\n"); + + CA_CERTS = new StaticTrustAnchors((X509Certificate[]) certs.toArray(new X509Certificate[0])); + } +} diff --git a/gnu/javax/net/ssl/provider/Alert.java b/gnu/javax/net/ssl/provider/Alert.java new file mode 100644 index 000000000..c31e1bef5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Alert.java @@ -0,0 +1,474 @@ +/* Alert.java -- SSL Alert message. + 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * An alert message in the SSL protocol. Alerts are sent both as warnings + * which may allow execution to continue, or they may be fatal, which will + * halt this session. An alert object is composed of two enums -- the level, + * which indicates the seriousness of the alert, and the description, which + * indicates the reason for the alert. + * + * <pre> + * struct { + * AlertLevel level; + * AlertDescription description; + * } + * </pre> + */ +final class Alert implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** The alert level enumerated. */ + private final Level level; + + /** The alert description enumerated. */ + private final Description description; + + // Constructor. + // ------------------------------------------------------------------------- + + Alert(Level level, Description description) + { + this.level = level; + this.description = description; + } + + // Class method. + // ------------------------------------------------------------------------- + + static Alert read(InputStream in) throws IOException + { + Level level = Level.read(in); + Description desc = Description.read(in); + return new Alert(level, desc); + } + + static Alert forName(String name) + { + if (name == null) + { + return new Alert(Level.FATAL, Description.INTERNAL_ERROR); + } + Description desc = Description.INTERNAL_ERROR; + if (name.equals("close_notify")) + { + desc = Description.CLOSE_NOTIFY; + } + else if (name.equals("unexpected_message")) + { + desc = Description.UNEXPECTED_MESSAGE; + } + else if (name.equals("bad_record_mac")) + { + desc = Description.BAD_RECORD_MAC; + } + else if (name.equals("DECRYPTION_FAILED")) + { + desc = Description.DECRYPTION_FAILED; + } + else if (name.equals("record_overflow")) + { + desc = Description.RECORD_OVERFLOW; + } + else if (name.equals("decompression_failure")) + { + desc = Description.DECOMPRESSION_FAILURE; + } + else if (name.equals("handshake_failure")) + { + desc = Description.HANDSHAKE_FAILURE; + } + else if (name.equals("no_certificate")) + { + desc = Description.NO_CERTIFICATE; + } + else if (name.equals("bad_certificate")) + { + desc = Description.BAD_CERTIFICATE; + } + else if (name.equals("unsupported_certificate")) + { + desc = Description.UNSUPPORTED_CERTIFICATE; + } + else if (name.equals("certificate_revoked")) + { + desc = Description.CERTIFICATE_REVOKED; + } + else if (name.equals("certificate_expired")) + { + desc = Description.CERTIFICATE_EXPIRED; + } + else if (name.equals("certificate_unknown")) + { + desc = Description.CERTIFICATE_UNKNOWN; + } + else if (name.equals("illegal_parameter")) + { + desc = Description.ILLEGAL_PARAMETER; + } + else if (name.equals("unknown_ca")) + { + desc = Description.UNKNOWN_CA; + } + else if (name.equals("access_denied")) + { + desc = Description.ACCESS_DENIED; + } + else if (name.equals("decode_error")) + { + desc = Description.DECODE_ERROR; + } + else if (name.equals("decrypt_error")) + { + desc = Description.DECRYPT_ERROR; + } + else if (name.equals("export_restriction")) + { + desc = Description.EXPORT_RESTRICTION; + } + else if (name.equals("protocol_version")) + { + desc = Description.PROTOCOL_VERSION; + } + else if (name.equals("insufficient_security")) + { + desc = Description.INSUFFICIENT_SECURITY; + } + else if (name.equals("internal_error")) + { + desc = Description.INTERNAL_ERROR; + } + else if (name.equals("user_canceled")) + { + desc = Description.USER_CANCELED; + } + else if (name.equals("no_renegotiation")) + { + desc = Description.NO_RENEGOTIATION; + } + else if (name.equals("unsupported_extension")) + { + desc = Description.UNSUPPORTED_EXTENSION; + } + else if (name.equals("certificate_unobtainable")) + { + desc = Description.CERTIFICATE_UNOBTAINABLE; + } + else if (name.equals("unrecognized_name")) + { + desc = Description.UNRECOGNIZED_NAME; + } + else if (name.equals("bad_certificate_status_response")) + { + desc = Description.BAD_CERTIFICATE_STATUS_RESPONSE; + } + else if (name.equals("bad_certificate_hash_value")) + { + desc = Description.BAD_CERTIFICATE_HASH_VALUE; + } + else if (name.equals("unknown_srp_username")) + { + desc = Description.UNKNOWN_SRP_USERNAME; + } + else if (name.equals("missing_srp_username")) + { + desc = Description.MISSING_SRP_USERNAME; + } + return new Alert(Level.FATAL, desc); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write((byte) level.getValue()); + out.write((byte) description.getValue()); + } + + byte[] getEncoded() + { + return new byte[] { (byte) level.getValue(), + (byte) description.getValue() }; + } + + Level getLevel() + { + return level; + } + + Description getDescription() + { + return description; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "struct {" + nl + + " level = " + level + ";" + nl + + " description = " + description + ";" + nl + + "} Alert;" + nl; + } + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * The level enumeration. + * + * <pre> + * enum { warning(1), fatal(2), (255) } AlertLevel; + * </pre> + */ + static final class Level implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final Level WARNING = new Level(1), FATAL = new Level(2); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Level(int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static Level read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of stream"); + } + switch (i & 0xFF) + { + case 1: return WARNING; + case 2: return FATAL; + default: return new Level(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 1: return "warning"; + case 2: return "fatal"; + default: return "unknown(" + value + ")"; + } + } + } + + /** + * The description enumeration. + */ + static final class Description implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final Description + CLOSE_NOTIFY = new Description( 0), + UNEXPECTED_MESSAGE = new Description( 10), + BAD_RECORD_MAC = new Description( 20), + DECRYPTION_FAILED = new Description( 21), + RECORD_OVERFLOW = new Description( 22), + DECOMPRESSION_FAILURE = new Description( 30), + HANDSHAKE_FAILURE = new Description( 40), + NO_CERTIFICATE = new Description( 41), + BAD_CERTIFICATE = new Description( 42), + UNSUPPORTED_CERTIFICATE = new Description( 43), + CERTIFICATE_REVOKED = new Description( 44), + CERTIFICATE_EXPIRED = new Description( 45), + CERTIFICATE_UNKNOWN = new Description( 46), + ILLEGAL_PARAMETER = new Description( 47), + UNKNOWN_CA = new Description( 48), + ACCESS_DENIED = new Description( 49), + DECODE_ERROR = new Description( 50), + DECRYPT_ERROR = new Description( 51), + EXPORT_RESTRICTION = new Description( 60), + PROTOCOL_VERSION = new Description( 70), + INSUFFICIENT_SECURITY = new Description( 71), + INTERNAL_ERROR = new Description( 80), + USER_CANCELED = new Description( 90), + NO_RENEGOTIATION = new Description(100), + UNSUPPORTED_EXTENSION = new Description(110), + CERTIFICATE_UNOBTAINABLE = new Description(111), + UNRECOGNIZED_NAME = new Description(112), + BAD_CERTIFICATE_STATUS_RESPONSE = new Description(113), + BAD_CERTIFICATE_HASH_VALUE = new Description(114), + UNKNOWN_SRP_USERNAME = new Description(120), + MISSING_SRP_USERNAME = new Description(121); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Description(int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static Description read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (i) + { + case 0: return CLOSE_NOTIFY; + case 10: return UNEXPECTED_MESSAGE; + case 20: return BAD_RECORD_MAC; + case 21: return DECRYPTION_FAILED; + case 22: return RECORD_OVERFLOW; + case 30: return DECOMPRESSION_FAILURE; + case 40: return HANDSHAKE_FAILURE; + case 41: return NO_CERTIFICATE; + case 42: return BAD_CERTIFICATE; + case 43: return UNSUPPORTED_CERTIFICATE; + case 44: return CERTIFICATE_REVOKED; + case 45: return CERTIFICATE_EXPIRED; + case 46: return CERTIFICATE_UNKNOWN; + case 47: return ILLEGAL_PARAMETER; + case 48: return UNKNOWN_CA; + case 49: return ACCESS_DENIED; + case 50: return DECODE_ERROR; + case 51: return DECRYPT_ERROR; + case 60: return EXPORT_RESTRICTION; + case 70: return PROTOCOL_VERSION; + case 71: return INSUFFICIENT_SECURITY; + case 80: return INTERNAL_ERROR; + case 90: return USER_CANCELED; + case 100: return NO_RENEGOTIATION; + case 120: return UNKNOWN_SRP_USERNAME; + case 121: return MISSING_SRP_USERNAME; + default: return new Description(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "close_notify"; + case 10: return "unexpected_message"; + case 20: return "bad_record_mac"; + case 21: return "decryption_failed"; + case 22: return "record_overflow"; + case 30: return "decompression_failure"; + case 40: return "handshake_failure"; + case 42: return "bad_certificate"; + case 43: return "unsupported_certificate"; + case 44: return "certificate_revoked"; + case 45: return "certificate_expired"; + case 46: return "certificate_unknown"; + case 47: return "illegal_parameter"; + case 48: return "unknown_ca"; + case 49: return "access_denied"; + case 50: return "decode_error"; + case 51: return "decrypt_error"; + case 60: return "export_restriction"; + case 70: return "protocol_version"; + case 71: return "insufficient_security"; + case 80: return "internal_error"; + case 90: return "user_canceled"; + case 100: return "no_renegotiation"; + case 110: return "unsupported_extension"; + case 111: return "certificate_unobtainable"; + case 112: return "unrecognized_name"; + case 113: return "bad_certificate_status_response"; + case 114: return "bad_certificate_hash_value"; + case 120: return "unknown_srp_username"; + case 121: return "missing_srp_username"; + default: return "unknown(" + value + ")"; + } + } + } +} diff --git a/gnu/javax/net/ssl/provider/AlertException.java b/gnu/javax/net/ssl/provider/AlertException.java new file mode 100644 index 000000000..666efe5ac --- /dev/null +++ b/gnu/javax/net/ssl/provider/AlertException.java @@ -0,0 +1,76 @@ +/* AlertException.java -- exceptions generated by SSL alerts. + 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.net.ssl.provider; + +import javax.net.ssl.SSLException; + +class AlertException extends SSLException +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Alert alert; + private final boolean isLocal; + + // Constructor. + // ------------------------------------------------------------------------- + + AlertException(Alert alert, boolean isLocal) + { + super(alert.getDescription().toString()); + this.alert = alert; + this.isLocal = isLocal; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getMessage() + { + return alert.getDescription() + ": " + + (isLocal ? "locally generated; " : "remotely generated; ") + + alert.getLevel(); + } + + public Alert getAlert () + { + return alert; + } +} diff --git a/gnu/javax/net/ssl/provider/Certificate.java b/gnu/javax/net/ssl/provider/Certificate.java new file mode 100644 index 000000000..b1d6b2a01 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Certificate.java @@ -0,0 +1,194 @@ +/* Certificate.java -- SSL Certificate message. + 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import java.util.LinkedList; + +import javax.net.ssl.SSLProtocolException; + +final class Certificate implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final X509Certificate[] certs; + + // Constructors. + // ------------------------------------------------------------------------- + + Certificate(X509Certificate[] certs) + { + if (certs == null) + { + throw new NullPointerException(); + } + this.certs = certs; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Certificate read(InputStream in, CertificateType type) + throws IOException + { + if (type == CertificateType.X509) + { + int len = (in.read() & 0xFF) << 16 | (in.read() & 0xFF) << 8 + | (in.read() & 0xFF); + byte[] buf = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(buf, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of stream"); + } + count += l; + } + try + { + LinkedList certs = new LinkedList(); + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream bin = new ByteArrayInputStream(buf); + count = 0; + while (count < len) + { + int len2 = (bin.read() & 0xFF) << 16 | (bin.read() & 0xFF) << 8 + | (bin.read() & 0xFF); + certs.add(fact.generateCertificate(bin)); + count += len2 + 3; + } + return new Certificate((X509Certificate[]) + certs.toArray(new X509Certificate[certs.size()])); + } + catch (CertificateException ce) + { + SSLProtocolException sslpe = new SSLProtocolException(ce.getMessage()); + sslpe.initCause (ce); + throw sslpe; + } + } + else if (type == CertificateType.OPEN_PGP) + { + throw new UnsupportedOperationException("not yet implemented"); + } + else + throw new Error("unsupported certificate type "+type); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + try + { + for (int i = 0; i < certs.length; i++) + { + byte[] enc = certs[i].getEncoded(); + bout.write((enc.length >>> 16) & 0xFF); + bout.write((enc.length >>> 8) & 0xFF); + bout.write( enc.length & 0xFF); + bout.write(enc); + } + } + catch (CertificateEncodingException cee) + { + throw new Error("cannot encode certificates"); + } + catch (IOException ignored) + { + } + out.write(bout.size() >>> 16 & 0xFF); + out.write(bout.size() >>> 8 & 0xFF); + out.write(bout.size() & 0xFF); + bout.writeTo(out); + } + + X509Certificate[] getCertificates() + { + return certs; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" certificateList ="); + for (int i = 0; i < certs.length; i++) + { + BufferedReader r = + new BufferedReader(new StringReader(certs[i].toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println("} Certificate;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/CertificateRequest.java b/gnu/javax/net/ssl/provider/CertificateRequest.java new file mode 100644 index 000000000..0f788039b --- /dev/null +++ b/gnu/javax/net/ssl/provider/CertificateRequest.java @@ -0,0 +1,285 @@ +/* CertificateRequest.java -- SSL CertificateRequest message. + 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.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import java.util.LinkedList; +import java.security.Principal; + +final class CertificateRequest implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ClientType[] types; + private final Principal[] authorities; + + // Constructor. + // ------------------------------------------------------------------------- + + CertificateRequest(ClientType[] types, Principal[] authorities) + { + if (types == null) + { + throw new NullPointerException(); + } + this.types = types; + if (authorities == null) + { + throw new NullPointerException(); + } + this.authorities = authorities; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static CertificateRequest read(InputStream in) throws IOException + { + DataInputStream din = new DataInputStream(in); + ClientType[] types = new ClientType[din.readUnsignedByte()]; + for (int i = 0; i < types.length; i++) + { + types[i] = ClientType.read(din); + } + + LinkedList authorities = new LinkedList(); + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + ByteArrayInputStream bin = new ByteArrayInputStream(buf); + try + { + String x500name = Util.getSecurityProperty("jessie.x500.class"); + if (x500name == null) + { + x500name = "org.metastatic.jessie.pki.X500Name"; + } + Class x500class = null; + ClassLoader cl = ClassLoader.getSystemClassLoader(); + if (cl != null) + { + x500class = cl.loadClass(x500name); + } + else + { + x500class = Class.forName(x500name); + } + Constructor c = x500class.getConstructor(new Class[] { new byte[0].getClass() }); + while (bin.available() > 0) + { + buf = new byte[(bin.read() & 0xFF) << 8 | (bin.read() & 0xFF)]; + bin.read(buf); + authorities.add(c.newInstance(new Object[] { buf })); + } + } + catch (IOException ioe) + { + throw ioe; + } + catch (Exception ex) + { + throw new Error(ex.toString()); + } + return new CertificateRequest(types, + (Principal[]) authorities.toArray(new Principal[authorities.size()])); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + out.write(types.length); + for (int i = 0; i < types.length; i++) + { + out.write(types[i].getValue()); + } + + try + { + Class x500class = authorities[0].getClass(); + Method m = x500class.getMethod("getEncoded", null); + for (int i = 0; i < authorities.length; i++) + { + byte[] buf = (byte[]) m.invoke(authorities[i], null); + bout.write(buf.length >>> 8 & 0xFF); + bout.write(buf.length & 0xFF); + bout.write(buf, 0, buf.length); + } + } + catch (Exception ex) + { + throw new Error(ex.toString()); + } + out.write(bout.size() >>> 8 & 0xFF); + out.write(bout.size() & 0xFF); + bout.writeTo(out); + } + + ClientType[] getTypes() + { + return types; + } + + String[] getTypeStrings() + { + try + { + return (String[]) Util.transform(types, String.class, "toString", null); + } + catch (Exception x) + { + return null; + } + } + + Principal[] getAuthorities() + { + return authorities; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.print(" types = "); + for (int i = 0; i < types.length; i++) + { + out.print(types[i]); + if (i != types.length - 1) + out.print(", "); + } + out.println(";"); + out.println(" authorities ="); + for (int i = 0; i < authorities.length; i++) + { + out.print(" "); + out.print(authorities[i].getName()); + if (i != types.length - 1) + out.println(","); + } + out.println(";"); + out.println("} CertificateRequest;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + static final class ClientType implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final ClientType + RSA_SIGN = new ClientType(1), DSS_SIGN = new ClientType(2), + RSA_FIXED_DH = new ClientType(3), DSS_FIXED_DH = new ClientType(4); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private ClientType(int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static ClientType read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (i & 0xFF) + { + case 1: return RSA_SIGN; + case 2: return DSS_SIGN; + case 3: return RSA_FIXED_DH; + case 4: return DSS_FIXED_DH; + default: return new ClientType(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 1: return "rsa_sign"; + case 2: return "dss_sign"; + case 3: return "rsa_fixed_dh"; + case 4: return "dss_fixed_dh"; + default: return "unknown(" + value + ")"; + } + } + } +} diff --git a/gnu/javax/net/ssl/provider/CertificateType.java b/gnu/javax/net/ssl/provider/CertificateType.java new file mode 100644 index 000000000..c5705939f --- /dev/null +++ b/gnu/javax/net/ssl/provider/CertificateType.java @@ -0,0 +1,104 @@ +/* CertificateType.java -- the certificate type 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.javax.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +final class CertificateType implements Enumerated +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + static final CertificateType X509 = new CertificateType(0); + static final CertificateType OPEN_PGP = new CertificateType(1); + + private final int value; + + // Constructor. + // ------------------------------------------------------------------------- + + private CertificateType(int value) + { + this.value = value; + } + + // Class method. + // ------------------------------------------------------------------------- + + static CertificateType read(InputStream in) throws IOException + { + int value = in.read(); + if (value == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (value & 0xFF) + { + case 0: return X509; + case 1: return OPEN_PGP; + default: return new CertificateType(value); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "X.509"; + case 1: return "OpenPGP"; + default: return "unknown(" + value + ")"; + } + } +} diff --git a/gnu/javax/net/ssl/provider/CertificateVerify.java b/gnu/javax/net/ssl/provider/CertificateVerify.java new file mode 100644 index 000000000..e0bf130f1 --- /dev/null +++ b/gnu/javax/net/ssl/provider/CertificateVerify.java @@ -0,0 +1,95 @@ +/* CertificateVerify.java -- SSL CertificateVerify message. + 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.security.PublicKey; + +final class CertificateVerify extends Signature implements Handshake.Body +{ + + // Contstructor. + // ------------------------------------------------------------------------- + + CertificateVerify(Object sigValue, String sigAlg) + { + super(sigValue, sigAlg); + } + + // Class method. + // -------------------------------------------------------------------------- + + static Signature read(InputStream in, CipherSuite suite, PublicKey key) + throws IOException + { + Signature sig = Signature.read(in, suite, key); + return new CertificateVerify(sig.getSigValue(), sig.getSigAlg()); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + BufferedReader r = new BufferedReader(new StringReader(super.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + out.println("} CertificateVerify;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/CipherSuite.java b/gnu/javax/net/ssl/provider/CipherSuite.java new file mode 100644 index 000000000..de916817b --- /dev/null +++ b/gnu/javax/net/ssl/provider/CipherSuite.java @@ -0,0 +1,754 @@ +/* CipherSuite.java -- Supported cipher suites. + 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.net.ssl.provider; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.lang.reflect.Field; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; + +final class CipherSuite implements Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final List tlsSuiteNames = new LinkedList(); + private static final HashMap namesToSuites = new HashMap(); + + // SSL CipherSuites. + static final CipherSuite SSL_NULL_WITH_NULL_NULL = + new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00, + "SSL_NULL_WITH_NULL_NULL", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_NULL_MD5 = + new CipherSuite("null", "RSA", "RSA", "SSLMAC-MD5", 0, 0x00, 0x01, + "SSL_RSA_WITH_NULL_MD5", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_NULL_SHA = + new CipherSuite("null", "RSA", "RSA", "SSLMAC-SHA", 0, 0x00, 0x02, + "SSL_RSA_WITH_NULL_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 5, 0x00, 0x03, + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_RC4_128_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 16, 0x00, 0x04, + "SSL_RSA_WITH_RC4_128_MD5", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_RC4_128_SHA = + new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x05, + "SSL_RSA_WITH_RC4_128_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 5, 0x00, 0x08, + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 8, 0x00, 0x09, + "SSL_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "RSA", "RSA", "SSLMAC-SHA", 24, 0x00, 0x0A, + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 5, 0x00, 0x0B, + "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 8, 0x00, 0x0C, + "SSL_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "DSS", "SSLMAC-SHA", 24, 0x00, 0x0D, + "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 5, 0x00, 0x0E, + "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 8, 0x00, 0x0F, + "SSL_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "RSA", "SSLMAC-SHA", 24, 0x00, 0x10, + "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 5, 0x00, 0x11, + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 8, 0x00, 0x12, + "SSL_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "DSS", "SSLMAC-SHA", 24, 0x00, 0x13, + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 5, 0x00, 0x14, + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 8, 0x00, 0x15, + "SSL_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "RSA", "SSLMAC-SHA", 24, 0x00, 0x16, + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + + // AES CipherSuites. + static final CipherSuite SSL_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x2F, + "SSL_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 16, 0x00, 0x30, + "SSL_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 16, 0x00, 0x31, + "SSL_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 16, 0x00, 0x32, + "SSL_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 16, 0x00, 0x33, + "SSL_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 32, 0x00, 0x35, + "SSL_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 32, 0x00, 0x36, + "SSL_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 32, 0x00, 0x37, + "SSL_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 32, 0x00, 0x38, + "SSL_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 32, 0x00, 0x39, + "SSL_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + + // Ciphersuites from the OpenPGP extension draft. + static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70, + "SSL_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71, + "SSL_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72, + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73, + "SSL_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74, + "SSL_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75, + "SSL_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76, + "SSL_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77, + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78, + "SSL_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79, + "SSL_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A, + "SSL_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B, + "SSL_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C, + "SSL_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D, + "SSL_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E, + "SSL_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3); + + static final CipherSuite TLS_NULL_WITH_NULL_NULL = + new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00, + "TLS_NULL_WITH_NULL_NULL", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_NULL_MD5 = + new CipherSuite("null", "RSA", "RSA", "HMAC-MD5", 0, 0x00, 0x01, + "TLS_RSA_WITH_NULL_MD5", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_NULL_SHA = + new CipherSuite("null", "RSA", "RSA", "HMAC-SHA", 0, 0x00, 0x02, + "TLS_RSA_WITH_NULL_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 5, 0x00, 0x03, + "TLS_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 16, 0x00, 0x04, + "TLS_RSA_WITH_RC4_128_MD5", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_RC4_128_SHA = + new CipherSuite("RC4", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x05, + "TLS_RSA_WITH_RC4_128_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 5, 0x00, 0x08, + "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 8, 0x00, 0x09, + "TLS_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-SHA", 24, 0x00, 0x0A, + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 5, 0x00, 0x0B, + "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 8, 0x00, 0x0C, + "TLS_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "DSS", "HMAC-SHA", 24, 0x00, 0x0D, + "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 5, 0x00, 0x0E, + "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 8, 0x00, 0x0F, + "TLS_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "RSA", "HMAC-SHA", 24, 0x00, 0x10, + "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 5, 0x00, 0x11, + "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 8, 0x00, 0x12, + "TLS_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-SHA", 24, 0x00, 0x13, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 5, 0x00, 0x14, + "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 8, 0x00, 0x15, + "TLS_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-SHA", 24, 0x00, 0x16, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + + // AES CipherSuites. + static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x2F, + "TLS_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 16, 0x00, 0x30, + "TLS_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 16, 0x00, 0x31, + "TLS_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x32, + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x33, + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 32, 0x00, 0x35, + "TLS_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 32, 0x00, 0x36, + "TLS_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 32, 0x00, 0x37, + "TLS_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 32, 0x00, 0x38, + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 32, 0x00, 0x39, + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + + // Secure remote password (SRP) ciphersuites + static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "SRP", "anon", "HMAC-SHA", 24, 0x00, 0x50, + "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "SRP", "RSA", "HMAC-SHA", 24, 0x00, 0x51, + "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "SRP", "DSS", "HMAC-SHA", 24, 0x00, 0x52, + "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 16, 0x00, 0x53, + "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 16, 0x00, 0x54, + "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 16, 0x00, 0x55, + "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 32, 0x00, 0x56, + "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 32, 0x00, 0x57, + "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 32, 0x00, 0x58, + "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + + // Ciphersuites from the OpenPGP extension draft. + static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70, + "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71, + "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73, + "TLS_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74, + "TLS_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75, + "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76, + "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78, + "TLS_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79, + "TLS_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A, + "TLS_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B, + "TLS_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C, + "TLS_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D, + "TLS_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E, + "TLS_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1); + + private final String cipherName; + private final String kexName; + private final String sigName; + private final String macName; + private final boolean exportable; + private final boolean isStream; + private final int keyLength; + private final byte[] id; + private final String name; + private final ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + private CipherSuite(String cipherName, String kexName, String sigName, + String macName, int keyLength, int id1, int id2, + String name, ProtocolVersion version) + { + this.cipherName = cipherName.intern(); + this.kexName = kexName.intern(); + this.sigName = sigName.intern(); + this.macName = macName.intern(); + this.exportable = keyLength <= 5; + this.isStream = cipherName.equals("null") || cipherName.equals("RC4"); + this.keyLength = keyLength; + this.id = new byte[] { (byte) id1, (byte) id2 }; + this.name = name.intern(); + this.version = version; + namesToSuites.put(name, this); + if (name.startsWith("TLS")) + { + tlsSuiteNames.add(name); + } + } + + private CipherSuite(byte[] id) + { + cipherName = null; + kexName = null; + sigName = null; + macName = null; + exportable = false; + isStream = false; + keyLength = 0; + this.id = id; + name = null; + version = null; + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Returns the cipher suite for the given name, or null if there is no + * such suite. + * + * @return The named cipher suite. + */ + static CipherSuite forName(String name) + { + return (CipherSuite) namesToSuites.get(name); + } + + static List availableSuiteNames() + { + return tlsSuiteNames; + } + + static CipherSuite read(InputStream in) throws IOException + { + DataInputStream din = new DataInputStream(in); + byte[] id = new byte[2]; + din.readFully(id); + return new CipherSuite(id); + } + + static IMode getCipher(String cbcCipherName) + { + IBlockCipher cipher = CipherFactory.getInstance(cbcCipherName); + if (cipher == null) + { + return null; + } + return ModeFactory.getInstance("CBC", cipher, cipher.defaultBlockSize()); + } + + static Cipher getJCECipher (final String name) + throws NoSuchAlgorithmException, NoSuchPaddingException + { + final String provider = Util.getSecurityProperty ("jessie.with.jce.provider"); + if (name.equals ("RC4")) + { + if (provider != null) + { + try + { + return Cipher.getInstance (name, provider); + } + catch (NoSuchProviderException nsae) + { + // Fall through. Try any available provider. + } + } + + return Cipher.getInstance (name); + } + else + { + // Oh, hey! Look! Something else Sun doesn't understand: SSLv3 padding + // is different than TLSv1 in subtle, but important, ways. But they + // sorta look the same, so why not make them equivalent? + // + // There should be a seperate padding "TLS1Padding". + if (provider != null) + { + try + { + return Cipher.getInstance (name + "/CBC/SSL3Padding", provider); + } + catch (NoSuchProviderException nspe) + { + // Fall through. Try any available provider. + } + } + return Cipher.getInstance (name + "/CBC/SSL3Padding"); + } + } + + static IMac getMac(String macName) + { + if (macName.startsWith("SSLMAC-")) + { + return new SSLHMac(macName.substring(7)); + } + else + { + return MacFactory.getInstance(macName); + } + } + + static Mac getJCEMac (final String name) + throws NoSuchAlgorithmException + { + final String provider = Util.getSecurityProperty ("jessie.with.jce.provider"); + if (provider != null) + { + try + { + return Mac.getInstance (name, provider); + } + catch (NoSuchProviderException nspe) + { + // Fall through. Try any available provider. + } + } + return Mac.getInstance (name); + } + + // Intance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write(id); + } + + CipherSuite resolve(ProtocolVersion version) + { + if (version == ProtocolVersion.SSL_3) + { + if (id[0] == 0x00) switch (id[1]) + { + case 0x00: return SSL_NULL_WITH_NULL_NULL; + case 0x01: return SSL_RSA_WITH_NULL_MD5; + case 0x02: return SSL_RSA_WITH_NULL_SHA; + case 0x03: return SSL_RSA_EXPORT_WITH_RC4_40_MD5; + case 0x04: return SSL_RSA_WITH_RC4_128_MD5; + case 0x05: return SSL_RSA_WITH_RC4_128_SHA; + case 0x08: return SSL_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x09: return SSL_RSA_WITH_DES_CBC_SHA; + case 0x0A: return SSL_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x0B: return SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x0C: return SSL_DH_DSS_WITH_DES_CBC_SHA; + case 0x0D: return SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x0E: return SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x0F: return SSL_DH_RSA_WITH_DES_CBC_SHA; + case 0x10: return SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x11: return SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x12: return SSL_DHE_DSS_WITH_DES_CBC_SHA; + case 0x13: return SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x14: return SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x15: return SSL_DHE_RSA_WITH_DES_CBC_SHA; + case 0x16: return SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x2F: return SSL_RSA_WITH_AES_128_CBC_SHA; + case 0x30: return SSL_DH_DSS_WITH_AES_128_CBC_SHA; + case 0x31: return SSL_DH_RSA_WITH_AES_128_CBC_SHA; + case 0x32: return SSL_DHE_DSS_WITH_AES_128_CBC_SHA; + case 0x33: return SSL_DHE_RSA_WITH_AES_128_CBC_SHA; + case 0x35: return SSL_RSA_WITH_AES_256_CBC_SHA; + case 0x36: return SSL_DH_DSS_WITH_AES_256_CBC_SHA; + case 0x37: return SSL_DH_RSA_WITH_AES_256_CBC_SHA; + case 0x38: return SSL_DHE_DSS_WITH_AES_256_CBC_SHA; + case 0x39: return SSL_DHE_RSA_WITH_AES_256_CBC_SHA; + } + } + else if (version == ProtocolVersion.TLS_1 || + version == ProtocolVersion.TLS_1_1) + { + if (id[0] == 0x00) switch (id[1]) + { + case 0x00: return TLS_NULL_WITH_NULL_NULL; + case 0x01: return TLS_RSA_WITH_NULL_MD5; + case 0x02: return TLS_RSA_WITH_NULL_SHA; + case 0x03: return TLS_RSA_EXPORT_WITH_RC4_40_MD5; + case 0x04: return TLS_RSA_WITH_RC4_128_MD5; + case 0x05: return TLS_RSA_WITH_RC4_128_SHA; + case 0x08: return TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x09: return TLS_RSA_WITH_DES_CBC_SHA; + case 0x0A: return TLS_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x0B: return TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x0C: return TLS_DH_DSS_WITH_DES_CBC_SHA; + case 0x0D: return TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x0E: return TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x0F: return TLS_DH_RSA_WITH_DES_CBC_SHA; + case 0x10: return TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x11: return TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x12: return TLS_DHE_DSS_WITH_DES_CBC_SHA; + case 0x13: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x14: return TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x15: return TLS_DHE_RSA_WITH_DES_CBC_SHA; + case 0x16: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x2F: return TLS_RSA_WITH_AES_128_CBC_SHA; + case 0x30: return TLS_DH_DSS_WITH_AES_128_CBC_SHA; + case 0x31: return TLS_DH_RSA_WITH_AES_128_CBC_SHA; + case 0x32: return TLS_DHE_DSS_WITH_AES_128_CBC_SHA; + case 0x33: return TLS_DHE_RSA_WITH_AES_128_CBC_SHA; + case 0x35: return TLS_RSA_WITH_AES_256_CBC_SHA; + case 0x36: return TLS_DH_DSS_WITH_AES_256_CBC_SHA; + case 0x37: return TLS_DH_RSA_WITH_AES_256_CBC_SHA; + case 0x38: return TLS_DHE_DSS_WITH_AES_256_CBC_SHA; + case 0x39: return TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + case 0x50: return TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA; + case 0x51: return TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x52: return TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x53: return TLS_SRP_SHA_WITH_AES_128_CBC_SHA; + case 0x54: return TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA; + case 0x55: return TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA; + case 0x56: return TLS_SRP_SHA_WITH_AES_256_CBC_SHA; + case 0x57: return TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA; + case 0x58: return TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA; + case 0x70: return TLS_DHE_DSS_WITH_CAST_128_CBC_SHA; + case 0x71: return TLS_DHE_DSS_WITH_CAST_128_CBC_RMD; + case 0x72: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD; + case 0x73: return TLS_DHE_DSS_WITH_AES_128_CBC_RMD; + case 0x74: return TLS_DHE_DSS_WITH_AES_256_CBC_RMD; + case 0x75: return TLS_DHE_RSA_WITH_CAST_128_CBC_SHA; + case 0x76: return TLS_DHE_RSA_WITH_CAST_128_CBC_RMD; + case 0x77: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD; + case 0x78: return TLS_DHE_RSA_WITH_AES_128_CBC_RMD; + case 0x79: return TLS_DHE_RSA_WITH_AES_256_CBC_RMD; + case 0x7A: return TLS_RSA_WITH_CAST_128_CBC_SHA; + case 0x7B: return TLS_RSA_WITH_CAST_128_CBC_RMD; + case 0x7C: return TLS_RSA_WITH_3DES_EDE_CBC_RMD; + case 0x7D: return TLS_RSA_WITH_AES_128_CBC_RMD; + case 0x7E: return TLS_RSA_WITH_AES_256_CBC_RMD; + } + } + return this; + } + + String getCipher() + { + return cipherName; + } + + int getKeyLength() + { + return keyLength; + } + + String getKeyExchange() + { + return kexName; + } + + String getSignature() + { + return sigName; + } + + String getMac() + { + return macName; + } + + boolean isExportable() + { + return exportable; + } + + boolean isStreamCipher() + { + return isStream; + } + + String getAuthType() + { + if (kexName.equals("RSA")) + { + if (isExportable()) + { + return "RSA_EXPORT"; + } + return "RSA"; + } + return kexName + "_" + sigName; + } + + byte[] getId() + { + return id; + } + + ProtocolVersion getVersion() + { + return version; + } + + public boolean equals(Object o) + { + if (!(o instanceof CipherSuite)) + { + return false; + } + if (o == this) + return true; + byte[] id = ((CipherSuite) o).getId(); + return id[0] == this.id[0] && + id[1] == this.id[1]; + } + + public int hashCode() + { + if (version == null) + { + return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF); + } + return version.getMajor() << 24 | version.getMinor() << 16 + | (id[0] & 0xFF) << 8 | (id[1] & 0xFF); + } + + public String toString() + { + if (name == null) + { + return "UNKNOWN { " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }"; + } + return name; + } +} diff --git a/gnu/javax/net/ssl/provider/ClientHello.java b/gnu/javax/net/ssl/provider/ClientHello.java new file mode 100644 index 000000000..259051df1 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ClientHello.java @@ -0,0 +1,253 @@ +/* ClientHello.java -- SSL ClientHello message. + 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.SSLProtocolException; + +final class ClientHello implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private ProtocolVersion version; + private Random random; + private byte[] sessionId; + private List suites; + private List comp; + private List extensions; + + // Constructor. + // ------------------------------------------------------------------------- + + ClientHello(ProtocolVersion version, Random random, + byte[] sessionId, List suites, List comp) + { + this(version, random, sessionId, suites, comp, null); + } + + ClientHello(ProtocolVersion version, Random random, + byte[] sessionId, List suites, List comp, List extensions) + { + this.version = version; + this.random = random; + this.sessionId = sessionId; + this.suites = suites; + this.comp = comp; + this.extensions = extensions; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ClientHello read(InputStream in) throws IOException + { + ProtocolVersion vers = ProtocolVersion.read(in); + Random rand = Random.read(in); + byte[] id = new byte[in.read() & 0xFF]; + in.read(id); + int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + ArrayList suites = new ArrayList(len / 2); + for (int i = 0; i < len; i += 2) + { + suites.add(CipherSuite.read(in).resolve(vers)); + } + len = in.read() & 0xFF; + ArrayList comp = new ArrayList(len); + for (int i = 0; i < len; i++) + { + comp.add(CompressionMethod.read(in)); + } + + List ext = null; + // Since parsing MAY need to continue into the extensions fields, or it + // may end here, the specified input stream MUST be a ByteArrayInputStream + // over all the data this hello contains. Otherwise this will mess up + // the data stream. + if (in.available() > 0) // then we have extensions. + { + ext = new LinkedList(); + len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + int count = 0; + while (count < len) + { + Extension e = Extension.read(in); + ext.add(e); + count += e.getValue().length + 4; + } + } + return new ClientHello(vers, rand, id, suites, comp, ext); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + version.write(out); + random.write(out); + out.write(sessionId.length); + out.write(sessionId); + out.write((suites.size() << 1) >>> 8 & 0xFF); + out.write((suites.size() << 1) & 0xFF); + for (Iterator i = suites.iterator(); i.hasNext(); ) + { + ((CipherSuite) i.next()).write(out); + } + out.write(comp.size()); + for (Iterator i = comp.iterator(); i.hasNext(); ) + { + out.write(((CompressionMethod) i.next()).getValue()); + } + if (extensions != null) + { + ByteArrayOutputStream out2 = new ByteArrayOutputStream(); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + { + ((Extension) i.next()).write(out2); + } + out.write(out2.size() >>> 8 & 0xFF); + out.write(out2.size() & 0xFF); + out2.writeTo(out); + } + } + + ProtocolVersion getVersion() + { + return version; + } + + Random getRandom() + { + return random; + } + + byte[] getSessionId() + { + return sessionId; + } + + List getCipherSuites() + { + return suites; + } + + List getCompressionMethods() + { + return comp; + } + + List getExtensions() + { + return extensions; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" version = " + version + ";"); + BufferedReader r = new BufferedReader(new StringReader(random.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";"); + out.println(" cipherSuites = {"); + for (Iterator i = suites.iterator(); i.hasNext(); ) + { + out.print(" "); + out.println(i.next()); + } + out.println(" };"); + out.print(" compressionMethods = { "); + for (Iterator i = comp.iterator(); i.hasNext(); ) + { + out.print(i.next()); + if (i.hasNext()) + out.print(", "); + } + out.println(" };"); + if (extensions != null) + { + out.println(" extensions = {"); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + { + r = new BufferedReader(new StringReader(i.next().toString())); + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println(" };"); + } + out.println("} ClientHello;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/gnu/javax/net/ssl/provider/ClientKeyExchange.java new file mode 100644 index 000000000..828aa8d5e --- /dev/null +++ b/gnu/javax/net/ssl/provider/ClientKeyExchange.java @@ -0,0 +1,181 @@ +/* ClientKeyExchange.java -- SSL ClientKeyExchange message. + 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.security.PublicKey; +import java.security.interfaces.RSAKey; +import javax.crypto.interfaces.DHPublicKey; + +final class ClientKeyExchange implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Object exObject; + + // Constructors. + // ------------------------------------------------------------------------- + + ClientKeyExchange(byte[] encryptedSecret) + { + exObject = encryptedSecret; + } + + ClientKeyExchange(BigInteger bigint) + { + exObject = bigint; + } + + // Class method. + // ------------------------------------------------------------------------- + + static ClientKeyExchange read(InputStream in, CipherSuite suite, + PublicKey key) + throws IOException + { + DataInputStream din = new DataInputStream(in); + if (suite.getKeyExchange().equals("RSA")) + { + int len = 0; + if (suite.getVersion() == ProtocolVersion.SSL_3) + { + len = (((RSAKey) key).getModulus().bitLength()+7) / 8; + } + else + { + len = din.readUnsignedShort(); + } + byte[] buf = new byte[len]; + din.readFully(buf); + return new ClientKeyExchange(buf); + } + else if (suite.getKeyExchange().equals("SRP")) + { + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + return new ClientKeyExchange(new BigInteger(1, buf)); + } + else if (key == null || !(key instanceof DHPublicKey)) // explicit. + { + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + return new ClientKeyExchange(new BigInteger(1, buf)); + } + else + { + return new ClientKeyExchange(new byte[0]); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + throw new UnsupportedOperationException("use write(java.io.OutputStream,ProtocolVersion) instead"); + } + + public void write(OutputStream out, ProtocolVersion version) throws IOException + { + if (exObject instanceof byte[]) + { + byte[] b = (byte[]) exObject; + if (b.length > 0) + { + if (version != ProtocolVersion.SSL_3) + { + out.write(b.length >>> 8 & 0xFF); + out.write(b.length & 0xFF); + } + out.write(b); + } + } + else + { + byte[] bigint = ((BigInteger) exObject).toByteArray(); + if (bigint[0] == 0x00) + { + out.write(bigint.length - 1 >>> 8 & 0xFF); + out.write(bigint.length - 1 & 0xFF); + out.write(bigint, 1, bigint.length - 1); + } + else + { + out.write(bigint.length >>> 8 & 0xFF); + out.write(bigint.length & 0xFF); + out.write(bigint); + } + } + } + + Object getExchangeObject() + { + return exObject; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + if (exObject instanceof byte[] && ((byte[]) exObject).length > 0) + { + out.println(" encryptedPreMasterSecret ="); + out.print(Util.hexDump((byte[]) exObject, " ")); + } + else if (exObject instanceof BigInteger) + { + out.println(" clientPublic = " + ((BigInteger) exObject).toString(16) + ";"); + } + out.println("} ClientKeyExchange;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/CompressionMethod.java b/gnu/javax/net/ssl/provider/CompressionMethod.java new file mode 100644 index 000000000..c2fdf05f9 --- /dev/null +++ b/gnu/javax/net/ssl/provider/CompressionMethod.java @@ -0,0 +1,104 @@ +/* CompressionMethod.java -- the compression method enum. + 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +final class CompressionMethod implements Enumerated +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + static final CompressionMethod NULL = new CompressionMethod(0), + ZLIB = new CompressionMethod(1); + + private final int value; + + // Constructor. + // ------------------------------------------------------------------------- + + private CompressionMethod(int value) + { + this.value = value; + } + + // Class method. + // ------------------------------------------------------------------------- + + static CompressionMethod read(InputStream in) throws IOException + { + int value = in.read(); + if (value == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (value & 0xFF) + { + case 0: return NULL; + case 1: return ZLIB; + default: return new CompressionMethod(value); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "null"; + case 1: return "zlib"; + default: return "unknown(" + value + ")"; + } + } +} diff --git a/gnu/javax/net/ssl/provider/Constructed.java b/gnu/javax/net/ssl/provider/Constructed.java new file mode 100644 index 000000000..ee3f56a7f --- /dev/null +++ b/gnu/javax/net/ssl/provider/Constructed.java @@ -0,0 +1,57 @@ +/* Constructed.java -- constructed type. + 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.net.ssl.provider; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * The base interface to SSL constructed types. + */ +interface Constructed +{ + + /** + * Writes this structure's encoded form to the given output stream. + * + * @param out The output stream. + * @throws IOException If an I/O error occurs. + */ + void write(OutputStream out) throws IOException; +} diff --git a/gnu/javax/net/ssl/provider/ContentType.java b/gnu/javax/net/ssl/provider/ContentType.java new file mode 100644 index 000000000..336809467 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ContentType.java @@ -0,0 +1,135 @@ +/* ContentType.java -- record layer content type. + 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +/** + * The content type enumeration, which marks packets in the record layer. + * + * <pre>enum { change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) } ContentType;</pre> + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +final class ContentType implements Enumerated +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + static final ContentType CLIENT_HELLO_V2 = new ContentType( 1); + static final ContentType CHANGE_CIPHER_SPEC = new ContentType(20); + static final ContentType ALERT = new ContentType(21); + static final ContentType HANDSHAKE = new ContentType(22); + static final ContentType APPLICATION_DATA = new ContentType(23); + + private int value; + + // Constructors. + // ------------------------------------------------------------------------ + + private ContentType(int value) + { + this.value = value; + } + + // Class methods. + // ------------------------------------------------------------------------ + + static final ContentType read(InputStream in) throws IOException + { + int value = in.read(); + if (value == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (value & 0xFF) + { + case 1: return CLIENT_HELLO_V2; + case 20: return CHANGE_CIPHER_SPEC; + case 21: return ALERT; + case 22: return HANDSHAKE; + case 23: return APPLICATION_DATA; + default: return new ContentType(value); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public boolean equals(Object o) + { + if (o == null || !(o instanceof ContentType)) + { + return false; + } + return ((ContentType) o).value == value; + } + + public int hashCode() + { + return getValue(); + } + + public String toString() + { + switch (value) + { + case 1: return "v2_client_hello"; + case 20: return "change_cipher_spec"; + case 21: return "alert"; + case 22: return "handshake"; + case 23: return "application_data"; + default: return "unknown(" + value + ")"; + } + } +} diff --git a/gnu/javax/net/ssl/provider/Context.java b/gnu/javax/net/ssl/provider/Context.java new file mode 100644 index 000000000..2bd7193f2 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Context.java @@ -0,0 +1,334 @@ +/* Context.java -- SSLContext implementation. + 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.net.ssl.provider; + +import java.io.File; +import java.io.InputStream; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStoreException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.sql.SQLException; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContextSpi; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.SRPTrustManager; +import gnu.javax.net.ssl.StaticTrustAnchors; + +/** + * This is Jessie's implementation of a {@link javax.net.ssl.SSLContext} + * engine, and is available under the algorithm names ``SSLv3'', ``SSL'', + * ``TLSv1'', and ``TLS''. + */ +public final class Context extends SSLContextSpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private SessionContext clientSessions; + private SessionContext serverSessions; + private X509KeyManager keyManager; + private X509TrustManager trustManager; + private SRPTrustManager srpTrustManager; + private SecureRandom random; + + // Constructor. + // ------------------------------------------------------------------------- + + public Context() + { + String codec = Util.getSecurityProperty("jessie.clientSessionContext.codec"); + String codecClass = null; + if (codec == null) + { + codec = "null"; + } + if (codec.equalsIgnoreCase("xml")) + { + codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext"; + } + else if (codec.equalsIgnoreCase("jdbc")) + { + codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext"; + } + else if (codec.equalsIgnoreCase("null")) + { + codecClass = "gnu.javax.net.ssl.provider.SessionContext"; + } + else + { + throw new IllegalArgumentException("no such codec: " + codec); + } + try + { + ClassLoader cl = Context.class.getClassLoader(); + if (cl == null) + { + cl = ClassLoader.getSystemClassLoader(); + } + clientSessions = (SessionContext) cl.loadClass(codecClass).newInstance(); + } + catch (Exception ex) + { + ex.printStackTrace(); + throw new IllegalArgumentException(ex.toString()); + } + + codec = Util.getSecurityProperty("jessie.serverSessionContext.codec"); + if (codec == null) + { + codec = "null"; + } + if (codec.equalsIgnoreCase("xml")) + { + codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext"; + } + else if (codec.equalsIgnoreCase("jdbc")) + { + codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext"; + } + else if (codec.equalsIgnoreCase("null")) + { + codecClass = "gnu.javax.net.ssl.provider.SessionContext"; + } + else + { + throw new IllegalArgumentException("no such codec: " + codec); + } + try + { + ClassLoader cl = Context.class.getClassLoader(); + if (cl == null) + { + cl = ClassLoader.getSystemClassLoader(); + } + serverSessions = (SessionContext) cl.loadClass(codecClass).newInstance(); + } + catch (Exception ex) + { + ex.printStackTrace(); + throw new IllegalArgumentException(ex.toString()); + } + } + + // Engine methods. + // ------------------------------------------------------------------------- + + protected SSLSessionContext engineGetClientSessionContext() + { + return clientSessions; + } + + protected SSLSessionContext engineGetServerSessionContext() + { + return serverSessions; + } + + protected javax.net.ssl.SSLServerSocketFactory engineGetServerSocketFactory() + { + if (keyManager == null || (trustManager == null && srpTrustManager == null) + || random == null) + { + throw new IllegalStateException(); + } + return new SSLServerSocketFactory(trustManager, srpTrustManager, keyManager, + random, serverSessions); + } + + protected javax.net.ssl.SSLSocketFactory engineGetSocketFactory() + { + if (keyManager == null || trustManager == null || random == null) + { + throw new IllegalStateException(); + } + return new SSLSocketFactory(trustManager, keyManager, random, clientSessions); + } + + protected void engineInit(KeyManager[] keyManagers, + TrustManager[] trustManagers, SecureRandom random) + throws KeyManagementException + { + keyManager = null; + trustManager = null; + srpTrustManager = null; + if (keyManagers != null) + { + for (int i = 0; i < keyManagers.length; i++) + { + if (keyManagers[i] instanceof X509KeyManager) + { + keyManager = (X509KeyManager) keyManagers[i]; + break; + } + } + } + if (keyManager == null) + { + keyManager = defaultKeyManager(); + } + if (trustManagers != null) + { + for (int i = 0; i < trustManagers.length; i++) + { + if (trustManagers[i] instanceof X509TrustManager) + { + if (trustManager == null) + { + trustManager = (X509TrustManager) trustManagers[i]; + } + } + else if (trustManagers[i] instanceof SRPTrustManager) + { + if (srpTrustManager == null) + { + srpTrustManager = (SRPTrustManager) trustManagers[i]; + } + } + } + } + if (trustManager == null && srpTrustManager == null) + { + trustManager = defaultTrustManager(); + } + if (random != null) + { + this.random = random; + } + else + { + this.random = defaultRandom(); + } + } + + // Own methods. + // ------------------------------------------------------------------------- + + private X509KeyManager defaultKeyManager() throws KeyManagementException + { + KeyManagerFactory fact = null; + try + { + fact = KeyManagerFactory.getInstance("JessieX509", "Jessie"); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(); + } + catch (NoSuchProviderException nspe) + { + throw new KeyManagementException(); + } + try + { + fact.init(null, null); + return (X509KeyManager) fact.getKeyManagers()[0]; + } + catch (NoSuchAlgorithmException nsae) { } + catch (KeyStoreException kse) { } + catch (UnrecoverableKeyException uke) { } + catch (IllegalStateException ise) { } + + try + { + fact.init(new NullManagerParameters()); + return (X509KeyManager) fact.getKeyManagers()[0]; + } + catch (Exception shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + } + + private X509TrustManager defaultTrustManager() throws KeyManagementException + { + try + { + TrustManagerFactory fact = + TrustManagerFactory.getInstance("JessieX509", "Jessie"); + fact.init(StaticTrustAnchors.CA_CERTS); + return (X509TrustManager) fact.getTrustManagers()[0]; + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(nsae.toString()); + } + catch (NoSuchProviderException nspe) + { + throw new KeyManagementException(nspe.toString()); + } + catch (InvalidAlgorithmParameterException kse) + { + throw new KeyManagementException(kse.toString()); + } + } + + private SecureRandom defaultRandom() throws KeyManagementException + { + String alg = Util.getSecurityProperty("jessie.secure.random"); + if (alg == null) + { + alg = "Fortuna"; + } + SecureRandom rand = null; + try + { + rand = SecureRandom.getInstance(alg); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(nsae.toString()); + } + + return rand; + } +} diff --git a/gnu/javax/net/ssl/provider/DiffieHellman.java b/gnu/javax/net/ssl/provider/DiffieHellman.java new file mode 100644 index 000000000..ad48c7959 --- /dev/null +++ b/gnu/javax/net/ssl/provider/DiffieHellman.java @@ -0,0 +1,285 @@ +/* DiffieHellman.java -- Diffie-Hellman key exchange. + 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.net.ssl.provider; + +import java.math.BigInteger; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; + +/** + * <p>Simple implementation of two-party Diffie-Hellman key agreement.</p> + * + * <p>The primes used in this class are from the following documents:</p> + * + * <ul> + * <li>D. Harkins and D. Carrel, "The Internet Key Exchange (IKE)", <a + * href="http://www.ietf.org/rfc/rfc2409.txt">RFC 2409</a>.</li> + * <li>T. Kivinen and M. Kojo, "More Modular + * Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange + * (IKE)", <a href="http://www.ietf.org/rfc/rfc3526.txt">RFC + * 3526</a>.</li> + * </li> + * + * <p>The generator for all these primes is 2.</p> + */ +final class DiffieHellman +{ + + // Class method. + // ------------------------------------------------------------------------- + + /** + * Get the system's Diffie-Hellman parameters, in which <i>g</i> is 2 + * and <i>p</i> is determined by the property + * <code>"jessie.keypool.dh.group"</code>. The default value for <i>p</i> + * is 18, corresponding to {@link #GROUP_18}. + */ + static GnuDHPrivateKey getParams() + { + BigInteger p = DiffieHellman.GROUP_5; + String group = Util.getSecurityProperty("jessie.key.dh.group"); + if (group != null) + { + group = group.trim(); + if (group.equals("1")) + p = DiffieHellman.GROUP_1; + else if (group.equals("2")) + p = DiffieHellman.GROUP_2; + else if (group.equals("5")) + p = DiffieHellman.GROUP_5; + else if (group.equals("14")) + p = DiffieHellman.GROUP_14; + else if (group.equals("15")) + p = DiffieHellman.GROUP_15; + else if (group.equals("16")) + p = DiffieHellman.GROUP_16; + else if (group.equals("17")) + p = DiffieHellman.GROUP_17; + else if (group.equals("18")) + p = DiffieHellman.GROUP_18; + } + return new GnuDHPrivateKey(null, p, DH_G, null); + } + + // Constants. + // ------------------------------------------------------------------------- + + /** + * The generator for all Diffie Hellman groups below. + */ + static final BigInteger DH_G = BigInteger.valueOf(2L); + + /** + * p = 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } + */ + static final BigInteger GROUP_1 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } + */ + static final BigInteger GROUP_2 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + + "FFFFFFFFFFFFFFFF", 16); + + /** + * This prime p = 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }. + */ + static final BigInteger GROUP_5 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }. + */ + static final BigInteger GROUP_14 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }. + */ + static final BigInteger GROUP_15 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }. + */ + static final BigInteger GROUP_16 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + + "FFFFFFFFFFFFFFFF", 16); + + static final BigInteger GROUP_17 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + + "6DCC4024FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }. + * + * <p>This value, while quite large, is estimated to provide the equivalent + * cryptographic strength of a symmetric key between 190 and 320 bits. + */ + static final BigInteger GROUP_18 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" + + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" + + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" + + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" + + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" + + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" + + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" + + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" + + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" + + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16); + +} diff --git a/gnu/javax/net/ssl/provider/DigestInputStream.java b/gnu/javax/net/ssl/provider/DigestInputStream.java new file mode 100644 index 000000000..dd138b436 --- /dev/null +++ b/gnu/javax/net/ssl/provider/DigestInputStream.java @@ -0,0 +1,103 @@ +/* DigestInputStream.java -- digesting input stream. + 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.net.ssl.provider; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +import gnu.java.security.hash.IMessageDigest; + +final class DigestInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private IMessageDigest md5, sha; + private boolean digesting; + + // Constructor. + // ------------------------------------------------------------------------- + + DigestInputStream(InputStream in, IMessageDigest md5, IMessageDigest sha) + { + super(in); + if (md5 == null || sha == null) + throw new NullPointerException(); + this.md5 = md5; + this.sha = sha; + digesting = true; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + void setDigesting(boolean digesting) + { + this.digesting = digesting; + } + + public int read() throws IOException + { + int i = in.read(); + if (digesting && i != -1) + { + md5.update((byte) i); + sha.update((byte) i); + } + 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 + { + int ret = in.read(buf, off, len); + if (digesting && ret != -1) + { + md5.update(buf, off, ret); + sha.update(buf, off, ret); + } + return ret; + } +} diff --git a/gnu/javax/net/ssl/provider/DigestOutputStream.java b/gnu/javax/net/ssl/provider/DigestOutputStream.java new file mode 100644 index 000000000..f1548459e --- /dev/null +++ b/gnu/javax/net/ssl/provider/DigestOutputStream.java @@ -0,0 +1,107 @@ +/* DigestOutputStream.java -- digesting output stream. + 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.net.ssl.provider; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import gnu.java.security.hash.IMessageDigest; + +final class DigestOutputStream extends FilterOutputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private IMessageDigest md5, sha; + private boolean digesting; + + // Constructor. + // ------------------------------------------------------------------------- + + DigestOutputStream(OutputStream out, IMessageDigest md5, IMessageDigest sha) + { + super(out); + this.md5 = md5; + this.sha = sha; + digesting = true; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + void setDigesting(boolean digesting) + { + this.digesting = digesting; + } + + public void write(int b) throws IOException + { + if (digesting) + { + md5.update((byte) b); + sha.update((byte) b); + } + out.write(b); + } + + public void write(byte[] buf) throws IOException + { + write(buf, 0, buf.length); + } + + public void write(byte[] buf, int off, int len) throws IOException + { + if (buf == null) + { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || off+len > buf.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + if (digesting) + { + md5.update(buf, off, len); + sha.update(buf, off, len); + } + out.write(buf, off, len); + } +} diff --git a/gnu/javax/net/ssl/provider/Enumerated.java b/gnu/javax/net/ssl/provider/Enumerated.java new file mode 100644 index 000000000..8875addab --- /dev/null +++ b/gnu/javax/net/ssl/provider/Enumerated.java @@ -0,0 +1,79 @@ +/* Enumerated.java -- Interface to enumerated types. + 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.net.ssl.provider; + +/** + * An enumerated type in the SSL protocols. Enumerated values take on + * one of a set of possible numeric values, which are not specifically + * ordered, and may be extensible to a maximum value. + * + * <pre>enum { e1(v1), e2(v2), ... [[, (n) ]] }</pre> + * + * <p>Enumerated types are encoded as big-endian multibyte integers, + * which take up the least possible number of bytes. Thus, an + * enumeration with up to 255 values will be encoded in a single byte, + * and so on. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +interface Enumerated +{ + + /** + * Returns the encoded value of this enumerated value, which is + * appropriate to send over-the-wire. + * + * @return The encoded value. + */ + byte[] getEncoded(); + + /** + * Returns the numeric value of this enumerated value. + * + * @return The numeric value. + */ + int getValue(); + + /** + * Returns a string representation of this enumerated value. + * + * @return The string. + */ + String toString(); +} diff --git a/gnu/javax/net/ssl/provider/Extension.java b/gnu/javax/net/ssl/provider/Extension.java new file mode 100644 index 000000000..1c79dd5cb --- /dev/null +++ b/gnu/javax/net/ssl/provider/Extension.java @@ -0,0 +1,214 @@ +/* Extension.java -- A TLS hello 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.javax.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +final class Extension implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Type type; + private final byte[] value; + + // Constructor. + // ------------------------------------------------------------------------- + + Extension(Type type, byte[] value) + { + if (type == null || value == null) + { + throw new NullPointerException(); + } + this.type = type; + this.value = value; + } + + // Class method. + // ------------------------------------------------------------------------- + + static Extension read(InputStream in) throws IOException + { + Type t = Type.read(in); + int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + byte[] v = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(v, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of extension"); + } + count += l; + } + return new Extension(t, v); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write(type.getEncoded()); + out.write(value.length >>> 8 & 0xFF); + out.write(value.length & 0xFF); + out.write(value); + } + + Type getType() + { + return type; + } + + byte[] getValue() + { + return value; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" type = " + type + ";"); + out.println(" value ="); + out.println(Util.hexDump(value, " ")); + out.println("} Extension;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + static final class Type implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final Type SERVER_NAME = new Type(0); + static final Type MAX_FRAGMENT_LENGTH = new Type(1); + static final Type CLIENT_CERTIFICATE_URL = new Type(2); + static final Type TRUSTED_CA_KEYS = new Type(3); + static final Type TRUNCATED_HMAC = new Type(4); + static final Type STATUS_REQUEST = new Type(5); + static final Type SRP = new Type(6); + static final Type CERT_TYPE = new Type(7); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Type(int value) + { + this.value = value; + } + + // Class methods. + // ----------------------------------------------------------------------- + + static Type read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + int value = (i & 0xFF) << 8; + i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + value |= i & 0xFF; + switch (value) + { + case 0: return SERVER_NAME; + case 1: return MAX_FRAGMENT_LENGTH; + case 2: return CLIENT_CERTIFICATE_URL; + case 3: return TRUSTED_CA_KEYS; + case 4: return TRUNCATED_HMAC; + case 5: return STATUS_REQUEST; + case 6: return SRP; + case 7: return CERT_TYPE; + default: return new Type(value); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { + (byte) (value >>> 8 & 0xFF), (byte) (value & 0xFF) + }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "server_name"; + case 1: return "max_fragment_length"; + case 2: return "client_certificate_url"; + case 3: return "trusted_ca_keys"; + case 4: return "truncated_hmac"; + case 5: return "status_request"; + case 6: return "srp"; + case 7: return "cert_type"; + default: return "unknown(" + value + ")"; + } + } + } +} diff --git a/gnu/javax/net/ssl/provider/Extensions.java b/gnu/javax/net/ssl/provider/Extensions.java new file mode 100644 index 000000000..9ed9619f0 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Extensions.java @@ -0,0 +1,159 @@ +/* Extensions.java -- various static extension utilities. + 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.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import javax.security.auth.x500.X500Principal; + +import gnu.java.security.x509.X500DistinguishedName; + +final class Extensions +{ + + // Constants. + // ------------------------------------------------------------------------- + + private static final Integer _512 = new Integer(512), + _1024 = new Integer(1024), _2048 = new Integer(2048), + _4096 = new Integer(4096); + + // Class methods only. + private Extensions() { } + + // Class methods. + // ------------------------------------------------------------------------- + + static List getServerName(Extension ex) + { + LinkedList l = new LinkedList(); + byte[] buf = ex.getValue(); + int pos = 0; + try + { + while (pos < buf.length) + { + if (buf[pos++] != 0) + break; + int len = (buf[pos++] & 0xFF) << 8; + len |= buf[pos++] & 0xFF; + l.add(new String(buf, pos, len, "UTF-8")); + pos += len; + } + } + catch (Exception x) + { + } + return Collections.unmodifiableList(l); + } + + static List getClientCertTypes(Extension ex) throws IOException + { + List l = new LinkedList(); + ByteArrayInputStream in = new ByteArrayInputStream(ex.getValue()); + final int len = in.read() & 0xFF; + for (int i = 0; i < len; i++) + { + l.add(CertificateType.read(in)); + } + return Collections.unmodifiableList(l); + } + + static CertificateType getServerCertType(Extension ex) throws IOException + { + return CertificateType.read(new ByteArrayInputStream(ex.getValue())); + } + + static Integer getMaxFragmentLength(Extension ex) + { + switch (ex.getValue()[0] & 0xFF) + { + case 1: return _512; + case 2: return _1024; + case 3: return _2048; + case 4: return _4096; + } + throw new IllegalArgumentException(); + } + + static Object[] getTrustedCA(Extension ex) + { + byte[] buf = ex.getValue(); + int type = buf[0] & 0xFF; + try + { + switch (type) + { + case 0: + return new Object[] { new Integer(type), null }; + case 1: + case 3: + return new Object[] { new Integer(type), + Util.trim(buf, 1, 20) }; + case 2: + return new Object[] { new Integer(type), + new X500Principal(Util.trim(buf, 1, 20)) }; + } + } + catch (Exception x) + { + } + throw new IllegalArgumentException(); + } + + static String getSRPUsername(Extension ex) + { + int len = ex.getValue()[0] & 0xFF; + if (len > ex.getValue().length - 1) + throw new IllegalArgumentException(); + try + { + return new String(ex.getValue(), 1, len, "UTF-8"); + } + catch (UnsupportedEncodingException uee) + { + throw new Error(uee.toString()); + } + } +} diff --git a/gnu/javax/net/ssl/provider/Finished.java b/gnu/javax/net/ssl/provider/Finished.java new file mode 100644 index 000000000..8b9c220a5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Finished.java @@ -0,0 +1,143 @@ +/* Finished.java -- SSL Finished message. + 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.net.ssl.provider; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +final class Finished implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** TLSv1.x verify data. */ + private final byte[] verifyData; + + /** SSLv3 message digest pair. */ + private final byte[] md5, sha; + + // Constructor. + // ------------------------------------------------------------------------- + + Finished(byte[] verifyData) + { + this.verifyData = verifyData; + md5 = sha = null; + } + + Finished(byte[] md5, byte[] sha) + { + this.md5 = md5; + this.sha = sha; + verifyData = null; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Finished read(InputStream in, CipherSuite suite) + throws IOException + { + DataInputStream din = new DataInputStream(in); + if (suite.getVersion().equals(ProtocolVersion.SSL_3)) + { + byte[] md5 = new byte[16]; + byte[] sha = new byte[20]; + din.readFully(md5); + din.readFully(sha); + return new Finished(md5, sha); + } + else + { + byte[] buf = new byte[12]; + din.readFully(buf); + return new Finished(buf); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + if (verifyData != null) + out.write(verifyData); + else + { + out.write(md5); + out.write(sha); + } + } + + byte[] getVerifyData() + { + return verifyData; + } + + byte[] getMD5Hash() + { + return md5; + } + + byte[] getSHAHash() + { + return sha; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + if (verifyData != null) + { + return "struct {" + nl + + " verifyData = " + Util.toHexString(verifyData, ':') + ";" + nl + + "} Finished;" + nl; + } + else + { + return "struct {" + nl + + " md5Hash = " + Util.toHexString(md5, ':') + ";" + nl + + " shaHash = " + Util.toHexString(sha, ':') + ";" + nl + + "} Finished;" + nl; + } + } +} diff --git a/gnu/javax/net/ssl/provider/GNUSecurityParameters.java b/gnu/javax/net/ssl/provider/GNUSecurityParameters.java new file mode 100644 index 000000000..a04c3fd5c --- /dev/null +++ b/gnu/javax/net/ssl/provider/GNUSecurityParameters.java @@ -0,0 +1,490 @@ +/* GNUSecurityParameters.java -- SSL security parameters. + 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; + +import java.security.SecureRandom; +import java.security.Security; +import java.util.Arrays; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +import javax.net.ssl.SSLException; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mode.IMode; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +/** + * This class implements the {@link SecurityParameters} interface, using the + * GNU Crypto interface for ciphers and macs, and the JZlib package for + * record compression. + */ +class GNUSecurityParameters implements SecurityParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG_RECORD_LAYER = false; + private static final PrintWriter debug = new PrintWriter (System.err, true); + + /** + * The CBC block cipher, if any. + */ + IMode inCipher, outCipher; + + /** + * The RC4 PRNG, if any. + */ + IRandom inRandom, outRandom; + + /** + * The MAC algorithm. + */ + IMac inMac, outMac; + + long inSequence, outSequence; + Session session; + ProtocolVersion version; + int fragmentLength; + private Inflater inflater; + private Deflater deflater; + + // Constructors. + // ------------------------------------------------------------------------- + + GNUSecurityParameters (Session session) + { + inSequence = 0; + outSequence = 0; + this.session = session; + fragmentLength = 16384; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void reset() + { + inSequence = 0L; + outSequence = 0L; + inCipher = null; + outCipher = null; + inMac = null; + outMac = null; + inRandom = null; + outRandom = null; + deflater = null; + inflater = null; + } + + public ProtocolVersion getVersion() + { + return version; + } + + public void setVersion(ProtocolVersion version) + { + this.version = version; + } + + public void setInCipher(Object inCipher) + { + if (inCipher instanceof IMode) + { + this.inCipher = (IMode) inCipher; + inRandom = null; + } + else + { + inRandom = (IRandom) inCipher; + this.inCipher = null; + } + } + + public void setOutCipher(Object outCipher) + { + if (outCipher instanceof IMode) + { + this.outCipher = (IMode) outCipher; + outRandom = null; + } + else + { + outRandom = (IRandom) outCipher; + this.outCipher = null; + } + } + + public void setInMac(Object inMac) + { + this.inMac = (IMac) inMac; + inSequence = 0L; + } + + public void setOutMac(Object outMac) + { + this.outMac = (IMac) outMac; + outSequence = 0L; + } + + public void setDeflating (boolean deflate) + { + if (deflate) + { + if (deflater == null) + deflater = new Deflater(); + } + else + deflater = null; + } + + public void setInflating (boolean inflate) + { + if (inflate) + { + if (inflater == null) + inflater = new Inflater(); + } + else + inflater = null; + } + + public int getFragmentLength() + { + return fragmentLength; + } + + public void setFragmentLength (int fragmentLength) + { + this.fragmentLength = fragmentLength; + } + + /** + * Decrypt, verify, and decompress a fragment, returning the transformed + * fragment. + * + * @param fragment The fragment to decrypt. + * @param version The protocol version of the fragment's record. + * @param type The content type of the record. + * @return The decrypted fragment. + * @throws MacException If the MAC could not be verified. + * @throws OverflowException If the inflated data is too large. + * @throws SSLException If decompressing fails. + */ + public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version, + ContentType type) + throws MacException, OverflowException, SSLException + { + boolean badPadding = false; + + // Decrypt the ciphertext, if it is encrypted. + if (inCipher != null) + { + int bs = inCipher.currentBlockSize (); + for (int i = 0; i < fragment.length; i += bs) + { + inCipher.update (fragment, i, fragment, i); + } + int padLen = fragment[fragment.length-1] & 0xFF; + int len = fragment.length - padLen - 1; + if (version == ProtocolVersion.SSL_3) + { + // SSLv3 requires that the padding length not exceed the + // cipher's block size. + if (padLen >= bs) + { + badPadding = true; + } + } + else + { + for (int i = len; i < fragment.length; i++) + { + // If the TLS padding is wrong, throw a MAC exception below. + if ((fragment[i] & 0xFF) != padLen) + { + badPadding = true; + } + } + } + fragment = Util.trim (fragment, len); + } + else if (inRandom != null) + { + transformRC4 (fragment, 0, fragment.length, fragment, 0, inRandom); + } + + // Check the MAC. + if (inMac != null) + { + inMac.update ((byte) (inSequence >>> 56)); + inMac.update ((byte) (inSequence >>> 48)); + inMac.update ((byte) (inSequence >>> 40)); + inMac.update ((byte) (inSequence >>> 32)); + inMac.update ((byte) (inSequence >>> 24)); + inMac.update ((byte) (inSequence >>> 16)); + inMac.update ((byte) (inSequence >>> 8)); + inMac.update ((byte) inSequence); + inMac.update ((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + inMac.update ((byte) version.getMajor()); + inMac.update ((byte) version.getMinor()); + } + int macLen = inMac.macSize (); + int fragLen = fragment.length - macLen; + inMac.update ((byte) (fragLen >>> 8)); + inMac.update ((byte) fragLen); + inMac.update (fragment, 0, fragLen); + byte[] mac = inMac.digest (); + inMac.reset (); + for (int i = 0; i < macLen; i++) + { + if (fragment[i + fragLen] != mac[i]) + { + throw new MacException(); + } + } + if (badPadding) + { + throw new MacException(); + } + fragment = Util.trim (fragment, fragLen); + } + + if (inflater != null) + { + byte[] buf = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1); + inflater.setInput (fragment); + int len; + try + { + while ((len = inflater.inflate (buf)) > 0) + { + bout.write (buf, 0, len); + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("inflated data too large"); + } + } + catch (DataFormatException dfe) + { + throw new SSLException (String.valueOf (dfe)); + } + fragment = bout.toByteArray(); + inflater.reset(); + } + + inSequence++; + return fragment; + } + + /** + * Compress, MAC, encrypt, and write a record. The fragment of the + * record is taken from <i>buf</i> as <i>len</i> bytes starting at + * <i>offset</i>. <i>len</i> <b>must</b> be smaller than or equal to + * the configured fragment length. + * + * @param buf The fragment bytes. + * @param off The offset from whence to read. + * @param len The size of the fragment. + * @param type The content-type for this record. + * @param out The output stream to write the record to. + * @throws IOException If an I/O error occurs. + * @throws SSLException If compression fails. + * @throws OverflowException If compression inflates the data beyond + * the fragment length plus 1024 bytes. + */ + public synchronized byte[] encrypt (byte[] buf, int off, int len, + ContentType type) + throws SSLException, OverflowException + { + // If we are compressing, do it. + if (deflater != null) + { + byte[] buf2 = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1); + deflater.setInput (buf, off, len); + deflater.finish(); + len = 0; + while ((len = deflater.deflate (buf2)) > 0) + bout.write (buf2, 0, len); + // This should technically never happen for zlib. + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("deflated data too large"); + buf = bout.toByteArray(); + off = 0; + len = buf.length; + deflater.reset(); + } + + // If there is a MAC, compute it. + byte[] mac = new byte[0]; + if (outMac != null) + { + outMac.update((byte) (outSequence >>> 56)); + outMac.update((byte) (outSequence >>> 48)); + outMac.update((byte) (outSequence >>> 40)); + outMac.update((byte) (outSequence >>> 32)); + outMac.update((byte) (outSequence >>> 24)); + outMac.update((byte) (outSequence >>> 16)); + outMac.update((byte) (outSequence >>> 8)); + outMac.update((byte) outSequence); + outMac.update((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + outMac.update((byte) version.getMajor()); + outMac.update((byte) version.getMinor()); + } + outMac.update((byte) (len >>> 8)); + outMac.update((byte) len); + outMac.update(buf, off, len); + mac = outMac.digest(); + outMac.reset(); + } + outSequence++; + + // Compute padding if needed. + byte[] pad = new byte[0]; + if (outCipher != null) + { + int padLen = outCipher.currentBlockSize() - + ((len + mac.length + 1) % outCipher.currentBlockSize()); + // Use a random amount of padding if the protocol is TLS. + if (version != ProtocolVersion.SSL_3 && session.random != null) + { + padLen += (Math.abs(session.random.nextInt ()) & 7) * + outCipher.currentBlockSize(); + while (padLen > 255) + { + padLen -= outCipher.currentBlockSize(); + } + } + pad = new byte[padLen+1]; + Arrays.fill (pad, (byte) padLen); + } + + // Write the record header. + final int fraglen = len + mac.length + pad.length; + + // Encrypt and write the fragment. + if (outCipher != null) + { + byte[] buf2 = new byte[fraglen]; + System.arraycopy (buf, off, buf2, 0, len); + System.arraycopy (mac, 0, buf2, len, mac.length); + System.arraycopy (pad, 0, buf2, len + mac.length, pad.length); + int bs = outCipher.currentBlockSize (); + for (int i = 0; i < fraglen; i += bs) + { + outCipher.update (buf2, i, buf2, i); + } + return buf2; + } + else if (outRandom != null) + { + byte[] buf2 = new byte[fraglen]; + transformRC4 (buf, off, len, buf2, 0, outRandom); + transformRC4 (mac, 0, mac.length, buf2, len, outRandom); + return buf2; + } + else + { + if (mac.length == 0) + { + return Util.trim (buf, off, len); + } + else + { + return Util.concat (Util.trim (buf, off, len), mac); + } + } + } + + // Own methods. + // ------------------------------------------------------------------------- + + /** + * Encrypt/decrypt a byte array with the RC4 stream cipher. + * + * @param in The input data. + * @param off The input offset. + * @param len The number of bytes to transform. + * @param out The output buffer. + * @param outOffset The offest into the output buffer. + * @param random The ARCFOUR PRNG. + */ + private static void transformRC4(byte[] in, int off, int len, + byte[] out, int outOffset, IRandom random) + { + if (random == null) + { + throw new IllegalStateException(); + } + if (in == null || out == null) + { + throw new NullPointerException(); + } + if (off < 0 || off + len > in.length || + outOffset < 0 || outOffset + len > out.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + + try + { + for (int i = 0; i < len; i++) + { + out[outOffset+i] = (byte) (in[off+i] ^ random.nextByte()); + } + } + catch (LimitReachedException cannotHappen) + { + throw new Error(cannotHappen.toString()); + } + } +} diff --git a/gnu/javax/net/ssl/provider/Handshake.java b/gnu/javax/net/ssl/provider/Handshake.java new file mode 100644 index 000000000..ef9e72381 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Handshake.java @@ -0,0 +1,440 @@ +/* Handshake.java -- SSL handshake message. + 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.security.PublicKey; + +import java.util.ArrayList; +import java.util.Collections; + +import javax.net.ssl.SSLProtocolException; + +final class Handshake implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final buffer BUF = new buffer(); + + private final Type type; + private final Body body; + + // Constructors. + // ------------------------------------------------------------------------- + + Handshake(Type type, Body body) + { + this.type = type; + this.body = body; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Handshake read(byte[] buffer) throws IOException + { + return read(new ByteArrayInputStream(buffer)); + } + + static Handshake read(byte[] buffer, CipherSuite suite, PublicKey key) + throws IOException + { + return read(new ByteArrayInputStream(buffer), suite, key); + } + + static Handshake read(InputStream in) throws IOException + { + return read(in, null, null); + } + + static Handshake read(InputStream in, CipherSuite suite, PublicKey key) + throws IOException + { + return read(in, suite, key, null); + } + + static Handshake read(InputStream in, CertificateType certType) + throws IOException + { + return read(in, null, null, certType); + } + + static Handshake read(InputStream in, CipherSuite suite, PublicKey key, + CertificateType certType) + throws IOException + { + Type type = Type.read(in); + byte[] lenbuf = new byte[3]; + in.read(lenbuf); + int len = (lenbuf[0] & 0xFF) << 16 | (lenbuf[1] & 0xFF) << 8 + | (lenbuf[2] & 0xFF); + Body body = null; + if (type == Type.HELLO_REQUEST) + { + body = null; + } + else if (type == Type.CLIENT_HELLO) + { + // Most likely a V2 hello. If the first byte is 0x30, and if this + // is not a V2 client hello, then it is a V3 client hello with + // at least 1.5 million cipher specs, which is unlikely. + if (lenbuf[0] == 3 && (lenbuf[1] >= 0 && lenbuf[1] <= 2)) + { + ProtocolVersion vers = null; + switch (lenbuf[1]) + { + case 0: + vers = ProtocolVersion.SSL_3; + break; + case 1: + vers = ProtocolVersion.TLS_1; + break; + case 2: + vers = ProtocolVersion.TLS_1_1; + break; + } + int specLen = (lenbuf[2] & 0xFF) << 8 | (in.read() & 0xFF); + int idLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + int chalLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + + ArrayList suites = new ArrayList(specLen / 3); + for (int i = 0; i < specLen; i += 3) + { + if (in.read() == 0) + { + suites.add(CipherSuite.read(in).resolve(vers)); + } + else + { + in.read(); + in.read(); + } + } + byte[] id = new byte[idLen]; + in.read(id); + byte[] challenge = new byte[chalLen]; + in.read(challenge); + if (challenge.length > 32) + challenge = Util.trim(challenge, 32); + else if (challenge.length < 32) + { + byte[] b = new byte[32]; + System.arraycopy(challenge, 0, b, b.length - challenge.length, + challenge.length); + challenge = b; + } + int time = (challenge[0] & 0xFF) << 24 | (challenge[1] & 0xFF) << 16 + | (challenge[2] & 0xFF) << 8 | (challenge[3] & 0xFF); + Random rand = new Random(time, Util.trim(challenge, 4, 28)); + return new Handshake(Handshake.Type.CLIENT_HELLO, + new ClientHello(vers, rand, id, suites, + Collections.singletonList(CompressionMethod.NULL))); + } + // Since hello messages may contain extensions, we read the whole + // thing here. + byte[] buf = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(buf, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of input stream"); + } + count += l; + } + body = ClientHello.read(new ByteArrayInputStream(buf)); + } + else if (type == Type.SERVER_HELLO) + { + byte[] buf = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(buf, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of input stream"); + } + count += l; + } + body = ServerHello.read(new ByteArrayInputStream(buf)); + } + else if (type == Type.CERTIFICATE) + { + body = Certificate.read(in, certType); + } + else if (type == Type.SERVER_KEY_EXCHANGE) + { + body = ServerKeyExchange.read(in, suite, key); + } + else if (type == Type.CERTIFICATE_REQUEST) + { + body = CertificateRequest.read(in); + } + else if (type == Type.CERTIFICATE_VERIFY) + { + body = (CertificateVerify) CertificateVerify.read(in, suite, key); + } + else if (type == Type.CLIENT_KEY_EXCHANGE) + { + body = ClientKeyExchange.read(in, suite, key); + } + else if (type == Type.SERVER_HELLO_DONE) + { + body = null; + } + else if (type == Type.FINISHED) + { + body = Finished.read(in, suite); + } + else + { + throw new SSLProtocolException("unknown HandshakeType: " + + type.getValue()); + } + + return new Handshake(type, body); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) + { + throw new UnsupportedOperationException(); + } + + public int write(OutputStream out, ProtocolVersion version) + throws IOException + { + out.write(type.getValue()); + if (body == null) + { + out.write(0); + out.write(0); + out.write(0); + return 4; + } + else + { + ByteArrayOutputStream bout = BUF.getBuffer(); + bout.reset(); + if (body instanceof ServerKeyExchange) + { + ((ServerKeyExchange) body).write(bout, version); + } + else if (body instanceof ClientKeyExchange) + { + ((ClientKeyExchange) body).write(bout, version); + } + else if (body instanceof CertificateVerify) + { + ((CertificateVerify) body).write(bout, version); + } + else + { + body.write(bout); + } + out.write(bout.size() >>> 16 & 0xFF); + out.write(bout.size() >>> 8 & 0xFF); + out.write(bout.size() & 0xFF); + bout.writeTo(out); + return 4 + bout.size(); + } + } + + Type getType() + { + return type; + } + + Body getBody() + { + return body; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + String nl = System.getProperty("line.separator"); + StringBuffer buf = new StringBuffer(); + out.println("struct {"); + out.println(" type = " + type + ";"); + if (body != null) + { + BufferedReader r = new BufferedReader(new StringReader(body.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println("} Handshake;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + static interface Body extends Constructed + { + } + + static class Type implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + public static final Type + HELLO_REQUEST = new Type( 0), CLIENT_HELLO = new Type( 1), + SERVER_HELLO = new Type( 2), CERTIFICATE = new Type(11), + SERVER_KEY_EXCHANGE = new Type(12), CERTIFICATE_REQUEST = new Type(13), + SERVER_HELLO_DONE = new Type(14), CERTIFICATE_VERIFY = new Type(15), + CLIENT_KEY_EXCHANGE = new Type(16), FINISHED = new Type(20), + CERTIFICATE_URL = new Type(21), CERTIFICATE_STATUS = new Type(22); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Type(int value) + { + this.value = value; + } + + // Class methods. + // ----------------------------------------------------------------------- + + public static Type read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (i & 0xFF) + { + case 0: return HELLO_REQUEST; + case 1: return CLIENT_HELLO; + case 2: return SERVER_HELLO; + case 11: return CERTIFICATE; + case 12: return SERVER_KEY_EXCHANGE; + case 13: return CERTIFICATE_REQUEST; + case 14: return SERVER_HELLO_DONE; + case 15: return CERTIFICATE_VERIFY; + case 16: return CLIENT_KEY_EXCHANGE; + case 20: return FINISHED; + case 21: return CERTIFICATE_URL; + case 22: return CERTIFICATE_STATUS; + default: return new Type(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "hello_request"; + case 1: return "client_hello"; + case 2: return "server_hello"; + case 11: return "certificate"; + case 12: return "server_key_exchange"; + case 13: return "certificate_request"; + case 14: return "server_hello_done"; + case 15: return "certificate_verify"; + case 16: return "client_key_exchange"; + case 20: return "finished"; + case 21: return "certificate_url"; + case 22: return "certificate_status"; + default: return "unknown(" + value + ")"; + } + } + } + + private static class buffer extends ThreadLocal + { + static final int SIZE = 2048; + + protected Object initialValue() + { + return new ByteArrayOutputStream(SIZE); + } + + ByteArrayOutputStream getBuffer() + { + return (ByteArrayOutputStream) get(); + } + } +} diff --git a/gnu/javax/net/ssl/provider/JCESecurityParameters.java b/gnu/javax/net/ssl/provider/JCESecurityParameters.java new file mode 100644 index 000000000..6663c97b5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/JCESecurityParameters.java @@ -0,0 +1,307 @@ +/* JCESecurityParameters.java -- JCE-based security parameters. + 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; + +import java.util.Arrays; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.Mac; + +import javax.net.ssl.SSLException; + +class JCESecurityParameters implements SecurityParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Cipher inCipher, outCipher; + private Mac inMac, outMac; + private Inflater inflater; + private Deflater deflater; + private int fragmentLength; + private long inSequence, outSequence; + private ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + JCESecurityParameters () + { + fragmentLength = 16384; + inSequence = 0L; + outSequence = 0L; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void reset() + { + inCipher = null; + outCipher = null; + inMac = null; + outMac = null; + deflater = null; + inflater = null; + } + + public void setInCipher (Object inCipher) + { + this.inCipher = (Cipher) inCipher; + } + + public void setOutCipher (Object outCipher) + { + this.outCipher = (Cipher) outCipher; + } + + public void setInMac (Object inMac) + { + this.inMac = (Mac) inMac; + inSequence = 0L; + } + + public void setOutMac (Object outMac) + { + this.outMac = (Mac) outMac; + outSequence = 0L; + } + + public void setDeflating (boolean deflate) + { + if (deflate) + { + if (deflater == null) + deflater = new Deflater(); + } + else + deflater = null; + } + + public void setInflating (boolean inflate) + { + if (inflate) + { + if (inflater == null) + inflater = new Inflater(); + } + else + inflater = null; + } + + public int getFragmentLength() + { + return fragmentLength; + } + + public void setFragmentLength (int fragmentLength) + { + this.fragmentLength = fragmentLength; + } + + public ProtocolVersion getVersion() + { + return version; + } + + public void setVersion (ProtocolVersion version) + { + this.version = version; + } + + public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version, + ContentType type) + throws MacException, OverflowException, SSLException + { + boolean badpad = false; + if (inCipher != null) + { + // We imagine that the JCE would be used in cases where hardware + // acceleration is available, since it isn't really that useful for + // pure Java crypto. We decrypt (and encrypt, below) in one go + // to minimize (potential) calls to native methods. + try + { + fragment = inCipher.doFinal (fragment); + } + catch (BadPaddingException bpe) + { + badpad = true; + } + catch (IllegalBlockSizeException ibse) + { + badpad = true; + } + } + + if (inMac != null) + { + int macLen = inMac.getMacLength(); + int fragLen = fragment.length - macLen; + byte[] mac = Util.trim (fragment, fragLen, macLen); + fragment = Util.trim (fragment, fragLen); + inMac.update ((byte) (inSequence >>> 56)); + inMac.update ((byte) (inSequence >>> 48)); + inMac.update ((byte) (inSequence >>> 40)); + inMac.update ((byte) (inSequence >>> 32)); + inMac.update ((byte) (inSequence >>> 24)); + inMac.update ((byte) (inSequence >>> 16)); + inMac.update ((byte) (inSequence >>> 8)); + inMac.update ((byte) inSequence); + inMac.update ((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + inMac.update ((byte) version.getMajor()); + inMac.update ((byte) version.getMinor()); + } + inMac.update ((byte) (fragLen >>> 8)); + inMac.update ((byte) fragLen); + inMac.update (fragment); + if (!Arrays.equals (mac, inMac.doFinal()) || badpad) + throw new MacException(); + } + + if (inflater != null) + { + byte[] buf = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1); + inflater.setInput (fragment); + int len; + try + { + while ((len = inflater.inflate (buf)) > 0) + { + bout.write (buf, 0, len); + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("inflated data too large"); + } + } + catch (DataFormatException dfe) + { + throw new SSLException (String.valueOf (dfe)); + } + fragment = bout.toByteArray(); + inflater.reset(); + } + + inSequence++; + return fragment; + } + + public synchronized byte[] encrypt (byte[] fragment, int off, int len, + ContentType type) + throws OverflowException, SSLException + { + if (deflater != null) + { + byte[] buf = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1); + deflater.setInput (fragment, off, len); + deflater.finish(); + len = 0; + while ((len = deflater.deflate (buf)) > 0) + bout.write (buf, 0, len); + // This should technically never happen for zlib. + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("deflated data too large"); + fragment = bout.toByteArray(); + off = 0; + len = fragment.length; + deflater.reset(); + } + + if (outMac != null) + { + outMac.update ((byte) (inSequence >>> 56)); + outMac.update ((byte) (inSequence >>> 48)); + outMac.update ((byte) (inSequence >>> 40)); + outMac.update ((byte) (inSequence >>> 32)); + outMac.update ((byte) (inSequence >>> 24)); + outMac.update ((byte) (inSequence >>> 16)); + outMac.update ((byte) (inSequence >>> 8)); + outMac.update ((byte) inSequence); + outMac.update ((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + outMac.update ((byte) version.getMajor()); + outMac.update ((byte) version.getMinor()); + } + outMac.update ((byte) (len >>> 8)); + outMac.update ((byte) len); + outMac.update (fragment, off, len); + fragment = Util.concat (fragment, outMac.doFinal()); + off = 0; + len = fragment.length; + } + + if (outCipher != null) + { + try + { + fragment = outCipher.doFinal (fragment, off, len); + } + catch (BadPaddingException shouldNeverHappen) + { + // This is nonsensical. Don't even pretend that we can handle this. + throw new RuntimeException ("bad padding thrown while encrypting"); + } + catch (IllegalBlockSizeException ibse) + { + // Ditto. + throw new RuntimeException ("illegal block size thrown while encrypting"); + } + off = 0; + len = fragment.length; + } + + outSequence++; + if (off == 0 && len == fragment.length) + return fragment; + else + return Util.trim (fragment, off, len); + } +} diff --git a/gnu/javax/net/ssl/provider/JDBCSessionContext.java b/gnu/javax/net/ssl/provider/JDBCSessionContext.java new file mode 100644 index 000000000..2b9b14034 --- /dev/null +++ b/gnu/javax/net/ssl/provider/JDBCSessionContext.java @@ -0,0 +1,356 @@ +/* JDBCSessionContext.java -- database persistent sessions. + 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.sql.Types; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.TreeSet; +import java.util.Vector; + +import javax.net.ssl.SSLSession; + +/** + * The SQL table this class stores sessions in, called <tt>SESSIONS</tt>, + * looks like this: + * + * <blockquote><pre> + * TABLE SESSIONS ( + * ID VARBINARY(32) PRIMARY KEY UNIQUE NOT NULL, + * CREATED TIMESTAMP NOT NULL, + * LAST_ACCESSED TIMESTAMP NOT NULL, + * PROTOCOL VARCHAR(7) NOT NULL, + * SUITE VARCHAR(255) NOT NULL, + * PEER_HOST TEXT NOT NULL, + * PEER_CERT_TYPE VARCHAR(32), + * PEER_CERTS BLOB, + * CERT_TYPE VARCHAR(32), + * CERTS BLOB, + * SECRET VARBINARY(48) NOT NULL + * ) + * </pre></blockquote> + * + * <p>Note that the master secret for sessions is not protected before + * being inserted into the database; it is up to the system to protect + * the stored data from unauthorized access. + */ +class JDBCSessionContext extends SessionContext +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected Connection connection; + protected PreparedStatement selectById; + protected PreparedStatement insert; + protected PreparedStatement selectTimestamp; + protected PreparedStatement updateTimestamp; + protected PreparedStatement deleteSession; + + // Constructor. + // ------------------------------------------------------------------------- + + JDBCSessionContext() throws SQLException + { + String url = Util.getSecurityProperty("jessie.SessionContext.jdbc.url"); + String user = Util.getSecurityProperty("jessie.SessionContext.jdbc.user"); + String passwd = Util.getSecurityProperty("jessie.SessionContext.jdbc.password"); + if (url == null) + { + throw new IllegalArgumentException("no JDBC URL"); + } + if (user == null || passwd == null) + { + connection = DriverManager.getConnection(url); + } + else + { + connection = DriverManager.getConnection(url, user, passwd); + } + selectById = + connection.prepareStatement("SELECT * FROM SESSIONS WHERE ID = ?"); + insert = connection.prepareStatement("INSERT INTO SESSIONS VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + selectTimestamp = + connection.prepareStatement("SELECT CREATED FROM SESSIONS WHERE ID = ?"); + updateTimestamp = + connection.prepareStatement("UPDATE SESSIONS SET LAST_ACCESSED = ? WHERE ID = ?"); + deleteSession = + connection.prepareStatement("DELETE FROM SESSIONS WHERE ID = ?"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public synchronized Enumeration getIds() + { + Vector ids = new Vector(); + try + { + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT ID FROM SESSIONS"); + while (rs.next()) + { + byte[] id = rs.getBytes("ID"); + ids.add(id); + } + } + catch (SQLException sqle) + { + } + return ids.elements(); + } + + public synchronized SSLSession getSession(byte[] sessionId) + { + Session session = (Session) super.getSession(sessionId); + if (session == null) + { + try + { + selectById.setBytes(1, sessionId); + ResultSet rs = selectById.executeQuery(); + if (rs.next()) + { + session = new Session(rs.getTimestamp("CREATED").getTime()); + session.enabledSuites = new ArrayList(SSLSocket.supportedSuites); + session.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols); + session.random = new SecureRandom(); + session.context = this; + session.sessionId = new Session.ID(rs.getBytes("ID")); + session.setLastAccessedTime(rs.getTimestamp("LAST_ACCESSED").getTime()); + long elapsed = System.currentTimeMillis() - session.getLastAccessedTime(); + if ((int) (elapsed / 1000L) > timeout) + { + removeSession(session.sessionId); + return null; + } + session.peerHost = rs.getString("PEER_HOST"); + String protocol = rs.getString("PROTOCOL"); + if (protocol.equals("SSLv3")) + { + session.protocol = ProtocolVersion.SSL_3; + } + else if (protocol.equals("TLSv1")) + { + session.protocol = ProtocolVersion.TLS_1; + } + else if (protocol.equals("TLSv1.1")) + { + session.protocol = ProtocolVersion.TLS_1_1; + } + else + { + return null; + } + session.cipherSuite = CipherSuite.forName(rs.getString("SUITE")); + String type = rs.getString("PEER_CERT_TYPE"); + boolean wasNull = rs.wasNull(); + InputStream certs = null; + if (!wasNull) + { + certs = rs.getBinaryStream("PEER_CERTS"); + wasNull = rs.wasNull(); + } + if (!wasNull) + { + CertificateFactory cf = CertificateFactory.getInstance(type); + session.peerCerts = (Certificate[]) + cf.generateCertificates(certs).toArray(new Certificate[0]); + session.peerVerified = true; + } + type = rs.getString("CERT_TYPE"); + wasNull = rs.wasNull(); + if (!wasNull) + { + certs = rs.getBinaryStream("CERTS"); + wasNull = rs.wasNull(); + } + if (!wasNull) + { + CertificateFactory cf = CertificateFactory.getInstance(type); + session.localCerts = (Certificate[]) + cf.generateCertificates(certs).toArray(new Certificate[0]); + } + session.masterSecret = rs.getBytes("SECRET"); + if (cacheSize == 0 || sessions.size() < cacheSize) + { + sessions.put(session.sessionId, session); + } + } + } + catch (Exception ex) + { + } + } + return session; + } + + synchronized boolean addSession(Session.ID id, Session s) + { + if (containsSessionID(id)) + { + return false; + } + try + { + insert.setBytes(1, id.getId()); + insert.setTimestamp(2, new Timestamp(s.getCreationTime())); + insert.setTimestamp(3, new Timestamp(s.getLastAccessedTime())); + insert.setString(4, s.getProtocol()); + insert.setString(5, s.getCipherSuite()); + insert.setString(6, s.peerHost); + if (s.peerCerts != null && s.peerCerts.length > 0) + { + insert.setString(7, s.peerCerts[0].getType()); + insert.setBytes(8, certs(s.peerCerts)); + } + else + { + insert.setNull(7, Types.VARCHAR); + insert.setNull(8, Types.LONGVARBINARY); + } + if (s.localCerts != null && s.localCerts.length > 0) + { + insert.setString(9, s.localCerts[0].getType()); + insert.setBytes(10, certs(s.localCerts)); + } + else + { + insert.setNull(9, Types.VARCHAR); + insert.setNull(10, Types.LONGVARBINARY); + } + insert.setBytes(11, s.masterSecret); + insert.executeUpdate(); + super.addSession(id, s); + } + catch (SQLException sqle) + { + return false; + } + return true; + } + + synchronized boolean containsSessionID(Session.ID sessionId) + { + try + { + selectTimestamp.setBytes(1, sessionId.getId()); + ResultSet rs = selectTimestamp.executeQuery(); + if (!rs.next()) + { + return false; + } + Timestamp ts = rs.getTimestamp("CREATED"); + if (rs.wasNull()) + { + return false; + } + long elapsed = System.currentTimeMillis() - ts.getTime(); + if ((int) (elapsed / 1000) > timeout) + { + removeSession(sessionId); + return false; + } + return true; + } + catch (SQLException sqle) + { + return false; + } + } + + protected boolean removeSession(Session.ID sessionId) + { + super.removeSession(sessionId); + try + { + deleteSession.setBytes(1, sessionId.getId()); + return deleteSession.executeUpdate() > 0; + } + catch (SQLException sqle) + { + } + return false; + } + + synchronized void notifyAccess(Session session) + { + try + { + updateTimestamp.setTimestamp(1, new Timestamp(session.getLastAccessedTime())); + updateTimestamp.setBytes(2, session.getId()); + updateTimestamp.executeUpdate(); + } + catch (SQLException sqle) + { + } + } + + private byte[] certs(Certificate[] certs) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + for (int i = 0; i < certs.length; i++) + { + try + { + out.write(certs[i].getEncoded()); + } + catch (Exception x) + { + } + } + return out.toByteArray(); + } +} diff --git a/gnu/javax/net/ssl/provider/Jessie.java b/gnu/javax/net/ssl/provider/Jessie.java new file mode 100644 index 000000000..14b671d02 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Jessie.java @@ -0,0 +1,91 @@ +/* Jessie.java -- JESSIE's JSSE provider. + 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.net.ssl.provider; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +/** + * This is the security provider for Jessie. It implements the following + * algorithms: + * + * <pre> + * {@link javax.net.ssl.SSLContext}.SSLv3 + * {@link javax.net.ssl.SSLContext}.SSL + * {@link javax.net.ssl.SSLContext}.TLSv1 + * {@link javax.net.ssl.SSLContext}.TLS + * {@link javax.net.ssl.KeyManagerFactory}.JessieX509 + * {@link javax.net.ssl.TrustManagerFactory}.JessieX509 + * {@link javax.net.ssl.TrustManagerFactory}.SRP + * </pre> + * + */ +public class Jessie extends Provider +{ + + public static final String VERSION = "1.0.0"; + public static final double VERSION_DOUBLE = 1.0; + + public Jessie() + { + super("Jessie", VERSION_DOUBLE, + "Implementing SSLv3, TLSv1 SSL Contexts; X.509 Key Manager Factories;" + + System.getProperty("line.separator") + + "X.509 and SRP Trust Manager Factories, continuously-seeded secure random." ); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + put("SSLContext.SSLv3", Context.class.getName()); + put("Alg.Alias.SSLContext.SSL", "SSLv3"); + put("Alg.Alias.SSLContext.TLSv1", "SSLv3"); + put("Alg.Alias.SSLContext.TLS", "SSLv3"); + //put("Alg.Alias.SSLContext.TLSv1.1", "SSLv3"); + + put("KeyManagerFactory.JessieX509", X509KeyManagerFactory.class.getName()); + put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName()); + put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName()); + + return null; + } + }); + } +} diff --git a/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java b/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java new file mode 100644 index 000000000..1997458dd --- /dev/null +++ b/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java @@ -0,0 +1,99 @@ +/* JessieDHPrivateKey.java -- simple DH private 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.net.ssl.provider; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.spec.DHParameterSpec; + +class JessieDHPrivateKey implements DHPrivateKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final DHParameterSpec params; + private final BigInteger x; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieDHPrivateKey(DHParameterSpec params, BigInteger x) + { + this.params = params; + this.x = x; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "Diffie-Hellman"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public DHParameterSpec getParams() + { + return params; + } + + public BigInteger getX() + { + return x; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "P: " + params.getP() + nl + + "G: " + params.getG() + nl + + "X: " + x; + } +} diff --git a/gnu/javax/net/ssl/provider/JessieDHPublicKey.java b/gnu/javax/net/ssl/provider/JessieDHPublicKey.java new file mode 100644 index 000000000..dc6587288 --- /dev/null +++ b/gnu/javax/net/ssl/provider/JessieDHPublicKey.java @@ -0,0 +1,99 @@ +/* JessieDHPublicKey.java -- simple DH public 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.net.ssl.provider; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; + +class JessieDHPublicKey implements DHPublicKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final DHParameterSpec params; + private final BigInteger y; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieDHPublicKey(DHParameterSpec params, BigInteger y) + { + this.params = params; + this.y = y; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "Diffie-Hellman"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public DHParameterSpec getParams() + { + return params; + } + + public BigInteger getY() + { + return y; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "P: " + params.getP() + nl + + "G: " + params.getG() + nl + + "Y: " + y; + } +} diff --git a/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java b/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java new file mode 100644 index 000000000..4ec71a7aa --- /dev/null +++ b/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java @@ -0,0 +1,98 @@ +/* JessieRSAPrivateKey.java -- simple RSA private 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.net.ssl.provider; + +import java.math.BigInteger; +import java.security.interfaces.RSAPrivateKey; + +class JessieRSAPrivateKey implements RSAPrivateKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final BigInteger modulus; + private final BigInteger exponent; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieRSAPrivateKey(BigInteger modulus, BigInteger exponent) + { + this.modulus = modulus; + this.exponent = exponent; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPrivateExponent() + { + return exponent; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "RSAPrivateKey {" + nl + + " modulus = " + modulus.toString(16) + ";" + nl + + " exponent = " + exponent.toString(16) + ";" + nl + + "};"; + } +} diff --git a/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java b/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java new file mode 100644 index 000000000..19921d98c --- /dev/null +++ b/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java @@ -0,0 +1,98 @@ +/* JessieRSAPublicKey.java -- simple RSA public 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.net.ssl.provider; + +import java.math.BigInteger; +import java.security.interfaces.RSAPublicKey; + +class JessieRSAPublicKey implements RSAPublicKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final BigInteger modulus; + private final BigInteger exponent; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieRSAPublicKey(BigInteger modulus, BigInteger exponent) + { + this.modulus = modulus; + this.exponent = exponent; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return exponent; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "RSAPublicKey {" + nl + + " modulus = " + modulus.toString(16) + ";" + nl + + " exponent = " + exponent.toString(16) + ";" + nl + + "};"; + } +} diff --git a/gnu/javax/net/ssl/provider/KeyPool.java b/gnu/javax/net/ssl/provider/KeyPool.java new file mode 100644 index 000000000..e342700c2 --- /dev/null +++ b/gnu/javax/net/ssl/provider/KeyPool.java @@ -0,0 +1,119 @@ +/* KeyPool.java -- A set of ephemeral key pairs. + 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.net.ssl.provider; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.Security; +import java.util.LinkedList; +import javax.crypto.spec.DHParameterSpec; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Prime2; + +final class KeyPool +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final BigInteger ONE = BigInteger.ONE; + private static final BigInteger TWO = BigInteger.valueOf(2L); + private static final BigInteger E = BigInteger.valueOf(65537L); + private static final SecureRandom RANDOM = new SecureRandom (); + + // Constructor. + // ------------------------------------------------------------------------- + + private KeyPool() + { + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Generate an export-class (512 bit) RSA key pair. + * + * @return The new key pair. + */ + static KeyPair generateRSAKeyPair() + { + BigInteger p, q, n, d; + + // Simplified version of GNU Crypto's RSAKeyPairGenerator. + + int M = 256; + BigInteger lower = TWO.pow(255); + BigInteger upper = TWO.pow(256).subtract(ONE); + byte[] kb = new byte[32]; + while (true) + { + nextBytes(kb); + p = new BigInteger(1, kb).setBit(0); + if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0 && + Prime2.isProbablePrime(p) && p.gcd(E).equals(ONE)) + break; + } + + while (true) + { + nextBytes(kb); + q = new BigInteger(1, kb).setBit(0); + n = q.multiply(p); + if (n.bitLength() == 512 && Prime2.isProbablePrime(q) && + q.gcd(E).equals(ONE)) + break; + } + + d = E.modInverse(p.subtract(ONE).multiply(q.subtract(ONE))); + + return new KeyPair(new JessieRSAPublicKey(n, E), + new JessieRSAPrivateKey(n, d)); + } + + private static void nextBytes(byte[] buf) + { + RANDOM.nextBytes (buf); + } +} diff --git a/gnu/javax/net/ssl/provider/MacException.java b/gnu/javax/net/ssl/provider/MacException.java new file mode 100644 index 000000000..b8c479fdb --- /dev/null +++ b/gnu/javax/net/ssl/provider/MacException.java @@ -0,0 +1,53 @@ +/* MacException.java -- signals a bad record MAC. + 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.net.ssl.provider; + +import java.io.IOException; + +class MacException extends IOException +{ + + // Constructor. + // ------------------------------------------------------------------------- + + MacException() + { + super(); + } +} diff --git a/gnu/javax/net/ssl/provider/OverflowException.java b/gnu/javax/net/ssl/provider/OverflowException.java new file mode 100644 index 000000000..93bdcaec5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/OverflowException.java @@ -0,0 +1,57 @@ +/* OverflowException.java -- signals an input overflow. + 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.net.ssl.provider; + +import java.io.IOException; + +class OverflowException extends IOException +{ + + // Constructors. + // ------------------------------------------------------------------------- + + OverflowException() + { + } + + OverflowException(String msg) + { + super(msg); + } +} diff --git a/gnu/javax/net/ssl/provider/PRNG.java b/gnu/javax/net/ssl/provider/PRNG.java new file mode 100644 index 000000000..8145fcd17 --- /dev/null +++ b/gnu/javax/net/ssl/provider/PRNG.java @@ -0,0 +1,41 @@ +/* PRNG.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.net.ssl.provider; + +import java.security.SecureRandom;
\ No newline at end of file diff --git a/gnu/javax/net/ssl/provider/ProtocolVersion.java b/gnu/javax/net/ssl/provider/ProtocolVersion.java new file mode 100644 index 000000000..5f5d1d979 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ProtocolVersion.java @@ -0,0 +1,180 @@ +/* ProtocolVersion.java -- An SSL version number. + 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.net.ssl.provider; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +final class ProtocolVersion implements Comparable, Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0); + static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1); + static final ProtocolVersion TLS_1_1 = new ProtocolVersion(3, 2); + + private final int major; + private final int minor; + + // Constructor. + // ------------------------------------------------------------------------- + + private ProtocolVersion(int major, int minor) + { + this.major = major; + this.minor = minor; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ProtocolVersion read(InputStream in) throws IOException + { + int major = in.read() & 0xFF; + int minor = in.read() & 0xFF; + return getInstance(major, minor); + } + + static ProtocolVersion getInstance(int major, int minor) + { + if (major == 3) + { + switch (minor) + { + case 0: return SSL_3; + case 1: return TLS_1; + case 2: return TLS_1_1; + } + } + return new ProtocolVersion(major, minor); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write(major); + out.write(minor); + } + + byte[] getEncoded() + { + return new byte[] { + (byte) major, (byte) minor + }; + } + + int getMajor() + { + return major; + } + + int getMinor() + { + return minor; + } + + public boolean equals(Object o) + { + if (o == null || !(o instanceof ProtocolVersion)) + { + return false; + } + return ((ProtocolVersion) o).major == this.major + && ((ProtocolVersion) o).minor == this.minor; + } + + public int hashCode() + { + return major << 8 | minor; + } + + public int compareTo(Object o) + { + if (o == null || !(o instanceof ProtocolVersion)) + { + return 1; + } + if (this.equals(o)) + { + return 0; + } + if (major > ((ProtocolVersion) o).major) + { + return 1; + } + else if (major < ((ProtocolVersion) o).major) + { + return -1; + } + if (minor > ((ProtocolVersion) o).minor) + { + return 1; + } + else if (minor < ((ProtocolVersion) o).minor) + { + return -1; + } + return 0; + } + + public String toString() + { + if (this == SSL_3) + { + return "SSLv3"; + } + else if (this == TLS_1) + { + return "TLSv1"; + } + else if (this == TLS_1_1) + { + return "TLSv1.1"; + } + else + { + return "Unsupported; major=" + major + " minor=" + minor; + } + } +} diff --git a/gnu/javax/net/ssl/provider/Random.java b/gnu/javax/net/ssl/provider/Random.java new file mode 100644 index 000000000..c42592b14 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Random.java @@ -0,0 +1,124 @@ +/* Random.java -- SSL Random structure. + 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +class Random implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final int gmtUnixTime; + private final byte[] randomBytes; + + // Constructors. + // ------------------------------------------------------------------------- + + Random(int gmtUnixTime, byte[] randomBytes) + { + this.gmtUnixTime = gmtUnixTime; + this.randomBytes = (byte[]) randomBytes.clone(); + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Random read(InputStream in) throws IOException + { + int time = (in.read() & 0xFF) << 24 | (in.read() & 0xFF) << 16 + | (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + byte[] buf = new byte[28]; + in.read(buf); + return new Random(time, buf); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write((gmtUnixTime >>> 24) & 0xFF); + out.write((gmtUnixTime >>> 16) & 0xFF); + out.write((gmtUnixTime >>> 8) & 0xFF); + out.write(gmtUnixTime & 0xFF); + out.write(randomBytes); + } + + byte[] getEncoded() + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(32); + try + { + write(bout); + } + catch (IOException cantHappen) + { + throw new Error(cantHappen.toString()); + } + return bout.toByteArray(); + } + + int getTime() + { + return gmtUnixTime; + } + + byte[] getRandomBytes() + { + return randomBytes; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" gmt_unix_time = " + gmtUnixTime + ";"); + out.println(" random_bytes = " + Util.toHexString(randomBytes, ':') + ";"); + out.println("} Random;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/RecordInput.java b/gnu/javax/net/ssl/provider/RecordInput.java new file mode 100644 index 000000000..d4ba5b596 --- /dev/null +++ b/gnu/javax/net/ssl/provider/RecordInput.java @@ -0,0 +1,232 @@ +/* RecordInput.java -- record layer input. + 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.net.ssl.provider; + +import gnu.classpath.SystemProperties; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.PrintWriter; + +import java.util.logging.Logger; + +import javax.net.ssl.SSLProtocolException; + +class RecordInput +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG_RECORD_LAYER = true; + private static final Logger logger = SystemLogger.SYSTEM; + + private byte[] fragment; + private int index; + private ContentType type; + + private final DataInputStream in; + private Session session; + + // Constructor. + // ------------------------------------------------------------------------- + + RecordInput (final InputStream in, final Session session) + { + this.in = new DataInputStream (in); + this.session = session; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + synchronized int available (ContentType type) throws IOException + { + if (fragment == null) + { + readRecord (); + } + if (type != this.type) + { + return 0; + } + return fragment.length - index; + } + + void setSession (Session session) + { + this.session = session; + } + + synchronized int read (byte[] buf, int off, int len, ContentType type) + throws IOException + { + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException ("size=" + buf.length + + " off=" + off + " len=" + len); + } + if (fragment == null || index >= fragment.length) + { + readRecord (); + } + if (type != this.type) + { + return 0; + } + len = Math.min (len, fragment.length - index); + System.arraycopy (fragment, index, buf, off, len); + index += len; + return len; + } + + boolean pollClose () throws IOException + { + if (fragment == null || index >= fragment.length) + { + try + { + readRecord(); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert(); + if (alert.getDescription() == Alert.Description.CLOSE_NOTIFY) + { + return true; + } + throw ae; + } + } + return false; + } + + private void readRecord() throws IOException + { + type = ContentType.read (in); + if ((type.getValue() & 0x80) != 0 || (type.getValue() & 0x40) != 0) + { + in.read(); + if ((type.getValue() & 0x40) != 0) + { + in.read(); + } + type = ContentType.read(in); + if (type != ContentType.CLIENT_HELLO_V2) + { + throw new SSLProtocolException("unsupported V2 message"); + } + type = ContentType.HANDSHAKE; + // Record this message, and re-present it as a normal handshake + // layer message. ClientHello will handle the real parsing. + ByteArrayOutputStream buffer = new ByteArrayOutputStream (256); + buffer.write(1); // The type we just read. + RecordingInputStream in2 = new RecordingInputStream (in, buffer); + ProtocolVersion version = ProtocolVersion.read (in2); + if (version.compareTo (ProtocolVersion.SSL_3) < 0) + { + throw new SSLProtocolException("unsupported client version"); + } + int len = (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF); + len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF); + len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF); + int count = 0; + while (count < len) + { + int l = (int) in2.skip(len - count); + if (l > 0) + { + count += l; + } + } + fragment = buffer.toByteArray (); + index = 0; + + // We can't be encrypted/MACed/compressed here, since a V2 message + // will only be sent as the first message, and only by the client. + return; + } + ProtocolVersion v = ProtocolVersion.read (in); + int len = in.readUnsignedShort (); + if (len > session.params.getFragmentLength() + 2048) + { + throw new OverflowException(); + } + fragment = new byte [len]; + in.readFully (fragment); + + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + ">> READ RECORD <<{4}" + + "struct {{4}" + + " type = {0};{4}" + + " version = {1};{4}" + + " length = {2};{4}" + + "{3}{4}" + + "} TLSCiphertext;", new Object[] + { + type, v, new Integer (len), + Util.hexDump (fragment, " "), + SystemProperties.getProperty ("line.separator") + }); + } + + fragment = session.params.decrypt (fragment, v, type); + index = 0; + + if (session.random != null) + session.random.setSeed (fragment); + + if (type == ContentType.ALERT) + { + Alert alert = Alert.read (new ByteArrayInputStream (fragment)); + session.currentAlert = alert; + } + if (session.currentAlert != null) + { + throw new AlertException (session.currentAlert, false); + } + } +} diff --git a/gnu/javax/net/ssl/provider/RecordInputStream.java b/gnu/javax/net/ssl/provider/RecordInputStream.java new file mode 100644 index 000000000..14cf829ac --- /dev/null +++ b/gnu/javax/net/ssl/provider/RecordInputStream.java @@ -0,0 +1,106 @@ +/* RecordInputStream.java -- record layer input stream interface. + 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.net.ssl.provider; + +import java.io.IOException; +import java.io.InputStream; + +class RecordInputStream extends InputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * The record input instance. + */ + private final RecordInput in; + + /** + * The content type this stream is reading. + */ + private final ContentType type; + + // Constructor. + // ------------------------------------------------------------------------- + + RecordInputStream (RecordInput in, ContentType type) + { + this.in = in; + this.type = type; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int available () throws IOException + { + return in.available (type); + } + + public int read () throws IOException + { + byte[] b = new byte[1]; + int ret; + while ((ret = read (b)) != 1) + { + if (ret == -1) + { + return -1; + } + Thread.yield (); + } + return b[0] & 0xFF; + } + + public int read (byte[] buf) throws IOException + { + return read (buf, 0, buf.length); + } + + public int read (byte[] buf, int off, int len) throws IOException + { + return in.read (buf, off, len, type); + } + + public String toString () + { + return RecordInputStream.class.getName () + " [ type=" + type + " ]"; + } +} diff --git a/gnu/javax/net/ssl/provider/RecordOutputStream.java b/gnu/javax/net/ssl/provider/RecordOutputStream.java new file mode 100644 index 000000000..3bf228f2d --- /dev/null +++ b/gnu/javax/net/ssl/provider/RecordOutputStream.java @@ -0,0 +1,189 @@ +/* RecordOutputStream.java -- record layer output. + 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.net.ssl.provider; + +import gnu.classpath.SystemProperties; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; + +import java.util.logging.Logger; + +/** + * An output stream for writing data to the record layer. All data written + * to this stream (through any of the write methods) is immediately sent + * as a full record, so it is advisable to write large arrays to the stream + * instead of one byte at a time (alternatively, a {@link + * java.io.BufferedOutputStream} can be used). + */ +class RecordOutputStream extends FilterOutputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG_RECORD_LAYER = true; + private static final Logger logger = SystemLogger.SYSTEM; + + /** + * The content type of this output stream. + */ + private final ContentType type; + + /** + * The security parameters. + */ + private final SecurityParameters params; + + private final boolean emitEmpty; + + private static final byte[] ZERO = new byte[0]; + + // Constructor. + // ------------------------------------------------------------------------- + + RecordOutputStream (final OutputStream out, final ContentType type, + final SecurityParameters params) + { + super (out); + this.type = type; + this.params = params; + String empty = Util.getSecurityProperty ("jessie.emit.empty.records"); + if (empty == null) + { + // IE panics if it gets an empty record; so, leave this false + // for the default. + empty = "false"; + } + emitEmpty = Boolean.valueOf (empty).booleanValue () && + type == ContentType.APPLICATION_DATA; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write (int b) throws IOException + { + write (new byte[] { (byte) b }); + } + + public void write (byte[] buf) throws IOException + { + write (buf, 0, buf.length); + } + + public void write (byte[] buf, int off, int len) throws IOException + { + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException ("size=" + buf.length + + " off=" + off + " len=" + len); + } + + int count = 0; + int len2 = 0; + do + { + if (emitEmpty) + { + byte[] fragment = params.encrypt (ZERO, 0, 0, type); + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + ">> WRITING RECORD <<{4}" + + "struct {{4}" + + " type = {0};{4}" + + " version = {1};{4}" + + " length = {2};{4}" + + "{3}{4}" + + "} TLSCiphertext;", new Object[] + { + type, params.getVersion (), new Integer (fragment.length), + Util.hexDump (fragment, " "), + SystemProperties.getProperty ("line.separator") + }); + } + out.write (type.getValue()); + params.getVersion().write (out); + out.write ((fragment.length >>> 8) & 0xFF); + out.write ( fragment.length & 0xFF); + out.write (fragment); + out.flush (); + } + len2 = Math.min (len - count, params.getFragmentLength()); + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + "writing chunk size={0}", new Integer (len2)); + } + synchronized (out) + { + byte[] fragment = params.encrypt (buf, off + count, len2, type); + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + ">> WRITING RECORD <<{4}" + + "struct {{4}" + + " type = {0};{4}" + + " version = {1};{4}" + + " length = {2};{4}" + + "{3}{4}" + + "} TLSCiphertext;", new Object[] + { + type, params.getVersion (), new Integer (fragment.length), + Util.hexDump (fragment, " "), + SystemProperties.getProperty ("line.separator") + }); + } + out.write (type.getValue()); + params.getVersion().write (out); + out.write ((fragment.length >>> 8) & 0xFF); + out.write ( fragment.length & 0xFF); + out.write (fragment); + out.flush (); + } + count += len2; + } + while (count < len); + } +} diff --git a/gnu/javax/net/ssl/provider/RecordingInputStream.java b/gnu/javax/net/ssl/provider/RecordingInputStream.java new file mode 100644 index 000000000..d81b652d5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/RecordingInputStream.java @@ -0,0 +1,131 @@ +/* RecordingInputStream.java -- Input stream that records data. + 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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * A filter input stream that records every byte read from the underlying + * input stream. This class is useful for protocols that require portions + * of the communication to be saved, such as the handshake and key + * derivation in SSL. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +class RecordingInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected ByteArrayOutputStream sink; + + // Constructors. + // ------------------------------------------------------------------------- + + RecordingInputStream(InputStream in) + { + this(in, new ByteArrayOutputStream()); + } + + RecordingInputStream(InputStream in, ByteArrayOutputStream sink) + { + super(in); + this.sink = sink; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public synchronized int read() throws IOException + { + int i = in.read(); + sink.write(i); + return i; + } + + public synchronized int read(byte[] buf, int off, int len) throws IOException + { + int l = in.read(buf, off, len); + sink.write(buf, off, l); + return l; + } + + public synchronized int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public synchronized long skip(long len) throws IOException + { + long l = 0; + int i = 0; + byte[] buf = new byte[1024]; + while (l < len) + { + i = read(buf, 0, (int) Math.min((long) buf.length, len - l)); + if (i == -1) + break; + l += i; + } + return l; + } + + /** + * Returns all bytes recorded after this instance was created, or the last + * call to {@link resetSink()}. + * + * @return The recorded bytes. + */ + byte[] getBytes() + { + return sink.toByteArray(); + } + + /** + * Clears the recording buffer off all previously-recorded bytes. + */ + void resetSink() + { + sink.reset(); + } +} diff --git a/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java b/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java new file mode 100644 index 000000000..5822afe05 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java @@ -0,0 +1,225 @@ +/* SRPTrustManagerFactory.java -- trust manager for SRP. + 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.net.ssl.provider; + +import java.io.IOException; +import java.math.BigInteger; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.Security; + +import java.util.HashMap; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; + +import gnu.java.security.key.IKeyPairGenerator; +import gnu.javax.crypto.key.srp6.SRPKeyPairGenerator; +import gnu.javax.crypto.sasl.srp.PasswordFile; +import gnu.javax.crypto.sasl.srp.SRP; + +import gnu.javax.net.ssl.SRPManagerParameters; +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * This is an implementation of a {@link javax.net.ssl.TrustManagerFactory} + * engine for the ``SRP'' algorithm. You must initialize instances of this + * algorithm with {@link SRPManagerParameters}. + */ +public class SRPTrustManagerFactory extends TrustManagerFactorySpi +{ + + // Field. + // ------------------------------------------------------------------------- + + private Manager current; + + // Constructor. + // ------------------------------------------------------------------------- + + public SRPTrustManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected TrustManager[] engineGetTrustManagers() + { + if (current == null) + throw new IllegalStateException("not initialized"); + return new TrustManager[] { current }; + } + + protected void engineInit(KeyStore ks) + { + throw new IllegalArgumentException("only accepts SRPManagerParameters"); + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params == null) + { + try + { + String srpPasswd = Util.getSecurityProperty("jessie.srp.password.file"); + if (srpPasswd == null) + { + current = new Manager(new PasswordFile()); + return; + } + String srpPasswd2 = Util.getSecurityProperty("jessie.srp.password.file2"); + if (srpPasswd2 == null) + srpPasswd2 = srpPasswd + "2"; + String srpConfig = Util.getSecurityProperty("jessie.srp.config"); + if (srpConfig == null) + srpConfig = srpPasswd + ".conf"; + current = new Manager(new PasswordFile(srpPasswd, srpPasswd2, srpConfig)); + return; + } + catch (IOException ioe) + { + throw new InvalidAlgorithmParameterException("default initialization failed: " + + ioe.toString()); + } + } + if (params instanceof SRPManagerParameters) + { + current = new Manager(((SRPManagerParameters) params).getPasswordFile()); + return; + } + throw new InvalidAlgorithmParameterException(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class Manager implements SRPTrustManager + { + + // Field. + // ----------------------------------------------------------------------- + + private final PasswordFile file; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(PasswordFile file) + { + this.file = file; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public boolean contains(String user) + { + try + { + return file.contains(user); + } + catch (IOException ioe) { } + return false; + } + + public KeyPair getKeyPair(String user) + { + try + { + if (file.contains(user)) + { + SRP srp = SRP.instance("SHA"); + String[] ent = file.lookup(user, "SHA"); + String[] cnf = file.lookupConfig(ent[2]); + BigInteger v, N, g; + v = new BigInteger(1, gnu.java.security.util.Util.fromBase64(ent[0])); + N = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[0])); + g = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[1])); + IKeyPairGenerator kpg = new SRPKeyPairGenerator(); + HashMap attr = new HashMap(); + attr.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attr.put(SRPKeyPairGenerator.GENERATOR, g); + attr.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attr); + return kpg.generate(); + } + } + catch (IOException ioe) { } + return null; + } + + public byte[] getSalt(String user) + { + try + { + if (file.contains(user)) + { + return gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[1]); + } + } + catch (IOException ioe) { } + return null; + } + + public BigInteger getVerifier(String user) + { + try + { + if (file.contains(user)) + { + return new BigInteger(1, + gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[0])); + } + } + catch (IOException ioe) { } + return null; + } + + public PasswordFile getPasswordFile() + { + return file; + } + } +} diff --git a/gnu/javax/net/ssl/provider/SSLHMac.java b/gnu/javax/net/ssl/provider/SSLHMac.java new file mode 100644 index 000000000..002b3077f --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLHMac.java @@ -0,0 +1,158 @@ +/* SSLHMac.java -- SSLv3's MAC algorithm. + 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.net.ssl.provider; + +import java.util.Arrays; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mac.IMac; + +/** + * The MAC function in SSLv3. This mac is defined as: + * + * <pre> + * hash(MAC_write_secret, pad_2 + + * hash(MAC_write_secret + pad_1 + data));</pre> + * + * <p><tt>hash</tt> is e.g. MD5 or SHA-1, <tt>pad_1</tt> is the value + * 0x36 48 times for MD5 and 40 times for SHA-1, and <tt>pad_2</tt> is + * the value 0x5c repeated similarly. + */ +class SSLHMac implements IMac, Cloneable +{ + + // Fields. + // ------------------------------------------------------------------------- + + static final byte PAD1 = 0x36; + static final byte PAD2 = 0x5c; + + protected IMessageDigest md; + protected byte[] key; + protected final byte[] pad1, pad2; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLHMac(String mdName) + { + super(); + this.md = HashFactory.getInstance(mdName); + if (mdName.equalsIgnoreCase("MD5")) + { + pad1 = new byte[48]; + pad2 = new byte[48]; + } + else + { + pad1 = new byte[40]; + pad2 = new byte[40]; + } + Arrays.fill(pad1, PAD1); + Arrays.fill(pad2, PAD2); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException cnse) + { + throw new Error(); + } + } + + public String name() + { + return "SSLHMac-" + md.name(); + } + + public int macSize() + { + return md.hashSize(); + } + + public void init(Map attributes) + { + key = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (key == null) + throw new NullPointerException(); + reset(); + } + + public void reset() + { + md.reset(); + md.update(key, 0, key.length); + md.update(pad1, 0, pad1.length); + } + + public byte[] digest() + { + byte[] h1 = md.digest(); + md.update(key, 0, key.length); + md.update(pad2, 0, pad2.length); + md.update(h1, 0, h1.length); + byte[] result = md.digest(); + reset(); + return result; + } + + public void update(byte b) + { + md.update(b); + } + + public void update(byte[] buf, int off, int len) + { + md.update(buf, off, len); + } + + public boolean selfTest() + { + return true; // XXX + } +} diff --git a/gnu/javax/net/ssl/provider/SSLRSASignature.java b/gnu/javax/net/ssl/provider/SSLRSASignature.java new file mode 100644 index 000000000..2f8c6cfe6 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLRSASignature.java @@ -0,0 +1,235 @@ +/* SSLRSASignature.java -- SSL's RSA signature algorithm. + 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.net.ssl.provider; + +import java.math.BigInteger; + +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Arrays; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.rsa.RSA; + +/** + * The RSA signature algorithm as used in the SSL protocol. Note that this + * is different from the RSA signature used to verify certificates. + * + * <p>This signature scheme works as follows:</p> + * + * <blockquote><p><pre>digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }</pre></p></blockquote> + * + * <p>Where a <code>digitally-signed struct</code> is RSA-encrypted with + * block type 0 or 1 according to PKCS #1, version 1.5.</p> + */ +final class SSLRSASignature implements ISignature +{ + + // Fields. + // ------------------------------------------------------------------------- + + private RSAPublicKey pubkey; + private RSAPrivateKey privkey; + private final IMessageDigest md5, sha; + private boolean initVerify = false, initSign = false; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLRSASignature() + { + this(HashFactory.getInstance("MD5"), HashFactory.getInstance("SHA-1")); + } + + SSLRSASignature(IMessageDigest md5, IMessageDigest sha) + { + this.md5 = md5; + this.sha = sha; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String name() + { + return "RSA/SSL"; + } + + public void setupVerify(Map attrib) + { + PublicKey key = (PublicKey) attrib.get(VERIFIER_KEY); + if (key == null) + { + if (initSign) + { + return; // re-use. + } + throw new IllegalArgumentException("no key supplied"); + } + if (!(key instanceof RSAPublicKey)) + { + throw new IllegalArgumentException("not an RSA key"); + } + pubkey = (RSAPublicKey) key; + privkey = null; + initSign = false; + initVerify = true; + } + + public void setupSign(Map attrib) + { + PrivateKey key = (PrivateKey) attrib.get(SIGNER_KEY); + if (key == null) + { + if (initVerify) + { + return; // re-use. + } + throw new IllegalArgumentException("no key supplied"); + } + if (!(key instanceof RSAPrivateKey)) + { + throw new IllegalArgumentException("not an RSA key"); + } + privkey = (RSAPrivateKey) key; + pubkey = null; + initVerify = false; + initSign = true; + } + + public void update(byte b) + { + if (!initVerify && !initSign) + { + throw new IllegalStateException(); + } + md5.update(b); + sha.update(b); + } + + public void update(byte[] buf, int off, int len) + { + if (!initVerify && !initSign) + { + throw new IllegalStateException(); + } + md5.update(buf, off, len); + sha.update(buf, off, len); + } + + public Object sign() + { + if (!initSign) + { + throw new IllegalStateException(); + } + // Pad the hash results with RSA block type 1. + final int k = (privkey.getModulus().bitLength() + 7) >>> 3; + final byte[] d = Util.concat(md5.digest(), sha.digest()); + if (k - 11 < d.length) + { + throw new IllegalArgumentException("message too long"); + } + final byte[] eb = new byte[k]; + eb[0] = 0x00; + eb[1] = 0x01; + for (int i = 2; i < k - d.length - 1; i++) + { + eb[i] = (byte) 0xFF; + } + System.arraycopy(d, 0, eb, k - d.length, d.length); + BigInteger EB = new BigInteger(eb); + + // Private-key encrypt the padded hashes. + BigInteger EM = RSA.sign(privkey, EB); + return Util.trim(EM); + } + + public boolean verify(Object signature) + { + if (!initVerify) + { + throw new IllegalStateException(); + } + // Public-key decrypt the signature representative. + BigInteger EM = new BigInteger(1, (byte[]) signature); + BigInteger EB = RSA.verify(pubkey, EM); + + // Unpad the decrypted message. + int i = 0; + final byte[] eb = EB.toByteArray(); + if (eb[0] == 0x00) + { + for (i = 0; i < eb.length && eb[i] == 0x00; i++); + } + else if (eb[0] == 0x01) + { + for (i = 1; i < eb.length && eb[i] != 0x00; i++) + { + if (eb[i] != (byte) 0xFF) + { + throw new IllegalArgumentException("bad padding"); + } + } + i++; + } + else + { + throw new IllegalArgumentException("decryption failed"); + } + byte[] d1 = Util.trim(eb, i, eb.length - i); + byte[] d2 = Util.concat(md5.digest(), sha.digest()); + return Arrays.equals(d1, d2); + } + + public Object clone() + { + throw new UnsupportedOperationException(); + } +} diff --git a/gnu/javax/net/ssl/provider/SSLRandom.java b/gnu/javax/net/ssl/provider/SSLRandom.java new file mode 100644 index 000000000..0b28f1044 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLRandom.java @@ -0,0 +1,165 @@ +/* SSLRandom.java -- SSLv3 pseudo-random function. + 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.net.ssl.provider; + +import java.util.Map; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +class SSLRandom implements IRandom +{ + + // Fields. + // ------------------------------------------------------------------------- + + static final String SECRET = "jessie.sslprng.secret"; + static final String SEED = "jessie.sslprng.seed"; + + private final IMessageDigest md5, sha; + private byte[] secret; + private byte[] buffer; + private byte pad; + private byte[] seed; + private int idx; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLRandom() + { + md5 = HashFactory.getInstance("MD5"); + sha = HashFactory.getInstance("SHA-1"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void init(Map attrib) + { + secret = (byte[]) attrib.get(SECRET); + seed = (byte[]) attrib.get(SEED); + + if (secret == null || seed == null) + throw new NullPointerException(); + + pad = (byte) 'A'; + try { buffer = nextBlock(); } + catch (LimitReachedException cantHappen) { } + } + + public String name() + { + return "SSLRandom"; + } + + public Object clone() + { + throw new UnsupportedOperationException(); + } + + public byte nextByte() throws LimitReachedException + { + if (buffer == null) + throw new IllegalStateException(); + if (idx >= buffer.length) + buffer = nextBlock(); + return buffer[idx++]; + } + + public void nextBytes(byte[] buf, int off, int len) + throws LimitReachedException + { + if (buffer == null) + throw new IllegalStateException(); + if (buf == null) + throw new NullPointerException(); + if (off < 0 || len < 0 || off+len > buf.length) + throw new IndexOutOfBoundsException(); + int count = 0; + while (count < len) + { + if (idx >= buffer.length) + buffer = nextBlock(); + int l = Math.min(buffer.length-idx, len-count); + System.arraycopy(buffer, idx, buf, off+count, l); + count += l; + idx += l; + } + } + + public boolean selfTest() + { + return true; // XXX + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } + + // Own methods. + // ------------------------------------------------------------------------- + + private byte[] nextBlock() throws LimitReachedException + { + int count = pad - 'A' + 1; + if (count > 26) + throw new LimitReachedException(); + for (int i = 0; i < count; i++) + sha.update(pad); + sha.update(secret, 0, secret.length); + sha.update(seed, 0, seed.length); + byte[] b = sha.digest(); + md5.update(secret, 0, secret.length); + md5.update(b, 0, b.length); + idx = 0; + pad++; + return md5.digest(); + } +} diff --git a/gnu/javax/net/ssl/provider/SSLServerSocket.java b/gnu/javax/net/ssl/provider/SSLServerSocket.java new file mode 100644 index 000000000..ee96b8d1b --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLServerSocket.java @@ -0,0 +1,283 @@ +/* SSLServerSocket.java -- SSL server socket. + 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.net.ssl.provider; + +import java.io.IOException; + +import java.net.InetAddress; +import java.net.Socket; + +import java.security.SecureRandom; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.SRPTrustManager; + +class SSLServerSocket extends javax.net.ssl.SSLServerSocket +{ + + // Fields. + // ------------------------------------------------------------------------- + + private SessionContext sessions; + private SortedSet enabledProtocols = new TreeSet(SSLSocket.supportedProtocols); + private List enabledSuites = new ArrayList(SSLSocket.supportedSuites); + private boolean clientMode = false; + private boolean needClientAuth = false; + private boolean wantClientAuth = false; + private boolean createSessions = true; + private SRPTrustManager srpTrustManager; + private X509TrustManager trustManager; + private X509KeyManager keyManager; + private SecureRandom random; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLServerSocket() throws IOException + { + super(); + } + + SSLServerSocket(int port) throws IOException + { + super(port); + } + + SSLServerSocket(int port, int backlog) throws IOException + { + super(port, backlog); + } + + SSLServerSocket(int port, int backlog, InetAddress address) + throws IOException + { + super(port, backlog, address); + } + + // SSL methods. + // ------------------------------------------------------------------------- + + public String[] getSupportedCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + public String[] getEnabledCipherSuites() + { + synchronized (enabledSuites) + { + String[] s = new String[enabledSuites.size()]; + int i = 0; + for (Iterator it = enabledSuites.iterator(); it.hasNext(); ) + s[i++] = it.next().toString(); + return s; + } + } + + public void setEnabledCipherSuites(String[] suites) + { + if (suites == null || suites.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < suites.length; i++) + if (CipherSuite.forName(suites[i]) == null) + throw new IllegalArgumentException("unsupported suite: " + + suites[i]); + synchronized (enabledSuites) + { + enabledSuites.clear(); + for (int i = 0; i < suites.length; i++) + { + CipherSuite suite = CipherSuite.forName(suites[i]); + if (!enabledSuites.contains(suite)) + enabledSuites.add(suite); + } + } + } + + public String[] getSupportedProtocols() + { + return new String[] { "SSLv3", "TLSv1", "TLSv1.1" }; + } + + public String[] getEnabledProtocols() + { + synchronized (enabledProtocols) + { + String[] s = new String[enabledProtocols.size()]; + int i = 0; + for (Iterator it = enabledProtocols.iterator(); it.hasNext(); ) + s[i++] = it.next().toString(); + return s; + } + } + + public void setEnabledProtocols(String[] protocols) + { + if (protocols == null || protocols.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < protocols.length; i++) + { + if (!(protocols[i].equalsIgnoreCase("SSLv3") || + protocols[i].equalsIgnoreCase("TLSv1") || + protocols[i].equalsIgnoreCase("TLSv1.1"))) + { + throw new + IllegalArgumentException("unsupported protocol: " + + protocols[i]); + } + } + synchronized (enabledProtocols) + { + enabledProtocols.clear(); + for (int i = 0; i < protocols.length; i++) + { + if (protocols[i].equalsIgnoreCase("SSLv3")) + enabledProtocols.add(ProtocolVersion.SSL_3); + else if (protocols[i].equalsIgnoreCase("TLSv1")) + enabledProtocols.add(ProtocolVersion.TLS_1); + else + enabledProtocols.add(ProtocolVersion.TLS_1_1); + } + } + } + + public void setUseClientMode(boolean clientMode) + { + this.clientMode = clientMode; + } + + public boolean getUseClientMode() + { + return clientMode; + } + + public void setNeedClientAuth(boolean needClientAuth) + { + this.needClientAuth = needClientAuth; + } + + public boolean getNeedClientAuth() + { + return needClientAuth; + } + + public void setWantClientAuth(boolean wantClientAuth) + { + this.wantClientAuth = wantClientAuth; + } + + public boolean getWantClientAuth() + { + return wantClientAuth; + } + + // I misspelled this method in javax.net.SSLServerSocket, and that version + // made it into kaffe 1.1.4. + public void setEnabledSessionCreation(boolean createSessions) + { + setEnableSessionCreation(createSessions); + } + + public void setEnableSessionCreation(boolean createSessions) + { + this.createSessions = createSessions; + } + + public boolean getEnableSessionCreation() + { + return createSessions; + } + + // Socket methods. + // ------------------------------------------------------------------------- + + public Socket accept() throws IOException + { + SSLSocket socket = new SSLSocket(); + implAccept(socket); + socket.setUseClientMode(clientMode); + socket.setNeedClientAuth(needClientAuth); + socket.setWantClientAuth(wantClientAuth); + socket.setEnableSessionCreation(createSessions); + socket.setSessionContext(sessions); + socket.setEnabledCipherSuites(new ArrayList(enabledSuites)); + socket.setEnabledProtocols(new TreeSet(enabledProtocols)); + socket.setSRPTrustManager(srpTrustManager); + socket.setTrustManager(trustManager); + socket.setKeyManager(keyManager); + socket.setRandom(random); + return socket; + } + + // Package methods. + // ------------------------------------------------------------------------- + + void setSessionContext(SessionContext sessions) + { + this.sessions = sessions; + } + + void setKeyManager(X509KeyManager keyManager) + { + this.keyManager = keyManager; + } + + void setTrustManager(X509TrustManager trustManager) + { + this.trustManager = trustManager; + } + + void setSRPTrustManager(SRPTrustManager srpTrustManager) + { + this.srpTrustManager = srpTrustManager; + } + + void setRandom(SecureRandom random) + { + this.random = random; + } +} diff --git a/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java b/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java new file mode 100644 index 000000000..72fb512c5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java @@ -0,0 +1,136 @@ +/* SSLServerSocketFactory.java -- factory for SSL server sockets. + 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.net.ssl.provider; + +import java.io.IOException; + +import java.net.InetAddress; +import java.net.ServerSocket; + +import java.security.SecureRandom; + +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.SRPTrustManager; + +class SSLServerSocketFactory extends javax.net.ssl.SSLServerSocketFactory +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final SessionContext sessions; + private final X509KeyManager keyManager; + private final X509TrustManager trustManager; + private final SRPTrustManager srpTrustManager; + private final SecureRandom random; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLServerSocketFactory(X509TrustManager trustManager, + SRPTrustManager srpTrustManager, + X509KeyManager keyManager, + SecureRandom random, + SessionContext sessions) + { + super(); + this.trustManager = trustManager; + this.srpTrustManager = srpTrustManager; + this.keyManager = keyManager; + this.random = random; + this.sessions = sessions; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String[] getDefaultCipherSuites() + { + return getSupportedCipherSuites(); + } + + public String[] getSupportedCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + public ServerSocket createServerSocket() throws IOException + { + SSLServerSocket socket = new SSLServerSocket(); + setup(socket); + return socket; + } + + public ServerSocket createServerSocket(int port) throws IOException + { + SSLServerSocket socket = new SSLServerSocket(port); + setup(socket); + return socket; + } + + public ServerSocket createServerSocket(int port, int backlog) + throws IOException + { + SSLServerSocket socket = new SSLServerSocket(port, backlog); + setup(socket); + return socket; + } + + public ServerSocket createServerSocket(int port, int backlog, InetAddress addr) + throws IOException + { + SSLServerSocket socket = new SSLServerSocket(port, backlog, addr); + setup(socket); + return socket; + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void setup(SSLServerSocket socket) + { + socket.setSessionContext(sessions); + socket.setKeyManager(keyManager); + socket.setTrustManager(trustManager); + socket.setSRPTrustManager(srpTrustManager); + socket.setRandom(random); + } +} diff --git a/gnu/javax/net/ssl/provider/SSLSocket.java b/gnu/javax/net/ssl/provider/SSLSocket.java new file mode 100644 index 000000000..a564659c0 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLSocket.java @@ -0,0 +1,3530 @@ +/* SSLSocket.java -- the SSL socket class. + 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.net.ssl.provider; + +import java.io.BufferedOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + +import java.math.BigInteger; + +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; + +import java.nio.channels.SocketChannel; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import java.util.logging.Logger; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLProtocolException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import gnu.java.security.Registry; +import gnu.javax.security.auth.callback.DefaultCallbackHandler; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.dh.DiffieHellmanKeyAgreement; +import gnu.javax.crypto.key.dh.ElGamalKeyAgreement; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; +import gnu.javax.crypto.key.srp6.SRPPrivateKey; +import gnu.javax.crypto.key.srp6.SRPPublicKey; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.prng.ARCFour; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPRegistry; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.SignatureFactory; +import gnu.java.security.sig.dss.DSSSignature; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; +import gnu.java.security.sig.rsa.RSA; + +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * This is the core of the Jessie SSL implementation; it implements the {@link + * javax.net.ssl.SSLSocket} for normal and "wrapped" sockets, and handles all + * protocols implemented by this library. + */ +final class SSLSocket extends javax.net.ssl.SSLSocket +{ + + // This class is almost unbearably large and complex, but is laid out + // as follows: + // + // 1. Fields. + // 2. Constructors. + // 3. SSLSocket methods. These are the public methods defined in + // javax.net.ssl.SSLSocket. + // 4. Socket methods. These override the public methods of java.net.Socket, + // and delegate the method call to either the underlying socket if this is + // a wrapped socket, or to the superclass. + // 5. Package-private methods that various pieces of Jessie use. + // 6. Private methods. These compose the SSL handshake. + // + // Each part is preceeded by a form feed. + +// Constants and fields. + // ------------------------------------------------------------------------- + + // Debuggery. + private static final boolean DEBUG_HANDSHAKE_LAYER = true; + private static final boolean DEBUG_KEY_EXCHANGE = false; + private static final Logger logger = SystemLogger.SYSTEM; + + // Fields for using this class as a wrapped socket. + private Socket underlyingSocket; + private int underlyingPort; + private boolean autoClose; + + // Cryptography fields. + SessionContext sessionContext; + Session session; + LinkedList handshakeListeners; + private boolean clientMode, wantClientAuth, needClientAuth, createSessions; + private boolean handshakeDone; + + // I/O fields. + private String remoteHost; + private InputStream socketIn; + private OutputStream socketOut; + private InputStream applicationIn; + private OutputStream applicationOut; + private InputStream handshakeIn; + private OutputStream handshakeOut; +// private ThreadGroup recordLayer; + RecordInput recordInput; +// RecordOutput recordOutput; + private long handshakeTime; + + private SocketChannel channel; + + static SortedSet supportedProtocols = new TreeSet(); + static List supportedSuites = new ArrayList(30); + +// Static initializer. + // ------------------------------------------------------------------------- + + static + { + //supportedProtocols.add(ProtocolVersion.TLS_1_1); + supportedProtocols.add(ProtocolVersion.TLS_1); + supportedProtocols.add(ProtocolVersion.SSL_3); + + // These are in preference order. It's my preference order, but I'm not + // a total idiot. + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_MD5); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_MD5); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_SHA); + } + +// Constructors. + // ------------------------------------------------------------------------- + + SSLSocket(Socket socket, String host, int port, boolean autoClose) + throws IOException + { + underlyingSocket = socket; + remoteHost = host; + underlyingPort = port; + this.autoClose = autoClose; + initialize(); + } + + SSLSocket (Socket socket, SocketChannel channel) throws IOException + { + underlyingSocket = socket; + this.channel = channel; + initialize (); + } + + SSLSocket() throws IOException + { + super(); + initialize(); + } + + SSLSocket(InetAddress addr, int port) throws IOException + { + super(addr, port); + initialize(); + remoteHost = addr.getHostName(); + if (remoteHost == null) + { + remoteHost = addr.getHostAddress(); + } + } + + SSLSocket(InetAddress addr, int port, InetAddress laddr, int lport) + throws IOException + { + super(addr, port, laddr, lport); + initialize(); + remoteHost = addr.getHostName(); + if (remoteHost == null) + remoteHost = addr.getHostAddress(); + } + + SSLSocket(String host, int port) throws IOException + { + super(host, port); + initialize(); + remoteHost = host; + } + + SSLSocket(String host, int port, InetAddress laddr, int lport) + throws IOException + { + super(host, port, laddr, lport); + initialize(); + remoteHost = host; + } + + private void initialize() + { + session = new Session(); + session.enabledSuites = new ArrayList(supportedSuites); + session.enabledProtocols = new TreeSet(supportedProtocols); + session.protocol = ProtocolVersion.TLS_1; + session.params.setVersion (ProtocolVersion.TLS_1); + handshakeListeners = new LinkedList(); + handshakeDone = false; + } + +// SSL methods. + // ------------------------------------------------------------------------- + + public void addHandshakeCompletedListener(HandshakeCompletedListener l) + { + synchronized (handshakeListeners) + { + if (l == null) + throw new NullPointerException(); + if (!handshakeListeners.contains(l)) + handshakeListeners.add(l); + } + } + + public void removeHandshakeCompletedListener(HandshakeCompletedListener l) + { + synchronized (handshakeListeners) + { + handshakeListeners.remove(l); + } + } + + public String[] getEnabledProtocols() + { + synchronized (session.enabledProtocols) + { + try + { + return (String[]) Util.transform(session.enabledProtocols.toArray(), + String.class, "toString", null); + } + catch (Exception x) + { + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + } + } + + public void setEnabledProtocols(String[] protocols) + { + if (protocols == null || protocols.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < protocols.length; i++) + { + if (!(protocols[i].equalsIgnoreCase("SSLv3") || + protocols[i].equalsIgnoreCase("TLSv1") || + protocols[i].equalsIgnoreCase("TLSv1.1"))) + { + throw new + IllegalArgumentException("unsupported protocol: " + + protocols[i]); + } + } + synchronized (session.enabledProtocols) + { + session.enabledProtocols.clear(); + for (int i = 0; i < protocols.length; i++) + { + if (protocols[i].equalsIgnoreCase("SSLv3")) + { + session.enabledProtocols.add(ProtocolVersion.SSL_3); + } + else if (protocols[i].equalsIgnoreCase("TLSv1")) + { + session.enabledProtocols.add(ProtocolVersion.TLS_1); + } + else + { + session.enabledProtocols.add(ProtocolVersion.TLS_1_1); + } + } + } + } + + public String[] getSupportedProtocols() + { + return new String[] { /* "TLSv1.1", */ "TLSv1", "SSLv3" }; + } + + public String[] getEnabledCipherSuites() + { + synchronized (session.enabledSuites) + { + try + { + return (String[]) Util.transform(session.enabledSuites.toArray(), + String.class, "toString", null); + } + catch (Exception x) + { + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + } + } + + public void setEnabledCipherSuites(String[] suites) + { + if (suites == null || suites.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < suites.length; i++) + if (CipherSuite.forName(suites[i]) == null) + throw new IllegalArgumentException("unsupported suite: " + + suites[i]); + synchronized (session.enabledSuites) + { + session.enabledSuites.clear(); + for (int i = 0; i < suites.length; i++) + { + CipherSuite suite = CipherSuite.forName(suites[i]); + if (!session.enabledSuites.contains(suite)) + { + session.enabledSuites.add(suite); + } + } + } + } + + public String[] getSupportedCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[52]); + } + + public SSLSession getSession() + { + return session; + } + + public boolean getEnableSessionCreation() + { + return createSessions; + } + + public void setEnableSessionCreation(boolean flag) + { + createSessions = flag; + } + + public boolean getNeedClientAuth() + { + return needClientAuth; + } + + public void setNeedClientAuth(boolean flag) + { + needClientAuth = flag; + } + + public boolean getWantClientAuth() + { + return wantClientAuth; + } + + public void setWantClientAuth(boolean flag) + { + wantClientAuth = flag; + } + + public boolean getUseClientMode() + { + return clientMode; + } + + public void setUseClientMode(boolean flag) + { + this.clientMode = flag; + } + + public synchronized void startHandshake() throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "startHandshake called in {0}", + Thread.currentThread()); + handshakeTime = System.currentTimeMillis(); + } + if (handshakeDone) + { + if (clientMode) + { + handshakeDone = false; + doClientHandshake(); + } + else + { + Handshake req = new Handshake(Handshake.Type.HELLO_REQUEST, null); + req.write (handshakeOut, session.protocol); + handshakeOut.flush(); +// recordOutput.setHandshakeAvail(req.write(handshakeOut, session.protocol)); + } + return; + } + if (recordInput == null) + { + setupIO(); + } + if (clientMode) + { + doClientHandshake(); + } + else + { + doServerHandshake(); + } + } + +// Socket methods. + // ------------------------------------------------------------------------- + + public InetAddress getInetAddress() + { + if (underlyingSocket != null) + { + return underlyingSocket.getInetAddress(); + } + else + { + return super.getInetAddress(); + } + } + + public InetAddress getLocalAddress() + { + if (underlyingSocket != null) + { + return underlyingSocket.getLocalAddress(); + } + else + { + return super.getLocalAddress(); + } + } + + public int getPort() + { + if (underlyingSocket != null) + { + return underlyingSocket.getPort(); + } + else + { + return super.getPort(); + } + } + + public int getLocalPort() + { + if (underlyingSocket != null) + { + return underlyingSocket.getLocalPort(); + } + else + { + return super.getLocalPort(); + } + } + + public InputStream getInputStream() throws IOException + { + if (applicationIn == null) + { + setupIO(); + } + return applicationIn; + } + + public OutputStream getOutputStream() throws IOException + { + if (applicationOut == null) + { + setupIO(); + } + return applicationOut; + } + + public void setTcpNoDelay(boolean flag) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setTcpNoDelay(flag); + } + else + { + super.setTcpNoDelay(flag); + } + } + + public boolean getTcpNoDelay() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getTcpNoDelay(); + } + else + { + return super.getTcpNoDelay(); + } + } + + public void setSoLinger(boolean flag, int linger) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setSoLinger(flag, linger); + } + else + { + super.setSoLinger(flag, linger); + } + } + + public int getSoLinger() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getSoLinger(); + } + else + { + return super.getSoLinger(); + } + } + + public void sendUrgentData(int data) throws IOException + { + throw new UnsupportedOperationException("not implemented"); + } + + public void setSoTimeout(int timeout) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setSoTimeout(timeout); + } + else + { + super.setSoTimeout(timeout); + } + } + + public int getSoTimeout() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getSoTimeout(); + } + else + { + return super.getSoTimeout(); + } + } + + public void setSendBufferSize(int size) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setSendBufferSize(size); + } + else + { + super.setSendBufferSize(size); + } + } + + public int getSendBufferSize() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getSendBufferSize(); + } + else + { + return super.getSendBufferSize(); + } + } + + public void setReceiveBufferSize(int size) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setReceiveBufferSize(size); + } + else + { + super.setReceiveBufferSize(size); + } + } + + public int getReceiveBufferSize() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getReceiveBufferSize(); + } + else + { + return super.getReceiveBufferSize(); + } + } + + public synchronized void close() throws IOException + { + if (recordInput == null) + { + if (underlyingSocket != null) + { + if (autoClose) + underlyingSocket.close(); + } + else + super.close(); + return; + } +// while (recordOutput.applicationDataPending()) Thread.yield(); + Alert close = new Alert (Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY); + sendAlert (close); + long wait = System.currentTimeMillis() + 60000L; + while (session.currentAlert == null && !recordInput.pollClose()) + { + + Thread.yield(); + if (wait <= System.currentTimeMillis()) + { + break; + } + } + boolean gotClose = session.currentAlert != null && + session.currentAlert.getDescription() == Alert.Description.CLOSE_NOTIFY; +// recordInput.setRunning(false); +// recordOutput.setRunning(false); +// recordLayer.interrupt(); + recordInput = null; +// recordOutput = null; +// recordLayer = null; + if (underlyingSocket != null) + { + if (autoClose) + underlyingSocket.close(); + } + else + super.close(); + if (!gotClose) + { + session.invalidate(); + throw new SSLException("did not receive close notify"); + } + } + + public String toString() + { + if (underlyingSocket != null) + { + return SSLSocket.class.getName() + " [ " + underlyingSocket + " ]"; + } + else + { + return SSLSocket.class.getName() + " [ " + super.toString() + " ]"; + } + } + + // Configuration insanity begins here. + + public void connect(SocketAddress saddr) throws IOException + { + if (underlyingSocket != null) + { + underlyingSocket.connect(saddr); + } + else + { + super.connect(saddr); + } + } + + public void connect(SocketAddress saddr, int timeout) throws IOException + { + if (underlyingSocket != null) + { + underlyingSocket.connect(saddr, timeout); + } + else + { + super.connect(saddr, timeout); + } + } + + public void bind(SocketAddress saddr) throws IOException + { + if (underlyingSocket != null) + { + underlyingSocket.bind(saddr); + } + else + { + super.bind(saddr); + } + } + + public SocketAddress getLocalSocketAddress() + { + if (underlyingSocket != null) + { + return underlyingSocket.getLocalSocketAddress(); + } + else + { + return super.getLocalSocketAddress(); + } + } + + public SocketChannel getChannel() + { + return channel; + } + + public boolean isBound() + { + if (underlyingSocket != null) + { + return underlyingSocket.isBound(); + } + else + { + return super.isBound(); + } + //throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isClosed() + { + if (underlyingSocket != null) + { + return underlyingSocket.isClosed(); + } + else + { + return super.isClosed(); + } + //throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + //public SocketAddress getRemoteSocketAddress() + //{ + // if (underlyingSocket != null) + // { + // return underlyingSocket.getRemoteSocketAddress(); + // } + // else + // { + // return super.getRemoteSocketAddress(); + // } + //} + + public void setOOBInline(boolean flag) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setOOBInline(flag); + // } + //else + // { + // super.setOOBInline(flag); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean getOOBInline() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getOOBInline(); + // } + //else + // { + // return super.getOOBInline(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void setKeepAlive(boolean flag) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setKeepAlive(flag); + // } + //else + // { + // super.setKeepAlive(flag); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean getKeepAlive() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getKeepAlive(); + // } + //else + // { + // return super.getKeepAlive(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void setTrafficClass(int clazz) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setTrafficClass(clazz); + // } + //else + // { + // super.setTrafficClass(clazz); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public int getTrafficClass() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getTrafficClass(); + // } + //else + // { + // return super.getTrafficClass(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void setReuseAddress(boolean flag) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setReuseAddress(flag); + // } + //else + // { + // super.setReuseAddress(flag); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean getReuseAddress() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getReuseAddress(); + // } + //else + // { + // return super.getReuseAddress(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void shutdownInput() throws IOException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.shutdownInput(); + // } + //else + // { + // super.shutdownInput(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void shutdownOutput() throws IOException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.shutdownOutput(); + // } + //else + // { + // super.shutdownOutput(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isConnected() + { + if (underlyingSocket != null) + { + return underlyingSocket.isConnected(); + } + else + { + return super.isConnected(); + } + //throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isInputShutdown() + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.isInputShutdown(); + // } + //else + // { + // return super.isInputShutdown(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isOutputShutdown() + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.isOutputShutdown(); + // } + //else + // { + // return super.isOutputShutdown(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + protected void finalize() + { + if (session.currentAlert == null) + { + try + { + close(); + } + catch (Exception ignore) { } + } + } + +// Package methods. + // ------------------------------------------------------------------------- + + void setSessionContext(SessionContext sessionContext) + { + this.sessionContext = sessionContext; + } + + void setEnabledCipherSuites(List suites) + { + session.enabledSuites = suites; + } + + void setEnabledProtocols(SortedSet protocols) + { + session.enabledProtocols = protocols; + } + + void setSRPTrustManager(SRPTrustManager srpTrustManager) + { + session.srpTrustManager = srpTrustManager; + } + + void setTrustManager(X509TrustManager trustManager) + { + session.trustManager = trustManager; + } + + void setKeyManager(X509KeyManager keyManager) + { + session.keyManager = keyManager; + } + + void setRandom(SecureRandom random) + { + session.random = random; + } + + void sendAlert (Alert alert) throws IOException + { + RecordOutputStream out = + new RecordOutputStream (socketOut, ContentType.ALERT, session.params); + out.write (alert.getEncoded ()); + } + + /** + * Gets the most-recently-received alert message. + * + * @return The alert message. + */ + Alert checkAlert() + { + return session.currentAlert; + } + + synchronized void checkHandshakeDone() throws IOException + { + if (!handshakeDone) + { + startHandshake(); + } + Alert alert = session.currentAlert; + if (alert != null && alert.getLevel() == Alert.Level.FATAL) + { + throw new AlertException(alert, false); + } + if (handshakeIn.available() > 0 && !clientMode) + { + handshakeDone = false; + startHandshake(); + } + } + +// Own methods. + // ------------------------------------------------------------------------- + + private static final byte[] SENDER_CLIENT = + new byte[] { 0x43, 0x4C, 0x4E, 0x54 }; + private static final byte[] SENDER_SERVER = + new byte[] { 0x53, 0x52, 0x56, 0x52 }; + + private void changeCipherSpec () throws IOException + { + RecordOutputStream out = + new RecordOutputStream (socketOut, ContentType.CHANGE_CIPHER_SPEC, session.params); + out.write (1); + } + + private void readChangeCipherSpec () throws IOException + { + RecordInputStream in = + new RecordInputStream (recordInput, ContentType.CHANGE_CIPHER_SPEC); + if (in.read() != 1) + { + throw new SSLProtocolException ("bad change cipher spec message"); + } + } + + /** + * Initializes the application data streams and starts the record layer + * threads. + */ + private synchronized void setupIO() throws IOException + { + if (recordInput != null) + { + return; + } + if (underlyingSocket != null) + { + socketIn = underlyingSocket.getInputStream(); + socketOut = underlyingSocket.getOutputStream(); + } + else + { + socketIn = super.getInputStream(); + socketOut = super.getOutputStream(); + } +// recordLayer = new ThreadGroup("record_layer"); +// recordInput = new RecordInput(in, session, recordLayer); +// recordOutput = new RecordOutput(out, session, recordLayer); +// recordInput.setRecordOutput(recordOutput); +// recordLayer.setDaemon(true); +// recordInput.start(); +// recordOutput.start(); + recordInput = new RecordInput (socketIn, session); + applicationIn = new SSLSocketInputStream( + new RecordInputStream (recordInput, ContentType.APPLICATION_DATA), this); + applicationOut = new SSLSocketOutputStream( + new RecordOutputStream (socketOut, ContentType.APPLICATION_DATA, session.params), this); + handshakeIn = new SSLSocketInputStream( + new RecordInputStream (recordInput, ContentType.HANDSHAKE), this, false); + handshakeOut = new BufferedOutputStream (new SSLSocketOutputStream( + new RecordOutputStream (socketOut, ContentType.HANDSHAKE, session.params), this, false), 8096); + } + + private void handshakeCompleted () + { + handshakeDone = true; + HandshakeCompletedEvent event = new HandshakeCompletedEvent (this, session); + for (Iterator it = handshakeListeners.iterator (); it.hasNext (); ) + { + try + { + ((HandshakeCompletedListener) it.next ()).handshakeCompleted (event); + } + catch (Throwable t) { } + } + if (createSessions) + { + synchronized (session) + { + sessionContext.addSession (session.sessionId, session); + session.access (); + } + } + + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "Handshake finished in {0}", + Thread.currentThread()); + handshakeTime = System.currentTimeMillis() - handshakeTime; + logger.log (Component.SSL_HANDSHAKE, "Elapsed time {0}s", + new Long (handshakeTime / 1000)); + } + } + + /* + * Perform the client handshake. The process looks like this: + * + * ClientHello --> + * ServerHello <-- + * Certificate* <-- + * ServerKeyExchange* <-- + * CertificateRequest* <-- + * ServerHelloDone* <-- + * Certificate* --> + * ClientKeyExchange --> + * CertificateVerify* --> + * [ChangeCipherSpec] --> + * Finished --> + * [ChangeCipherSpec] <-- + * Finished <-- + * + * With --> denoting output and <-- denoting input. * denotes optional + * messages. + * + * Alternatively, this may be an abbreviated handshake if we are resuming + * a session: + * + * ClientHello --> + * ServerHello <-- + * [ChangeCipherSpec] <-- + * Finished <-- + * [ChangeCipherSpec] --> + * Finished --> + */ + private void doClientHandshake() throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "starting client handshake in {0}", + Thread.currentThread()); + } + + IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH); + IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH); + DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha); + DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha); + Session continuedSession = null; + byte[] sessionId = new byte[0]; + List extensions = null; + String user = null; + CertificateType certType = CertificateType.X509; + + // Look through the available sessions to see if an appropriate one is + // available. + for (Enumeration e = sessionContext.getIds(); e.hasMoreElements(); ) + { + byte[] id = (byte[]) e.nextElement(); + continuedSession = (Session) sessionContext.getSession(id); + if (continuedSession == null) + { + continue; + } + if (!session.enabledProtocols.contains(continuedSession.protocol)) + { + continue; + } + if (continuedSession.getPeerHost().equals(remoteHost)) + { + sessionId = id; + break; + } + } + + // If a SRP suite is enabled, ask for a username so we can include it + // with our extensions list. + for (Iterator i = session.enabledSuites.iterator(); i.hasNext(); ) + { + CipherSuite s = (CipherSuite) i.next(); + if (s.getKeyExchange() == "SRP") + { + extensions = new LinkedList(); + user = askUserName(remoteHost); + byte[] b = user.getBytes("UTF-8"); + if (b.length > 255) + { + handshakeFailure(); + throw new SSLException("SRP username too long"); + } + extensions.add(new Extension(Extension.Type.SRP, + Util.concat(new byte[] { (byte) b.length }, b))); + + break; + } + } + + // If the jessie.fragment.length property is set, add the appropriate + // extension to the list. The fragment length is only actually set if + // the server responds with the same extension. + try + { + int flen = Integer.parseInt(Util.getSecurityProperty("jessie.fragment.length")); + byte[] ext = new byte[1]; + if (flen == 512) + ext[0] = 1; + else if (flen == 1024) + ext[0] = 2; + else if (flen == 2048) + ext[0] = 3; + else if (flen == 4096) + ext[0] = 4; + else + throw new NumberFormatException(); + if (extensions == null) + extensions = new LinkedList(); + extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH, ext)); + } + catch (NumberFormatException nfe) { } + + // FIXME: set certificate types. + + // Send the client hello. + ProtocolVersion version = session.protocol; + Random clientRandom = + new Random(Util.unixTime(), session.random.generateSeed(28)); + session.protocol = (ProtocolVersion) session.enabledProtocols.last(); + List comp = new ArrayList(2); + comp.add(CompressionMethod.ZLIB); + comp.add(CompressionMethod.NULL); + ClientHello clientHello = + new ClientHello(session.protocol, clientRandom, sessionId, + session.enabledSuites, comp, extensions); + Handshake msg = new Handshake(Handshake.Type.CLIENT_HELLO, clientHello); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write (dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version)); + dout.flush(); +// try +// { +// Thread.sleep(150); +// } +// catch (InterruptedException ie) +// { +// } + + // Receive the server hello. + msg = Handshake.read(din); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.SERVER_HELLO) + { + throwUnexpectedMessage(); + } + ServerHello serverHello = (ServerHello) msg.getBody(); + Random serverRandom = serverHello.getRandom(); + version = serverHello.getVersion(); + + // If we don't directly support the server's protocol version, choose + // the highest one we support that is less than the server's version. + if (!session.enabledProtocols.contains(version)) + { + ProtocolVersion v1 = null, v2 = null; + for (Iterator it = session.enabledProtocols.iterator(); + it.hasNext(); ) + { + v1 = (ProtocolVersion) it.next(); + if (v1.compareTo(version) > 0) + break; + v2 = v1; + } + version = v1; + } + + // The server's version is either unsupported by us (unlikely) or the user + // has only enabled incompatible versions. + if (version == null) + { + Alert.Description desc = null; + if (serverHello.getVersion() == ProtocolVersion.SSL_3) + { + desc = Alert.Description.HANDSHAKE_FAILURE; + } + else + { + desc = Alert.Description.PROTOCOL_VERSION; + } + Alert alert = new Alert(Alert.Level.FATAL, desc); + sendAlert(alert); + session.currentAlert = alert; + fatal(); + throw new AlertException(alert, true); + } + + if (serverHello.getExtensions() != null) + { + for (Iterator it = serverHello.getExtensions().iterator(); + it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.getType() == Extension.Type.MAX_FRAGMENT_LENGTH) + { + int len = Extensions.getMaxFragmentLength(e).intValue(); + session.params.setFragmentLength(len); +// recordOutput.setFragmentLength(len); +// recordInput.setFragmentLength(len); + } + else if (e.getType() == Extension.Type.CERT_TYPE) + { + certType = Extensions.getServerCertType(e); + } + } + } + + CipherSuite suite = serverHello.getCipherSuite().resolve(version); + boolean newSession = true; + if (sessionId.length > 0 && + Arrays.equals(sessionId, serverHello.getSessionId())) + { + SecurityParameters params = session.params; + SecureRandom random = session.random; + session = (Session) continuedSession.clone(); + session.params = params; + session.random = random; + recordInput.setSession(session); +// recordOutput.setSession(session); + suite = session.cipherSuite; + newSession = false; + } + else + { + sessionContext.removeSession(new Session.ID(sessionId)); + } + if (newSession) + { + session.peerHost = remoteHost; + session.sessionId = new Session.ID(serverHello.getSessionId()); + session.cipherSuite = suite; + } + session.params.reset(); +// session.params.setInMac(null); +// session.params.setOutMac(null); +// session.params.setInRandom(null); +// session.params.setOutRandom(null); +// session.params.setInCipher(null); +// session.params.setOutCipher(null); + session.currentAlert = null; + session.valid = true; + session.protocol = version; + + // If the server responded with the same session id that we sent, we + // assume that the session will be continued, and skip the bulk of the + // handshake. + if (newSession) + { + PublicKey serverKey = null, serverKex = null; + KeyPair clientKeys = null, clientKex = null; + CertificateRequest certReq; + boolean sendKeyExchange = false; + BigInteger srp_x = null; + IKeyAgreementParty clientKA = null; + IncomingMessage in; // used for key agreement protocol exchange + OutgoingMessage out = null; + + if (suite.getKeyExchange() == "SRP") + { + String password = askPassword(user); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, + "SRP: password read is ''{0}''", password); + } + byte[] userSrpPassword = password.getBytes("UTF-8"); + + // instantiate and setup client-side key agreement party + clientKA = KeyAgreementFactory.getPartyAInstance(Registry.SRP_TLS_KA); + Map clientAttributes = new HashMap(); + clientAttributes.put(SRP6KeyAgreement.HASH_FUNCTION, + Registry.SHA160_HASH); + clientAttributes.put(SRP6KeyAgreement.USER_IDENTITY, user); + clientAttributes.put(SRP6KeyAgreement.USER_PASSWORD, userSrpPassword); + try + { + clientKA.init(clientAttributes); + // initiate the exchange + out = clientKA.processMessage(null); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + } + + if (suite.getSignature() != "anon") + { + msg = Handshake.read(din, certType); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.CERTIFICATE) + { + throwUnexpectedMessage(); + } + Certificate serverCertificate = (Certificate) msg.getBody(); + X509Certificate[] peerCerts = serverCertificate.getCertificates(); + try + { + session.trustManager.checkServerTrusted(peerCerts, + suite.getAuthType()); + if (suite.getSignature() == "RSA" && + !(peerCerts[0].getPublicKey() instanceof RSAPublicKey)) + throw new InvalidKeyException("improper public key"); + if (suite.getKeyExchange() == "DH" && + !(peerCerts[0].getPublicKey() instanceof DHPublicKey)) + throw new InvalidKeyException("improper public key"); + if (suite.getKeyExchange() == "DHE") + { + if (suite.getSignature() == "RSA" && + !(peerCerts[0].getPublicKey() instanceof RSAPublicKey)) + throw new InvalidKeyException("improper public key"); + if (suite.getSignature() == "DSS" && + !(peerCerts[0].getPublicKey() instanceof DSAPublicKey)) + throw new InvalidKeyException("improper public key"); + } + session.peerCerts = peerCerts; + session.peerVerified = true; + } + catch (InvalidKeyException ike) + { + throwHandshakeFailure(); + } + catch (Exception x) + { + if (!checkCertificates(peerCerts)) + { + peerUnverified(peerCerts); + SSLPeerUnverifiedException e = + new SSLPeerUnverifiedException ("could not verify peer certificate: "+ + peerCerts[0].getSubjectDN()); + e.initCause (x); + throw e; + } + session.peerCerts = peerCerts; + session.peerVerified = true; + } + serverKey = peerCerts[0].getPublicKey(); + serverKex = serverKey; + } + + msg = Handshake.read(din, suite, serverKey); + + // Receive the server's key exchange. + if (msg.getType() == Handshake.Type.SERVER_KEY_EXCHANGE) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + ServerKeyExchange skex = (ServerKeyExchange) msg.getBody(); + serverKex = skex.getPublicKey(); + if (suite.getSignature() != "anon") + { + ISignature sig = null; + if (suite.getSignature() == "RSA") + { + sig = new SSLRSASignature(); + } + else if (suite.getSignature() == "DSS") + { + sig = SignatureFactory.getInstance(Registry.DSS_SIG); + } + sig.setupVerify(Collections.singletonMap( + ISignature.VERIFIER_KEY, serverKey)); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + if (suite.getKeyExchange() == "RSA") + { + updateSig(sig, ((RSAPublicKey) serverKex).getModulus()); + updateSig(sig, ((RSAPublicKey) serverKex).getPublicExponent()); + } + else if (suite.getKeyExchange() == "DHE") + { + updateSig(sig, ((DHPublicKey) serverKex).getParams().getP()); + updateSig(sig, ((DHPublicKey) serverKex).getParams().getG()); + updateSig(sig, ((DHPublicKey) serverKex).getY()); + } + else if (suite.getKeyExchange() == "SRP") + { + updateSig(sig, ((SRPPublicKey) serverKex).getN()); + updateSig(sig, ((SRPPublicKey) serverKex).getG()); + byte[] srpSalt = skex.getSRPSalt(); + sig.update((byte) srpSalt.length); + sig.update(srpSalt, 0, srpSalt.length); + updateSig(sig, ((SRPPublicKey) serverKex).getY()); + } + if (!sig.verify(skex.getSignature().getSigValue())) + { + throwHandshakeFailure(); + } + } + + if (suite.getKeyExchange() == "SRP") + { + // use server's key exchange data to continue + // agreement protocol by faking a received incoming + // message. again the following code can be broken + // into multiple blocks for more accurate exception + // handling + try + { + out = new OutgoingMessage(); + out.writeMPI(((SRPPublicKey) serverKex).getN()); + out.writeMPI(((SRPPublicKey) serverKex).getG()); + out.writeMPI(new BigInteger(1, skex.getSRPSalt())); + out.writeMPI(((SRPPublicKey) serverKex).getY()); + + in = new IncomingMessage(out.toByteArray()); + + out = clientKA.processMessage(in); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "clientKA isComplete? {0}", + Boolean.valueOf (clientKA.isComplete())); + } + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + } + msg = Handshake.read(din, suite, serverKey); + } + + // See if the server wants us to send our certificates. + certReq = null; + if (msg.getType() == Handshake.Type.CERTIFICATE_REQUEST) + { + if (suite.getSignature() == "anon") + { + throwHandshakeFailure(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + certReq = (CertificateRequest) msg.getBody(); + msg = Handshake.read(din); + } + + // Read ServerHelloDone. + if (msg.getType() != Handshake.Type.SERVER_HELLO_DONE) + { + throwUnexpectedMessage(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + + // Send our certificate chain if the server asked for it. + if (certReq != null) + { + String alias = session.keyManager.chooseClientAlias( + certReq.getTypeStrings(), certReq.getAuthorities(), null); + if (alias == null && version == ProtocolVersion.SSL_3) + { + Alert alert = + new Alert(Alert.Level.WARNING, Alert.Description.NO_CERTIFICATE); + sendAlert(alert); + } + else + { + X509Certificate[] chain = + session.keyManager.getCertificateChain(alias); + PrivateKey key = session.keyManager.getPrivateKey(alias); + if (chain == null) + { + chain = new X509Certificate[0]; + } + Certificate cert = new Certificate(chain); + msg = new Handshake(Handshake.Type.CERTIFICATE, cert); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + dout.flush(); + if (chain.length > 0) + { + session.localCerts = chain; + clientKeys = new KeyPair(chain[0].getPublicKey(), key); + } + } + } + + // Send our key exchange. + byte[] preMasterSecret = null; + ClientKeyExchange ckex = null; + if (suite.getKeyExchange() == "RSA") + { + ProtocolVersion v = + (ProtocolVersion) session.enabledProtocols.last(); + byte[] b = new byte[46]; + session.random.nextBytes (b); + preMasterSecret = Util.concat(v.getEncoded(), b); + EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance((RSAPublicKey) serverKex); + BigInteger bi = new BigInteger(1, + pkcs1.encode(preMasterSecret, session.random)); + bi = RSA.encrypt((RSAPublicKey) serverKex, bi); + ckex = new ClientKeyExchange(Util.trim(bi)); + } + else if (suite.getKeyExchange().startsWith("DH")) + { + if (clientKeys == null || + !(clientKeys.getPublic() instanceof DHPublicKey)) + { + GnuDHPrivateKey tmpKey = + new GnuDHPrivateKey(null, ((DHPublicKey) serverKex).getParams().getP(), + ((DHPublicKey) serverKex).getParams().getG(), null); + clientKA = KeyAgreementFactory.getPartyBInstance(Registry.DH_KA); + Map attr = new HashMap(); + attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY, + tmpKey); + attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS, + session.random); + try + { + clientKA.init(attr); + out = new OutgoingMessage(); + out.writeMPI(((DHPublicKey) serverKex).getY()); + in = new IncomingMessage(out.toByteArray()); + out = clientKA.processMessage(in); + in = new IncomingMessage(out.toByteArray()); + ckex = new ClientKeyExchange(in.readMPI()); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + } + else + { + clientKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA); + Map attr = new HashMap(); + attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY, + clientKeys.getPrivate()); + try + { + // The key exchange is already complete here; our public + // value was sent with our certificate. + clientKA.init(attr); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + ckex = new ClientKeyExchange(new byte[0]); + } + } + else if (suite.getKeyExchange() == "SRP") + { + // at this point, out --the outgoing message-- already contains + // what we want. so... + BigInteger A = null; + try + { + in = new IncomingMessage(out.toByteArray()); + A = in.readMPI(); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "client A:{0}", A); + } + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + ckex = new ClientKeyExchange(A); + } + msg = new Handshake(Handshake.Type.CLIENT_KEY_EXCHANGE, ckex); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write (dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + + // Generate the master secret. + if (suite.getKeyExchange().startsWith("DH")) + { + try + { + preMasterSecret = clientKA.getSharedSecret(); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + } + else if (suite.getKeyExchange() == "SRP") + { + try + { + preMasterSecret = clientKA.getSharedSecret(); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + finally + { + clientKA = null; + } + } + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}", + Util.toHexString (preMasterSecret, ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}", + Util.toHexString(clientRandom.getEncoded(), ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}", + Util.toHexString(serverRandom.getEncoded(), ':')); + } + IRandom genSecret = null; + if (version == ProtocolVersion.SSL_3) + { + genSecret = new SSLRandom(); + HashMap attr = new HashMap(); + attr.put(SSLRandom.SECRET, preMasterSecret); + attr.put(SSLRandom.SEED, + Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded())); + genSecret.init(attr); + } + else + { + genSecret = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, preMasterSecret); + attr.put(TLSRandom.SEED, + Util.concat(("master secret").getBytes("UTF-8"), + Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded()))); + genSecret.init(attr); + } + session.masterSecret = new byte[48]; + try + { + genSecret.nextBytes(session.masterSecret, 0, 48); + for (int i = 0; i < preMasterSecret.length; i++) + { + preMasterSecret[i] = 0; + } + } + catch (LimitReachedException shouldNotHappen) + { + internalError(); + RuntimeException re = new RuntimeException (shouldNotHappen.getMessage()); + re.initCause (shouldNotHappen); + throw re; + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}", + Util.toHexString(session.masterSecret, ':')); + } + + // Send our certificate verify message. + if (certReq != null && clientKeys != null) + { + IMessageDigest vMD5 = (IMessageDigest) md5.clone(); + IMessageDigest vSHA = (IMessageDigest) sha.clone(); + PrivateKey key = clientKeys.getPrivate(); + Object sig = null; + String sigAlg = null; + try + { + if (key instanceof DSAPrivateKey) + { + sig = DSSSignature.sign((DSAPrivateKey) key, vSHA.digest(), + session.random); + sigAlg = "DSS"; + } + else if (key instanceof RSAPrivateKey) + { + SSLRSASignature rsa = new SSLRSASignature(vMD5, vSHA); + rsa.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, key)); + sig = rsa.sign(); + sigAlg = "RSA"; + } + else + { + throw new InvalidKeyException("no appropriate key"); + } + } + catch (Exception x) + { + throwHandshakeFailure(); + } + CertificateVerify verify = new CertificateVerify(sig, sigAlg); + msg = new Handshake(Handshake.Type.CERTIFICATE_VERIFY, verify); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + } + dout.flush(); + } + + byte[][] keys = null; + try + { + keys = generateKeys(serverRandom.getEncoded(), + clientRandom.getEncoded(), version); + } + catch (Exception x) + { + internalError(); + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + + session.params.setVersion (version); + + // Initialize the algorithms with the derived keys. + Object readMac = null, writeMac = null; + Object readCipher = null, writeCipher = null; + try + { + if (session.params instanceof GNUSecurityParameters) + { + HashMap attr = new HashMap(); + writeMac = CipherSuite.getMac(suite.getMac()); + readMac = CipherSuite.getMac(suite.getMac()); + attr.put(IMac.MAC_KEY_MATERIAL, keys[0]); + ((IMac) writeMac).init(attr); + attr.put(IMac.MAC_KEY_MATERIAL, keys[1]); + ((IMac) readMac).init(attr); + if (suite.getCipher() == "RC4") + { + writeCipher = new ARCFour(); + readCipher = new ARCFour(); + attr.clear(); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]); + ((ARCFour) writeCipher).init(attr); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]); + ((ARCFour) readCipher).init(attr); + } + else if (!suite.isStreamCipher()) + { + writeCipher = CipherSuite.getCipher(suite.getCipher()); + readCipher = CipherSuite.getCipher(suite.getCipher()); + attr.clear(); + attr.put(IMode.KEY_MATERIAL, keys[2]); + attr.put(IMode.IV, keys[4]); + attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + ((IMode) writeCipher).init(attr); + attr.put(IMode.KEY_MATERIAL, keys[3]); + attr.put(IMode.IV, keys[5]); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + ((IMode) readCipher).init(attr); + } + } + else // JCESecurityParameters + { + writeMac = CipherSuite.getJCEMac (suite.getMac()); + readMac = CipherSuite.getJCEMac (suite.getMac()); + writeCipher = CipherSuite.getJCECipher (suite.getCipher()); + readCipher = CipherSuite.getJCECipher (suite.getCipher()); + ((Mac) writeMac).init (new SecretKeySpec (keys[0], suite.getMac())); + ((Mac) readMac).init (new SecretKeySpec (keys[1], suite.getMac())); + if (!suite.isStreamCipher()) + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher()), + new IvParameterSpec (keys[4])); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher()), + new IvParameterSpec (keys[5])); + } + else + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher())); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher())); + } + } + } + // These should technically never happen, if our key generation is not + // broken. + catch (InvalidKeyException ike) + { + internalError(); + RuntimeException re = new RuntimeException (ike.getMessage()); + re.initCause(ike); + throw re; + } + catch (InvalidAlgorithmParameterException iape) + { + internalError(); + RuntimeException re = new RuntimeException (iape.getMessage()); + re.initCause (iape); + throw re; + } + // These indicate a configuration error with the JCA. + catch (NoSuchAlgorithmException nsae) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException x = new SSLException ("suite " + suite + " not available in this configuration"); + x.initCause (nsae); + throw x; + } + catch (NoSuchPaddingException nspe) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException x = new SSLException ("suite " + suite + " not available in this configuration"); + x.initCause (nspe); + throw x; + } + + Finished finis = null; + + if (newSession) + { + changeCipherSpec(); + session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), true); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + if (session.currentAlert != null && + session.currentAlert.getLevel() == Alert.Level.FATAL) + { + fatal(); + throw new AlertException(session.currentAlert, false); + } + + synchronized (session.params) + { + readChangeCipherSpec (); + session.params.setInflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB); + session.params.setInMac(readMac); + session.params.setInCipher(readCipher); + session.params.notifyAll(); + } + + Finished verify = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), false); + + msg = Handshake.read(din, suite, null); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.FINISHED) + { + throwUnexpectedMessage(); + } + finis = (Finished) msg.getBody(); + if (version == ProtocolVersion.SSL_3) + { + if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) || + !Arrays.equals(finis.getSHAHash(), verify.getSHAHash())) + { + throwHandshakeFailure(); + } + } + else + { + if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData())) + { + throwHandshakeFailure(); + } + } + + if (!newSession) + { + changeCipherSpec(); + session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, md5, sha, true); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + handshakeCompleted(); + } + + /** + * Perform the server handshake. + */ + private void doServerHandshake() throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "doing server handshake in {0}", + Thread.currentThread()); + } + + if (remoteHost == null) + { + remoteHost = getInetAddress().getHostName(); + } + if (remoteHost == null) + { + remoteHost = getInetAddress().getHostAddress(); + } + + IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH); + IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH); + DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha); + DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha); + + // Read the client hello. + Handshake msg = Handshake.read(din); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.CLIENT_HELLO) + { + throwUnexpectedMessage(); + } + ClientHello clientHello = (ClientHello) msg.getBody(); + Random clientRandom = clientHello.getRandom(); + ProtocolVersion version = clientHello.getVersion(); + ProtocolVersion server = + (ProtocolVersion) session.enabledProtocols.last(); + CompressionMethod comp; + if (clientHello.getCompressionMethods().contains(CompressionMethod.ZLIB)) + comp = CompressionMethod.ZLIB; + else + comp = CompressionMethod.NULL; + if (!session.enabledProtocols.contains(version) + && version.compareTo(server) < 0) + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.PROTOCOL_VERSION); + sendAlert(alert); + session.currentAlert = alert; + throw new AlertException(alert, true); + } + + // Look through the extensions sent by the client (if any), and react to + // them appropriately. + List extensions = null; + String remoteUser = null; + if (clientHello.getExtensions() != null) + { + for (Iterator it = clientHello.getExtensions().iterator(); it.hasNext();) + { + Extension ex = (Extension) it.next(); + if (ex.getType() == Extension.Type.SERVER_NAME) + { + if (extensions == null) + { + extensions = new LinkedList(); + } + extensions.add(ex); + } + else if (ex.getType() == Extension.Type.MAX_FRAGMENT_LENGTH) + { + int maxLen = Extensions.getMaxFragmentLength(ex).intValue(); +// recordInput.setFragmentLength(maxLen); +// recordOutput.setFragmentLength(maxLen); + session.params.setFragmentLength(maxLen); + if (extensions == null) + { + extensions = new LinkedList(); + } + extensions.add(ex); + } + else if (ex.getType() == Extension.Type.SRP) + { + if (extensions == null) + { + extensions = new LinkedList(); + } + byte[] b = ex.getValue(); + remoteUser = new String(ex.getValue(), 1, b[0] & 0xFF, "UTF-8"); + session.putValue("srp-username", remoteUser); + } + } + } + + CipherSuite suite = selectSuite(clientHello.getCipherSuites(), version); + if (suite == null) + { + return; + } + + // If the selected suite turns out to be SRP, set up the key exchange + // objects. + IKeyAgreementParty serverKA = null; + IncomingMessage in; + OutgoingMessage out = null; + if (suite.getKeyExchange() == "SRP") + { + // FIXME + // Uhm, I don't think this can happen, because if remoteUser is null + // we cannot choose an SRP ciphersuite... + if (remoteUser == null) + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.MISSING_SRP_USERNAME); + sendAlert(alert); + throw new AlertException(alert, true); + } + + SRPAuthInfoProvider srpDB = new SRPAuthInfoProvider(); + Map dbAttributes = new HashMap(); + dbAttributes.put(SRPRegistry.PASSWORD_DB, + session.srpTrustManager.getPasswordFile()); + srpDB.activate(dbAttributes); + + // FIXME + // We can also fake that the user exists, and generate a dummy (and + // invalid) master secret, and let the handshake fail at the Finished + // message. This is better than letting the connecting side know that + // the username they sent isn't valid. + // + // But how to implement this? + if (!srpDB.contains(remoteUser)) + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.UNKNOWN_SRP_USERNAME); + sendAlert(alert); + throw new AlertException(alert, true); + } + + serverKA = KeyAgreementFactory.getPartyBInstance(Registry.SRP_TLS_KA); + Map serverAttributes = new HashMap(); + serverAttributes.put(SRP6KeyAgreement.HASH_FUNCTION, + Registry.SHA160_HASH); + serverAttributes.put(SRP6KeyAgreement.HOST_PASSWORD_DB, srpDB); + + try + { + serverKA.init(serverAttributes); + out = new OutgoingMessage(); + out.writeString(remoteUser); + in = new IncomingMessage(out.toByteArray()); + out = serverKA.processMessage(in); + } + catch (KeyAgreementException x) + { + throwHandshakeFailure(); + } + } + + // Check if the session specified by the client's ID corresponds + // to a saved session, and if so, continue it. + boolean newSession = true; + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "saved sessions: {0}", sessionContext); + } + if (sessionContext.containsSessionID( + new Session.ID(clientHello.getSessionId()))) + { + Session old = session; + session = (Session) sessionContext.getSession(clientHello.getSessionId()); + if (!clientHello.getCipherSuites().contains(session.cipherSuite)) + { + throwHandshakeFailure(); + } + if (session.getPeerHost().equals(remoteHost) && + old.enabledProtocols.contains(session.protocol)) + { + session = (Session) session.clone(); + suite = session.cipherSuite; + newSession = false; + recordInput.setSession(session); + session.currentAlert = null; + session.params = old.params; + session.random = old.random; + } + else + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "rejected section; hosts equal? {0}, same suites? {1}", + new Object[] { Boolean.valueOf (session.getPeerHost().equals(remoteHost)), + Boolean.valueOf (old.enabledProtocols.contains(session.protocol)) }); + } + session = old; + session.peerHost = remoteHost; + newSession = true; + } + } + else if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "rejected session; have session id? {0}, saved sessions: {1}", + new Object[] { Boolean.valueOf (sessionContext.containsSessionID(new Session.ID(clientHello.getSessionId()))), + sessionContext }); + } + if (newSession) + { + byte[] buf = new byte[32]; + Session.ID sid = null; + do + { + session.random.nextBytes(buf); + sid = new Session.ID(buf); + } + while (sessionContext.containsSessionID(sid)); + session.sessionId = sid; + } + session.valid = true; + session.peerHost = remoteHost; + session.cipherSuite = suite; + session.protocol = version; + session.params.setVersion (version); + + // Send the server hello. + Random serverRandom = new Random(Util.unixTime(), + session.random.generateSeed(28)); + ServerHello serverHello = new ServerHello(version, serverRandom, + session.getId(), suite, + comp, extensions); + msg = new Handshake(Handshake.Type.SERVER_HELLO, serverHello); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version)); + dout.flush(); + + if (newSession) + { + X509Certificate[] certs = null; + PrivateKey serverKey = null; + if (suite.getSignature() != "anon") + { + // Send our CA-issued certificate to the client. + String alias = session.keyManager.chooseServerAlias(suite.getAuthType(), + null, null); + certs = session.keyManager.getCertificateChain(alias); + serverKey = session.keyManager.getPrivateKey(alias); + if (certs == null || serverKey == null) + { + throwHandshakeFailure(); + } + session.localCerts = certs; + Certificate serverCert = new Certificate(certs); + msg = new Handshake(Handshake.Type.CERTIFICATE, serverCert); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + dout.flush(); + } + + // If the certificate we sent does not contain enough information to + // do the key exchange (in the case of ephemeral Diffie-Hellman, + // export RSA, and SRP) we send a signed public key to be used for the + // key exchange. + KeyPair signPair = null; + if (certs != null) + { + signPair = new KeyPair(certs[0].getPublicKey(), serverKey); + } + KeyPair kexPair = signPair; + ServerKeyExchange skex = null; + + // Set up our key exchange, and/or prepare our ServerKeyExchange + // message. + if ((suite.getKeyExchange() == "RSA" && suite.isExportable() && + ((RSAPrivateKey) serverKey).getModulus().bitLength() > 512)) + { + kexPair = KeyPool.generateRSAKeyPair(); + RSAPublicKey pubkey = (RSAPublicKey) kexPair.getPublic(); + Signature s = null; + if (suite.getSignature() != "anon") + { + SSLRSASignature sig = new SSLRSASignature(); + sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, + signPair.getPrivate())); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + updateSig(sig, pubkey.getModulus()); + updateSig(sig, pubkey.getPublicExponent()); + s = new Signature(sig.sign(), "RSA"); + } + skex = new ServerKeyExchange(pubkey, s); + } + else if (suite.getKeyExchange() == "DH") + { + serverKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA); + Map attr = new HashMap(); + attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY, + serverKey); + try + { + serverKA.init(attr); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + // We don't send a ServerKeyExchange for this suite. + } + else if (suite.getKeyExchange() == "DHE") + { + serverKA = KeyAgreementFactory.getPartyAInstance(Registry.DH_KA); + Map attr = new HashMap(); + GnuDHPrivateKey servParams = DiffieHellman.getParams(); + attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY, + servParams); + attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS, + session.random); + BigInteger serv_y = null; + try + { + serverKA.init(attr); + out = serverKA.processMessage(null); + in = new IncomingMessage(out.toByteArray()); + serv_y = in.readMPI(); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DHE exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + GnuDHPublicKey pubkey = + new GnuDHPublicKey(null, servParams.getParams().getP(), + servParams.getParams().getG(), serv_y); + Signature s = null; + if (suite.getSignature() != "anon") + { + ISignature sig = null; + if (suite.getSignature() == "RSA") + { + sig = new SSLRSASignature(); + } + else + { + sig = SignatureFactory.getInstance(Registry.DSS_SIG); + } + sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, + signPair.getPrivate())); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + updateSig(sig, pubkey.getParams().getP()); + updateSig(sig, pubkey.getParams().getG()); + updateSig(sig, pubkey.getY()); + s = new Signature(sig.sign(), suite.getSignature()); + } + skex = new ServerKeyExchange(pubkey, s); + } + else if (suite.getKeyExchange() == "SRP") + { + BigInteger N = null; + BigInteger g = null; + BigInteger salt = null; + BigInteger B = null; + try + { + in = new IncomingMessage(out.toByteArray()); + N = in.readMPI(); + g = in.readMPI(); + salt = in.readMPI(); + B = in.readMPI(); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + Signature s = null; + final byte[] srpSalt = Util.trim(salt); + if (suite.getSignature() != "anon") + { + ISignature sig = null; + if (suite.getSignature() == "RSA") + { + sig = new SSLRSASignature(); + } + else + { + sig = SignatureFactory.getInstance(Registry.DSS_SIG); + } + sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, + signPair.getPrivate())); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + updateSig(sig, N); + updateSig(sig, g); + sig.update((byte) srpSalt.length); + sig.update(srpSalt, 0, srpSalt.length); + updateSig(sig, B); + s = new Signature(sig.sign(), suite.getSignature()); + } + final SRPPublicKey pubkey = new SRPPublicKey(N, g, B); + skex = new ServerKeyExchange(pubkey, s, srpSalt); + } + if (skex != null) + { + msg = new Handshake(Handshake.Type.SERVER_KEY_EXCHANGE, skex); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + dout.flush(); + } + + // If we are configured to want or need client authentication, then + // ask for it. + if (wantClientAuth || needClientAuth) + { + Principal[] auths = null; + CertificateRequest.ClientType[] types = + new CertificateRequest.ClientType[] { + CertificateRequest.ClientType.RSA_SIGN, + CertificateRequest.ClientType.DSS_SIGN, + CertificateRequest.ClientType.RSA_FIXED_DH, + CertificateRequest.ClientType.DSS_FIXED_DH + }; + try + { + auths = (Principal[]) + Util.transform(session.trustManager.getAcceptedIssuers(), + Principal.class, "getSubjectDN", null); + } + catch (Exception x) + { + internalError(); + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + CertificateRequest req = new CertificateRequest(types, auths); + msg = new Handshake(Handshake.Type.CERTIFICATE_REQUEST, req); + msg.write(dout, version); + dout.flush(); + } + + // Send our server hello done. + msg = new Handshake(Handshake.Type.SERVER_HELLO_DONE, null); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + + if (suite.getKeyExchange() == "RSA") + { + msg = Handshake.read(din, suite, kexPair.getPublic()); + } + else + { + msg = Handshake.read(din, suite, null); + } + boolean clientCertOk = false; + boolean clientCanSign = false; + X509Certificate[] clientChain = null; + PublicKey clientKey = null; + + // Read the client's certificate, if sent. + if (msg.getType() == Handshake.Type.CERTIFICATE) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + Certificate cliCert = (Certificate) msg.getBody(); + clientChain = cliCert.getCertificates(); + try + { + session.trustManager.checkClientTrusted(clientChain, + suite.getAuthType()); + session.peerCerts = clientChain; + session.peerVerified = true; + clientKey = clientChain[0].getPublicKey(); + } + catch (Exception x) + { + } + clientCanSign = ((clientKey instanceof DSAPublicKey) || + (clientKey instanceof RSAPublicKey)); + if (suite.getKeyExchange().startsWith("DH")) + { + msg = Handshake.read(din, suite, clientKey); + } + else + { + msg = Handshake.read(din, suite, kexPair.getPublic()); + } + } + + // If we require client authentication, and the client sent an + // unverifiable certificate or no certificate at all, drop the + // connection. + if (!session.peerVerified && needClientAuth) + { + throwHandshakeFailure(); + } + + // Read the client key exchange. + if (msg.getType() != Handshake.Type.CLIENT_KEY_EXCHANGE) + { + throwUnexpectedMessage(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + ClientKeyExchange ckex = (ClientKeyExchange) msg.getBody(); + byte[] preMasterSecret = null; + if (suite.getKeyExchange() == "RSA") + { + byte[] enc = (byte[]) ckex.getExchangeObject(); + BigInteger bi = new BigInteger(1, enc); + try + { + bi = RSA.decrypt(kexPair.getPrivate(), bi); + EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance( + (RSAPrivateKey) kexPair.getPrivate()); + preMasterSecret = pkcs1.decode(Util.concat(new byte[1], bi.toByteArray())); + //rsa.init(kexPair); + //preMasterSecret = rsa.decrypt(enc); + } + catch (Exception x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "RSA exception", x); + } + // Generate a fake pre-master secret if the RSA decryption + // fails. + byte[] b = new byte[46]; + session.random.nextBytes (b); + preMasterSecret = Util.concat(version.getEncoded(), b); + } + } + else if (suite.getKeyExchange().startsWith("DH")) + { + try + { + out = new OutgoingMessage(); + if (clientKey == null) + out.writeMPI((BigInteger) ckex.getExchangeObject()); + else + out.writeMPI(((DHPublicKey) clientKey).getY()); + in = new IncomingMessage(out.toByteArray()); + serverKA.processMessage(in); + preMasterSecret = serverKA.getSharedSecret(); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + } + else if (suite.getKeyExchange() == "SRP") + { + BigInteger A = (BigInteger) ckex.getExchangeObject(); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP: client A: {0}", A); + } + try + { + out = new OutgoingMessage(); + out.writeMPI(A); + in = new IncomingMessage(out.toByteArray()); + out = serverKA.processMessage(in); + preMasterSecret = serverKA.getSharedSecret(); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + finally + { + serverKA = null; + } + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}", + Util.toHexString(preMasterSecret, ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}", + Util.toHexString(clientRandom.getEncoded(), ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}", + Util.toHexString(serverRandom.getEncoded(), ':')); + } + + // Generate the master secret. + IRandom genSecret = null; + if (version == ProtocolVersion.SSL_3) + { + genSecret = new SSLRandom(); + HashMap attr = new HashMap(); + attr.put(SSLRandom.SECRET, preMasterSecret); + attr.put(SSLRandom.SEED, Util.concat(clientRandom.getEncoded(), + serverRandom.getEncoded())); + genSecret.init(attr); + } + else + { + genSecret = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, preMasterSecret); + attr.put(TLSRandom.SEED, + Util.concat(("master secret").getBytes("UTF-8"), + Util.concat(clientRandom.getEncoded(), + serverRandom.getEncoded()))); + genSecret.init(attr); + } + session.masterSecret = new byte[48]; + try + { + genSecret.nextBytes(session.masterSecret, 0, 48); + for (int i = 0; i < preMasterSecret.length; i++) + { + preMasterSecret[i] = 0; + } + } + catch (LimitReachedException shouldNotHappen) + { + internalError(); + RuntimeException re = new RuntimeException(); + re.initCause (shouldNotHappen); + throw re; + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}", + Util.toHexString(session.masterSecret, ':')); + } + + // Read the client's certificate verify message, if needed. + if (clientCanSign && (wantClientAuth || needClientAuth)) + { + msg = Handshake.read(din); + if (msg.getType() != Handshake.Type.CERTIFICATE_VERIFY) + { + throwUnexpectedMessage(); + } + CertificateVerify verify = (CertificateVerify) msg.getBody(); + if (clientChain != null && clientChain.length > 0) + { + IMessageDigest cvMD5 = (IMessageDigest) md5.clone(); + IMessageDigest cvSHA = (IMessageDigest) sha.clone(); + clientKey = clientChain[0].getPublicKey(); + if (clientKey instanceof RSAPublicKey) + { + SSLRSASignature sig = new SSLRSASignature(cvMD5, cvSHA); + sig.setupVerify(Collections.singletonMap(ISignature.VERIFIER_KEY, clientKey)); + if (!sig.verify(verify.getSigValue())) + { + handshakeFailure(); + throw new SSLHandshakeException("client certificate verify failed"); + } + } + else if (clientKey instanceof DSAPublicKey) + { + try + { + if (!DSSSignature.verify((DSAPublicKey) clientKey, cvSHA.digest(), + (BigInteger[]) verify.getSigValue())) + { + throw new Exception("client's certificate could not be verified"); + } + } + catch (Exception x) + { + handshakeFailure(); + SSLHandshakeException e = new SSLHandshakeException (x.getMessage()); + e.initCause (x); + throw e; + } + } + } + } + } + + // Generate the session keys. + byte[][] keys = null; + try + { + keys = generateKeys(serverRandom.getEncoded(), + clientRandom.getEncoded(), version); + } + catch (Exception x) + { + internalError(); + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + + // Initialize the algorithms with the derived keys. + Object readMac = null, writeMac = null; + Object readCipher = null, writeCipher = null; + try + { + if (session.params instanceof GNUSecurityParameters) + { + HashMap attr = new HashMap(); + writeMac = CipherSuite.getMac(suite.getMac()); + readMac = CipherSuite.getMac(suite.getMac()); + attr.put(IMac.MAC_KEY_MATERIAL, keys[1]); + ((IMac) writeMac).init(attr); + attr.put(IMac.MAC_KEY_MATERIAL, keys[0]); + ((IMac) readMac).init(attr); + if (suite.getCipher() == "RC4") + { + writeCipher = new ARCFour(); + readCipher = new ARCFour(); + attr.clear(); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]); + ((ARCFour) writeCipher).init(attr); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]); + ((ARCFour) readCipher).init(attr); + } + else if (!suite.isStreamCipher()) + { + writeCipher = CipherSuite.getCipher(suite.getCipher()); + readCipher = CipherSuite.getCipher(suite.getCipher()); + attr.clear(); + attr.put(IMode.KEY_MATERIAL, keys[3]); + attr.put(IMode.IV, keys[5]); + attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + ((IMode) writeCipher).init(attr); + attr.put(IMode.KEY_MATERIAL, keys[2]); + attr.put(IMode.IV, keys[4]); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + ((IMode) readCipher).init(attr); + } + } + else // JCESecurityParameters + { + writeMac = CipherSuite.getJCEMac (suite.getMac()); + readMac = CipherSuite.getJCEMac (suite.getMac()); + writeCipher = CipherSuite.getJCECipher (suite.getCipher()); + readCipher = CipherSuite.getJCECipher (suite.getCipher()); + ((Mac) writeMac).init (new SecretKeySpec (keys[1], suite.getMac())); + ((Mac) readMac).init (new SecretKeySpec (keys[0], suite.getMac())); + if (!suite.isStreamCipher()) + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher()), + new IvParameterSpec (keys[5])); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher()), + new IvParameterSpec (keys[4])); + } + else + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher())); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher())); + } + } + } + // These should technically never happen, if our key generation is not + // broken. + catch (InvalidKeyException ike) + { + internalError(); + RuntimeException re = new RuntimeException (ike.getMessage()); + re.initCause (ike); + throw new RuntimeException (String.valueOf (ike)); + } + catch (InvalidAlgorithmParameterException iape) + { + internalError(); + RuntimeException re = new RuntimeException (iape.getMessage()); + re.initCause (iape); + throw re; + } + // These indicate a configuration error with the JCA. + catch (NoSuchAlgorithmException nsae) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException e = new SSLException ("suite " + suite + " not available in this configuration"); + e.initCause (nsae); + throw e; + } + catch (NoSuchPaddingException nspe) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException e = new SSLException ("suite " + suite + " not available in this configuration"); + e.initCause (nspe); + throw e; + } + + Finished finis = null; + // If we are continuing a session, we send our Finished message first. + if (!newSession) + { + changeCipherSpec(); + session.params.setDeflating(comp == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), false); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + if (session.currentAlert != null && + session.currentAlert.getLevel() == Alert.Level.FATAL) + { + fatal(); + throw new AlertException(session.currentAlert, false); + } + + // Wait until we receive a ChangeCipherSpec, then change the crypto + // algorithms for the incoming side. + synchronized (session.params) + { + readChangeCipherSpec (); + session.params.setInflating(comp == CompressionMethod.ZLIB); + session.params.setInMac(readMac); + session.params.setInCipher(readCipher); + session.params.notifyAll(); + } + + // Receive and verify the client's finished message. + Finished verify = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), true); + msg = Handshake.read(din, suite, null); + if (msg.getType() != Handshake.Type.FINISHED) + { + throwUnexpectedMessage(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + finis = (Finished) msg.getBody(); + if (version == ProtocolVersion.SSL_3) + { + if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) || + !Arrays.equals(finis.getSHAHash(), verify.getSHAHash())) + { + throwHandshakeFailure(); + } + } + else + { + if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData())) + { + throwHandshakeFailure(); + } + } + + // Send our Finished message last for new sessions. + if (newSession) + { + changeCipherSpec(); + session.params.setDeflating(comp == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, md5, sha, false); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + handshakeCompleted(); + } + + /** + * Generate the keys from the master secret. + * + * @param server The server's random value. + * @param client The client's random value. + * @param activeVersion The negotiated protocol version. + * @return The generated keys. + */ + private byte[][] generateKeys(byte[] server, byte[] client, + ProtocolVersion activeVersion) + throws LimitReachedException, IOException + { + CipherSuite suite = session.cipherSuite; + int macLen = (suite.getMac().indexOf("MD5") >= 0) ? 16 : 20; + int keyLen = suite.getKeyLength(); + int ivLen = 0; + if (suite.getCipher().indexOf("DES") >= 0) + { + ivLen = 8; + } + else if (suite.getCipher() == "AES") + { + ivLen = 16; + } + byte[][] keyMaterial = new byte[6][]; + keyMaterial[0] = new byte[macLen]; // client_write_MAC_secret + keyMaterial[1] = new byte[macLen]; // server_write_MAC_secret + keyMaterial[2] = new byte[keyLen]; // client_write_key + keyMaterial[3] = new byte[keyLen]; // server_write_key + keyMaterial[4] = new byte[ivLen]; // client_write_IV + keyMaterial[5] = new byte[ivLen]; // server_write_IV + IRandom prf = null; + if (activeVersion == ProtocolVersion.SSL_3) + { + prf = new SSLRandom(); + HashMap attr = new HashMap(); + attr.put(SSLRandom.SECRET, session.masterSecret); + attr.put(SSLRandom.SEED, Util.concat(server, client)); + prf.init(attr); + } + else + { + prf = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, session.masterSecret); + attr.put(TLSRandom.SEED, Util.concat("key expansion".getBytes("UTF-8"), + Util.concat(server, client))); + prf.init(attr); + } + for (int i = 0; i < keyMaterial.length; i++) + { + prf.nextBytes(keyMaterial[i], 0, keyMaterial[i].length); + } + + // Exportable ciphers transform their keys once more, and use a + // nonsecret IV for block ciphers. + if (suite.isExportable()) + { + int finalLen = suite.getCipher() == "DES" ? 8 : 16; + if (activeVersion == ProtocolVersion.SSL_3) + { + IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH); + md5.update(keyMaterial[2], 0, keyMaterial[2].length); + md5.update(client, 0, client.length); + md5.update(server, 0, server.length); + keyMaterial[2] = Util.trim(md5.digest(), finalLen); + md5.update(keyMaterial[3], 0, keyMaterial[3].length); + md5.update(server, 0, server.length); + md5.update(client, 0, client.length); + keyMaterial[3] = Util.trim(md5.digest(), finalLen); + if (!suite.isStreamCipher()) + { + md5.update(client, 0, client.length); + md5.update(server, 0, server.length); + keyMaterial[4] = Util.trim(md5.digest(), ivLen); + md5.update(server, 0, server.length); + md5.update(client, 0, client.length); + keyMaterial[5] = Util.trim(md5.digest(), ivLen); + } + } + else + { + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, keyMaterial[2]); + attr.put(TLSRandom.SEED, + Util.concat("client write key".getBytes("UTF-8"), + Util.concat(client, server))); + prf.init(attr); + keyMaterial[2] = new byte[finalLen]; + prf.nextBytes(keyMaterial[2], 0, finalLen); + attr.put(TLSRandom.SECRET, keyMaterial[3]); + attr.put(TLSRandom.SEED, + Util.concat("server write key".getBytes("UTF-8"), + Util.concat(client, server))); + prf.init(attr); + keyMaterial[3] = new byte[finalLen]; + prf.nextBytes(keyMaterial[3], 0, finalLen); + if (!suite.isStreamCipher()) + { + attr.put(TLSRandom.SECRET, new byte[0]); + attr.put(TLSRandom.SEED, Util.concat("IV block".getBytes("UTF-8"), + Util.concat(client, server))); + prf.init(attr); + prf.nextBytes(keyMaterial[4], 0, keyMaterial[4].length); + prf.nextBytes(keyMaterial[5], 0, keyMaterial[5].length); + } + } + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "Generated keys:"); + for (int i = 0; i < keyMaterial.length; i++) + logger.log (Component.SSL_KEY_EXCHANGE, "[{0}] {1}", + new Object[] { new Integer (i), + Util.toHexString(keyMaterial[i], ':') }); + } + + return keyMaterial; + } + + /** + * Generate a "finished" message, based on the hashes of the handshake + * messages, the agreed version, and a label. + * + * @param version The agreed version. + * @param md5 The current state of the handshake MD5 hash. + * @param sha The current state of the handshake SHA hash. + * @param client Should be true if the message is generated by the client. + */ + private Finished generateFinished(ProtocolVersion version, IMessageDigest md5, + IMessageDigest sha, boolean client) + { + if (version == ProtocolVersion.SSL_3) + { + if (client) + { + md5.update(SENDER_CLIENT, 0, 4); + } + else + { + md5.update(SENDER_SERVER, 0, 4); + } + byte[] ms = session.masterSecret; + md5.update(ms, 0, ms.length); + for (int i = 0; i < 48; i++) + { + md5.update(SSLHMac.PAD1); + } + byte[] b = md5.digest(); + md5.update(ms, 0, ms.length); + for (int i = 0; i < 48; i++) + { + md5.update(SSLHMac.PAD2); + } + md5.update(b, 0, b.length); + + if (client) + { + sha.update(SENDER_CLIENT, 0, 4); + } + else + { + sha.update(SENDER_SERVER, 0, 4); + } + sha.update(ms, 0, ms.length); + for (int i = 0; i < 40; i++) + { + sha.update(SSLHMac.PAD1); + } + b = sha.digest(); + sha.update(ms, 0, ms.length); + for (int i = 0; i < 40; i++) + { + sha.update(SSLHMac.PAD2); + } + sha.update(b, 0, b.length); + return new Finished(md5.digest(), sha.digest()); + } + else + { + byte[] h1 = md5.digest(); + byte[] h2 = sha.digest(); + String label = client ? "client finished" : "server finished"; + byte[] seed = null; + try + { + seed = Util.concat(label.getBytes("UTF-8"), Util.concat(h1, h2)); + } + catch (java.io.UnsupportedEncodingException uee) + { + RuntimeException re = new RuntimeException (uee.getMessage()); + re.initCause (uee); + throw re; + } + IRandom prf = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, session.masterSecret); + attr.put(TLSRandom.SEED, seed); + prf.init(attr); + byte[] finishedValue = new byte[12]; + try + { + prf.nextBytes(finishedValue, 0, 12); + } + catch (LimitReachedException lre) + { + RuntimeException re = new RuntimeException (lre.getMessage()); + re.initCause (lre); + throw re; + } + return new Finished(finishedValue); + } + } + + /** + * Send a fatal unexpected_message alert. + */ + private Alert unexpectedMessage() throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.UNEXPECTED_MESSAGE); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwUnexpectedMessage() throws IOException + { + throw new AlertException(unexpectedMessage(), true); + } + + /** + * Send a fatal handshake_failure alert. + */ + private Alert handshakeFailure() throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.HANDSHAKE_FAILURE); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwHandshakeFailure() throws IOException + { + throw new AlertException(handshakeFailure(), true); + } + + /** + * Send an internal_error alert. + */ + private Alert internalError() throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.INTERNAL_ERROR); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwInternalError() throws IOException + { + throw new AlertException(internalError(), true); + } + + private Alert peerUnverified(X509Certificate[] chain) throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.HANDSHAKE_FAILURE); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwPeerUnverified(X509Certificate[] chain) throws IOException + { + peerUnverified (chain); + throw new SSLPeerUnverifiedException("could not verify: "+ + chain[0].getSubjectDN()); + } + + /** + * Grab the first suite that is both in the client's requested suites + * and in our enabled suites, and for which we have the proper + * credentials. + * + * @param suites The client's requested suites. + * @param version The version being negotiated. + * @return The selected cipher suite. + * @throws SSLException If no appropriate suite can be selected. + */ + private CipherSuite selectSuite(List suites, ProtocolVersion version) + throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "selectSuite req:{0} suites:{1}", + new Object[] { suites, session.enabledSuites }); + boolean srpSuiteNoUser = false; + for (Iterator i = suites.iterator(); i.hasNext(); ) + { + CipherSuite herSuite = (CipherSuite) i.next(); + for (Iterator j = session.enabledSuites.iterator(); j.hasNext(); ) + { + CipherSuite mySuite = (CipherSuite) j.next(); + if (!mySuite.equals(herSuite)) + { + continue; + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0} == {1}", + new Object[] { mySuite, herSuite }); + if (mySuite.getSignature() != "anon" && session.keyManager != null && + session.keyManager.chooseServerAlias(mySuite.getAuthType(), null, null) == null) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}: no certificate/private key", + mySuite); + continue; + } + if (mySuite.getKeyExchange() == "SRP") + { + if (session.getValue("srp-username") == null) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "no SRP username"); + srpSuiteNoUser = true; + continue; + } + if (session.srpTrustManager == null) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "no SRP password file"); + continue; + } + } + return mySuite.resolve(version); + } + } + Alert alert = null; + if (srpSuiteNoUser) + { + alert = new Alert(Alert.Level.WARNING, + Alert.Description.MISSING_SRP_USERNAME); + sendAlert(alert); + return null; + } + else + alert = new Alert(Alert.Level.FATAL, + Alert.Description.INSUFFICIENT_SECURITY); + sendAlert(alert); + fatal(); + throw new AlertException(alert, true); + } + + /** + * Ask the user for their user name. + * + * @param remoteHost The remote host being connected to. + * @return The user name. + */ + private String askUserName(String remoteHost) + { + CallbackHandler handler = new DefaultCallbackHandler(); + try + { + Class c = Class.forName(Util.getSecurityProperty("jessie.srp.user.handler")); + handler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + TextInputCallback user = + new TextInputCallback("User name for " + remoteHost + ": ", + Util.getProperty("user.name")); + try + { + handler.handle(new Callback[] { user }); + } + catch (Exception x) { } + return user.getText(); + } + + /** + * Ask the user for a password. + * + * @param user The user name. + * @return The password. + */ + private String askPassword(String user) + { + CallbackHandler handler = new DefaultCallbackHandler(); + try + { + Class c = Class.forName(Util.getSecurityProperty("jessie.srp.password.handler")); + handler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + PasswordCallback passwd = new PasswordCallback(user + "'s password: ", false); + try + { + handler.handle(new Callback[] { passwd }); + } + catch (Exception x) { } + return new String(passwd.getPassword()); + } + + /** + * Ask the user (via a callback) if they will accept a certificate that + * could not be verified. + * + * @param chain The certificate chain in question. + * @return true if the user accepts the certificate chain. + */ + private boolean checkCertificates(X509Certificate[] chain) + { + CallbackHandler handler = new DefaultCallbackHandler(); + try + { + Class c = Class.forName(Util.getSecurityProperty("jessie.certificate.handler")); + handler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) + { + } + String nl = Util.getProperty("line.separator"); + ConfirmationCallback confirm = new ConfirmationCallback( + "The server's certificate could not be verified. There is no proof" + nl + + "that this server is who it claims to be, or that their certificate" + nl + + "is valid. Do you wish to continue connecting?", + ConfirmationCallback.ERROR, ConfirmationCallback.YES_NO_OPTION, + ConfirmationCallback.NO); + try + { + handler.handle(new Callback[] { confirm }); + } + catch (Exception x) + { + return false; + } + return confirm.getSelectedIndex() == ConfirmationCallback.YES; + } + + /** + * Update a signature object with a BigInteger, trimming the leading + * "00" octet if present. + * + * @param sig The signature being updated. + * @param bi The integer to feed into the signature. + */ + private void updateSig(ISignature sig, BigInteger bi) + { + byte[] buf = Util.trim(bi); + sig.update((byte) (buf.length >>> 8)); + sig.update((byte) buf.length); + sig.update(buf, 0, buf.length); + } + + /** + * Teardown everything on fatal errors. + */ + private void fatal() throws IOException + { + if (session != null) + { + session.invalidate(); + } +// recordInput.setRunning(false); +// recordOutput.setRunning(false); + if (underlyingSocket != null) + { + underlyingSocket.close(); + } + else + { + super.close(); + } + } +} diff --git a/gnu/javax/net/ssl/provider/SSLSocketFactory.java b/gnu/javax/net/ssl/provider/SSLSocketFactory.java new file mode 100644 index 000000000..24a8389c1 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLSocketFactory.java @@ -0,0 +1,133 @@ +/* SSLSocketFactory.java -- factory for SSL sockets. + 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.net.ssl.provider; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.SecureRandom; + +import javax.net.ssl.X509TrustManager; +import javax.net.ssl.X509KeyManager; + +class SSLSocketFactory extends javax.net.ssl.SSLSocketFactory +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final X509TrustManager trustManager; + private final X509KeyManager keyManager; + private final SecureRandom random; + private final SessionContext sessionContext; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLSocketFactory(X509TrustManager trustManager, X509KeyManager keyManager, + SecureRandom random, SessionContext sessionContext) + { + this.trustManager = trustManager; + this.keyManager = keyManager; + this.random = random; + this.sessionContext = sessionContext; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String[] getDefaultCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + public String[] getSupportedCipherSuites() + { + return getDefaultCipherSuites(); + } + + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) + throws IOException + { + return setup(new SSLSocket(socket, host, port, autoClose)); + } + + public Socket createSocket() throws IOException + { + return setup(new SSLSocket()); + } + + public Socket createSocket(String host, int port) + throws IOException, UnknownHostException + { + return setup(new SSLSocket(host, port)); + } + + public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) + throws IOException, UnknownHostException + { + return setup(new SSLSocket(host, port, localAddr, localPort)); + } + + public Socket createSocket(InetAddress address, int port) throws IOException + { + return setup(new SSLSocket(address, port)); + } + + public Socket createSocket(InetAddress address, int port, + InetAddress localAddr, int localPort) + throws IOException + { + return setup(new SSLSocket(address, port, localAddr, localPort)); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private SSLSocket setup(SSLSocket s) + { + s.setTrustManager(trustManager); + s.setKeyManager(keyManager); + s.setRandom(random); + s.setSessionContext(sessionContext); + s.setUseClientMode(true); + return s; + } +} diff --git a/gnu/javax/net/ssl/provider/SSLSocketInputStream.java b/gnu/javax/net/ssl/provider/SSLSocketInputStream.java new file mode 100644 index 000000000..69202ca33 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLSocketInputStream.java @@ -0,0 +1,181 @@ +/* SSLSocketInputStream.java -- InputStream for SSL sockets. + 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.net.ssl.provider; + +import java.io.EOFException; +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; +import javax.net.ssl.SSLException; + +class SSLSocketInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final SSLSocket socket; + private final boolean checkHandshake; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLSocketInputStream(InputStream in, SSLSocket socket) + { + this(in, socket, true); + } + + SSLSocketInputStream(InputStream in, SSLSocket socket, boolean checkHandshake) + { + super(in); + this.socket = socket; + this.checkHandshake = checkHandshake; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int available() throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + int ret = 0; + try + { + ret = super.available(); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert (); + if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY) + { + return -1; + } + else + { + throw ae; + } + } + return ret; + } + + public int read() throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + int ret = 0; + try + { + ret = in.read(); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert (); + if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY) + { + return -1; + } + else + { + throw ae; + } + } + return ret; + } + + 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 (checkHandshake) + { + socket.checkHandshakeDone(); + } + if (buf == null) + { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + int ret = 0; + try + { + ret = in.read(buf, off, len); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert (); + if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY) + { + return -1; + } + else + { + throw ae; + } + } + return ret; + } + + // Own methods. + // ------------------------------------------------------------------------- + + private boolean checkAlert() throws IOException + { + Alert alert = socket.checkAlert(); + if (alert == null) return false; + if (alert.getLevel().equals(Alert.Level.FATAL)) + throw new AlertException(alert, false); + if (alert.getDescription().equals(Alert.Description.CLOSE_NOTIFY)) + { + try { return (in.available() <= 0); } + catch (IOException ioe) { } + } + return false; + } +} diff --git a/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java b/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java new file mode 100644 index 000000000..fe769a85f --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java @@ -0,0 +1,115 @@ +/* SSLSocketOutputStream.java -- output stream for SSL sockets. + 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.net.ssl.provider; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import javax.net.ssl.SSLException; + +class SSLSocketOutputStream extends FilterOutputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final SSLSocket socket; + private final boolean checkHandshake; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLSocketOutputStream(OutputStream out, SSLSocket socket) + { + this(out, socket, true); + } + + SSLSocketOutputStream(OutputStream out, SSLSocket socket, + boolean checkHandshake) + { + super(out); + this.socket = socket; + this.checkHandshake = checkHandshake; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(int b) throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + checkAlert(); + out.write(b); + checkAlert(); + } + + public void write(byte[] buf) throws IOException + { + write(buf, 0, buf.length); + } + + public void write(byte[] buf, int off, int len) throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + if (buf == null) + throw new NullPointerException(); + if (off < 0 || len < 0 || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + checkAlert(); + out.write(buf, off, len); + checkAlert(); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private synchronized void checkAlert() throws SSLException + { + Alert alert = socket.checkAlert(); + if (alert == null) return; + if (alert.getLevel().equals(Alert.Level.FATAL)) + throw new AlertException(alert, false); + } +} diff --git a/gnu/javax/net/ssl/provider/SecurityParameters.java b/gnu/javax/net/ssl/provider/SecurityParameters.java new file mode 100644 index 000000000..aa06680e2 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SecurityParameters.java @@ -0,0 +1,178 @@ +/* SecurityParameters.java -- SSL security parameters. + 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.net.ssl.provider; + +import javax.net.ssl.SSLException; + +/** + * The interface that all security parameters used by Jessie must implement. + * Security parameters handle all transforming of data, including encryption, + * authentication, and compression. + */ +interface SecurityParameters +{ + + // Methods. + // ------------------------------------------------------------------------- + + /** + * Decrypts, verifies, and inflates a fragment received. The fragment is + * just the data field of a text object, without the version, type, and + * length fields. An exception is thrown if any step fails. + * + * @param fragment The fragment being decrypted. + * @param version The version field of the received text. + * @param type The type field of the received text. + * @return The decrypted fragment. + * @throws MacException If the MAC could not be verified, or if the padding + * on the decrypted fragment is incorrect. + * @throws OverflowException If the processed text overflows the configured + * maximum fragment size. + * @throws SSLException If any other error occurs. + */ + byte[] decrypt (byte[] fragment, ProtocolVersion version, ContentType type) + throws MacException, OverflowException, SSLException; + + /** + * Deflates, authenticates, and encrypts a fragment to be sent. + * + * @param buf The fragment being encrypted. + * @param off The offset into the buffer to start at. + * @param len The number of bytes in this fragment. + * @param type The content type of this text. + * @return The encrypted fragment. + * @throws OverflowException If deflating increases the size of the fragment + * too much. + * @throws SSLException If any other error occurs. + */ + byte[] encrypt (byte[] buf, int off, int len, ContentType type) + throws OverflowException, SSLException; + + /** + * Set all crypto primitives to <code>null</code>, meaning that any calls + * to {@link #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)} or + * {@link #decrypt(byte[],org.metastatic.jessie.provider.ProtocolVersion,org.metastatic.jessie.provider.ContentType}) + * will perform the identity transformation. + */ + void reset(); + + /** + * Returns the version of texts being sent. + * + * @return The version. + */ + ProtocolVersion getVersion(); + + /** + * Sets the version of texts being sent. This affects the {@link + * #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)} + * method. + * + * @param version The version to set. + */ + void setVersion (ProtocolVersion version); + + /** + * Turns zlib deflating on or off. + * + * @param deflate Whether or not to deflate outgoing fragments. + */ + void setDeflating (boolean deflate); + + /** + * Turns zlib inflating on or off. + * + * @param inflate Whether or not to inflate incoming fragments. + */ + void setInflating (boolean inflate); + + /** + * Returns the maximum size that plaintext fragments may be. + * + * @return The fragment length. + */ + int getFragmentLength(); + + /** + * Sets the maximum size that plaintext fragments may be. + * + * @param fragmentLength The new fragment length. + */ + void setFragmentLength (int fragmentLength); + + /** + * Set the cipher used to decrypt incoming fragments. The parameter must be + * appropriate for the implementation. + * + * @param cipher The cipher. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setInCipher (Object cipher); + + /** + * Set the cipher used to encrypt outgoing fragments. The parameter must be + * appropriate for the implementation. + * + * @param cipher The cipher. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setOutCipher (Object cipher); + + /** + * Set the MAC used to verify incoming fragments. The parameter must be + * appropriate for the implementation. + * + * @param mac The MAC. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setInMac (Object mac); + + /** + * Set the MAC used to authenticating outgoinging fragments. The parameter + * must be appropriate for the implementation. + * + * @param mac The MAC. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setOutMac (Object mac); +} diff --git a/gnu/javax/net/ssl/provider/ServerHello.java b/gnu/javax/net/ssl/provider/ServerHello.java new file mode 100644 index 000000000..8b7853c7f --- /dev/null +++ b/gnu/javax/net/ssl/provider/ServerHello.java @@ -0,0 +1,216 @@ +/* ServerHello.java -- SSL ServerHello message. + 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.SSLProtocolException; + +class ServerHello implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ProtocolVersion version; + private final Random random; + private final byte[] sessionId; + private final CipherSuite suite; + private final CompressionMethod comp; + private final List extensions; + + // Constructor. + // ------------------------------------------------------------------------- + + ServerHello(ProtocolVersion version, Random random, + byte[] sessionId, CipherSuite suite, + CompressionMethod comp) + { + this(version, random, sessionId, suite, comp, null); + } + + ServerHello(ProtocolVersion version, Random random, + byte[] sessionId, CipherSuite suite, + CompressionMethod comp, List extensions) + { + this.version = version; + this.random = random; + this.sessionId = sessionId; + this.suite = suite; + this.comp = comp; + this.extensions = extensions; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ServerHello read(InputStream in) throws IOException + { + ProtocolVersion vers = ProtocolVersion.read(in); + Random rand = Random.read(in); + byte[] id = new byte[in.read() & 0xFF]; + in.read(id); + CipherSuite suite = CipherSuite.read(in).resolve(vers); + CompressionMethod comp = CompressionMethod.read(in); + List ext = null; + if (in.available() > 0) + { + ext = new LinkedList(); + int len = (in.read() >>> 8 & 0xFF) | (in.read() & 0xFF); + int count = 0; + while (count < len) + { + Extension e = Extension.read(in); + ext.add(e); + count += e.getValue().length + 4; + } + } + return new ServerHello(vers, rand, id, suite, comp, ext); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + version.write(out); + random.write(out); + out.write(sessionId.length); + out.write(sessionId); + suite.write(out); + out.write(comp.getValue()); + if (extensions != null) + { + ByteArrayOutputStream out2 = new ByteArrayOutputStream(); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + ((Extension) i.next()).write(out2); + out.write(out2.size() >>> 8 & 0xFF); + out.write(out2.size() & 0xFF); + out2.writeTo(out); + } + } + + ProtocolVersion getVersion() + { + return version; + } + + Random getRandom() + { + return random; + } + + byte[] getSessionId() + { + return (byte[]) sessionId.clone(); + } + + CipherSuite getCipherSuite() + { + return suite; + } + + CompressionMethod getCompressionMethod() + { + return comp; + } + + List getExtensions() + { + return extensions; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" version = " + version + ";"); + BufferedReader r = new BufferedReader(new StringReader(random.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";"); + out.println(" cipherSuite = " + suite + ";"); + out.println(" compressionMethod = " + comp + ";"); + if (extensions != null) + { + out.println(" extensions = {"); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + { + r = new BufferedReader(new StringReader(i.next().toString())); + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println(" };"); + } + out.println("} ServerHello;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/gnu/javax/net/ssl/provider/ServerKeyExchange.java new file mode 100644 index 000000000..583041593 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ServerKeyExchange.java @@ -0,0 +1,286 @@ +/* ServerKeyExchange.java -- SSL ServerKeyExchange message. + 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; + +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; + +import javax.net.ssl.SSLProtocolException; + +import gnu.javax.crypto.key.dh.GnuDHPublicKey; +import gnu.javax.crypto.key.srp6.SRPPublicKey; + +class ServerKeyExchange implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private PublicKey publicKey; + private Signature signature; + private byte[] srpSalt; + + // Constructor. + // ------------------------------------------------------------------------- + + ServerKeyExchange(PublicKey publicKey, Signature signature) + { + this(publicKey, signature, null); + } + + ServerKeyExchange(PublicKey publicKey, Signature signature, byte[] srpSalt) + { + this.publicKey = publicKey; + this.signature = signature; + this.srpSalt = srpSalt; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ServerKeyExchange read(InputStream in, CipherSuite suite, + PublicKey serverKey) + throws IOException + { + DataInputStream din = new DataInputStream(in); + PublicKey key = null; + byte[] salt = null; + String kex = suite.getKeyExchange(); + if (kex.equals("DHE")) + { + BigInteger p, g, y; + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + p = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + g = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + y = new BigInteger(1, buf); + key = new GnuDHPublicKey(null, p, g, y); + } + else if (kex.equals("RSA")) + { + BigInteger n, e; + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + n = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + e = new BigInteger(1, buf); + key = new JessieRSAPublicKey(n, e); + } + else if (kex.equals("SRP")) + { + BigInteger N, g, B; + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + N = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + g = new BigInteger(1, buf); + salt = new byte[din.readUnsignedByte()]; + din.readFully(salt); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + B = new BigInteger(1, buf); + try + { + key = new SRPPublicKey(N, g, B); + } + catch (IllegalArgumentException iae) + { + throw new SSLProtocolException(iae.getMessage()); + } + } + else + { + throw new SSLProtocolException("invalid kex algorithm"); + } + + Signature sig = null; + if (!suite.getSignature().equals("anon")) + { + sig = Signature.read(in, suite, serverKey); + } + return new ServerKeyExchange(key, sig, salt); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + write(out, ProtocolVersion.TLS_1); + } + + public void write(OutputStream out, ProtocolVersion version) + throws IOException + { + if (publicKey instanceof DHPublicKey) + { + writeBigint(out, ((DHPublicKey) publicKey).getParams().getP()); + writeBigint(out, ((DHPublicKey) publicKey).getParams().getG()); + writeBigint(out, ((DHPublicKey) publicKey).getY()); + } + else if (publicKey instanceof RSAPublicKey) + { + writeBigint(out, ((RSAPublicKey) publicKey).getModulus()); + writeBigint(out, ((RSAPublicKey) publicKey).getPublicExponent()); + } + else if (publicKey instanceof SRPPublicKey) + { + writeBigint(out, ((SRPPublicKey) publicKey).getN()); + writeBigint(out, ((SRPPublicKey) publicKey).getG()); + out.write(srpSalt.length); + out.write(srpSalt); + writeBigint(out, ((SRPPublicKey) publicKey).getY()); + } + if (signature != null) + { + signature.write(out, version); + } + } + + PublicKey getPublicKey() + { + return publicKey; + } + + Signature getSignature() + { + return signature; + } + + byte[] getSRPSalt() + { + return srpSalt; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" publicKey = struct {"); + if (publicKey instanceof DHPublicKey) + { + out.println(" p = " + + ((DHPublicKey) publicKey).getParams().getP().toString(16) + + ";"); + out.println(" g = " + + ((DHPublicKey) publicKey).getParams().getG().toString(16) + + ";"); + out.println(" y = " + ((DHPublicKey) publicKey).getY().toString(16) + + ";"); + out.println(" } DHPublicKey;"); + } + else if (publicKey instanceof RSAPublicKey) + { + out.println(" modulus = " + + ((RSAPublicKey) publicKey).getModulus().toString(16) + + ";"); + out.println(" exponent = " + + ((RSAPublicKey) publicKey).getPublicExponent().toString(16) + + ";"); + out.println(" } RSAPublicKey;"); + } + else if (publicKey instanceof SRPPublicKey) + { + out.println(" N = "+((SRPPublicKey) publicKey).getN().toString(16)+";"); + out.println(" g = "+((SRPPublicKey) publicKey).getG().toString(16)+";"); + out.println(" salt = " + Util.toHexString(srpSalt, ':') + ";"); + out.println(" B = "+((SRPPublicKey) publicKey).getY().toString(16)+";"); + out.println(" } SRPPublicKey;"); + } + if (signature != null) + { + out.println(" signature ="); + BufferedReader r = new BufferedReader(new StringReader(signature.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println("} ServerKeyExchange;"); + return str.toString(); + } + + private void writeBigint(OutputStream out, BigInteger bigint) + throws IOException + { + byte[] b = bigint.toByteArray(); + if (b[0] == 0x00) + { + out.write((b.length - 1) >>> 8 & 0xFF); + out.write((b.length - 1) & 0xFF); + out.write(b, 1, b.length - 1); + } + else + { + out.write(b.length >>> 8 & 0xFF); + out.write(b.length & 0xFF); + out.write(b); + } + } +} diff --git a/gnu/javax/net/ssl/provider/Session.java b/gnu/javax/net/ssl/provider/Session.java new file mode 100644 index 000000000..e13758b03 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Session.java @@ -0,0 +1,381 @@ +/* Session.java -- SSL and TLS session data. + 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.net.ssl.provider; + +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLPermission; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionBindingEvent; +import javax.net.ssl.SSLSessionBindingListener; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; +import javax.security.cert.X509Certificate; + +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * A generic SSL session implementation for SSL and TLS. + */ +final class Session implements SSLSession +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final SSLPermission GET_SESSION_CONTEXT_PERMISSION = + new SSLPermission("getSSLSessionContext"); + + private final long creationTime; + private Date lastAccessedTime; + ID sessionId; + Certificate[] localCerts; + Certificate[] peerCerts; + X509Certificate[] peerCertChain; + String peerHost; + boolean peerVerified; + SessionContext context; + HashMap values; + boolean valid; + List enabledSuites; + CipherSuite cipherSuite; + SortedSet enabledProtocols; + ProtocolVersion protocol; + byte[] masterSecret; + SRPTrustManager srpTrustManager; + X509TrustManager trustManager; + X509KeyManager keyManager; + SecureRandom random; + SecurityParameters params; + Alert currentAlert; + + // Constructor. + // ------------------------------------------------------------------------- + + Session() + { + this(System.currentTimeMillis()); + } + + Session(long creationTime) + { + peerVerified = false; + valid = true; + this.creationTime = creationTime; + lastAccessedTime = new Date(0L); + values = new HashMap(); + if (("true").equalsIgnoreCase (Util.getSecurityProperty ("jessie.with.jce"))) + params = new JCESecurityParameters(); + else + params = new GNUSecurityParameters (this); + } + + // Public instance methods. + // ------------------------------------------------------------------------- + + protected Object clone() + { + Session result = new Session(creationTime); + result.lastAccessedTime = lastAccessedTime; + result.sessionId = sessionId; + result.localCerts = (localCerts != null ? (Certificate[]) localCerts.clone() : null); + result.peerCerts = (peerCerts != null ? (Certificate[]) peerCerts.clone() : null); + result.peerHost = peerHost; + result.peerVerified = peerVerified; + result.context = context; + result.values = values; + result.enabledSuites = new ArrayList(enabledSuites); + result.cipherSuite = cipherSuite; + result.enabledProtocols = new TreeSet(enabledProtocols); + result.protocol = protocol; + result.masterSecret = masterSecret; + result.keyManager = keyManager; + result.srpTrustManager = srpTrustManager; + result.trustManager = trustManager; + result.random = random; + return result; + } + + public String getCipherSuite() + { + return cipherSuite.toString(); + } + + public long getCreationTime() + { + return creationTime; + } + + public byte[] getId() + { + return (sessionId != null ? sessionId.getId() : null); + } + + public long getLastAccessedTime() + { + return lastAccessedTime.getTime(); + } + + public Certificate[] getLocalCertificates() + { + return (Certificate[]) (localCerts != null ? localCerts.clone() : null); + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException + { + if (!peerVerified) + { + throw new SSLPeerUnverifiedException("peer not verified"); + } + return (Certificate[]) (peerCerts != null ? peerCerts.clone() : null); + } + + public X509Certificate[] getPeerCertificateChain() + throws SSLPeerUnverifiedException + { + if (!peerVerified) + { + throw new SSLPeerUnverifiedException("peer not verified"); + } + if (peerCerts == null) + { + return null; + } + if (peerCertChain != null) + { + return (X509Certificate[]) peerCertChain.clone(); + } + try + { + peerCertChain = new X509Certificate[peerCerts.length]; + for (int i = 0; i < peerCerts.length; i++) + { + peerCertChain[i] = X509Certificate.getInstance(peerCerts[i].getEncoded()); + } + return (X509Certificate[]) peerCertChain.clone(); + } + catch (javax.security.cert.CertificateException ce) + { + return null; + } + catch (CertificateException ce2) + { + return null; + } + } + + public String getPeerHost() + { + return peerHost; + } + + public String getProtocol() + { + return protocol.toString(); + } + + public SSLSessionContext getSessionContext() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + sm.checkPermission(GET_SESSION_CONTEXT_PERMISSION); + } + return context; + } + + public String[] getValueNames() + { + Set names = values.keySet(); + return (String[]) names.toArray(new String[names.size()]); + } + + public Object getValue(String name) + { + return values.get(name); + } + + public void putValue(String name, Object value) + { + values.put(name, value); + if (value instanceof SSLSessionBindingListener) + { + ((SSLSessionBindingListener) value).valueBound( + new SSLSessionBindingEvent(this, name)); + } + } + + public void removeValue(String name) + { + Object value = values.remove(name); + if (value != null && (value instanceof SSLSessionBindingListener)) + { + ((SSLSessionBindingListener) value).valueUnbound( + new SSLSessionBindingEvent(this, name)); + } + } + + public void invalidate() + { + if (masterSecret != null) + { + for (int i = 0; i < masterSecret.length; i++) + { + masterSecret[i] = 0; + } + masterSecret = null; + } + valid = false; + } + + synchronized void access() + { + lastAccessedTime.setTime(System.currentTimeMillis()); + context.notifyAccess(this); + } + + void setLastAccessedTime(long lastAccessedTime) + { + this.lastAccessedTime.setTime(lastAccessedTime); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * A byte array with appropriate <code>equals()</code>, + * <code>hashCode()</code>, and <code>compareTo()</code> semantics. + */ + static final class ID implements Comparable + { + + // Fields. + // ----------------------------------------------------------------------- + + /** The ID itself. */ + private final byte[] id; + + // Constructor. + // ----------------------------------------------------------------------- + + /** + * Creates a new ID. + * + * @param id The ID. The array is not cloned. + */ + ID(byte[] id) + { + if (id == null) + { + throw new IllegalArgumentException(); + } + this.id = id; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getId() + { + return (byte[]) id.clone(); + } + + public boolean equals(Object other) + { + if (other == null || !(other instanceof ID)) + { + return false; + } + return Arrays.equals(id, ((ID) other).id); + } + + public int hashCode() + { + int code = 0; + for (int i = 0; i < id.length; i++) + { + code |= (id[i] & 0xFF) << ((i & 3) << 3); + } + return code; + } + + public int compareTo(Object other) + { + if (other == null || !(other instanceof ID)) + { + return 1; + } + byte[] id2 = ((ID) other).id; + if (id.length != id2.length) + { + return (id.length < id2.length) ? -1 : 1; + } + for (int i = 0; i < id.length; i++) + { + if (id[i] < id2[i]) + { + return -1; + } + else if (id[i] > id2[i]) + { + return 1; + } + } + return 0; + } + + public String toString() + { + return Util.toHexString(id, ':'); + } + } +} diff --git a/gnu/javax/net/ssl/provider/SessionContext.java b/gnu/javax/net/ssl/provider/SessionContext.java new file mode 100644 index 000000000..9e265429a --- /dev/null +++ b/gnu/javax/net/ssl/provider/SessionContext.java @@ -0,0 +1,250 @@ +/* SessionContext.java -- Implementation of a session context. + 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.net.ssl.provider; + +import java.security.Security; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Vector; + +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; + +/** + * A collection of SSL sessions. This implementation is a memory-only + * store; subclasses may implement persistent storage. + */ +class SessionContext implements SSLSessionContext +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** The map of Session.ID objects to Sessions. */ + protected final HashMap sessions; + + /** The number of sessions to cache. */ + protected int cacheSize; + + /** The session timeout, in seconds. */ + protected int timeout; + + // Constructor. + // ------------------------------------------------------------------------- + + SessionContext() + { + sessions = new HashMap(); + cacheSize = 0; + try + { + timeout = Integer.parseInt(Util.getSecurityProperty("jessie.session.timeout")); + } + catch (Exception x) + { + // Default 24-hour timeout. + timeout = 86400; + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public synchronized Enumeration getIds() + { + Vector ids = new Vector(); + for(Iterator i = sessions.keySet().iterator(); i.hasNext(); ) + { + Session.ID id = (Session.ID) i.next(); + ids.add(id.getId()); + } + return ids.elements(); + } + + public synchronized SSLSession getSession(byte[] sessionId) + { + Session session = (Session) sessions.get(new Session.ID(sessionId)); + if (session == null) + return null; + long elapsed = System.currentTimeMillis() - session.getLastAccessedTime(); + if ((int) (elapsed / 1000) > timeout) + { + removeSession(session.sessionId); + session.invalidate(); + return null; + } + if (!session.valid) + { + removeSession(session.sessionId); + session.invalidate(); + return null; + } + return session; + } + + public int getSessionCacheSize() + { + return cacheSize; + } + + public void setSessionCacheSize(int cacheSize) + { + if (cacheSize < 0) + throw new IllegalArgumentException(); + this.cacheSize = cacheSize; + } + + public int getSessionTimeout() + { + return timeout; + } + + public void setSessionTimeout(int timeout) + { + if (timeout <= 0) + throw new IllegalArgumentException(); + this.timeout = timeout; + } + + public String toString() + { + return sessions.keySet().toString(); + } + + // Package methods. + // ------------------------------------------------------------------------- + + /** + * Adds a session to this context. This method: + * + * <ol> + * <li>Will do nothing if the cache already contains the given ID.</li> + * <li>Will do nothing if the cache limit has been reached (and is + * not zero).</li> + * <li>Will remove any invalid sessions in the cache before trying to insert + * the new one.</li> + * <li>Will remove any expired sessions before trying to insert the new + * one.</li> + * </ol> + * + * @param sessionId This session's ID. + * @param session The session to add. + * @return True if the session was added, false otherwise. + */ + synchronized boolean addSession(Session.ID sessionId, Session session) + { + if (sessions.containsKey(sessionId)) + return false; + if (cacheSize > 0 && sessions.size() > cacheSize) + { + boolean removed = false; + for (Iterator i = sessions.values().iterator(); i.hasNext(); ) + { + Session s = (Session) i.next(); + long elapsed = System.currentTimeMillis() - s.getCreationTime(); + if (!s.valid) + { + removeSession(session.sessionId); + removed = true; + } + else if ((int) (elapsed / 1000) > timeout) + { + removeSession(session.sessionId); + removed = true; + } + } + if (removed) + { + sessions.put(sessionId, session); + session.context = this; + session.sessionId = sessionId; + return true; + } + return false; + } + else + { + sessions.put(sessionId, session); + session.context = this; + session.sessionId = sessionId; + return true; + } + } + + /** + * Returns whether or not a session with the given ID is cached by this + * context. + */ + synchronized boolean containsSessionID(Session.ID sessionId) + { + Session s = (Session) sessions.get(sessionId); + if (s == null) + { + return false; + } + long elapsed = System.currentTimeMillis() - s.getCreationTime(); + if (!s.valid || (int) (elapsed / 1000) > timeout) + { + removeSession(sessionId); + return false; + } + return true; + } + + /** + * Removes a session from this context. + * + * @param sessionId The ID of the session to remove. + */ + synchronized boolean removeSession(Session.ID sessionId) + { + return sessions.remove(sessionId) != null; + } + + /** + * Notifies this context of an access event on a session. + * + * @param session The session that was accessed. + */ + void notifyAccess(Session session) + { + } +} diff --git a/gnu/javax/net/ssl/provider/Signature.java b/gnu/javax/net/ssl/provider/Signature.java new file mode 100644 index 000000000..c9be64143 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Signature.java @@ -0,0 +1,158 @@ +/* Signature.java -- SSL signature message. + 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.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.security.PublicKey; +import java.security.interfaces.RSAKey; + +import java.util.Arrays; + +import gnu.java.security.der.*; + +class Signature implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Object sigValue; + private final String sigAlg; + + // Constructor. + // ------------------------------------------------------------------------- + + Signature(Object sigValue, String sigAlg) + { + this.sigValue = sigValue; + this.sigAlg = sigAlg; + } + + // Class method. + // ------------------------------------------------------------------------- + + static Signature read(InputStream in, CipherSuite suite, PublicKey key) + throws IOException + { + Object sigValue = null; + DataInputStream din = new DataInputStream(in); + int len = din.readUnsignedShort(); + sigValue = new byte[len]; + din.readFully((byte[]) sigValue); + if (suite.getSignature() == "DSS") + { + DERReader der = new DERReader(new ByteArrayInputStream((byte[]) sigValue)); + if (der.read().getTag() != DER.SEQUENCE) + { + throw new IOException("expecting DER SEQUENCE"); + } + BigInteger r = (BigInteger) der.read().getValue(); + BigInteger s = (BigInteger) der.read().getValue(); + sigValue = new BigInteger[] { r, s }; + } + return new Signature(sigValue, suite.getSignature()); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + write(out, ProtocolVersion.TLS_1); + } + + public void write(OutputStream out, ProtocolVersion version) + throws IOException + { + byte[] result = null; + if (sigValue instanceof byte[]) + { + result = (byte[]) sigValue; + } + else + { + DERValue r = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[0]); + DERValue s = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[1]); + DERValue sig = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, + Arrays.asList(new Object[] { r, s })); + result = sig.getEncoded(); + } + out.write(result.length >>> 8 & 0xFF); + out.write(result.length & 0xFF); + out.write(result); + } + + Object getSigValue() + { + return sigValue; + } + + String getSigAlg() + { + return sigAlg; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + if (sigAlg.equals("RSA")) + { + out.print(Util.hexDump((byte[]) sigValue, " ")); + } + else + { + out.println(" r = " + ((BigInteger[]) sigValue)[0].toString(16) + ";"); + out.println(" s = " + ((BigInteger[]) sigValue)[1].toString(16) + ";"); + } + out.println("} Signature;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/SynchronizedRandom.java b/gnu/javax/net/ssl/provider/SynchronizedRandom.java new file mode 100644 index 000000000..4e22f08be --- /dev/null +++ b/gnu/javax/net/ssl/provider/SynchronizedRandom.java @@ -0,0 +1,104 @@ +/* SynchronizedRandom.java -- Thread-safe IRandom wrapper. + 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.net.ssl.provider; + +import java.util.Map; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +class SynchronizedRandom implements IRandom +{ + + // Field. + // ------------------------------------------------------------------------- + + private final IRandom random; + + // Constructor. + // ------------------------------------------------------------------------- + + SynchronizedRandom(IRandom random) + { + this.random = random; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String name() + { + return random.name(); + } + + public synchronized void init(Map attrib) + { + random.init(attrib); + } + + public synchronized byte nextByte() + throws IllegalStateException, LimitReachedException + { + return random.nextByte(); + } + + public synchronized void nextBytes(byte[] buf, int off, int len) + throws IllegalStateException, LimitReachedException + { + random.nextBytes(buf, off, len); + } + + public synchronized Object clone() + throws CloneNotSupportedException + { + return new SynchronizedRandom((IRandom) random.clone()); + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } +} diff --git a/gnu/javax/net/ssl/provider/TLSHMac.java b/gnu/javax/net/ssl/provider/TLSHMac.java new file mode 100644 index 000000000..18aa8f5f4 --- /dev/null +++ b/gnu/javax/net/ssl/provider/TLSHMac.java @@ -0,0 +1,138 @@ +/* TLSHMac.java -- HMAC used in TLS. + 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.net.ssl.provider; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mac.HMac; + +/** + * The operation of this HMac is identical to normal HMacs, but this one + * allows keys with short lengths (including zero). + */ +class TLSHMac extends HMac +{ + + // Constants. + // ------------------------------------------------------------------------- + + private static final byte IPAD_BYTE = 0x36; + private static final byte OPAD_BYTE = 0x5C; + + // Constructor. + // ------------------------------------------------------------------------- + + TLSHMac(IMessageDigest hash) + { + super(hash); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + 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; + } + + 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; + } +} diff --git a/gnu/javax/net/ssl/provider/TLSRandom.java b/gnu/javax/net/ssl/provider/TLSRandom.java new file mode 100644 index 000000000..ded632928 --- /dev/null +++ b/gnu/javax/net/ssl/provider/TLSRandom.java @@ -0,0 +1,252 @@ +/* TLSRandom.java -- The TLS pseudo-random function. + 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.net.ssl.provider; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.javax.crypto.mac.IMac; +import gnu.java.security.prng.IRandom; + +class TLSRandom implements IRandom +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * Property name for the secret that will be used to initialize the HMACs. + */ + static final String SECRET = "jessie.tls.prng.secret"; + + /** + * Property name for the seed. + */ + static final String SEED = "jessie.tls.prng.seed"; + + private final IMac hmac_sha, hmac_md5; + private byte[] sha_a, md5_a; + private byte[] seed; + private final byte[] buffer; + private int idx; + private boolean init; + + // Constructors. + // ------------------------------------------------------------------------- + + TLSRandom() + { + hmac_sha = new TLSHMac(HashFactory.getInstance("SHA1")); + hmac_md5 = new TLSHMac(HashFactory.getInstance("MD5")); + buffer = new byte[80]; // 80 == LCM of 16 and 20. + idx = 0; + init = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException shouldNotHappen) + { + throw new Error(); + } + } + + public void init(Map attributes) + { + HashMap sha_attr = new HashMap(); + HashMap md5_attr = new HashMap(); + byte[] secret = (byte[]) attributes.get(SECRET); + if (secret != null) + { + int l = (secret.length >>> 1) + (secret.length & 1); + byte[] s1 = Util.trim(secret, 0, l); + byte[] s2 = Util.trim(secret, secret.length - l, l); + md5_attr.put(IMac.MAC_KEY_MATERIAL, s1); + sha_attr.put(IMac.MAC_KEY_MATERIAL, s2); + try + { + hmac_md5.init(md5_attr); + hmac_sha.init(sha_attr); + } + catch (InvalidKeyException ike) + { + throw new Error(ike.toString()); + } + } + else if (!init) + { + throw new IllegalArgumentException("no secret supplied"); + } + // else re-use + + byte[] seeed = (byte[]) attributes.get(SEED); + if (seeed != null) + { + seed = (byte[]) seeed.clone(); + } + else if (!init) + { + throw new IllegalArgumentException("no seed supplied"); + } + // else re-use + + // A(0) is the seed, A(1) = HMAC_hash(secret, A(0)). + hmac_md5.update(seed, 0, seed.length); + md5_a = hmac_md5.digest(); + hmac_md5.reset(); + hmac_sha.update(seed, 0, seed.length); + sha_a = hmac_sha.digest(); + hmac_sha.reset(); + fillBuffer(); + init = true; + } + + public String name() + { + return "TLSRandom"; + } + + public byte nextByte() + { + if (!init) + throw new IllegalStateException(); + if (idx >= buffer.length) + fillBuffer(); + return buffer[idx++]; + } + + public void nextBytes(byte[] buf, int off, int len) + { + if (!init) + throw new IllegalStateException(); + if (buf == null) + throw new NullPointerException(); + if (off < 0 || off > buf.length || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + int count = 0; + if (idx >= buffer.length) + fillBuffer(); + while (count < len) + { + int l = Math.min(buffer.length-idx, len-count); + System.arraycopy(buffer, idx, buf, off+count, l); + idx += l; + count += l; + if (count < len && idx >= buffer.length) + fillBuffer(); + } + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } + + // Own methods. + // ------------------------------------------------------------------------- + + /* + * The PRF is defined as: + * + * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR + * P_SHA-1(S2, label + seed); + * + * P_hash is defined as: + * + * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + + * HMAC_hash(secret, A(2) + seed) + + * HMAC_hash(secret, A(3) + seed) + ... + * + * And A() is defined as: + * + * A(0) = seed + * A(i) = HMAC_hash(secret, A(i-1)) + * + * For simplicity, we compute an 80-byte block on each call, which + * corresponds to five iterations of MD5, and four of SHA-1. + */ + private synchronized void fillBuffer() + { + int len = hmac_md5.macSize(); + for (int i = 0; i < buffer.length; i += len) + { + hmac_md5.update(md5_a, 0, md5_a.length); + hmac_md5.update(seed, 0, seed.length); + byte[] b = hmac_md5.digest(); + hmac_md5.reset(); + System.arraycopy(b, 0, buffer, i, len); + hmac_md5.update(md5_a, 0, md5_a.length); + md5_a = hmac_md5.digest(); + hmac_md5.reset(); + } + len = hmac_sha.macSize(); + for (int i = 0; i < buffer.length; i += len) + { + hmac_sha.update(sha_a, 0, sha_a.length); + hmac_sha.update(seed, 0, seed.length); + byte[] b = hmac_sha.digest(); + hmac_sha.reset(); + for (int j = 0; j < len; j++) + { + buffer[j + i] ^= b[j]; + } + hmac_sha.update(sha_a, 0, sha_a.length); + sha_a = hmac_sha.digest(); + hmac_sha.reset(); + } + idx = 0; + } +} diff --git a/gnu/javax/net/ssl/provider/Util.java b/gnu/javax/net/ssl/provider/Util.java new file mode 100644 index 000000000..15790dd26 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Util.java @@ -0,0 +1,422 @@ +/* Util.java -- Miscellaneous utility methods. + 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.net.ssl.provider; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Security; + +/** + * A collection of useful class methods. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +final class Util +{ + + // Constants. + // ------------------------------------------------------------------------- + + static final String HEX = "0123456789abcdef"; + + // Static methods only. + private Util() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Convert a hexadecimal string into its byte representation. + * + * @param hex The hexadecimal string. + * @return The converted bytes. + */ + static byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } + + /** + * Convert a byte array to a hexadecimal string, as though it were a + * big-endian arbitrarily-sized integer. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @return A hexadecimal representation of the specified bytes. + */ + static String toHexString(byte[] buf, int off, int len) + { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int)}. + */ + static String toHexString(byte[] buf) + { + return Util.toHexString(buf, 0, buf.length); + } + + /** + * Convert a byte array to a hexadecimal string, separating octets + * with the given character. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @param sep The character to insert between octets. + * @return A hexadecimal representation of the specified bytes. + */ + static String toHexString(byte[] buf, int off, int len, char sep) + { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + if (i < len - 1) + str.append(sep); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int,char)}. + */ + static String toHexString(byte[] buf, char sep) + { + return Util.toHexString(buf, 0, buf.length, sep); + } + + /** + * Create a representation of the given byte array similar to the + * output of <code>`hexdump -C'</code>, which is + * + * <p><pre>OFFSET SIXTEEN-BYTES-IN-HEX PRINTABLE-BYTES</pre> + * + * <p>The printable bytes show up as-is if they are printable and + * not a newline character, otherwise showing as '.'. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to encode. + * @param prefix A string to prepend to every line. + * @return The formatted string. + */ + static String hexDump(byte[] buf, int off, int len, String prefix) + { + String nl = getProperty("line.separator"); + StringBuffer str = new StringBuffer(); + int i = 0; + while (i < len) + { + if (prefix != null) + str.append(prefix); + str.append(Util.formatInt(i+off, 16, 8)); + str.append(" "); + String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' '); + str.append(s); + for (int j = 56 - (56 - s.length()); j < 56; j++) + str.append(" "); + for (int j = 0; j < Math.min(16, len - i); j++) + { + if ((buf[i+off+j] & 0xFF) < 0x20 || (buf[i+off+j] & 0xFF) > 0x7E) + str.append('.'); + else + str.append((char) (buf[i+off+j] & 0xFF)); + } + str.append(nl); + i += 16; + } + return str.toString(); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + static String hexDump(byte[] buf, int off, int len) + { + return hexDump(buf, off, len, ""); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + static String hexDump(byte[] buf, String prefix) + { + return hexDump(buf, 0, buf.length, prefix); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + static String hexDump(byte[] buf) + { + return hexDump(buf, 0, buf.length); + } + + /** + * Format an integer into the specified radix, zero-filled. + * + * @param i The integer to format. + * @param radix The radix to encode to. + * @param len The target length of the string. The string is + * zero-padded to this length, but may be longer. + * @return The formatted integer. + */ + static String formatInt(int i, int radix, int len) + { + String s = Integer.toString(i, radix); + StringBuffer buf = new StringBuffer(); + for (int j = 0; j < len - s.length(); j++) + buf.append("0"); + buf.append(s); + return buf.toString(); + } + + /** + * Concatenate two byte arrays into one. + * + * @param b1 The first byte array. + * @param b2 The second byte array. + * @return The concatenation of b1 and b2. + */ + static byte[] concat(byte[] b1, byte[] b2) + { + byte[] b3 = new byte[b1.length+b2.length]; + System.arraycopy(b1, 0, b3, 0, b1.length); + System.arraycopy(b2, 0, b3, b1.length, b2.length); + return b3; + } + + /** + * See {@link #trim(byte[],int,int)}. + */ + static byte[] trim(byte[] buffer, int len) + { + return trim(buffer, 0, len); + } + + /** + * Returns a portion of a byte array, possibly zero-filled. + * + * @param buffer The byte array to trim. + * @param off The offset to begin reading at. + * @param len The number of bytes to return. This value can be larger + * than <i>buffer.length - off</i>, in which case the rest of the + * returned byte array will be filled with zeros. + * @throws IndexOutOfBoundsException If <i>off</i> or <i>len</i> is + * negative, or if <i>off</i> is larger than the byte array's + * length. + * @return The trimmed byte array. + */ + static byte[] trim(byte[] buffer, int off, int len) + { + if (off < 0 || len < 0 || off > buffer.length) + throw new IndexOutOfBoundsException("max=" + buffer.length + + " off=" + off + " len=" + len); + if (off == 0 && len == buffer.length) + return buffer; + byte[] b = new byte[len]; + System.arraycopy(buffer, off, b, 0, Math.min(len, buffer.length - off)); + return b; + } + + /** + * Returns the byte array representation of the given big integer with + * the leading zero byte (if any) trimmed off. + * + * @param bi The integer to trim. + * @return The byte representation of the big integer, with any leading + * zero removed. + */ + static byte[] trim(BigInteger bi) + { + byte[] buf = bi.toByteArray(); + if (buf[0] == 0x00 && !bi.equals(BigInteger.ZERO)) + { + return trim(buf, 1, buf.length - 1); + } + else + { + return buf; + } + } + + /** + * Returns the integer value of <code>{@link + * java.lang.System#currentTimeMillis()} / 1000</code>. + * + * @return The current time, in seconds. + */ + static int unixTime() + { + return (int) (System.currentTimeMillis() / 1000L); + } + + /** + * Transform an Object array into another by calling the given method + * on each object. The returned object array will have the runtime + * type of <i>returnType</i>. For example, the following will transform + * array of objects into their String representations, returning a String + * array. For example: + * + * <blockquote><p><code> + * String[] strings = (String[]) Util.transform(array, String.class, + * "toString", null); + * </code></p></blockquote> + * + * <p>If any element of the given array is <tt>null</tt>, then that + * entry in the returned array will also be <tt>null</tt>. + * + * @param array The array to transform. It does not need to be of + * uniform type. + * @param returnType The desired return type of the returned array. + * This must by the <i>component</i> type, not the array type. + * @param method The name of the method to invoke from each object. + * @param args The arguments to pass to the method, or <tt>null</tt> + * if the method takes no arguments. + * @throws InvocationTargetException If an exception occurs while + * calling <i>method</i> of any object. + * @throws NoSuchMethodException If <i>method</i> is not the name of + * a valid method of any component of the array. + * @throws ClassCastException If the returned object from the method + * is not assignable to the return type. + * @throws IllegalArgumentException If <i>args</i> is not appropriate + * for <i>method</i> + * @throws IllegalAccessException If <i>method</i> is not accessible. + * @throws SecurityException If <i>method</i> is not accessible. + * @return An array containing the output of <i>method</i> called on + * each element of <i>array</i> with <i>args</i>. The return type + * of the array will be an array of <i>returnType</i>. + */ + static Object[] transform(Object[] array, Class returnType, + String method, Object[] args) + throws InvocationTargetException, NoSuchMethodException, + IllegalAccessException + { + if (args == null) + args = new Object[0]; + Object[] result = (Object[]) Array.newInstance(returnType, array.length); + Class[] argsClasses = new Class[args.length]; + for (int i = 0; i < args.length; i++) + { + argsClasses[i] = args[i].getClass(); + } + for (int i = 0; i < array.length; i++) + { + if (array[i] == null) + { + result[i] = null; + continue; + } + Class objClass = array[i].getClass(); + Method objMethod = objClass.getMethod(method, argsClasses); + Object o = objMethod.invoke(array[i], args); + if (!returnType.isAssignableFrom(o.getClass())) + throw new ClassCastException(); + result[i] = o; + } + return result; + } + + /** + * Get a system property as a privileged action. + * + * @param name The name of the property to get. + * @return The property named <i>name</i>, or null if the property is + * not set. + * @throws SecurityException If the Jessie code still does not have + * permission to read the property. + */ + static String getProperty(final String name) + { + return (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return System.getProperty(name); + } + } + ); + } + + /** + * Get a security property as a privileged action. + * + * @param name The name of the property to get. + * @return The property named <i>name</i>, or null if the property is + * not set. + * @throws SecurityException If the Jessie code still does not have + * permission to read the property. + */ + static String getSecurityProperty(final String name) + { + return (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return Security.getProperty(name); + } + } + ); + } +} diff --git a/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java b/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java new file mode 100644 index 000000000..476655c45 --- /dev/null +++ b/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java @@ -0,0 +1,359 @@ +/* X509KeyManagerFactory.java -- X.509 key manager factory. + 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.net.ssl.provider; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.Socket; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Enumeration; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.List; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactorySpi; +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.X509KeyManager; + +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.PrivateCredentials; + +/** + * This class implements a {@link javax.net.ssl.KeyManagerFactory} engine + * for the ``JessieX509'' algorithm. + */ +public class X509KeyManagerFactory extends KeyManagerFactorySpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Manager current; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509KeyManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected KeyManager[] engineGetKeyManagers() + { + if (current == null) + { + throw new IllegalStateException(); + } + return new KeyManager[] { current }; + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params instanceof NullManagerParameters) + { + current = new Manager(Collections.EMPTY_MAP, Collections.EMPTY_MAP); + } + else if (params instanceof PrivateCredentials) + { + List chains = ((PrivateCredentials) params).getCertChains(); + List keys = ((PrivateCredentials) params).getPrivateKeys(); + int i = 0; + HashMap certMap = new HashMap(); + HashMap keyMap = new HashMap(); + Iterator c = chains.iterator(); + Iterator k = keys.iterator(); + while (c.hasNext() && k.hasNext()) + { + certMap.put(String.valueOf(i), c.next()); + keyMap.put(String.valueOf(i), k.next()); + i++; + } + current = new Manager(keyMap, certMap); + } + else + { + throw new InvalidAlgorithmParameterException(); + } + } + + protected void engineInit(KeyStore store, char[] passwd) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableKeyException + { + if (store == null) + { + String s = Util.getProperty("javax.net.ssl.keyStoreType"); + if (s == null) + s = KeyStore.getDefaultType(); + store = KeyStore.getInstance(s); + s = Util.getProperty("javax.net.ssl.keyStore"); + if (s == null) + return; + String p = Util.getProperty("javax.net.ssl.keyStorePassword"); + try + { + store.load(new FileInputStream(s), p != null ? p.toCharArray() : null); + } + catch (IOException ioe) + { + throw new KeyStoreException(ioe.toString()); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce.toString()); + } + } + + HashMap p = new HashMap(); + HashMap c = new HashMap(); + Enumeration aliases = store.aliases(); + UnrecoverableKeyException exception = null; + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + if (!store.isKeyEntry(alias)) + { + continue; + } + X509Certificate[] chain = null; + Certificate[] chain2 = store.getCertificateChain (alias); + if (chain2 != null && chain2.length > 0 && + (chain2[0] instanceof X509Certificate)) + { + chain = toX509Chain(chain2); + } + else + { + continue; + } + PrivateKey key = null; + try + { + key = (PrivateKey) store.getKey(alias, passwd); + } + catch (UnrecoverableKeyException uke) + { + exception = uke; + continue; + } + if (key == null) + { + continue; + } + p.put(alias, key); + c.put(alias, chain); + } + if (p.isEmpty () && c.isEmpty ()) + { + if (exception != null) + { + throw exception; + } + throw new KeyStoreException ("no private credentials found"); + } + current = this.new Manager(p, c); + } + + private static X509Certificate[] toX509Chain(Certificate[] chain) + { + if (chain instanceof X509Certificate[]) + { + return (X509Certificate[]) chain; + } + X509Certificate[] _chain = new X509Certificate[chain.length]; + for (int i = 0; i < chain.length; i++) + _chain[i] = (X509Certificate) chain[i]; + return _chain; + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class Manager implements X509KeyManager + { + // Fields. + // ----------------------------------------------------------------------- + + private final Map privateKeys; + private final Map certChains; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(Map privateKeys, Map certChains) + { + this.privateKeys = privateKeys; + this.certChains = certChains; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public String chooseClientAlias(String[] keyTypes, Principal[] issuers, + Socket socket) + { + for (int i = 0; i < keyTypes.length; i++) + { + String[] s = getClientAliases(keyTypes[i], issuers); + if (s.length > 0) + return s[0]; + } + return null; + } + + public String[] getClientAliases(String keyType, Principal[] issuers) + { + return getAliases(keyType, issuers); + } + + public String chooseServerAlias(String keyType, Principal[] issuers, + Socket socket) + { + String[] s = getServerAliases(keyType, issuers); + if (s.length > 0) + return s[0]; + return null; + } + + public String[] getServerAliases(String keyType, Principal[] issuers) + { + return getAliases(keyType, issuers); + } + + private String[] getAliases(String keyType, Principal[] issuers) + { + LinkedList l = new LinkedList(); + for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); ) + { + String alias = (String) i.next(); + X509Certificate[] chain = getCertificateChain(alias); + if (chain.length == 0) + continue; + PrivateKey privKey = getPrivateKey(alias); + if (privKey == null) + continue; + PublicKey pubKey = chain[0].getPublicKey(); + if (keyType.equals("RSA") || keyType.equals("DHE_RSA") || + keyType.equals("SRP_RSA") || keyType.equals("rsa_sign")) + { + if (!(privKey instanceof RSAPrivateKey) || + !(pubKey instanceof RSAPublicKey)) + continue; + } + if (keyType.equals("DHE_DSS") || keyType.equals("dss_sign") || + keyType.equals("SRP_DSS")) + { + if (!(privKey instanceof DSAPrivateKey) || + !(pubKey instanceof DSAPublicKey)) + continue; + } + if (keyType.equals("DH_RSA") || keyType.equals("rsa_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA")) + continue; + } + if (keyType.equals("DH_DSS") || keyType.equals("dss_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA")) + continue; + } + if (issuers == null || issuers.length == 0) + { + l.add(alias); + continue; + } + for (int j = 0; j < issuers.length; j++) + if (chain[0].getIssuerDN().equals(issuers[j])) + { + l.add(alias); + break; + } + } + return (String[]) l.toArray(new String[l.size()]); + } + + public X509Certificate[] getCertificateChain(String alias) + { + X509Certificate[] c = (X509Certificate[]) certChains.get(alias); + return c != null ? (X509Certificate[]) c.clone() : null; + } + + public PrivateKey getPrivateKey(String alias) + { + return (PrivateKey) privateKeys.get(alias); + } + } +} diff --git a/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java b/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java new file mode 100644 index 000000000..4f049e916 --- /dev/null +++ b/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java @@ -0,0 +1,298 @@ +/* X509TrustManagerFactory.java -- X.509 trust manager factory. + 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.net.ssl.provider; + +import java.io.FileInputStream; +import java.io.IOException; + +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedList; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.SignatureException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.StaticTrustAnchors; + +/** + * This class implements a {@link javax.net.ssl.TrustManagerFactory} engine + * for the ``JessieX509'' algorithm. + */ +public class X509TrustManagerFactory extends TrustManagerFactorySpi +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + /** + * The location of the JSSE key store. + */ + private static final String JSSE_CERTS = Util.getProperty("java.home") + + Util.getProperty("file.separator") + "lib" + + Util.getProperty("file.separator") + "security" + + Util.getProperty("file.separator") + "jssecerts"; + + /** + * The location of the system key store, containing the CA certs. + */ + private static final String CA_CERTS = Util.getProperty("java.home") + + Util.getProperty("file.separator") + "lib" + + Util.getProperty("file.separator") + "security" + + Util.getProperty("file.separator") + "cacerts"; + + private Manager current; + + // Construtors. + // ------------------------------------------------------------------------- + + public X509TrustManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected TrustManager[] engineGetTrustManagers() + { + if (current == null) + { + throw new IllegalStateException("not initialized"); + } + return new TrustManager[] { current }; + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params instanceof StaticTrustAnchors) + { + current = new Manager(((StaticTrustAnchors) params).getCertificates()); + } + else if (params instanceof NullManagerParameters) + { + current = new Manager(new X509Certificate[0]); + } + else + { + throw new InvalidAlgorithmParameterException(); + } + } + + protected void engineInit(KeyStore store) throws KeyStoreException + { + if (store == null) + { + String s = Util.getProperty("javax.net.ssl.trustStoreType"); + if (s == null) + s = KeyStore.getDefaultType(); + store = KeyStore.getInstance(s); + try + { + s = Util.getProperty("javax.net.ssl.trustStore"); + FileInputStream in = null; + if (s == null) + { + try + { + in = new FileInputStream(JSSE_CERTS); + } + catch (IOException e) + { + in = new FileInputStream(CA_CERTS); + } + } + else + { + in = new FileInputStream(s); + } + String p = Util.getProperty("javax.net.ssl.trustStorePassword"); + store.load(in, p != null ? p.toCharArray() : null); + } + catch (IOException ioe) + { + throw new KeyStoreException(ioe.toString()); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce.toString()); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyStoreException(nsae.toString()); + } + } + + LinkedList l = new LinkedList(); + Enumeration aliases = store.aliases(); + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + if (!store.isCertificateEntry(alias)) + continue; + Certificate c = store.getCertificate(alias); + if (!(c instanceof X509Certificate)) + continue; + l.add(c); + } + current = this.new Manager((X509Certificate[]) + l.toArray(new X509Certificate[l.size()])); + } + + // Inner class. + // ------------------------------------------------------------------------- + + /** + * The actual manager implementation returned. + */ + private class Manager implements X509TrustManager + { + + // Fields. + // ----------------------------------------------------------------------- + + private final X509Certificate[] trusted; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(X509Certificate[] trusted) + { + this.trusted = trusted; + } + + // Instance methodns. + // ----------------------------------------------------------------------- + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + checkTrusted(chain, authType); + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + checkTrusted(chain, authType); + } + + public X509Certificate[] getAcceptedIssuers() + { + if (trusted == null) + return new X509Certificate[0]; + return (X509Certificate[]) trusted.clone(); + } + + // Own methods. + // ----------------------------------------------------------------------- + + private void checkTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + // NOTE: this is not a full-featured path validation algorithm. + // + // Step 0: check if the target is valid now. + chain[0].checkValidity(); + + // Step 1: verify that the chain is complete and valid. + for (int i = 1; i < chain.length; i++) + { + chain[i].checkValidity(); + try + { + chain[i-1].verify(chain[i].getPublicKey()); + } + catch (NoSuchAlgorithmException nsae) + { + throw new CertificateException(nsae.toString()); + } + catch (NoSuchProviderException nspe) + { + throw new CertificateException(nspe.toString()); + } + catch (InvalidKeyException ike) + { + throw new CertificateException(ike.toString()); + } + catch (SignatureException se) + { + throw new CertificateException(se.toString()); + } + } + + // Step 2: verify that the root of the chain was issued by a trust anchor. + if (trusted == null || trusted.length == 0) + throw new CertificateException("no trust anchors"); + for (int i = 0; i < trusted.length; i++) + { + try + { + trusted[i].checkValidity(); + chain[chain.length-1].verify(trusted[i].getPublicKey()); + return; + } + catch (Exception e) + { + } + //catch (CertificateException ce) { } + //catch (NoSuchAlgorithmException nsae) { } + //catch (NoSuchProviderException nspe) { } + //catch (InvalidKeyException ike) { } + //catch (SignatureException se) { } + } + throw new CertificateException(); + } + } +} diff --git a/gnu/javax/net/ssl/provider/XMLSessionContext.java b/gnu/javax/net/ssl/provider/XMLSessionContext.java new file mode 100644 index 000000000..dcfa9d4ad --- /dev/null +++ b/gnu/javax/net/ssl/provider/XMLSessionContext.java @@ -0,0 +1,619 @@ +/* XMLSessionContext.java -- XML-encoded persistent SSL sessions. + 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.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.PrintStream; + +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeSet; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.prng.IPBE; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.PRNGFactory; + +import gnu.javax.net.ssl.Base64; + +/** + * An implementation of session contexts that stores session data on the + * filesystem in a simple XML-encoded file. + */ +class XMLSessionContext extends SessionContext +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final File file; + private final IRandom pbekdf; + private final boolean compress; + private final SecureRandom random; + private boolean encoding; + + // Constructor. + // ------------------------------------------------------------------------- + + XMLSessionContext() throws IOException, SAXException + { + file = new File(Util.getSecurityProperty("jessie.SessionContext.xml.file")); + String password = Util.getSecurityProperty("jessie.SessionContext.xml.password"); + compress = new Boolean(Util.getSecurityProperty("jessie.SessionContext.xml.compress")).booleanValue(); + if (password == null) + { + password = ""; + } + pbekdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA1"); + HashMap kdfattr = new HashMap(); + kdfattr.put(IPBE.PASSWORD, password.toCharArray()); + // Dummy salt. This is replaced by a real salt when encoding. + kdfattr.put(IPBE.SALT, new byte[8]); + kdfattr.put(IPBE.ITERATION_COUNT, new Integer(1000)); + pbekdf.init(kdfattr); + encoding = false; + if (file.exists()) + { + decode(); + } + encoding = true; + random = new SecureRandom (); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + synchronized boolean addSession(Session.ID sessionId, Session session) + { + boolean ret = super.addSession(sessionId, session); + if (ret && encoding) + { + try + { + encode(); + } + catch (IOException ioe) + { + } + } + return ret; + } + + synchronized void notifyAccess(Session session) + { + try + { + encode(); + } + catch (IOException ioe) + { + } + } + + synchronized boolean removeSession(Session.ID sessionId) + { + if (super.removeSession(sessionId)) + { + try + { + encode(); + } + catch (Exception x) + { + } + return true; + } + return false; + } + + private void decode() throws IOException, SAXException + { + SAXParser parser = null; + try + { + parser = SAXParserFactory.newInstance().newSAXParser(); + } + catch (Exception x) + { + throw new Error(x.toString()); + } + SAXHandler handler = new SAXHandler(this, pbekdf); + InputStream in = null; + if (compress) + in = new GZIPInputStream(new FileInputStream(file)); + else + in = new FileInputStream(file); + parser.parse(in, handler); + } + + private void encode() throws IOException + { + IMode cipher = ModeFactory.getInstance("CBC", "AES", 16); + HashMap cipherAttr = new HashMap(); + IMac mac = MacFactory.getInstance("HMAC-SHA1"); + HashMap macAttr = new HashMap(); + byte[] key = new byte[32]; + byte[] iv = new byte[16]; + byte[] mackey = new byte[20]; + byte[] salt = new byte[8]; + byte[] encryptedSecret = new byte[48]; + cipherAttr.put(IMode.KEY_MATERIAL, key); + cipherAttr.put(IMode.IV, iv); + cipherAttr.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + macAttr.put(IMac.MAC_KEY_MATERIAL, mackey); + PrintStream out = null; + if (compress) + { + out = new PrintStream(new GZIPOutputStream(new FileOutputStream(file))); + } + else + { + out = new PrintStream(new FileOutputStream(file)); + } + out.println("<?xml version=\"1.0\"?>"); + out.println("<!DOCTYPE sessions ["); + out.println(" <!ELEMENT sessions (session*)>"); + out.println(" <!ATTLIST sessions size CDATA \"0\">"); + out.println(" <!ATTLIST sessions timeout CDATA \"86400\">"); + out.println(" <!ELEMENT session (peer, certificates?, secret)>"); + out.println(" <!ATTLIST session id CDATA #REQUIRED>"); + out.println(" <!ATTLIST session protocol (SSLv3|TLSv1|TLSv1.1) #REQUIRED>"); + out.println(" <!ATTLIST session suite CDATA #REQUIRED>"); + out.println(" <!ATTLIST session created CDATA #REQUIRED>"); + out.println(" <!ATTLIST session timestamp CDATA #REQUIRED>"); + out.println(" <!ELEMENT peer (certificates?)>"); + out.println(" <!ATTLIST peer host CDATA #REQUIRED>"); + out.println(" <!ELEMENT certificates (#PCDATA)>"); + out.println(" <!ATTLIST certificates type CDATA \"X.509\">"); + out.println(" <!ELEMENT secret (#PCDATA)>"); + out.println(" <!ATTLIST secret salt CDATA #REQUIRED>"); + out.println("]>"); + out.println(); + out.print("<sessions size=\""); + out.print(cacheSize); + out.print("\" timeout=\""); + out.print(timeout); + out.println("\">"); + for (Iterator it = sessions.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry entry = (Map.Entry) it.next(); + Session.ID id = (Session.ID) entry.getKey(); + Session session = (Session) entry.getValue(); + if (!session.valid) + { + continue; + } + out.print("<session id=\""); + out.print(Base64.encode(id.getId(), 0)); + out.print("\" suite=\""); + out.print(session.getCipherSuite()); + out.print("\" protocol=\""); + out.print(session.getProtocol()); + out.print("\" created=\""); + out.print(session.getCreationTime()); + out.print("\" timestamp=\""); + out.print(session.getLastAccessedTime()); + out.println("\">"); + out.print("<peer host=\""); + out.print(session.getPeerHost()); + out.println("\">"); + Certificate[] certs = session.getPeerCertificates(); + if (certs != null && certs.length > 0) + { + out.print("<certificates type=\""); + out.print(certs[0].getType()); + out.println("\">"); + for (int i = 0; i < certs.length; i++) + { + out.println("-----BEGIN CERTIFICATE-----"); + try + { + out.print(Base64.encode(certs[i].getEncoded(), 70)); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + out.println("-----END CERTIFICATE-----"); + } + out.println("</certificates>"); + } + out.println("</peer>"); + certs = session.getLocalCertificates(); + if (certs != null && certs.length > 0) + { + out.print("<certificates type=\""); + out.print(certs[0].getType()); + out.println("\">"); + for (int i = 0; i < certs.length; i++) + { + out.println("-----BEGIN CERTIFICATE-----"); + try + { + out.print(Base64.encode(certs[i].getEncoded(), 70)); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + out.println("-----END CERTIFICATE-----"); + } + out.println("</certificates>"); + } + random.nextBytes (salt); + pbekdf.init(Collections.singletonMap(IPBE.SALT, salt)); + try + { + pbekdf.nextBytes(key, 0, key.length); + pbekdf.nextBytes(iv, 0, iv.length); + pbekdf.nextBytes(mackey, 0, mackey.length); + cipher.reset(); + cipher.init(cipherAttr); + mac.init(macAttr); + } + catch (Exception ex) + { + throw new Error(ex.toString()); + } + for (int i = 0; i < session.masterSecret.length; i += 16) + { + cipher.update(session.masterSecret, i, encryptedSecret, i); + } + mac.update(encryptedSecret, 0, encryptedSecret.length); + byte[] macValue = mac.digest(); + out.print("<secret salt=\""); + out.print(Base64.encode(salt, 0)); + out.println("\">"); + out.print(Base64.encode(Util.concat(encryptedSecret, macValue), 70)); + out.println("</secret>"); + out.println("</session>"); + } + out.println("</sessions>"); + out.close(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class SAXHandler extends DefaultHandler + { + + // Field. + // ----------------------------------------------------------------------- + + private SessionContext context; + private Session current; + private IRandom pbekdf; + private StringBuffer buf; + private String certType; + private int state; + private IMode cipher; + private HashMap cipherAttr; + private IMac mac; + private HashMap macAttr; + private byte[] key; + private byte[] iv; + private byte[] mackey; + + private static final int START = 0; + private static final int SESSIONS = 1; + private static final int SESSION = 2; + private static final int PEER = 3; + private static final int PEER_CERTS = 4; + private static final int CERTS = 5; + private static final int SECRET = 6; + + // Constructor. + // ----------------------------------------------------------------------- + + SAXHandler(SessionContext context, IRandom pbekdf) + { + this.context = context; + this.pbekdf = pbekdf; + buf = new StringBuffer(); + state = START; + cipher = ModeFactory.getInstance("CBC", "AES", 16); + cipherAttr = new HashMap(); + mac = MacFactory.getInstance("HMAC-SHA1"); + macAttr = new HashMap(); + key = new byte[32]; + iv = new byte[16]; + mackey = new byte[20]; + cipherAttr.put(IMode.KEY_MATERIAL, key); + cipherAttr.put(IMode.IV, iv); + cipherAttr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + macAttr.put(IMac.MAC_KEY_MATERIAL, mackey); + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void startElement(String u, String n, String qname, Attributes attr) + throws SAXException + { + qname = qname.toLowerCase(); + switch (state) + { + case START: + if (qname.equals("sessions")) + { + try + { + timeout = Integer.parseInt(attr.getValue("timeout")); + cacheSize = Integer.parseInt(attr.getValue("size")); + if (timeout <= 0 || cacheSize < 0) + throw new SAXException("timeout or cache size out of range"); + } + catch (NumberFormatException nfe) + { + throw new SAXException(nfe); + } + state = SESSIONS; + } + else + throw new SAXException("expecting sessions"); + break; + + case SESSIONS: + if (qname.equals("session")) + { + try + { + current = new Session(Long.parseLong(attr.getValue("created"))); + current.enabledSuites = new ArrayList(SSLSocket.supportedSuites); + current.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols); + current.context = context; + current.sessionId = new Session.ID(Base64.decode(attr.getValue("id"))); + current.setLastAccessedTime(Long.parseLong(attr.getValue("timestamp"))); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + String prot = attr.getValue("protocol"); + if (prot.equals("SSLv3")) + current.protocol = ProtocolVersion.SSL_3; + else if (prot.equals("TLSv1")) + current.protocol = ProtocolVersion.TLS_1; + else if (prot.equals("TLSv1.1")) + current.protocol = ProtocolVersion.TLS_1_1; + else + throw new SAXException("bad protocol: " + prot); + current.cipherSuite = CipherSuite.forName(attr.getValue("suite")); + state = SESSION; + } + else + throw new SAXException("expecting session"); + break; + + case SESSION: + if (qname.equals("peer")) + { + current.peerHost = attr.getValue("host"); + state = PEER; + } + else if (qname.equals("certificates")) + { + certType = attr.getValue("type"); + state = CERTS; + } + else if (qname.equals("secret")) + { + byte[] salt = null; + try + { + salt = Base64.decode(attr.getValue("salt")); + } + catch (IOException ioe) + { + throw new SAXException(ioe); + } + pbekdf.init(Collections.singletonMap(IPBE.SALT, salt)); + state = SECRET; + } + else + throw new SAXException("bad element: " + qname); + break; + + case PEER: + if (qname.equals("certificates")) + { + certType = attr.getValue("type"); + state = PEER_CERTS; + } + else + throw new SAXException("bad element: " + qname); + break; + + default: + throw new SAXException("bad element: " + qname); + } + } + + public void endElement(String uri, String name, String qname) + throws SAXException + { + qname = qname.toLowerCase(); + switch (state) + { + case SESSIONS: + if (qname.equals("sessions")) + state = START; + else + throw new SAXException("expecting sessions"); + break; + + case SESSION: + if (qname.equals("session")) + { + current.valid = true; + context.addSession(current.sessionId, current); + state = SESSIONS; + } + else + throw new SAXException("expecting session"); + break; + + case PEER: + if (qname.equals("peer")) + state = SESSION; + else + throw new SAXException("unexpected element: " + qname); + break; + + case PEER_CERTS: + if (qname.equals("certificates")) + { + try + { + CertificateFactory fact = CertificateFactory.getInstance(certType); + current.peerCerts = (Certificate[]) + fact.generateCertificates(new ByteArrayInputStream( + buf.toString().getBytes())).toArray(new Certificate[0]); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + current.peerVerified = true; + state = PEER; + } + else + throw new SAXException("unexpected element: " + qname); + break; + + case CERTS: + if (qname.equals("certificates")) + { + try + { + CertificateFactory fact = CertificateFactory.getInstance(certType); + current.localCerts = (Certificate[]) + fact.generateCertificates(new ByteArrayInputStream( + buf.toString().getBytes())).toArray(new Certificate[0]); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + state = SESSION; + } + else + throw new SAXException("unexpected element: " + qname); + break; + + case SECRET: + if (qname.equals("secret")) + { + byte[] encrypted = null; + try + { + encrypted = Base64.decode(buf.toString()); + if (encrypted.length != 68) + throw new IOException("encrypted secret not 68 bytes long"); + pbekdf.nextBytes(key, 0, key.length); + pbekdf.nextBytes(iv, 0, iv.length); + pbekdf.nextBytes(mackey, 0, mackey.length); + cipher.reset(); + cipher.init(cipherAttr); + mac.init(macAttr); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + mac.update(encrypted, 0, 48); + byte[] macValue = mac.digest(); + for (int i = 0; i < macValue.length; i++) + { + if (macValue[i] != encrypted[48+i]) + throw new SAXException("MAC mismatch"); + } + current.masterSecret = new byte[48]; + for (int i = 0; i < current.masterSecret.length; i += 16) + { + cipher.update(encrypted, i, current.masterSecret, i); + } + state = SESSION; + } + else + throw new SAXException("unexpected element: " + qname); + break; + + default: + throw new SAXException("unexpected element: " + qname); + } + buf.setLength(0); + } + + public void characters(char[] ch, int off, int len) throws SAXException + { + if (state != CERTS && state != PEER_CERTS && state != SECRET) + { + throw new SAXException("illegal character data"); + } + buf.append(ch, off, len); + } + } +} diff --git a/gnu/javax/security/auth/Password.java b/gnu/javax/security/auth/Password.java new file mode 100644 index 000000000..7284b7d68 --- /dev/null +++ b/gnu/javax/security/auth/Password.java @@ -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); + } +} diff --git a/gnu/javax/security/auth/callback/AWTCallbackHandler.java b/gnu/javax/security/auth/callback/AWTCallbackHandler.java new file mode 100644 index 000000000..539c4a17e --- /dev/null +++ b/gnu/javax/security/auth/callback/AWTCallbackHandler.java @@ -0,0 +1,452 @@ +/* AWTCallbackHandler.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.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.TextField; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +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; + +public class AWTCallbackHandler extends AbstractCallbackHandler + implements ActionListener, WindowListener +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected String actionCommand; + + private static final String ACTION_CANCEL = "CANCEL"; + private static final String ACTION_NO = "NO"; + private static final String ACTION_NONE = "NONE"; + private static final String ACTION_OK = "OK"; + private static final String ACTION_YES = "YES"; + + // Constructor. + // ------------------------------------------------------------------------- + + public AWTCallbackHandler() + { + super ("AWT"); + actionCommand = ACTION_NONE; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected synchronized void handleChoice(ChoiceCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + String[] choices = c.getChoices(); + dialog.setTitle(c.getPrompt()); + Label label = new Label(c.getPrompt()); + List list = new List(Math.min(5, choices.length), + c.allowMultipleSelections()); + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + for (int i = 0; i < choices.length; i++) + { + list.add(choices[i]); + } + if (c.getDefaultChoice() >= 0 && c.getDefaultChoice() < choices.length) + { + list.select(c.getDefaultChoice()); + } + dialog.setLayout(new BorderLayout()); + dialog.add(label, BorderLayout.NORTH); + dialog.add(list, BorderLayout.CENTER); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(cancel); + buttons.add(ok); + dialog.add(buttons, BorderLayout.SOUTH); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + if (c.allowMultipleSelections()) + { + c.setSelectedIndexes(list.getSelectedIndexes()); + } + else + { + c.setSelectedIndex(list.getSelectedIndex()); + } + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleConfirmation(ConfirmationCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + switch (c.getMessageType()) + { + case ConfirmationCallback.ERROR: + dialog.setTitle(messages.getString("callback.error")); + break; + case ConfirmationCallback.INFORMATION: + dialog.setTitle(messages.getString("callback.information")); + break; + case ConfirmationCallback.WARNING: + dialog.setTitle(messages.getString("callback.warning")); + break; + default: + dialog.setTitle(""); + } + dialog.setLayout(new GridLayout(2, 1)); + dialog.add(new Label(c.getPrompt())); + Panel buttons = new Panel(); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + dialog.add(buttons); + String[] choices = null; + int[] values = null; + switch (c.getOptionType()) + { + case ConfirmationCallback.OK_CANCEL_OPTION: + choices = new String[] { + messages.getString("callback.cancel"), + messages.getString("callback.ok") + }; + values = new int[] { + ConfirmationCallback.CANCEL, ConfirmationCallback.OK + }; + break; + case ConfirmationCallback.YES_NO_CANCEL_OPTION: + choices = new String[] { + messages.getString("callback.cancel"), + messages.getString("callback.no"), + messages.getString("callback.yes") + }; + values = new int[] { + ConfirmationCallback.CANCEL, ConfirmationCallback.NO, + ConfirmationCallback.YES + }; + break; + case ConfirmationCallback.YES_NO_OPTION: + choices = new String[] { + messages.getString("callback.no"), + messages.getString("callback.yes") + }; + values = new int[] { + ConfirmationCallback.NO, ConfirmationCallback.YES + }; + break; + case ConfirmationCallback.UNSPECIFIED_OPTION: + choices = c.getOptions(); + values = new int[choices.length]; + for (int i = 0; i < values.length; i++) + values[i] = i; + break; + default: + throw new IllegalArgumentException(); + } + for (int i = 0; i < choices.length; i++) + { + Button b = new Button(choices[i]); + b.setActionCommand(choices[i]); + b.addActionListener(this); + buttons.add(b); + } + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + for (int i = 0; i < choices.length; i++) + { + if (actionCommand.equals(choices[i])) + { + c.setSelectedIndex(values[i]); + break; + } + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleLanguage(LanguageCallback c) + { + Locale[] locales = Locale.getAvailableLocales(); + String[] languages = new String[locales.length]; + Locale def = Locale.getDefault(); + int defind = 0; + for (int i = 0; i < locales.length; i++) + { + StringBuffer lang = + new StringBuffer(locales[i].getDisplayLanguage(locales[i])); + String country = locales[i].getDisplayCountry(locales[i]); + String variant = locales[i].getDisplayVariant(locales[i]); + if (country.length() > 0 && variant.length() > 0) + { + lang.append(" ("); + lang.append(country); + lang.append(", "); + lang.append(variant); + lang.append(")"); + } + else if (country.length() > 0) + { + lang.append(" ("); + lang.append(country); + lang.append(")"); + } + else if (variant.length() > 0) + { + lang.append(" ("); + lang.append(variant); + lang.append(")"); + } + languages[i] = lang.toString(); + if (locales[i].equals(def)) + defind = i; + } + ChoiceCallback c2 = + new ChoiceCallback(messages.getString("callback.language"), languages, + defind, false); + handleChoice(c2); + c.setLocale(def); + if (c2.getSelectedIndexes() != null && c2.getSelectedIndexes().length > 0) + { + int index = c2.getSelectedIndexes()[0]; + if (index >= 0 && index < locales.length) + c.setLocale(locales[index]); + } + } + + protected synchronized void handleName(NameCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setTitle(c.getPrompt()); + dialog.setLayout(new GridLayout(3, 1)); + Label label = new Label(c.getPrompt()); + TextField input = new TextField(); + if (c.getDefaultName() != null) + { + input.setText(c.getDefaultName()); + } + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + dialog.add(label); + dialog.add(input); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + buttons.add(cancel); + dialog.add(buttons); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + c.setName(input.getText()); + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handlePassword(PasswordCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setTitle(c.getPrompt()); + dialog.setLayout(new GridLayout(3, 1)); + Label label = new Label(c.getPrompt()); + TextField input = new TextField(); + if (!c.isEchoOn()) + { + input.setEchoChar('*'); + } + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + dialog.add(label); + dialog.add(input); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + buttons.add(cancel); + dialog.add(buttons); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + c.setPassword(input.getText().toCharArray()); + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleTextInput(TextInputCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setTitle(c.getPrompt()); + dialog.setLayout(new BorderLayout()); + Label label = new Label(c.getPrompt()); + TextArea text = new TextArea(10, 40); + if (c.getDefaultText() != null) + { + text.setText(c.getDefaultText()); + } + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + dialog.add(label, BorderLayout.NORTH); + dialog.add(text, BorderLayout.CENTER); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + buttons.add(cancel); + dialog.add(buttons, BorderLayout.SOUTH); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + c.setText(text.getText()); + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleTextOutput(TextOutputCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setLayout(new GridLayout(2, 1)); + switch (c.getMessageType() /*c.getStyle()*/) + { + case ConfirmationCallback.ERROR: + dialog.setTitle(messages.getString("callback.error")); + break; + case ConfirmationCallback.INFORMATION: + dialog.setTitle(messages.getString("callback.information")); + break; + case ConfirmationCallback.WARNING: + dialog.setTitle(messages.getString("callback.warning")); + break; + default: + dialog.setTitle(""); + } + Label label = new Label(c.getMessage()); + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + ok.addActionListener(this); + dialog.add(label); + dialog.add(buttons); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + dialog.dispose(); + ownerFrame.dispose(); + } + + // ActionListener interface implementation. + // ------------------------------------------------------------------------- + + public synchronized void actionPerformed(ActionEvent ae) + { + actionCommand = ae.getActionCommand(); + notifyAll(); + } + + // WindowListener interface implementation. + // ------------------------------------------------------------------------- + + public synchronized void windowClosing(WindowEvent we) + { + actionCommand = ACTION_NONE; + notifyAll(); + } + + public void windowOpened(WindowEvent we) { } + public void windowClosed(WindowEvent we) { } + public void windowIconified(WindowEvent we) { } + public void windowDeiconified(WindowEvent we) { } + public void windowActivated(WindowEvent we) { } + public void windowDeactivated(WindowEvent we) { } +} diff --git a/gnu/javax/security/auth/callback/AbstractCallbackHandler.java b/gnu/javax/security/auth/callback/AbstractCallbackHandler.java new file mode 100644 index 000000000..eeedf2605 --- /dev/null +++ b/gnu/javax/security/auth/callback/AbstractCallbackHandler.java @@ -0,0 +1,258 @@ +/* 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; + } + + // Class methods. + // ------------------------------------------------------------------------- + + public static CallbackHandler getInstance(String type) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(type, p[i]); + } + catch (NoSuchAlgorithmException ignored) + { + } + } + throw new NoSuchAlgorithmException(type); + } + + public static CallbackHandler getInstance(String type, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + Provider p = Security.getProvider(provider); + if (p == null) + { + throw new NoSuchProviderException(provider); + } + return getInstance(type, p); + } + + public static CallbackHandler getInstance(String type, Provider provider) + throws NoSuchAlgorithmException + { + try + { + return (CallbackHandler) Engine.getInstance(SERVICE, type, provider); + } + catch (InvocationTargetException ite) + { + Throwable cause = ite.getCause(); + if (cause instanceof NoSuchAlgorithmException) + throw (NoSuchAlgorithmException) cause; + NoSuchAlgorithmException nsae = new NoSuchAlgorithmException(type); + if (cause != null) + nsae.initCause (cause); + throw nsae; + } + catch (ClassCastException cce) + { + NoSuchAlgorithmException nsae = new NoSuchAlgorithmException(type); + nsae.initCause (cce); + throw nsae; + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + 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); + } +} diff --git a/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java b/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java new file mode 100644 index 000000000..4ce22cb30 --- /dev/null +++ b/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java @@ -0,0 +1,289 @@ +/* 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(new Integer(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.println(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 + }; + 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.println(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()); + } +} diff --git a/gnu/javax/security/auth/callback/DefaultCallbackHandler.java b/gnu/javax/security/auth/callback/DefaultCallbackHandler.java new file mode 100644 index 000000000..fc48782fe --- /dev/null +++ b/gnu/javax/security/auth/callback/DefaultCallbackHandler.java @@ -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) + { + } +} diff --git a/gnu/javax/security/auth/callback/GnuCallbacks.java b/gnu/javax/security/auth/callback/GnuCallbacks.java new file mode 100644 index 000000000..9fd72f926 --- /dev/null +++ b/gnu/javax/security/auth/callback/GnuCallbacks.java @@ -0,0 +1,64 @@ +/* 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()); + put("CallbackHandler.AWT", AWTCallbackHandler.class.getName()); + put("CallbackHandler.Swing", SwingCallbackHandler.class.getName()); + + return null; + } + }); + } +} diff --git a/gnu/javax/security/auth/callback/SwingCallbackHandler.java b/gnu/javax/security/auth/callback/SwingCallbackHandler.java new file mode 100644 index 000000000..8e3e46eff --- /dev/null +++ b/gnu/javax/security/auth/callback/SwingCallbackHandler.java @@ -0,0 +1,587 @@ + /* SwingCallbackHandler.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.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.io.IOException; + +import java.util.Locale; + +import javax.security.auth.callback.Callback; +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.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; + +public class SwingCallbackHandler extends AbstractCallbackHandler +{ + public SwingCallbackHandler () + { + super ("SWING"); + } + + protected void handleChoice (final ChoiceCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + dialog.setResizable (false); + Container content = dialog.getContentPane (); + GridBagLayout layout = new GridBagLayout (); + content.setLayout (layout); + JLabel prompt = new JLabel (callback.getPrompt (), JLabel.LEFT); + content.add (prompt, new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.WEST, + GridBagConstraints.NONE, + new Insets (5, 5, 5, 5), 5, 5)); + + String[] choices = callback.getChoices (); + final JList choicesList = new JList (choices); + JScrollPane choicesPane = new JScrollPane (choicesList, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + final int defaultChoice = callback.getDefaultChoice (); + choicesList.setSelectedIndex (defaultChoice); + choicesList.setSelectionMode (callback.allowMultipleSelections () + ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + : ListSelectionModel.SINGLE_SELECTION); + content.add (choicesPane, new GridBagConstraints (0, 1, 1, 1, 1.0, 1.0, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets (0, 10, 0, 10), 5, 5)); + + JPanel confirmButtons = new JPanel (); + confirmButtons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton ok = new JButton (messages.getString ("callback.ok")); + confirmButtons.add (cancel); + confirmButtons.add (ok); + content.add (confirmButtons, new GridBagConstraints (0, 2, 1, 1, 0, 0, + GridBagConstraints.EAST, + GridBagConstraints.NONE, + new Insets (5, 5, 5, 5), + 0, 0)); + dialog.getRootPane ().setDefaultButton (ok); + + cancel.addActionListener (new ActionListener () + { + public void actionPerformed (final ActionEvent ae) + { + callback.setSelectedIndex (defaultChoice); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }); + ok.addActionListener (new ActionListener () + { + public void actionPerformed (final ActionEvent ae) + { + if (callback.allowMultipleSelections ()) + { + int[] indices = choicesList.getSelectedIndices (); + if (indices != null && indices.length > 0) + callback.setSelectedIndexes (indices); + else + callback.setSelectedIndex (defaultChoice); + } + else + { + int selected = choicesList.getSelectedIndex (); + if (selected != -1) + callback.setSelectedIndex (selected); + else + callback.setSelectedIndex (defaultChoice); + } + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }); + + dialog.pack (); + dialog.setSize (new Dimension (400, 400)); + dialog.setVisible (true); + waitForInput (dialog, callback); + } + + protected void handleConfirmation (final ConfirmationCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + switch (callback.getMessageType ()) + { + case ConfirmationCallback.ERROR: + dialog.setTitle (messages.getString ("callback.error")); + break; + case ConfirmationCallback.WARNING: + dialog.setTitle (messages.getString ("callback.warning")); + break; + case ConfirmationCallback.INFORMATION: + dialog.setTitle (messages.getString ("callback.information")); + break; + } + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + String prompt = callback.getPrompt (); + if (prompt != null) + { + content.add (new JLabel (prompt), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.WEST, + GridBagConstraints.NONE, + new Insets (5, 5, 5, 25), 0, 0)); + } + + final String[] options = callback.getOptions (); + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (options != null) + { + for (int i = 0; i < options.length; i++) + { + if (cmd.equals (options[i])) + { + callback.setSelectedIndex (i); + break; + } + } + } + else + { + if (cmd.equals ("cancel")) + callback.setSelectedIndex (ConfirmationCallback.CANCEL); + else if (cmd.equals ("okay")) + callback.setSelectedIndex (ConfirmationCallback.OK); + else if (cmd.equals ("yes")) + callback.setSelectedIndex (ConfirmationCallback.YES); + else if (cmd.equals ("no")) + callback.setSelectedIndex (ConfirmationCallback.NO); + } + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + switch (callback.getOptionType ()) + { + case ConfirmationCallback.YES_NO_CANCEL_OPTION: + { + JButton cancel = new JButton (messages.getString ("callback.cancel")); + buttons.add (cancel); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + } + /* Fall-through. */ + case ConfirmationCallback.YES_NO_OPTION: + { + JButton yes = new JButton (messages.getString ("callback.yes")); + JButton no = new JButton (messages.getString ("callback.no")); + buttons.add (no); + buttons.add (yes); + yes.setActionCommand ("yes"); + yes.addActionListener (listener); + no.setActionCommand ("no"); + no.addActionListener (listener); + dialog.getRootPane ().setDefaultButton (yes); + } + break; + case ConfirmationCallback.OK_CANCEL_OPTION: + { + JButton okay = new JButton (messages.getString ("callback.ok")); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + buttons.add (cancel); + buttons.add (okay); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + dialog.getRootPane ().setDefaultButton (okay); + } + break; + case ConfirmationCallback.UNSPECIFIED_OPTION: + for (int i = 0; i < options.length; i++) + { + JButton button = new JButton (options[i]); + buttons.add (button); + button.setActionCommand (options[i]); + button.addActionListener (listener); + if (i == options.length - 1) + dialog.getRootPane ().setDefaultButton (button); + } + } + content.add (buttons, + new GridBagConstraints (0, GridBagConstraints.RELATIVE, + 1, 1, 1, 1, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.BOTH, + new Insets (5, 5, 5, 5), 0, 0)); + dialog.setResizable (false); + dialog.pack (); + dialog.setVisible (true); + waitForInput (dialog, callback); + } + + protected void handleLanguage (final LanguageCallback callback) + throws IOException + { + Locale locale = Locale.getDefault (); + Locale[] locales = Locale.getAvailableLocales (); + String[] localeNames = new String[locales.length+1]; + int defaultIndex = 0; + for (int i = 0; i < locales.length; i++) + { + localeNames[i+1] = locales[i].getDisplayLanguage (locales[i]); + String country = locales[i].getDisplayCountry (locales[i]); + if (country.length () > 0) + localeNames[i+1] += " (" + country + ")"; + if (locales[i].equals (locale)) + defaultIndex = i; + } + locales[0] = locale; + localeNames[0] = locale.getDisplayLanguage (locale); + String country = locale.getDisplayCountry (locale); + if (country.length () > 0) + localeNames[0] += " (" + country + ")"; + ChoiceCallback cb = new ChoiceCallback (messages.getString ("callback.language"), + localeNames, 0, + false); + handleChoice (cb); + int selected = cb.getSelectedIndexes ()[0]; + if (selected > 0) + callback.setLocale (locales[selected - 1]); + else + callback.setLocale (locale); + } + + protected void handleName (final NameCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + content.add (new JLabel (callback.getPrompt ()), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.NORTHEAST, + GridBagConstraints.VERTICAL, + new Insets (10, 10, 15, 5), 0, 0)); + + final JTextField name = new JTextField (); + name.setColumns (20); + String _name; + if ((_name = callback.getDefaultName ()) != null) + name.setText (_name); + content.add (name, new GridBagConstraints (1, 0, 1, 1, 1, 1, + GridBagConstraints.NORTHWEST, + GridBagConstraints.BOTH, + new Insets (10, 5, 15, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (cmd.equals ("okay")) + callback.setName (name.getText ()); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton okay = new JButton (messages.getString ("callback.ok")); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + buttons.add (cancel); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + buttons.add (okay); + content.add (buttons, new GridBagConstraints (0, 1, 2, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (false); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + protected void handlePassword (final PasswordCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + content.add (new JLabel (callback.getPrompt ()), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.NORTHEAST, + GridBagConstraints.VERTICAL, + new Insets (10, 10, 15, 5), 0, 0)); + + final JPasswordField password = new JPasswordField (); + password.setColumns (20); + password.setEchoChar (callback.isEchoOn () ? '\u0000' : '\u2022'); + content.add (password, new GridBagConstraints (1, 0, 1, 1, 1, 1, + GridBagConstraints.NORTHWEST, + GridBagConstraints.BOTH, + new Insets (10, 5, 15, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (cmd.equals ("okay")) + callback.setPassword (password.getPassword ()); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton okay = new JButton (messages.getString ("callback.ok")); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + buttons.add (cancel); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + buttons.add (okay); + content.add (buttons, new GridBagConstraints (0, 1, 2, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (false); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + protected void handleTextInput (final TextInputCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + content.add (new JLabel (callback.getPrompt ()), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.NORTHWEST, + GridBagConstraints.NONE, + new Insets (10, 10, 15, 5), 0, 0)); + + final JTextArea text = new JTextArea (24, 80); + text.setEditable (true); + String _text; + if ((_text = callback.getDefaultText ()) != null) + text.setText (_text); + text.setFont (new Font ("Monospaced", Font.PLAIN, 12)); + JScrollPane textPane = new JScrollPane (text, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + content.add (textPane, + new GridBagConstraints (0, 1, 1, 1, 1, 1, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets (5, 10, 5, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (cmd.equals ("okay")) + callback.setText (text.getText ()); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton okay = new JButton (messages.getString ("callback.ok")); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + buttons.add (cancel); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + buttons.add (okay); + content.add (buttons, new GridBagConstraints (0, 2, 1, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (true); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + protected void handleTextOutput (final TextOutputCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + switch (callback.getMessageType ()) + { + case TextOutputCallback.ERROR: + dialog.setTitle (messages.getString ("callback.error")); + break; + case TextOutputCallback.WARNING: + dialog.setTitle (messages.getString ("callback.warning")); + break; + case TextOutputCallback.INFORMATION: + dialog.setTitle (messages.getString ("callback.information")); + break; + } + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + final JTextArea text = new JTextArea (24, 80); + text.setEditable (false); + text.setText (callback.getMessage ()); + text.setFont (new Font ("Monospaced", Font.PLAIN, 12)); + JScrollPane textPane = new JScrollPane (text, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + content.add (textPane, + new GridBagConstraints (0, 0, 1, 1, 1, 1, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets (10, 10, 5, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JButton okay = new JButton (messages.getString ("callback.ok")); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + content.add (okay, new GridBagConstraints (0, 1, 1, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (true); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + private void waitForInput (JDialog dialog, Callback callback) + { + synchronized (callback) + { + while (dialog.isVisible ()) + { + try + { + callback.wait (1000); + } + catch (InterruptedException ignored) + { + } + } + } + dialog.dispose (); + } +}
\ No newline at end of file diff --git a/resource/gnu/javax/security/auth/callback/MessagesBundle.properties b/resource/gnu/javax/security/auth/callback/MessagesBundle.properties new file mode 100644 index 000000000..95ad337f5 --- /dev/null +++ b/resource/gnu/javax/security/auth/callback/MessagesBundle.properties @@ -0,0 +1,52 @@ +# MessagesBundle.properties -- Default messages bundle. +# Copyright (C) 2005 Free Software Foundation, Inc. +# +# This file is a part of GNU Classpath. +# +# GNU Classpath is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# GNU Classpath is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Classpath; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# +# Linking this library statically or dynamically with other modules is +# making a combined work based on this library. Thus, the terms and +# conditions of the GNU General Public License cover the whole +# combination. +# +# As a special exception, the copyright holders of this library give +# you permission to link this library with independent modules to +# produce an executable, regardless of the license terms of these +# independent modules, and to copy and distribute the resulting +# executable under terms of your choice, provided that you also meet, +# for each linked independent module, the terms and conditions of the +# license of that module. An independent module is a module which is +# not derived from or based on this library. If you modify this +# library, you may extend this exception to your version of the +# library, but you are not obligated to do so. If you do not wish to +# do so, delete this exception statement from your version. + +callback.yesNo=(yes or no)\ +callback.yesNoCancel=(yes, no, cancel)\ +callback.okCancel=(ok or cancel)\ +callback.language=Choose your language:\ + +callback.yes=Yes +callback.shortYes=y +callback.no=No +callback.shortNo=n +callback.cancel=Cancel +callback.ok=Okay + +callback.error=Error +callback.information=Information +callback.warning=Warning diff --git a/resource/java/security/classpath.security b/resource/java/security/classpath.security index c8e9dac94..cc7d49378 100644 --- a/resource/java/security/classpath.security +++ b/resource/java/security/classpath.security @@ -37,3 +37,6 @@ security.provider.1=gnu.java.security.provider.Gnu +security.provider.2=gnu.javax.crypto.jce.GnuCrypto +security.provider.3=gnu.javax.crypto.jce.GnuSasl +security.provider.4=gnu.javax.net.ssl.provider.Jessie |