Extracted out crypto classes. Added PGP handling
This commit is contained in:
parent
7388a8efb7
commit
88ccf24895
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
package dorkbox.util.crypto;
|
package dorkbox.util.crypto;
|
||||||
|
|
||||||
// Copyright (c) 2006 Damien Miller <djm@mindrot.org>
|
// Copyright (c) 2006 Damien Miller <djm@mindrot.org>
|
||||||
|
@ -16,11 +16,14 @@
|
|||||||
package dorkbox.util.crypto;
|
package dorkbox.util.crypto;
|
||||||
|
|
||||||
|
|
||||||
|
import com.twmacinta.util.MD5;
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
import dorkbox.util.bytes.LittleEndian;
|
import dorkbox.util.bytes.LittleEndian;
|
||||||
import org.bouncycastle.crypto.Digest;
|
import org.bouncycastle.crypto.Digest;
|
||||||
import org.bouncycastle.crypto.PBEParametersGenerator;
|
import org.bouncycastle.crypto.PBEParametersGenerator;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA1Digest;
|
||||||
import org.bouncycastle.crypto.digests.SHA256Digest;
|
import org.bouncycastle.crypto.digests.SHA256Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA512Digest;
|
||||||
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
|
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
|
||||||
import org.bouncycastle.crypto.params.KeyParameter;
|
import org.bouncycastle.crypto.params.KeyParameter;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
@ -57,6 +60,15 @@ import java.util.jar.JarFile;
|
|||||||
public final
|
public final
|
||||||
class Crypto {
|
class Crypto {
|
||||||
|
|
||||||
|
private
|
||||||
|
Crypto() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// CUSTOM_HEADER USE
|
||||||
|
// check to see if our extra data is OURS. if so, process it
|
||||||
|
// cafeʞ, as UN signed bytes is: [254, 202, 202, 158], or as hex: FECA CA9E
|
||||||
|
// cafeʞ, as signed bytes is: [-2, -54, -54, -98]
|
||||||
|
private static final byte[] CUSTOM_HEADER = new byte[] {(byte) -2, (byte) -54, (byte) -54, (byte) -98};
|
||||||
|
|
||||||
public static
|
public static
|
||||||
void addProvider() {
|
void addProvider() {
|
||||||
@ -67,16 +79,34 @@ class Crypto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
|
||||||
Crypto() {
|
public static
|
||||||
|
byte[] hashFileMD5(File file) {
|
||||||
|
try {
|
||||||
|
return MD5.getHash(file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
byte[] hashFileSHA1(File file) {
|
||||||
|
SHA1Digest digest = new SHA1Digest();
|
||||||
|
return hashFile(file, digest, null);
|
||||||
|
}
|
||||||
|
|
||||||
public static final
|
public static
|
||||||
class Util {
|
byte[] hashFileSHA256(File file) {
|
||||||
|
SHA256Digest digest = new SHA256Digest();
|
||||||
|
return hashFile(file, digest, null);
|
||||||
|
}
|
||||||
|
|
||||||
// CUSTOM_HEADER USE
|
public static
|
||||||
private static final byte[] CUSTOM_HEADER = new byte[] {(byte) -2, (byte) -54, (byte) -54, (byte) -98};
|
byte[] hashFileSHA512(File file) {
|
||||||
|
SHA512Digest digest = new SHA512Digest();
|
||||||
|
return hashFile(file, digest, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the hash of the file or NULL if file is invalid
|
* Return the hash of the file or NULL if file is invalid
|
||||||
@ -140,6 +170,8 @@ class Crypto {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (logger != null) {
|
if (logger != null) {
|
||||||
logger.error("Error hashing file: {}", file.getAbsolutePath(), e);
|
logger.error("Error hashing file: {}", file.getAbsolutePath(), e);
|
||||||
|
} else {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (inputStream != null) {
|
if (inputStream != null) {
|
||||||
@ -300,7 +332,7 @@ class Crypto {
|
|||||||
public static
|
public static
|
||||||
byte[] PBKDF2(char[] password, byte[] salt, int iterationCount) {
|
byte[] PBKDF2(char[] password, byte[] salt, int iterationCount) {
|
||||||
// will also zero out the password.
|
// will also zero out the password.
|
||||||
byte[] charToBytes = Crypto.Util.charToBytesPassword(password);
|
byte[] charToBytes = Crypto.charToBytesPassword_UTF16(password);
|
||||||
|
|
||||||
return PBKDF2(charToBytes, salt, iterationCount);
|
return PBKDF2(charToBytes, salt, iterationCount);
|
||||||
}
|
}
|
||||||
@ -335,7 +367,7 @@ class Crypto {
|
|||||||
* this saves the char array in UTF-16 format of bytes and BLANKS out the password char array.
|
* this saves the char array in UTF-16 format of bytes and BLANKS out the password char array.
|
||||||
*/
|
*/
|
||||||
public static
|
public static
|
||||||
byte[] charToBytesPassword(char[] password) {
|
byte[] charToBytesPassword_UTF16(char[] password) {
|
||||||
// note: this saves the char array in UTF-16 format of bytes.
|
// note: this saves the char array in UTF-16 format of bytes.
|
||||||
byte[] passwordBytes = new byte[password.length * 2];
|
byte[] passwordBytes = new byte[password.length * 2];
|
||||||
for (int i = 0; i < password.length; i++) {
|
for (int i = 0; i < password.length; i++) {
|
||||||
@ -351,9 +383,4 @@ class Crypto {
|
|||||||
return passwordBytes;
|
return passwordBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private
|
|
||||||
Util() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
package dorkbox.util.crypto;
|
package dorkbox.util.crypto;
|
||||||
|
|
||||||
import org.bouncycastle.crypto.BufferedBlockCipher;
|
import org.bouncycastle.crypto.BufferedBlockCipher;
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
package dorkbox.util.crypto;
|
package dorkbox.util.crypto;
|
||||||
|
|
||||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
package dorkbox.util.crypto;
|
package dorkbox.util.crypto;
|
||||||
|
|
||||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||||
|
815
Dorkbox-Util/src/dorkbox/util/crypto/CryptoPGP.java
Normal file
815
Dorkbox-Util/src/dorkbox/util/crypto/CryptoPGP.java
Normal file
@ -0,0 +1,815 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.util.crypto;
|
||||||
|
|
||||||
|
import dorkbox.util.OS;
|
||||||
|
import dorkbox.util.Sys;
|
||||||
|
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||||
|
import org.bouncycastle.bcpg.BCPGOutputStream;
|
||||||
|
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
|
||||||
|
import org.bouncycastle.openpgp.*;
|
||||||
|
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder;
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PGP crypto related methods
|
||||||
|
*/
|
||||||
|
public final
|
||||||
|
class CryptoPGP {
|
||||||
|
private static final BcPGPDigestCalculatorProvider digestCalculatorProvider = new BcPGPDigestCalculatorProvider();
|
||||||
|
private static final BcKeyFingerprintCalculator fingerprintCalculator = new BcKeyFingerprintCalculator();
|
||||||
|
|
||||||
|
|
||||||
|
// https://github.com/weiliatgithub/bouncycastle-gpg-exampleC
|
||||||
|
// https://gist.github.com/turingbirds/3df43f1920a98010667a
|
||||||
|
// http://sloanseaman.com/wordpress/2012/05/13/revisited-pgp-encryptiondecryption-in-java/
|
||||||
|
// http://bouncycastle-pgp-cookbook.blogspot.de/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a message using our private PGP key file, this matches gpg -ab "hello.txt"
|
||||||
|
*
|
||||||
|
* @param privateKeyInputStream
|
||||||
|
* this is an armored key file, not a binary stream
|
||||||
|
* @param userId
|
||||||
|
* this is the userID to get out of the private key
|
||||||
|
* @param password
|
||||||
|
* this is the password to unlock the private key
|
||||||
|
* @param messageAsUtf8Bytes
|
||||||
|
* this is the message, in bytes, to sign
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
byte[] signGpgCompatible(InputStream privateKeyInputStream, String userId, char[] password, byte[] messageAsUtf8Bytes)
|
||||||
|
throws PGPException {
|
||||||
|
|
||||||
|
// the signature type (in gpg terms), is "sigclass". gpg is BINARY_DOC (0x00)
|
||||||
|
return sign(privateKeyInputStream,
|
||||||
|
userId,
|
||||||
|
password,
|
||||||
|
new ByteArrayInputStream(messageAsUtf8Bytes),
|
||||||
|
PGPSignature.BINARY_DOCUMENT,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a message using our private PGP key file, this matches gpg -ab "hello.txt"
|
||||||
|
*
|
||||||
|
* @param privateKeyInputStream
|
||||||
|
* this is an armored key file, not a binary stream
|
||||||
|
* @param userId
|
||||||
|
* this is the userID to get out of the private key
|
||||||
|
* @param password
|
||||||
|
* this is the password to unlock the private key
|
||||||
|
* @param message
|
||||||
|
* this is the message to sign
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
byte[] signGpgCompatible(InputStream privateKeyInputStream, String userId, char[] password, InputStream message)
|
||||||
|
throws PGPException {
|
||||||
|
|
||||||
|
// the signature type (in gpg terms), is "sigclass". gpg is BINARY_DOC (0x00)
|
||||||
|
return sign(privateKeyInputStream,
|
||||||
|
userId,
|
||||||
|
password,
|
||||||
|
message,
|
||||||
|
PGPSignature.BINARY_DOCUMENT,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a message using our private PGP key file, this matches gpg -ab "hello.txt". This will save the signature of the passed-in
|
||||||
|
* file to file name + .asc
|
||||||
|
*
|
||||||
|
* @param privateKeyInputStream
|
||||||
|
* this is an armored key file, not a binary stream
|
||||||
|
* @param userId
|
||||||
|
* this is the userID to get out of the private key
|
||||||
|
* @param password
|
||||||
|
* this is the password to unlock the private key
|
||||||
|
* @param file
|
||||||
|
* this is the file to sign
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
void signGpgCompatible(InputStream privateKeyInputStream, String userId, char[] password, File file)
|
||||||
|
throws PGPException {
|
||||||
|
|
||||||
|
// the signature type (in gpg terms), is "sigclass". gpg is BINARY_DOC (0x00)
|
||||||
|
final byte[] sign = sign(privateKeyInputStream,
|
||||||
|
userId,
|
||||||
|
password,
|
||||||
|
file,
|
||||||
|
PGPSignature.BINARY_DOCUMENT,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false);
|
||||||
|
|
||||||
|
FileOutputStream fileOutputStream1 = null;
|
||||||
|
try {
|
||||||
|
fileOutputStream1 = new FileOutputStream(new File(file.getAbsolutePath() + ".asc"));
|
||||||
|
fileOutputStream1.write(sign);
|
||||||
|
fileOutputStream1.flush();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new PGPException("Unable to save signature to file " + file.getAbsolutePath() + ".asc", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PGPException("Unable to save signature to file " + file.getAbsolutePath() + ".asc", e);
|
||||||
|
} finally {
|
||||||
|
Sys.close(fileOutputStream1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a message using our private PGP key file, with a variety of options
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
|
public static
|
||||||
|
byte[] sign(InputStream privateKeyInputStream,
|
||||||
|
String userId,
|
||||||
|
char[] password,
|
||||||
|
InputStream message,
|
||||||
|
int signatureType,
|
||||||
|
boolean compressSignature,
|
||||||
|
boolean asciiArmoredOutput,
|
||||||
|
boolean includeDataInSignature,
|
||||||
|
boolean generateUserIdSubPacket,
|
||||||
|
boolean generateOnePassVersion) throws PGPException {
|
||||||
|
|
||||||
|
List<PGPSecretKey> secretKeys = getSecretKeys(privateKeyInputStream, userId);
|
||||||
|
PGPSignatureGenerator signature = createSignature(secretKeys, password, signatureType, generateUserIdSubPacket);
|
||||||
|
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
OutputStream outputStream = byteArrayOutputStream;
|
||||||
|
if (asciiArmoredOutput) {
|
||||||
|
outputStream = new ArmoredOutputStream(byteArrayOutputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPCompressedDataGenerator compressedDataGenerator = null;
|
||||||
|
BCPGOutputStream bcOutputStream;
|
||||||
|
|
||||||
|
if (compressSignature) {
|
||||||
|
compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
|
||||||
|
try {
|
||||||
|
bcOutputStream = new BCPGOutputStream(compressedDataGenerator.open(outputStream));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PGPException("Unable to open compression stream in the signature", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bcOutputStream = new BCPGOutputStream(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generateOnePassVersion) {
|
||||||
|
try {
|
||||||
|
signature.generateOnePassVersion(false)
|
||||||
|
.encode(bcOutputStream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PGPException("Unable to generate OnePass signature header", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPLiteralDataGenerator literalDataGenerator = null;
|
||||||
|
OutputStream literalDataOutput = null;
|
||||||
|
|
||||||
|
if (includeDataInSignature) {
|
||||||
|
literalDataGenerator = new PGPLiteralDataGenerator();
|
||||||
|
try {
|
||||||
|
literalDataOutput = literalDataGenerator.open(bcOutputStream,
|
||||||
|
PGPLiteralData.BINARY,
|
||||||
|
"_CONSOLE",
|
||||||
|
message.available(),
|
||||||
|
new Date());
|
||||||
|
} catch (IOException e1) {
|
||||||
|
throw new PGPException("Unable to generate Literal Data signature header", e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int read;
|
||||||
|
|
||||||
|
// update bytes in the streams
|
||||||
|
if (literalDataOutput != null) {
|
||||||
|
while ((read = message.read(buffer)) > 0) {
|
||||||
|
literalDataOutput.write(buffer, 0, read);
|
||||||
|
signature.update(buffer, 0, read);
|
||||||
|
}
|
||||||
|
literalDataOutput.flush();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
while ((read = message.read(buffer)) > 0) {
|
||||||
|
signature.update(buffer, 0, read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// close generators and update signature
|
||||||
|
if (literalDataGenerator != null) {
|
||||||
|
literalDataGenerator.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
signature.generate()
|
||||||
|
.encode(bcOutputStream);
|
||||||
|
|
||||||
|
|
||||||
|
if (compressedDataGenerator != null) {
|
||||||
|
compressedDataGenerator.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
Sys.close(bcOutputStream);
|
||||||
|
Sys.close(outputStream);
|
||||||
|
Sys.close(literalDataOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
return byteArrayOutputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a message using our private PGP key file, with a variety of options
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
|
public static
|
||||||
|
byte[] sign(InputStream privateKeyInputStream,
|
||||||
|
String userId,
|
||||||
|
char[] password,
|
||||||
|
File fileMessage,
|
||||||
|
int signatureType,
|
||||||
|
boolean compressSignature,
|
||||||
|
boolean asciiArmoredOutput,
|
||||||
|
boolean includeDataInSignature,
|
||||||
|
boolean generateUserIdSubPacket,
|
||||||
|
boolean generateOnePassVersion) throws PGPException {
|
||||||
|
|
||||||
|
List<PGPSecretKey> secretKeys = getSecretKeys(privateKeyInputStream, userId);
|
||||||
|
PGPSignatureGenerator signature = createSignature(secretKeys, password, signatureType, generateUserIdSubPacket);
|
||||||
|
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
OutputStream outputStream = byteArrayOutputStream;
|
||||||
|
if (asciiArmoredOutput) {
|
||||||
|
outputStream = new ArmoredOutputStream(byteArrayOutputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPCompressedDataGenerator compressedDataGenerator = null;
|
||||||
|
BCPGOutputStream bcOutputStream;
|
||||||
|
|
||||||
|
if (compressSignature) {
|
||||||
|
compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
|
||||||
|
try {
|
||||||
|
bcOutputStream = new BCPGOutputStream(compressedDataGenerator.open(outputStream));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PGPException("Unable to open compression stream in the signature", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bcOutputStream = new BCPGOutputStream(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generateOnePassVersion) {
|
||||||
|
try {
|
||||||
|
signature.generateOnePassVersion(false)
|
||||||
|
.encode(bcOutputStream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PGPException("Unable to generate OnePass signature header", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPLiteralDataGenerator literalDataGenerator = null;
|
||||||
|
OutputStream literalDataOutput = null;
|
||||||
|
|
||||||
|
if (includeDataInSignature) {
|
||||||
|
literalDataGenerator = new PGPLiteralDataGenerator();
|
||||||
|
try {
|
||||||
|
literalDataOutput = literalDataGenerator.open(bcOutputStream,
|
||||||
|
PGPLiteralData.BINARY,
|
||||||
|
fileMessage);
|
||||||
|
} catch (IOException e1) {
|
||||||
|
throw new PGPException("Unable to generate Literal Data signature header", e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final FileInputStream fileInputStream = new FileInputStream(fileMessage);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int read;
|
||||||
|
|
||||||
|
// update bytes in the streams
|
||||||
|
if (literalDataOutput != null) {
|
||||||
|
while ((read = fileInputStream.read(buffer)) > 0) {
|
||||||
|
literalDataOutput.write(buffer, 0, read);
|
||||||
|
signature.update(buffer, 0, read);
|
||||||
|
}
|
||||||
|
literalDataOutput.flush();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
while ((read = fileInputStream.read(buffer)) > 0) {
|
||||||
|
signature.update(buffer, 0, read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// close generators and update signature
|
||||||
|
if (literalDataGenerator != null) {
|
||||||
|
literalDataGenerator.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
signature.generate()
|
||||||
|
.encode(bcOutputStream);
|
||||||
|
|
||||||
|
|
||||||
|
if (compressedDataGenerator != null) {
|
||||||
|
compressedDataGenerator.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
Sys.close(bcOutputStream);
|
||||||
|
Sys.close(outputStream);
|
||||||
|
Sys.close(literalDataOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
return byteArrayOutputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find private gpg key in InputStream, also closes the input stream
|
||||||
|
*
|
||||||
|
* @param inputStream
|
||||||
|
* the inputStream that contains the private (secret) key
|
||||||
|
* @param userId
|
||||||
|
* the user id
|
||||||
|
*
|
||||||
|
* @return the PGP secret key
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
List<PGPSecretKey> getSecretKeys(InputStream inputStream, String userId) throws PGPException {
|
||||||
|
// iterate over every private key in the key ring
|
||||||
|
PGPSecretKeyRingCollection secretKeyRings;
|
||||||
|
try {
|
||||||
|
secretKeyRings = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(inputStream), fingerprintCalculator);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PGPException("No private key found in stream!", e);
|
||||||
|
} finally {
|
||||||
|
Sys.close(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for the key ring that is used to authenticate our reporting facilities
|
||||||
|
Iterator<PGPSecretKeyRing> secretKeys = secretKeyRings.getKeyRings(userId);
|
||||||
|
List<PGPSecretKey> pgpSecretKeys = new ArrayList<PGPSecretKey>();
|
||||||
|
|
||||||
|
// iterate over every private key in the ring
|
||||||
|
while (secretKeys.hasNext()) {
|
||||||
|
PGPSecretKeyRing secretKeyRing = secretKeys.next();
|
||||||
|
PGPSecretKey tmpKey = secretKeyRing.getSecretKey();
|
||||||
|
|
||||||
|
if (tmpKey != null) {
|
||||||
|
pgpSecretKeys.add(tmpKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pgpSecretKeys.isEmpty()) {
|
||||||
|
return pgpSecretKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PGPException("No private key found in stream!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the signature that will be used to PGP sign data
|
||||||
|
*
|
||||||
|
* @param secretKeys
|
||||||
|
* these are the secret keys
|
||||||
|
* @param password
|
||||||
|
* this is the password to unlock the secret key
|
||||||
|
*
|
||||||
|
* @return the signature used to sign data
|
||||||
|
*
|
||||||
|
* @throws PGPException
|
||||||
|
*/
|
||||||
|
private static
|
||||||
|
PGPSignatureGenerator createSignature(List<PGPSecretKey> secretKeys,
|
||||||
|
char[] password,
|
||||||
|
int signatureType,
|
||||||
|
boolean generateUserIdSubPacket) throws PGPException {
|
||||||
|
|
||||||
|
PGPSecretKey secretKey = null;
|
||||||
|
for (int i = 0; i < secretKeys.size(); i++) {
|
||||||
|
secretKey = secretKeys.get(i);
|
||||||
|
|
||||||
|
// we ONLY want the signing master key
|
||||||
|
if (!secretKey.isSigningKey() || !secretKey.isMasterKey()) {
|
||||||
|
secretKey = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secretKey == null) {
|
||||||
|
throw new PGPException("Secret key is not the signing master key");
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.err.println("Signing key = " + tmpKey.isSigningKey() +", Master key = " + tmpKey.isMasterKey() + ", UserId = " +
|
||||||
|
// userId );
|
||||||
|
|
||||||
|
if (password == null) {
|
||||||
|
password = new char[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
PBESecretKeyDecryptor build = new BcPBESecretKeyDecryptorBuilder(digestCalculatorProvider).build(password);
|
||||||
|
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
BcPGPContentSignerBuilder bcPGPContentSignerBuilder = new BcPGPContentSignerBuilder(secretKey.getPublicKey()
|
||||||
|
.getAlgorithm(),
|
||||||
|
PGPUtil.SHA1).setSecureRandom(random);
|
||||||
|
|
||||||
|
PGPSignatureGenerator signature = new PGPSignatureGenerator(bcPGPContentSignerBuilder);
|
||||||
|
signature.init(signatureType, secretKey.extractPrivateKey(build));
|
||||||
|
|
||||||
|
Iterator userIds = secretKey.getPublicKey()
|
||||||
|
.getUserIDs();
|
||||||
|
|
||||||
|
// use the first userId that matches
|
||||||
|
if (userIds.hasNext()) {
|
||||||
|
if (generateUserIdSubPacket) {
|
||||||
|
PGPSignatureSubpacketGenerator subpacketGenerator = new PGPSignatureSubpacketGenerator();
|
||||||
|
subpacketGenerator.setSignerUserID(false, (String) userIds.next());
|
||||||
|
signature.setHashedSubpackets(subpacketGenerator.generate());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
signature.setHashedSubpackets(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new PGPException("Did not find specified userId");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode a PGP public key block and return the keyring it represents.
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
PGPPublicKeyRing getKeyring(InputStream keyBlockStream) throws IOException {
|
||||||
|
|
||||||
|
BcKeyFingerprintCalculator keyfp = new BcKeyFingerprintCalculator();
|
||||||
|
|
||||||
|
// PGPUtil.getDecoderStream() will detect ASCII-armor automatically and decode it,
|
||||||
|
// the PGPObject factory then knows how to read all the data in the encoded stream
|
||||||
|
PGPObjectFactory factory = new PGPObjectFactory(PGPUtil.getDecoderStream(keyBlockStream), keyfp);
|
||||||
|
|
||||||
|
// these files should really just have one object in them, and that object should be a PGPPublicKeyRing.
|
||||||
|
Object o = factory.nextObject();
|
||||||
|
if (o instanceof PGPPublicKeyRing) {
|
||||||
|
return (PGPPublicKeyRing) o;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Input stream does not contain a PGP Public Key");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first encryption key from the given keyring.
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
PGPPublicKey getEncryptionKey(PGPPublicKeyRing keyRing) {
|
||||||
|
if (keyRing == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate over the keys on the ring, look for one which is suitable for encryption.
|
||||||
|
Iterator keys = keyRing.getPublicKeys();
|
||||||
|
PGPPublicKey key;
|
||||||
|
while (keys.hasNext()) {
|
||||||
|
key = (PGPPublicKey) keys.next();
|
||||||
|
if (key.isEncryptionKey()) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first decryption key from the given keyring.
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
PGPSecretKey getDecryptionKey(PGPSecretKeyRing keyRing) {
|
||||||
|
if (keyRing == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate over the keys on the ring, look for one which is suitable for encryption.
|
||||||
|
Iterator keys = keyRing.getSecretKeys();
|
||||||
|
PGPSecretKey key;
|
||||||
|
while (keys.hasNext()) {
|
||||||
|
key = (PGPSecretKey) keys.next();
|
||||||
|
if (key.isMasterKey()) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt plaintext message using public key from publickeyFile.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
*
|
||||||
|
* @return the string
|
||||||
|
*/
|
||||||
|
private
|
||||||
|
String encrypt(InputStream publicKeyInputStream, String message) throws PGPException, IOException, NoSuchProviderException {
|
||||||
|
// find the PGP key in the file
|
||||||
|
PGPPublicKey publicKey = findPublicGPGKey(publicKeyInputStream);
|
||||||
|
|
||||||
|
if (publicKey == null) {
|
||||||
|
System.err.println("Did not find public GPG key");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Encode the string into bytes using utf-8
|
||||||
|
byte[] utf8Bytes = message.getBytes(OS.UTF_8);
|
||||||
|
|
||||||
|
ByteArrayOutputStream compressedOutput = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// compress bytes with zip
|
||||||
|
PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator();
|
||||||
|
|
||||||
|
// the reason why we compress here is GPG not being able to decrypt our message input but if we do not compress.
|
||||||
|
// I guess pkzip compression also encodes only to GPG-friendly characters.
|
||||||
|
PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP);
|
||||||
|
try {
|
||||||
|
OutputStream literalDataOutput = literalDataGenerator.open(compressedOutput,
|
||||||
|
PGPLiteralData.BINARY,
|
||||||
|
"_CONSOLE",
|
||||||
|
utf8Bytes.length,
|
||||||
|
new Date());
|
||||||
|
// update bytes in the stream
|
||||||
|
literalDataOutput.write(utf8Bytes);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// catch but close the streams in finally
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
compressedDataGenerator.close();
|
||||||
|
Sys.close(compressedOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
|
// now we have zip-compressed bytes
|
||||||
|
byte[] compressedBytes = compressedOutput.toByteArray();
|
||||||
|
|
||||||
|
BcPGPDataEncryptorBuilder bcPGPDataEncryptorBuilder = new BcPGPDataEncryptorBuilder(PGPEncryptedData.CAST5)
|
||||||
|
.setWithIntegrityPacket(true)
|
||||||
|
.setSecureRandom(random);
|
||||||
|
|
||||||
|
PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(bcPGPDataEncryptorBuilder);
|
||||||
|
|
||||||
|
// use public key to encrypt data
|
||||||
|
|
||||||
|
BcPublicKeyKeyEncryptionMethodGenerator encKeyGen = new BcPublicKeyKeyEncryptionMethodGenerator(publicKey)
|
||||||
|
.setSecureRandom(random);
|
||||||
|
|
||||||
|
encryptedDataGenerator.addMethod(encKeyGen);
|
||||||
|
|
||||||
|
// literalDataOutput --> compressedOutput --> ArmoredOutputStream --> ByteArrayOutputStream
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
ArmoredOutputStream armoredOut = new ArmoredOutputStream(byteArrayOutputStream);
|
||||||
|
OutputStream encryptedOutput = null;
|
||||||
|
try {
|
||||||
|
encryptedOutput = encryptedDataGenerator.open(armoredOut, compressedBytes.length);
|
||||||
|
encryptedOutput.write(compressedBytes);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (PGPException e) {
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
Sys.close(encryptedOutput);
|
||||||
|
Sys.close(armoredOut);
|
||||||
|
}
|
||||||
|
String encrypted = new String(byteArrayOutputStream.toByteArray());
|
||||||
|
|
||||||
|
System.err.println("Message: " + message);
|
||||||
|
System.err.println("Encrypted: " + encrypted);
|
||||||
|
|
||||||
|
return encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find public gpg key in InputStream.
|
||||||
|
*
|
||||||
|
* @param inputStream
|
||||||
|
* the input stream
|
||||||
|
*
|
||||||
|
* @return the PGP public key
|
||||||
|
*/
|
||||||
|
private static
|
||||||
|
PGPPublicKey findPublicGPGKey(InputStream inputStream) throws IOException, PGPException {
|
||||||
|
|
||||||
|
// get all key rings in the input stream
|
||||||
|
PGPPublicKeyRingCollection publicKeyRingCollection = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(inputStream), fingerprintCalculator);
|
||||||
|
|
||||||
|
System.err.println("key ring size: " + publicKeyRingCollection.size());
|
||||||
|
|
||||||
|
Iterator<PGPPublicKeyRing> keyRingIter = publicKeyRingCollection.getKeyRings();
|
||||||
|
|
||||||
|
// iterate over keyrings
|
||||||
|
while (keyRingIter.hasNext()) {
|
||||||
|
PGPPublicKeyRing keyRing = keyRingIter.next();
|
||||||
|
Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys();
|
||||||
|
// iterate over public keys in the key ring
|
||||||
|
while (keyIter.hasNext()) {
|
||||||
|
PGPPublicKey tmpKey = keyIter.next();
|
||||||
|
|
||||||
|
if (tmpKey == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<String> userIDs = tmpKey.getUserIDs();
|
||||||
|
ArrayList<String> strings = new ArrayList<String>();
|
||||||
|
while (userIDs.hasNext()) {
|
||||||
|
String next = userIDs.next();
|
||||||
|
strings.add(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.err.println(
|
||||||
|
"Encryption key = " + tmpKey.isEncryptionKey() + ", Master key = " + tmpKey.isMasterKey() + ", UserId = " +
|
||||||
|
strings);
|
||||||
|
|
||||||
|
// we need a master encryption key
|
||||||
|
if (tmpKey.isEncryptionKey() && tmpKey.isMasterKey()) {
|
||||||
|
return tmpKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new PGPException("No public key found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static
|
||||||
|
void verify(final InputStream publicKeyInputStream, final byte[] signature) throws Exception {
|
||||||
|
PGPPublicKey publicKey = findPublicGPGKey(publicKeyInputStream);
|
||||||
|
|
||||||
|
String text = new String(signature);
|
||||||
|
|
||||||
|
Pattern regex = Pattern.compile(
|
||||||
|
"-----BEGIN PGP SIGNED MESSAGE-----\\r?\\n.*?\\r?\\n\\r?\\n(.*)\\r?\\n(-----BEGIN PGP SIGNATURE-----\\r?\\n.*-----END PGP SIGNATURE-----)",
|
||||||
|
Pattern.CANON_EQ | Pattern.DOTALL);
|
||||||
|
Matcher regexMatcher = regex.matcher(text);
|
||||||
|
if (regexMatcher.find()) {
|
||||||
|
String dataText = regexMatcher.group(1);
|
||||||
|
String signText = regexMatcher.group(2);
|
||||||
|
|
||||||
|
ByteArrayInputStream dataIn = new ByteArrayInputStream(dataText.getBytes("UTF8"));
|
||||||
|
ByteArrayInputStream signIn = new ByteArrayInputStream(signText.getBytes("UTF8"));
|
||||||
|
|
||||||
|
|
||||||
|
InputStream signIn2 = PGPUtil.getDecoderStream(signIn);
|
||||||
|
|
||||||
|
PGPObjectFactory pgpFact = new PGPObjectFactory(signIn2, new BcKeyFingerprintCalculator());
|
||||||
|
PGPSignatureList p3 = null;
|
||||||
|
|
||||||
|
Object o;
|
||||||
|
|
||||||
|
try {
|
||||||
|
o = pgpFact.nextObject();
|
||||||
|
if (o == null) {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new Exception("Invalid input data");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o instanceof PGPCompressedData) {
|
||||||
|
PGPCompressedData c1 = (PGPCompressedData) o;
|
||||||
|
|
||||||
|
pgpFact = new PGPObjectFactory(c1.getDataStream(), new BcKeyFingerprintCalculator());
|
||||||
|
|
||||||
|
p3 = (PGPSignatureList) pgpFact.nextObject();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p3 = (PGPSignatureList) o;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// PGPSignature sig = p3.get(0);
|
||||||
|
// PGPPublicKey key = KeyRing.getPublicKeyByID(sig.getKeyID());
|
||||||
|
//
|
||||||
|
// if (key == null)
|
||||||
|
// throw new Exception("Cannot find key 0x" + Integer.toHexString((int) sig.getKeyID()).toUpperCase() + " in the pubring");
|
||||||
|
//
|
||||||
|
// sig.initVerify(key, "BC");
|
||||||
|
//
|
||||||
|
// while ((ch = dataIn.read()) >= 0) {
|
||||||
|
// sig.update((byte) ch); //TODO migliorabile con byte[]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (sig.verify())
|
||||||
|
// return new PrintablePGPPublicKey(key).toString();
|
||||||
|
// else
|
||||||
|
// return null;
|
||||||
|
|
||||||
|
// return verifyFile(dataIn, signIn);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
CryptoPGP() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
void main(String[] args) throws Exception {
|
||||||
|
InputStream privateKeyInputStream = new FileInputStream(new File("/home/user/dorkbox/sonatype_private.key"));
|
||||||
|
|
||||||
|
byte[] textBytes = "hello".getBytes(OS.UTF_8);
|
||||||
|
|
||||||
|
byte[] bytes = CryptoPGP.signGpgCompatible(privateKeyInputStream, "Dorkbox <sonatype@dorkbox.com>", new char[0], textBytes);
|
||||||
|
|
||||||
|
// String s = new String(hello);
|
||||||
|
// String s1 = s.replaceAll("\n", "\r\n");
|
||||||
|
// byte[] bytes = s1.getBytes(OS.UTF_8);
|
||||||
|
|
||||||
|
//
|
||||||
|
// String signed = new String(bytes);
|
||||||
|
//
|
||||||
|
// System.err.println("Message: " + new String(messageAsUtf8Bytes));
|
||||||
|
// System.err.println("Signature: " + signed);
|
||||||
|
//
|
||||||
|
// return bytes;
|
||||||
|
|
||||||
|
// String s2 = new String(bytes);
|
||||||
|
|
||||||
|
|
||||||
|
// InputStream publicKeyInputStream = new FileInputStream(new File("/home/user/dorkbox/sonatype_public.key"));
|
||||||
|
// cryptoPGP.verify(publicKeyInputStream, hello);
|
||||||
|
|
||||||
|
|
||||||
|
FileOutputStream fileOutputStream = new FileOutputStream(new File("/home/user/dorkbox/hello2.txt"));
|
||||||
|
fileOutputStream.write(textBytes);
|
||||||
|
fileOutputStream.flush();
|
||||||
|
Sys.close(fileOutputStream);
|
||||||
|
|
||||||
|
|
||||||
|
FileOutputStream fileOutputStream1 = new FileOutputStream(new File("/home/user/dorkbox/hello2.txt.asc"));
|
||||||
|
fileOutputStream1.write(bytes);
|
||||||
|
fileOutputStream1.flush();
|
||||||
|
Sys.close(fileOutputStream1);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
package dorkbox.util.crypto;
|
package dorkbox.util.crypto;
|
||||||
|
|
||||||
import org.bouncycastle.crypto.AsymmetricBlockCipher;
|
import org.bouncycastle.crypto.AsymmetricBlockCipher;
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
package dorkbox.util.crypto;
|
package dorkbox.util.crypto;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
@ -86,7 +101,7 @@ class CryptoSCrypt {
|
|||||||
String encrypt(char[] password, byte[] salt, int N, int r, int p, int dkLen) {
|
String encrypt(char[] password, byte[] salt, int N, int r, int p, int dkLen) {
|
||||||
// Note: this saves the char array in UTF-16 format of bytes.
|
// Note: this saves the char array in UTF-16 format of bytes.
|
||||||
// can't use password after this as it's been changed to '*'
|
// can't use password after this as it's been changed to '*'
|
||||||
byte[] passwordBytes = Crypto.Util.charToBytesPassword(password);
|
byte[] passwordBytes = Crypto.charToBytesPassword_UTF16(password);
|
||||||
|
|
||||||
byte[] derived = encrypt(passwordBytes, salt, N, r, p, dkLen);
|
byte[] derived = encrypt(passwordBytes, salt, N, r, p, dkLen);
|
||||||
|
|
||||||
@ -118,7 +133,7 @@ class CryptoSCrypt {
|
|||||||
boolean verify(char[] password, String hashed) {
|
boolean verify(char[] password, String hashed) {
|
||||||
// Note: this saves the char array in UTF-16 format of bytes.
|
// Note: this saves the char array in UTF-16 format of bytes.
|
||||||
// can't use password after this as it's been changed to '*'
|
// can't use password after this as it's been changed to '*'
|
||||||
byte[] passwordBytes = Crypto.Util.charToBytesPassword(password);
|
byte[] passwordBytes = Crypto.charToBytesPassword_UTF16(password);
|
||||||
|
|
||||||
String[] parts = hashed.split("\\$");
|
String[] parts = hashed.split("\\$");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user