GOST 3411 Algorithm using Bouncy Castle - java

Am using GOST algorithm to create a hash based on key and input using Bouncy castle libs. Below code generates Hash that doesn't match with the one generated through online tools such as http://beautifytools.com/hmac-generator.php
HMac gMac= new HMac(new GOST3411Digest());
byte[] key = "keyphrase".getBytes();
byte[] input = "macinput".getBytes();
gMac.init(new KeyParameter(key));
gMac.update(input, 0, input.length);
byte[] mac = new byte[gMac.getMacSize()];
gMac.doFinal(mac, 0);
BigInteger in = new BigInteger(1, mac);
System.out.println(in.toString(16));
When this works, Need to use inside Mulesoft to call API which validates the Hash and gives authentication. Basically, The encyption is for generation of authentication token.
Have been referring to stackoverflow for a long time but never had an opportunity to post any questions. This is my first :)
Thanks,
Sudeep

GOST3411 algorithm has several SBox options, so try using different upon initialization. I had some luck with "D-Test" SBox, it matches with most if not all online tools. You can initialize different SBox like this:
HMac mac = new HMac(new GOST3411Digest(GOST28147Engine.getSBox("D-Test")));

Related

Java Sha-512 Message Digest with salting not matching linux shadow file hashed passwords

I'm trying to produce the same hashes found in the linux shadow file using the MessageDigest, given the password, salt value and hashing algorithm, although the results do not match with what I get from the function below.
Hash Algorithm = 6
Password = mandar
Salt Value = 5H0QpwprRiJQR19Y
Expected Output = $6$5H0QpwprRiJQR19Y$bXGOh7dIfOWpUb/Tuqr7yQVCqL3UkrJns9.7msfvMg4ZOPsFC5Tbt32PXAw9qRFEBs1254aLimFeNM8YsYOv.
Actual Output = ca0d04319f273d36f246975a4f9c71d0184c4ca7f3ba54bc0b3e0b4106f0eefca1e9a122a536fb17273b1077367bf68365c10fa8a2b18285a6825628f3614194
I have this function for generating the hash value
public String getSha512Hash(String password, String saltValue) throws NoSuchAlgorithmException{
String text = saltValue + password ;
MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
byte[] bytes = messageDigest.digest( text.getBytes() );
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; ++i) {
sb.append(Integer.toHexString((bytes[i] & 0xFF) | 0x100).substring(1,3));
}
return sb.toString();
}
I'm referring to this website.
The passwords in /etc/shadow are hashed using the crypt(3) system call (man crypt).
You can use the Apache Commons implementation which should mimic the same behavior.
The fundamental problem is that the site you are referring to uses Perl's crypt() which seems a direct call to libc crypt(). In the manual of crypt is not specified how the SHA-512 hash is actually computed, but I searched GitHub and found this ~400 LOC source file sha512-crypt.c.
I read throught it and can't tell if it refers to some standard or if it's the only program using that algorithm. Since the SHA-512 thing also seems a proprietary extension to the POSIX standard, it's absolutely not unlikely.
You could ask the maintainer or the mailing list and report your findings back, otherwise if you absolutely need that functionality, you could write a native extension (don't know if there are Java libraries already available).

Signing a message digest using BouncyCastle

At the moment in C# I'm signing a challenge like this:
RSACryptoServiceProvider rsa;
RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter(rsa);
RSAFormatter.SetHashAlgorithm("SHA1");
byte[] SignedHash = RSAFormatter.CreateSignature(paramDataToSign);
Then I give the SignedHash to Windows, it accepts it and everything is OK. But I need to move this part to Android and there's the problem, that I just can't get the same signed hash value.
In Android I tried to make the signed hash but they differ from the one generated in C#.
Signature signer = Signature.getInstance("SHA1withRSA", "BC");
signer.initSign(privateKey);
signer.update(paramDataToSign);
signer.sign();
In C# - using the following piece of code - I get the same result as in Android, but it is not an option cause then Windows does not accept the signed hash.
ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
signer.Init(true, privateKey);
signer.BlockUpdate(paramDataToSign, 0, paramDataToSign.Length);
signer.GenerateSignature();
Here's written that C# PKCS1SignatureFormatter and Java Signature should give the same result, but they do not. http://www.jensign.com/JavaScience/dotnet/VerifySig/
What could be the problem?
Here are the base 64 (WebSafe) values that I get:
Challenge = zHyz12Tk4m151nssYIBWqBCAxhQ
RSAPKCS1SignatureFormatter SignedHash = kmu39keplCAV4Qnu22wdprLz4nGSsrVtHbxQ5YMUG7p-0YwReCG4ROIlFvYs4CGfjCiAGFPw4PLrLx7mrlAA6iuhJMkgm_PMTW9alQYTH612hLEUP4EmK0M2kw8CveLcjI3HA08z8bByllIzRyAlM8bcR438vw2uhx_CbgvOOHn8vwBPnvWbFqpi2doYoq2xEuFBRe7eBPrxbMRqEd3ExdQ9c9rYT4ivOJ4pbioyi6D5i5_1crvGwM6nQanMZCmooRYJO65NP3B4wWnvQZpJLRD0U08wWcvyGBFWp188ZovDjnkTQZku6lzmwGXfqQwtBz9uNvLcTbp7cVyt5EyQxw
Signature and ISigner SignedHash = Vt-b5QfGPnSPpZuIB8-H4N1K5hQXpImS4e8k56_HruDSqy3DLsz96QKUrccshjr1z9nTK3Mwvd5yPdyTJOqSUcDQqxV46LPhWQNsubqKxAz97ePpeslIH1gHdnzkh46ixsWqgDrhR7egQtDkU8PPsph1qahCxaVkRYspQBV0jPZ-LK4EjoGGnuWTCihVKjruXJZ2VY8yZ9QRAsHVptr0Nv-mldO2MFK-oEVbtVbHqUPf5So8im3oRSm68OqY4g56bCdFNSbhcFBjrZ1QPjnxiIk43-_5tevafqoOB2D_E_mQHCJwmRg3MrNij6IdAdloCejnhCWzgMHdcG1Ug_Qmig
EDIT:
So the simplest solution is using Bouncy Castle API:
AsymmetricBlockCipher rsaEngine = new PKCS1Encoding(new RSABlindedEngine());
rsaEngine.init(true, privateKey);
DigestInfo dInfo = new DigestInfo(new AlgorithmIdentifier(X509ObjectIdentifiers.id_SHA1, DERNull.INSTANCE), paramDataToSign);
byte[] digestInfo = dInfo.getEncoded(ASN1Encoding.DER);
rsaEngine.processBlock(digestInfo, 0, digestInfo.length);
The problem is that RSAFormatter.CreateSignature(paramDataToSign); passes the hash value, while signer.update(paramDataToSign); passes the data before it is hashed. So it is likely that you have to remove a MessageDigest calculation for your Java code for this to work.
Alternatively, if you only have the hash value, you may have a look into the Bouncy Castle lightweight API to find a method that accepts a value that is pre-hashed. This can probably be performed using new RSADigestSigner(new StaticDigest(paramDataToSign, "SHA-1")).generateSignature().
Problem is that StaticDigest does not exist, so you'll have to comment here if you really require it. Alternative, mirror the implementation of RSADigestSigner but substitute a pre-calculated hash.

how to generate s3 style access/secret key using java

I am trying to generate access keys and secret keys in the same fashion as S3 using java but am having some trouble.
As a starting point I am looking at this bouncy castle example , I have this code up and running but am not sure of two things 1) how to set it up to use the same key generation as s3 which uses HMAC-SHA1 as outlined here and 2) how to get the friendly public/private key strings out for the the user.
You may have guessed I am new to java encryption and the bouncy castle libraries, however I did find JCEKeyGenerator.HMACSHA1 in the bc docs but am unable to find an example of its use. Any help would be greatly appreciated.
Thanks.
You'll need to make use of javax.crypto.KeyGenerator to create the AWSAccessKeyId and the AWSSecretAccessKey:
javax.crypto.KeyGenerator generator = javax.crypto.KeyGenerator.getInstance("HMACSHA1");
generator.init(120);
byte[] awsAccessKeyId = generator.generateKey().getEncoded();
generator.init(240);
byte[] awsSecretAccessKey = generator.generateKey().getEncoded();
Then, you'll want to base64 encode the bytes (this uses MimeUtility from mail.jar):
final ByteArrayOutputStream encoded = new ByteArrayOutputStream();
final OutputStream encoder = javax.mail.internet.MimeUtility.encode(encoded, "base64");
encoder.write(awsAccessKeyId);
encoder.flush();
encoder.close();
String accessKeyId = new String(encoded.toByteArray(), encoding).replaceAll("[\\r\\n]", "");

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.

SHA2 password storage with Java

I'm attempting to make a XML-RPC call that requires HmacSHA-256 hashing of a particular string. I'm currently using the Jasypt library with the following code:
StandardPBEStringEncryptor sha256 = new StandardPBEStringEncryptor();
sha256.setPassword(key);
sha256.setAlgorithm("PBEWithHmacSHA2");
On trying to use sha256.encrypt(string) I get this error:
Exception in thread "main" org.jasypt.exceptions.EncryptionInitializationException: java.security.NoSuchAlgorithmException: PBEWithHmacAndSHA256 SecretKeyFactory not available
at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.initialize(StandardPBEByteEncryptor.java:597)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.initialize(StandardPBEStringEncryptor.java:488)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.encrypt(StandardPBEStringEncryptor.java:541)
at nysenateapi.XmlRpc.main(XmlRpc.java:52)
Caused by: java.security.NoSuchAlgorithmException: PBEWithHmacAndSHA256 SecretKeyFactory not available
at javax.crypto.SecretKeyFactory.(DashoA13*..)
at javax.crypto.SecretKeyFactory.getInstance(DashoA13*..)
at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.initialize(StandardPBEByteEncryptor.java:584)
... 3 more
I downloaded the JCE Cryptography extension and placed the jars in my buildpath, but that doesn't seem to have done anything. I've tried using a number of combinations in setAlgorithm above, including "PBE", "PBEWithSha"(1|2|128|256)?, "PBEWithHmacSha", etc.
I also tried using BouncyCastle but I didn't have any luck there either. Any help or guidance appreciated!
As correctly noted by #Rook you need to specify a PBE algorithm that includes an encryption algorithm. Two examples out of many are "PBEWithSHA1AndDESede" which is supported by the SunJCE provider and "PBEWITHSHA256AND128BITAES-CBC-BC" which is supported by the Bouncycastle JCE provider.
The comments were helpful but I guess I was asking the wrong question. What I was looking to do was mimic the PHP function hash_hmac('sha256',string,key)...
I ended up using the following code:
Mac mac = Mac.getInstance("HmacSha256");
SecretKeySpec secret = new SecretKeySpec(key.getBytes(), "HmacSha256");
mac.init(secret);
byte[] shaDigest = mac.doFinal(phrase.getBytes());
String hash = "";
for(byte b:shaDigest) {
hash += String.format("%02x",b);
}
Thanks for the guidance, though. Will surely help me in the future.

Categories