зеркало из https://github.com/mono/ikvm-fork.git
Updated IcedTea crypto classes to support PBEwithMD5andDES.
This commit is contained in:
Родитель
fff2c860d3
Коммит
c39422e01c
|
@ -10035,6 +10035,7 @@ icedtea/jce/gnu/java/security/hash/Sha384.java
|
|||
icedtea/jce/gnu/java/security/hash/Sha512.java
|
||||
icedtea/jce/gnu/java/security/hash/Tiger.java
|
||||
icedtea/jce/gnu/java/security/hash/Whirlpool.java
|
||||
icedtea/jce/gnu/java/security/icedtea/CertBundleKeyStoreImpl.java
|
||||
icedtea/jce/gnu/java/security/icedtea/GNUTlsKeyMaterialGeneratorImpl.java
|
||||
icedtea/jce/gnu/java/security/icedtea/GNUTlsMasterSecretGenerator.java
|
||||
icedtea/jce/gnu/java/security/icedtea/GNUTlsPrfGeneratorImpl.java
|
||||
|
@ -10206,6 +10207,7 @@ icedtea/jce/gnu/javax/crypto/cipher/WeakKeyException.java
|
|||
icedtea/jce/gnu/javax/crypto/jce/DiffieHellmanImpl.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/GnuCrypto.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/GnuSasl.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/PBESecretKeyFactory.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java
|
||||
|
@ -10221,6 +10223,7 @@ icedtea/jce/gnu/javax/crypto/jce/cipher/DESSpi.java
|
|||
icedtea/jce/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/cipher/KhazadSpi.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/cipher/NullCipherSpi.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/cipher/PBE.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/cipher/PBES2.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/cipher/RijndaelSpi.java
|
||||
icedtea/jce/gnu/javax/crypto/jce/cipher/SerpentSpi.java
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/* CertBundleKeyStoreImpl.java
|
||||
Copyright (C) 2007 Casey Marshall <csm@gnu.org>
|
||||
|
||||
This file is part of IcedTea.
|
||||
|
||||
IcedTea is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, version 2.
|
||||
|
||||
IcedTea is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with IcedTea; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.security.icedtea;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.KeyStoreSpi;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* A key store implementation for "certificate bundle" files, commonly used
|
||||
* on many free operating systems. Certificate bundles are plain text files
|
||||
* containing one or more "PEM" encoded X.509 certificates, which comprise
|
||||
* a list of trusted root certificates.
|
||||
*
|
||||
* This class implements a read-only key store that reads in one or more
|
||||
* certificate bundles, storing all certificates successfully read. Calling
|
||||
* load multiple times will add certificates to the store.
|
||||
*
|
||||
* @author Casey Marshall (csm@gnu.org)
|
||||
*/
|
||||
public class CertBundleKeyStoreImpl extends KeyStoreSpi
|
||||
{
|
||||
private int x = 0;
|
||||
private Map<String, Certificate> certs = new HashMap<String, Certificate>();
|
||||
|
||||
@Override public Enumeration<String> engineAliases()
|
||||
{
|
||||
return new Vector<String>(certs.keySet()).elements();
|
||||
}
|
||||
|
||||
@Override public boolean engineContainsAlias(String alias)
|
||||
{
|
||||
return certs.containsKey(alias);
|
||||
}
|
||||
|
||||
@Override public void engineDeleteEntry(String alias) throws KeyStoreException
|
||||
{
|
||||
certs.remove(alias);
|
||||
}
|
||||
|
||||
@Override public Certificate engineGetCertificate(String alias)
|
||||
{
|
||||
return certs.get(alias);
|
||||
}
|
||||
|
||||
@Override public String engineGetCertificateAlias(Certificate cert)
|
||||
{
|
||||
for (Map.Entry<String, Certificate> e : certs.entrySet())
|
||||
{
|
||||
if (e.getValue().equals(cert))
|
||||
return e.getKey();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public Certificate[] engineGetCertificateChain(String arg0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public Date engineGetCreationDate(String alias)
|
||||
{
|
||||
return new Date(0);
|
||||
}
|
||||
|
||||
@Override public Key engineGetKey(String arg0, char[] arg1)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public boolean engineIsCertificateEntry(String alias)
|
||||
{
|
||||
return certs.containsKey(alias);
|
||||
}
|
||||
|
||||
@Override public boolean engineIsKeyEntry(String arg0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public void engineLoad(InputStream in, char[] arg1)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
PrintWriter out = new PrintWriter(new OutputStreamWriter(bout));
|
||||
BufferedReader rin = new BufferedReader(new InputStreamReader(in));
|
||||
String line;
|
||||
boolean push = false;
|
||||
while ((line = rin.readLine()) != null)
|
||||
{
|
||||
if (line.equals("-----BEGIN CERTIFICATE-----"))
|
||||
{
|
||||
push = true;
|
||||
out.println(line);
|
||||
}
|
||||
else if (push)
|
||||
{
|
||||
out.println(line);
|
||||
if (line.equals("-----END CERTIFICATE-----"))
|
||||
{
|
||||
push = false;
|
||||
out.flush();
|
||||
byte[] bytes = bout.toByteArray();
|
||||
Certificate cert = cf.generateCertificate(new ByteArrayInputStream(bytes));
|
||||
bout.reset();
|
||||
String alias = "cert-" + (x++);
|
||||
certs.put(alias, cert);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void engineSetCertificateEntry(String alias, Certificate cert)
|
||||
throws KeyStoreException
|
||||
{
|
||||
certs.put(alias, cert);
|
||||
}
|
||||
|
||||
@Override public void engineSetKeyEntry(String arg0, byte[] arg1,
|
||||
Certificate[] arg2)
|
||||
throws KeyStoreException
|
||||
{
|
||||
throw new KeyStoreException("not supported");
|
||||
}
|
||||
|
||||
@Override public void engineSetKeyEntry(String arg0, Key arg1, char[] arg2,
|
||||
Certificate[] arg3)
|
||||
throws KeyStoreException
|
||||
{
|
||||
throw new KeyStoreException("not supported");
|
||||
}
|
||||
|
||||
@Override public int engineSize()
|
||||
{
|
||||
return certs.size();
|
||||
}
|
||||
|
||||
@Override public void engineStore(OutputStream arg0, char[] arg1)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
throw new UnsupportedOperationException("read-only key stores");
|
||||
}
|
||||
}
|
|
@ -48,9 +48,13 @@ public class IcedTls extends Provider
|
|||
{
|
||||
super("IcedTls", 1.0, "Free replacements for encumbered Sun sources for TLS");
|
||||
|
||||
// Key generators for Sun's JSSE.
|
||||
put("KeyGenerator.SunTlsRsaPremasterSecret", GNUTlsRsaPreMasterSecretGeneratorImpl.class.getName());
|
||||
put("KeyGenerator.SunTlsMasterSecret", GNUTlsMasterSecretGenerator.class.getName());
|
||||
put("KeyGenerator.SunTlsKeyMaterial", GNUTlsKeyMaterialGeneratorImpl.class.getName());
|
||||
put("KeyGenerator.SunTlsPrf", GNUTlsPrfGeneratorImpl.class.getName());
|
||||
|
||||
// Certificate bundle key store.
|
||||
put("KeyStore.CertBundle", CertBundleKeyStoreImpl.class.getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,8 +94,54 @@ public final class DiffieHellmanImpl
|
|||
DHPublicKey pub = (DHPublicKey) incoming;
|
||||
DHParameterSpec s1 = key.getParams();
|
||||
DHParameterSpec s2 = pub.getParams();
|
||||
if (! s1.getG().equals(s2.getG()) || ! s1.getP().equals(s2.getP())
|
||||
|| s1.getL() != s2.getL())
|
||||
|
||||
/* ICEDTEA LOCAL: This change is not committed to Classpath because
|
||||
it's still waiting a response from Casey Marshall <csm@gnu.org>,
|
||||
the author.
|
||||
|
||||
From: Andrew Haley <aph-gcc@littlepinkcloud.COM>
|
||||
To: Casey Marshall <csm@gnu.org>, classpath-patches@gnu.org
|
||||
CC: Lillian Angel <langel@redhat.com>
|
||||
Subject: Fix DiffieHellmanImpl.java
|
||||
Date: Fri, 3 Aug 2007 18:19:07 +0100
|
||||
|
||||
I came across a problem with GNU Crypto that causes Diffie-Hellman key
|
||||
exchange to fail when running on IcedTea. We're doing what looks to
|
||||
me like an unnecessary check in DiffieHellmanImpl.engineDoPhase()
|
||||
which can fail in some circumstances, and this is triggered when
|
||||
running in IcedTea. The code runs correctly on Sun's Java 1.7, not on
|
||||
the IcedTea version of Java 1.7, which uses GNU Crypto.
|
||||
|
||||
With IcedTea and Classpath we get:
|
||||
|
||||
Exception in thread "main" java.security.InvalidKeyException: Incompatible key
|
||||
at gnu.javax.crypto.jce.DiffieHellmanImpl.engineDoPhase(DiffieHellmanImpl.java:99)
|
||||
at javax.crypto.KeyAgreement.doPhase(KeyAgreement.java:224)
|
||||
at Tt.main(Tt.java:35)
|
||||
|
||||
Here's my patch:
|
||||
|
||||
2007-08-03 Andrew Haley <aph@redhat.com>
|
||||
|
||||
* jce/gnu/javax/crypto/jce/DiffieHellmanImpl.java (engineDoPhase):
|
||||
Don't check the length of q.
|
||||
|
||||
--- gnu/javax/crypto/jce/DiffieHellmanImpl.java~ 2007-07-23 14:15:36.000000000 +0100
|
||||
+++ gnu/javax/crypto/jce/DiffieHellmanImpl.java 2007-08-03 17:49:09.000000000 +0100
|
||||
@@ -94,8 +94,7 @@
|
||||
DHPublicKey pub = (DHPublicKey) incoming;
|
||||
DHParameterSpec s1 = key.getParams();
|
||||
DHParameterSpec s2 = pub.getParams();
|
||||
- if (! s1.getG().equals(s2.getG()) || ! s1.getP().equals(s2.getP())
|
||||
- || s1.getL() != s2.getL())
|
||||
+ if (! s1.getG().equals(s2.getG()) || ! s1.getP().equals(s2.getP()))
|
||||
throw new InvalidKeyException("Incompatible key");
|
||||
if (! lastPhase)
|
||||
throw new IllegalArgumentException(
|
||||
|
||||
*/
|
||||
|
||||
if (! s1.getG().equals(s2.getG()) || ! s1.getP().equals(s2.getP()))
|
||||
throw new InvalidKeyException("Incompatible key");
|
||||
if (! lastPhase)
|
||||
throw new IllegalArgumentException(
|
||||
|
|
|
@ -316,6 +316,9 @@ public final class GnuCrypto
|
|||
gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.TripleDES.class.getName());
|
||||
put("Cipher.PBEWithHMacWhirlpoolAndTwofish",
|
||||
gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Twofish.class.getName());
|
||||
put("Cipher.PBE",
|
||||
gnu.javax.crypto.jce.cipher.PBE.MD5.DES.class.getName());
|
||||
put("Alg.Alias.Cipher.PBEWithMD5AndDES", "PBE");
|
||||
|
||||
// Key Wrapping Algorithm cipher
|
||||
put("Cipher." + Registry.AES128_KWA,
|
||||
|
@ -348,6 +351,10 @@ public final class GnuCrypto
|
|||
gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacTiger.class.getName());
|
||||
put("SecretKeyFactory.PBKDF2WithHMacWhirlpool",
|
||||
gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacWhirlpool.class.getName());
|
||||
put("SecretKeyFactory.PBEWithMD5AndDES",
|
||||
gnu.javax.crypto.jce.PBESecretKeyFactory.class.getName());
|
||||
|
||||
put("Alg.Alias.AlgorithmParameters.PBEWithMD5AndDES", "PBEWithMD5AndDES");
|
||||
|
||||
// Simple SecretKeyFactory implementations.
|
||||
put("SecretKeyFactory.Anubis",
|
||||
|
@ -553,7 +560,7 @@ public final class GnuCrypto
|
|||
put("KeyFactory.DH",
|
||||
gnu.javax.crypto.jce.sig.DHKeyFactory.class.getName());
|
||||
|
||||
put("Alg.Alias,KeyFactory.DiffieHellman", "DH");
|
||||
put("Alg.Alias.KeyFactory.DiffieHellman", "DH");
|
||||
|
||||
// Algorithm Parameters -----------------------------------------------
|
||||
put("AlgorithmParameters.DH",
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/* PBESecretKeyFactory.java --
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
This file is a part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
|
||||
USA
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are 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.javax.crypto.key.GnuPBEKey;
|
||||
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactorySpi;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
|
||||
public class PBESecretKeyFactory
|
||||
extends SecretKeyFactorySpi
|
||||
{
|
||||
protected String name;
|
||||
|
||||
public PBESecretKeyFactory()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
protected PBESecretKeyFactory(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected SecretKey engineGenerateSecret(KeySpec spec)
|
||||
throws InvalidKeySpecException
|
||||
{
|
||||
if (! (spec instanceof PBEKeySpec))
|
||||
throw new InvalidKeySpecException("not a PBEKeySpec");
|
||||
return new GnuPBEKey((PBEKeySpec) spec);
|
||||
}
|
||||
|
||||
protected KeySpec engineGetKeySpec(SecretKey key, Class clazz)
|
||||
throws InvalidKeySpecException
|
||||
{
|
||||
throw new InvalidKeySpecException("not supported");
|
||||
}
|
||||
|
||||
protected SecretKey engineTranslateKey(SecretKey key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -406,23 +406,23 @@ class CipherAdapter
|
|||
return 0;
|
||||
final int blockSize = mode.currentBlockSize();
|
||||
int blockCount = (partLen + inLen) / blockSize;
|
||||
|
||||
// always keep data for unpadding in padded decryption mode;
|
||||
// might even be a complete block
|
||||
if (pad != null
|
||||
&& ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION
|
||||
&& (partLen + inLen) % blockSize == 0)
|
||||
blockCount--;
|
||||
|
||||
final int result = blockCount * blockSize;
|
||||
if (result > out.length - outOff)
|
||||
throw new ShortBufferException();
|
||||
|
||||
if (blockCount == 0) // not enough bytes for even 1 block
|
||||
{
|
||||
System.arraycopy(in, inOff, partBlock, partLen, inLen);
|
||||
partLen += inLen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
final byte[] buf;
|
||||
// we have enough bytes for at least 1 block
|
||||
if (partLen == 0) // if no cached bytes use input
|
||||
|
@ -435,12 +435,14 @@ class CipherAdapter
|
|||
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);
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
/* PBE.java --
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
This file is a part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
|
||||
USA
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are 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 gnu.javax.crypto.key.GnuPBEKey;
|
||||
import gnu.javax.crypto.mode.BaseMode;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.PBEParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
*/
|
||||
public abstract class PBE
|
||||
extends CipherAdapter
|
||||
{
|
||||
MessageDigest hash;
|
||||
|
||||
protected PBE(String cipherName, String hashName)
|
||||
{
|
||||
super(cipherName);
|
||||
try
|
||||
{
|
||||
this.hash = MessageDigest.getInstance(hashName);
|
||||
}
|
||||
catch (NoSuchAlgorithmException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
protected void engineInit(int opmode, Key key, SecureRandom random)
|
||||
throws InvalidKeyException
|
||||
{
|
||||
if (! (key instanceof GnuPBEKey))
|
||||
throw new InvalidKeyException("not a GNU PBE key");
|
||||
GnuPBEKey k = (GnuPBEKey) key;
|
||||
int c1 = k.getIterationCount();
|
||||
byte[] s1 = k.getSalt();
|
||||
PBEPKCS5_V1Params pkcs5 = genParams(c1, s1, k.getPassword());
|
||||
initInternal(opmode, pkcs5.skSpec, pkcs5.ivSpec, random);
|
||||
}
|
||||
|
||||
protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
|
||||
SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException
|
||||
{
|
||||
if (! (key instanceof GnuPBEKey))
|
||||
throw new InvalidKeyException("not a GNU PBE key");
|
||||
GnuPBEKey k = (GnuPBEKey) key;
|
||||
int c1 = k.getIterationCount();
|
||||
byte[] s1 = k.getSalt();
|
||||
if (params != null)
|
||||
{
|
||||
if (! (params instanceof PBEParameterSpec))
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"The algorithm-parameter-spec, when not null, MUST be of type "
|
||||
+ "PBEParameterSpec or one of its subclasses");
|
||||
PBEParameterSpec ps = (PBEParameterSpec) params;
|
||||
// it must share the same salt and iteration count as the secret key
|
||||
int c2 = ps.getIterationCount();
|
||||
if (c1 == 0)
|
||||
c1 = c2;
|
||||
else if (c1 != c2)
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"The algorithm-parameter-spec and the key MUST share the same "
|
||||
+ "iteration count");
|
||||
byte[] s2 = ps.getSalt();
|
||||
// salt may be unspecified
|
||||
if (s1 == null)
|
||||
s1 = s2;
|
||||
else if ((s1 != null && s1.length > 0 && s2 == null)
|
||||
|| (s1 == null && s2 != null && s2.length > 0)
|
||||
|| (s1 != null && s2 != null && !Arrays.equals(s1, s2)))
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"The algorithm-parameter-spec and the key MUST share the same salt");
|
||||
}
|
||||
PBEPKCS5_V1Params pkcs5 = genParams(c1, s1, k.getPassword());
|
||||
initInternal(opmode, pkcs5.skSpec, pkcs5.ivSpec, random);
|
||||
}
|
||||
|
||||
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
|
||||
SecureRandom random) throws InvalidKeyException,
|
||||
InvalidAlgorithmParameterException
|
||||
{
|
||||
if (! (key instanceof GnuPBEKey))
|
||||
throw new InvalidKeyException("not a GNU PBE key");
|
||||
GnuPBEKey k = (GnuPBEKey) key;
|
||||
int c1 = k.getIterationCount();
|
||||
byte[] s1 = k.getSalt();
|
||||
if (params != null)
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"We [MUST] supply our own algorithm-parameter");
|
||||
PBEPKCS5_V1Params pkcs5 = genParams(c1, s1, k.getPassword());
|
||||
initInternal(opmode, pkcs5.skSpec, pkcs5.ivSpec, random);
|
||||
}
|
||||
|
||||
private void initInternal(int opmode, SecretKeySpec key,
|
||||
BlockCipherParameterSpec params,
|
||||
SecureRandom random) throws InvalidKeyException
|
||||
{
|
||||
try {
|
||||
super.engineInit(opmode, key, params, random);
|
||||
} catch (InvalidAlgorithmParameterException x) {
|
||||
// this should not happen since 'params' is generated by us with
|
||||
// the genParams() method. if it does re-throw as IKE
|
||||
throw new InvalidKeyException(x);
|
||||
}
|
||||
}
|
||||
|
||||
private PBEPKCS5_V1Params genParams(int c, byte[] s, char[] password)
|
||||
throws InvalidKeyException
|
||||
{
|
||||
// transform the password's chars into bytes assuming UTF-8
|
||||
byte[] p;
|
||||
try {
|
||||
p = new String(password).getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException x) {
|
||||
throw new InvalidKeyException(x);
|
||||
}
|
||||
|
||||
String name = cipher.name();
|
||||
int blockSize = cipher.defaultBlockSize();
|
||||
int keySize = cipher.defaultKeySize();
|
||||
int hashSize = this.hash.getDigestLength();
|
||||
Integer att_ivSize = (Integer) attributes.get(mode.MODE_BLOCK_SIZE);
|
||||
int ivSize = (att_ivSize == null ? blockSize : att_ivSize.intValue());
|
||||
|
||||
// digest once
|
||||
this.hash.update(p);
|
||||
byte[] buffer = s == null ? this.hash.digest() : this.hash.digest(s);
|
||||
|
||||
// and now complete the remaining iterations
|
||||
for (int i = 1; i < c; i++)
|
||||
buffer = this.hash.digest(buffer);
|
||||
|
||||
PBEPKCS5_V1Params result = new PBEPKCS5_V1Params();
|
||||
result.skSpec = new SecretKeySpec(buffer, 0, blockSize, name.substring(0, name.indexOf('-')));
|
||||
byte[] iv = new byte[ivSize];
|
||||
System.arraycopy(buffer, blockSize, iv, 0, hashSize - blockSize);
|
||||
result.ivSpec = new BlockCipherParameterSpec(iv, blockSize, keySize);
|
||||
return result;
|
||||
}
|
||||
|
||||
static class PBEPKCS5_V1Params {
|
||||
SecretKeySpec skSpec;
|
||||
BlockCipherParameterSpec ivSpec;
|
||||
}
|
||||
|
||||
public static class MD5
|
||||
extends PBE
|
||||
{
|
||||
public MD5(String cipher)
|
||||
{
|
||||
super(cipher, "MD5");
|
||||
}
|
||||
|
||||
public static class DES
|
||||
extends MD5
|
||||
{
|
||||
public DES()
|
||||
{
|
||||
// we really need a DES/CBC/PKCS5 combined padded block cipher
|
||||
super(Registry.DES_CIPHER);
|
||||
|
||||
// the superclass's field 'cipher' has a plain DES-ECB so we need to
|
||||
// change its mode and padding
|
||||
try {
|
||||
this.engineSetMode(Registry.CBC_MODE);
|
||||
} catch (NoSuchAlgorithmException ignored) {
|
||||
ignored.printStackTrace(System.err);
|
||||
}
|
||||
try {
|
||||
this.engineSetPadding(Registry.PKCS5_PAD);
|
||||
} catch (NoSuchPaddingException ignored) {
|
||||
ignored.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -85,11 +85,12 @@ public class GnuPBEKey
|
|||
|
||||
public String getFormat ()
|
||||
{
|
||||
return "NONE"; // FIXME?
|
||||
return "RAW";
|
||||
}
|
||||
|
||||
public byte[] getEncoded ()
|
||||
{
|
||||
return null; // FIXME?
|
||||
String pass = new String(getPassword());
|
||||
return pass.getBytes();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,10 @@ public class PBEKeySpec implements KeySpec
|
|||
*/
|
||||
public PBEKeySpec(char[] password)
|
||||
{
|
||||
setPassword(password);
|
||||
if (password == null)
|
||||
password = new char[0];
|
||||
|
||||
setPassword(password.clone());
|
||||
|
||||
// load the default values for unspecified variables.
|
||||
salt = null;
|
||||
|
@ -114,8 +117,12 @@ public class PBEKeySpec implements KeySpec
|
|||
*/
|
||||
public PBEKeySpec(char[] password, byte[] salt, int iterationCount)
|
||||
{
|
||||
setPassword(password);
|
||||
setSalt(salt);
|
||||
if (password == null)
|
||||
password = new char[0];
|
||||
|
||||
setPassword(password.clone());
|
||||
|
||||
setSalt(salt.clone());
|
||||
setIterationCount(iterationCount);
|
||||
|
||||
// load default values into unspecified variables.
|
||||
|
@ -140,8 +147,12 @@ public class PBEKeySpec implements KeySpec
|
|||
public PBEKeySpec(char[] password, byte[] salt, int iterationCount,
|
||||
int keyLength)
|
||||
{
|
||||
setPassword(password);
|
||||
setSalt(salt);
|
||||
if (password == null)
|
||||
password = new char[0];
|
||||
|
||||
setPassword(password.clone());
|
||||
|
||||
setSalt(salt.clone());
|
||||
setIterationCount(iterationCount);
|
||||
setKeyLength(keyLength);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче