Symmetric Encryption on java with Fernet - java

I want to encrypt and decrypt messages between python and java with the Fernet module. But I don't understand the example they're giving.
Deserialise an existing key:
final Key key = new Key("cw_0x689RpI-jtRR7oE8h_eQsKImvJapLeSbXpwF4e4=");
Create a token:
final Token token = Token.generate(random, key, "secret message");
Deserialise an existing token:
final Token token = Token.fromString("gAAAAAAdwJ6wAAECAwQFBgcICQoLDA0ODy021cpGVWKZ_eEwCGM4BLLF_5CV9dOPmrhuVUPgJobwOz7JcbmrR64jVmpU4IwqDA==");
Why do you need a random parameter to encrypt the secret message? I've implemented the fermet encryption in python and it never asked for any source of randomness.
>>> from cryptography.fernet import Fernet
>>> key = Fernet.generate_key()
>>> f = Fernet(key)
>>> token = f.encrypt(b"my deep dark secret")
>>> token
b'...'
>>> f.decrypt(token)
b'my deep dark secret
How can I get the same encryption standard as in python so I can use the same encryption key?

With the same key the implementations in Python and Java will be perfectly compatible. But on both sides you have to use the same one, of course. If you use the Python code as the base, do a print(key) and copy that same key to the Java variant (it will be a urlsafebase64 string, so no transport issues). In Java when generating the token, use a SecureRandom() instance. It's only used for the IV and that's part of the token anyway, so will be available for the decryption code in whatever language. Fernet Python uses good random automatically (it's transparant, you don't have to choose it). But whatever choice of random you pick in Java when generating tokens, will have no effect on the decryption code at all, just use the same key-string in both instances.

Related

Translating Java RSA encryption routine to Objective-C

I am trying to duplicate an encryption process that is working in Java over to iOS/OSX.
My Java code is as follows:
PublicKey publicKey = KeyFactory.getInstance("RSA").
generatePublic(new RSAPublicKeySpec(firstKeyInteger, secondKeyInteger));
// This always results in the public key OpenSSLRSAPublicKey{modulus=2b3b11f044.....58df890,publicExponent=10001}
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA1ANDMGF1PADDING");
String stringToEncode = "EncodeThisString";
byte[] bytesToEncode = stringToEncode.getBytes("UTF-8");
cipher.init(cipher.PUBLIC_KEY, publicKey);
byte[] encrypted = cipher.doFinal(plain);
The first challenge i'm struggling with is how to use the public key in iOS. Can I just dump the modulus into NSData and use it? Or must I store it in the keychain first? (I don't really need to use the keychain unless I must). Or is there a method similar to generatePublic() were I can recreate the public key using the 2 integers?
Then would I use SecKeyEncrypt to encrypt? Whenever I add this to my project I get Implicit declaration warnings even though I import the Security framework.
Thanks
EDIT -----
I think I have managed to get a Base64 encoded public key, which I believe is what is in a PEM certificate. Now, how to use it.

perl CBC DES equivalent in java

We are migrating some code from perl to java/scala and we hit a roadblock.
We're trying to figure out how to do this in Java/scala:
use Crypt::CBC;
$aesKey = "some key"
$cipher = new Crypt::CBC($aesKey, "DES");
$encrypted = $cipher->encrypt("hello world");
print $encrypted // prints: Salted__�,%�8XL�/1�&�n;����쀍c
$decrypted = $cipher->decrypt($encrypted);
print $decrypted // prints: hello world
I tried a few things in scala but didn't really get it right, for example something like this:
val secretKey = new SecretKeySpec("some key".getBytes("UTF-8"), "DES")
val encipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
encipher.init(Cipher.ENCRYPT_MODE, secretKey)
val encrypted = encipher.doFinal(bytes)
println("BYTES:" + bytes)
println("ENCRYPTED!!!!!!: " + encrypted)
println(toString(encrypted))
Any help or direction in Java/scala would very much be appreciated
Assuming that Crypt module is the one I find at https://metacpan.org/pod/Crypt::CBC it is documented as by default doing (the same as) openssl, apparently meaning commandline 'enc' (openssl library has MANY other options). That is not encryption
with the specified key (and IV) directly, but instead 'password-based' encryption (PBE) with a key and IV derived from the specified 'key' (really passphrase) plus (transmitted) salt, using a twist on the original (now unrecommended) PKCS#5 v1.5 algorithm, retronymed PBKDF1. See http://www.openssl.org/docs/crypto/EVP_BytesToKey.html (or the man page on a Unix system with openssl installed) and rfc2898 (or the original RSA Labs PKCS documents now somewhere at EMC).
You say you cannot change the perl sender. I hope the users/owners/whoever realize that original DES,
retronymed single-DES for clarity, has been practically brute-forceable for well over a decade, and
PBE-1DES may be even weaker; the openssl twist doesn't iterate as PKCS#5 (both KDF1 and KDF2) should.
Java (with the Suncle providers) does implement PBEWithMD5AndDES, which initted with PBEParameterSpec (salt, 1)
does successfully decrypt data from 'openssl enc -des-cbc', and thus I expect also your perl sender (not tested).
FWIW if you could change to triple-DES, Java implements PBEWithMD5AndTripleDES using an apparently nonstandard
extension of PBKDF1 (beyond hash size) that is quite unlike openssl's nonstandard extension, and thus incompatible if the perl module is in fact following openssl.
You would have to do the key-derivation yourself and then direct 3DES-CBC-pad, which isn't very hard.
Also note encrypted data from any modern computer algorithm is binary. "Printing" it as if it were text
in perl, or Java or nearly anything else, is likely to cause data corruption if you try to use it again.
If you are only looking to see 'is there any output at all, and is it visibly not the plaintext' you're okay.

RSA using SHA-256 hashing algorithm with my own Private Key

I'm trying to use a Google's OAuth 2.0 for Server to Server Applications and I ran into a roadblock.
It states:
"Sign the UTF-8 representation of the input using SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function) with the private key obtained from the API console. The output will be a byte array."
So I got most of down using Java libraries but how do I use a String as a private key?
I guess you need a fixed size key. So you can get the String,
hash the String and the result is your key for RSA.
Maybe this also helps:
bytes[] values = myString.getBytes(); //get byte[] from String

Veryfing signature generated by BouncyCastle on PC using native Java JCE

I am using BouncyCastle to generate a DSA signature but using the native JCE to verify the it.
NOTE: I am working with a j2me client that does not natively support signing hence the need for BouncyCastle)
So, on the client the signature is generated as follows:
DSASigner sig = new DSASigner();
sig.init(true, privateKey);
String plaintext = "This is the message being signed";
BigInteger[] sigArray = sig.generateSignature(plaintext.getBytes());
...
sigArray contains 2 BigIntegers r and s.
This signature then has to be transmitted to a server which uses native JCE to verify the sig. On the server side, using the native Java JCE, it should be possible to verify a signature as follows:
...
Signature sig = Signature.getInstance("SHA1withDSA");
byte[] sigbytes = Base64.decode(signature);
sig.initVerify(publicKey);
sig.update(plaintext.getBytes());
sig.verify(sigbytes)
The problem am having is: how do i encode sigArray into a format that can be sent to the pc/server as a single Base64 string (instead of separately as r and s) that can then be verified on the server using the native JCE method show in the second snippet of code?
So far i have tried to create DERObjects from the r,s arrays (separately, together as one array, encoded) but still no luck. Anybody faced this before? How did you tackle it?
According to Cryptographic Message Syntax Algorithms (RFC 3370) the DSA signature encoding is an ASN.1 sequence containing both integers r and s:
Dss-Sig-Value ::= SEQUENCE {
r INTEGER,
s INTEGER }

Capicom and SHA1 - Help translating a java code to Delphi

I have a java application that signs a string using a certificate. It works encrypting the string it with SHA1. I am trying to translate the code to Delphi 2010, but I have no idea how to get it working the same way the java app does (using sha1). So far, I have found this:
Delphi 7 access Windows X509 Certificate Store
It does work, but it does not use sha1 and I get different results when I run the java app.
Java code
char[] pass = (char[]) null;
PrivateKey key = (PrivateKey) getKeyStore().getKey(alias, pass);
Certificate[] chain = getKeyStore().getCertificateChain(alias);
CertStore certsAndCRLs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(Arrays.asList(chain)), "BC");
X509Certificate cert = (X509Certificate) chain[0];
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA1);
gen.addCertificatesAndCRLs(certsAndCRLs);
CMSProcessable data = new CMSProcessableByteArray(conteudoParaAssinar);
CMSSignedData signed = gen.generate(data, true, "SunMSCAPI");
byte[] envHex = signed.getEncoded();
CertInfo certInfo = new CertInfo();
certInfo.Hash = new BigInteger(envHex).toString(16);
return certInfo;
Delphi Code
var
lSigner: TSigner;
lSignedData: TSignedData;
fs: TFileStream;
qt: integer;
ch: PChar;
msg : WideString;
content : string;
cert: TCertificate;
begin
cert := Self.GetCert;
content := 'test';
lSigner := TSigner.Create(self);
lSigner.Certificate := cert.DefaultInterface;
lSignedData := TSignedData.Create(self);
lSignedData.content := content;
msg := lSignedData.Sign(lSigner.DefaultInterface, false, CAPICOM_ENCODE_BASE64);
lSignedData.Free;
lSigner.Free;
EDIT
Based on the java code, should I get the cert info in binary format, apply sha1 on it and them convert it to hex? Is this the right order and the same thing the java code does? I can see some SHA1 constants in the capicom tlb as well as a hash class, maybe I should use those classes, but I dont know how.
We use DCPCrypt in some delphi apps that interface with our Java Tomcat App and are able to get SHA-256 compatible hashes. I suspect SHA1 is also easy.
Here's an example
function Sha256FileStreamHash(fs : TFileStream): String;
var
Hash: TDCP_sha256;
Digest: array[0..31] of byte; // RipeMD-160 produces a 160bit digest (20bytes)
i: integer;
s: string;
begin
if fs <> nil then
begin
fs.Seek(0, soFromBeginning);
Hash:= TDCP_sha256.Create(nil); // create the hash
try
Hash.Init; // initialize it
Hash.UpdateStream(fs,fs.Size); // hash the stream contents
Hash.Final(Digest); // produce the digest
s:= '';
for i:= 0 to 31 do
s:= s + IntToHex(Digest[i],2);
Result:= s; // display the digest
finally
Hash.Free;
end;
end;
end;
First, what makes you think you're not using SHA-1 ? I'm asking because CAPICOM's sign function only works with SHA-1 signature.
Second, how do you know that you're getting a different result ? Have you tried to validate the answer ? If yes, using what ?
Third, there is something that you MUST know about CAPICOM: the "content" property is a widestring. This has various implication, including the fact that all content will be padded to 16-bits. If your input data is of different size, you'll get a different result.
Based on the java code, should I get the cert info in binary format, apply sha1 on it and them convert it to hex?
No. You get an interface to an instance of a ICertificate object (or, more likely, ICertificate2) and you just use that directly. If you have the B64 encoded version of the certificate, you can create a new ICertificate instance and then call the ICertificate.Import method. The hash of the certificate itself is only used by the signing authority to sign that specific cert.
The hash algorythm is actually used during the data signature process: the library reads the data, creates a hash of that data (using SHA-1 in case of CAPICOM) and then digitally sign that hash value. This reduction is necessary because signing the whole data block would be far too slow and because, that way, you only have to carry the hash if you're using a hardware crypto system.
Is this the right order and the same thing the java code does?
Yes and no. The Java code does all the necessary steps in explicit details, something you don't have (and actually cannot) do with CAPICOM. It should result in compatible result, though.
It also has an additional step not related to the signature itself: I'm not sure what it does because it seems to create a dummy certificate information data and store the SHA-1 hash value of the signed CMS message and return the resulting instance. I suppose that it's a way the Java dev has found to pass the hash value back to the caller.
I can see some SHA1 constants in the capicom tlb as well as a hash class, maybe I should use those classes, but I dont know how.
The HashedData class is used to (surprise) hash data. It has the same limitation as Signeddata i.e. it only works on widestrings so compatibility with other frameworks is dodgy at best.
Final note: Windows offers access to much more comprehensive cryptographic functions through the CAPI group of functions. CAPICOM is only an interface to that library that is used (mostly) in script language (JavaScript on web pages, VB, etc). You should do yourself a favor and try using it instead of CAPICOM because there is a good chance you'll encounter something that you simply cannot do properly using CAPICOM. At that stage, you will have to rewrite part for all of your application using CAPI (or another library). So save time now and skip CAPICOM if you don't have a requirement to use it.

Categories