Hi can anyone help me how to write the below code in java
$timestamp = time();
$uri = "https://sample.json";
$password = "*********";
$security_token = sha1($timestamp.$uri.$password);
Thanks for any help.
Could the following code be what you are looking for?
public class Main {
public static void main(String[] args) {
long timestamp = System.currentTimeMillis();
String uri = "https://sample.json";
String password = "*********";
String message = (timestamp + uri + password);
System.out.println("message: " + message);
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
byte[] securityToken = messageDigest.digest(message.getBytes());
System.out.println("SHA-1 Hex: " + bytesToHex(securityToken));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static String bytesToHex(byte[] in) {
final StringBuilder builder = new StringBuilder();
for(byte b : in) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
}
It outputs:
message: 1456907866378https://sample.json*********
SHA-1 Hex: 3a5b2e4857e7ebc9fea31d5a52b5d1fbaef59f53
Related
I'm trying to port the following Java code to C#, but so far it still says that the signature is invalid.
private static String generateSignStr(Map<String, String> params, String key) {
StringBuilder sb = new StringBuilder();
params.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> {
if (sb.length() > 0) {
sb.append('&');
}
sb.append(entry.getKey()).append('=');
sb.append(entry.getValue());
});
sb.append('&').append("api_secret")
.append('=').append(key);
return sb.toString();
}
private static String sign(String target) {
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
log.error("Fail to get MD5 instance");
return null;
}
md.update(target.getBytes());
byte[] dg = md.digest();
StringBuilder output = new StringBuilder(dg.length * 2);
for (byte dgByte : dg) {
int current = dgByte & 0xff;
if (current < 16) {
output.append("0");
}
output.append(Integer.toString(current, 16));
}
return output.toString();
}
private static string GenerateSign(Dictionary<string, object> query, string apiSecret)
{
var sb = new StringBuilder();
var queryParameterString = string.Join("&",
query.Where(kvp => !string.IsNullOrWhiteSpace(kvp.Value.ToString()))
.Select(kvp => $"{kvp.Key}={HttpUtility.UrlEncode(kvp.Value.ToString())}"));
sb.Append(queryParameterString);
if (sb.Length > 0)
{
sb.Append('&');
}
sb.Append("api_secret=").Append(apiSecret);
return sb.ToString();
}
private static string Sign(string source)
{
using var md5 = MD5.Create();
var sourceBytes = Encoding.UTF8.GetBytes(source);
var hash = md5.ComputeHash(sourceBytes);
return BitConverter.ToString(hash).Replace("-", string.Empty).ToLowerInvariant();
}
Edit:
This fixed it. However, it would be nice if someone knows a way to lexicographically sort the dictionary inside that method just like the Java code.
var #params = new Dictionary<string, object>
{
{ "api_key", _apiKey },
{ "req_time", now },
{ "op", "sub.personal" }
};
var javaSorted = #params.OrderBy(item => item.Key, StringComparer.Ordinal)
.ToDictionary(i => i.Key, i => i.Value);
var signature = Sign(GenerateSign(javaSorted, _apiSecret));
In GenerateSign method you can just create instance of SortedDictionary based on dictionary passed as parameter:
private static string GenerateSign(Dictionary<string, object> query, string apiSecret)
{
var sortedDict = new SortedDictionary<string, object>(query, StringComparer.Ordinal);
// rest of the method
}
Or you can do even better (note the important change from Dictionary to IDictionary):
private static string GenerateSign(IDictionary<string, object> query, string apiSecret)
{
query = new SortedDictionary<string, object>(query, StringComparer.Ordinal);
// rest of the method
}
I am trying to encrypt a json string using the below code:
public static final Charset CHARSET = StandardCharsets.UTF_8;
public static Cipher getDefaultCipherInstance(int mode)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException {
byte[] key = Base64.getDecoder().decode("encryptionKey".getBytes(CHARSET));
IvParameterSpec iv = new IvParameterSpec("RandomVector".getBytes(CHARSET));
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(mode, skeySpec, iv);
return cipher;
}
public static String encryptText(String plainText) {
try {
Cipher cipher = getDefaultCipherInstance(Cipher.ENCRYPT_MODE);
byte[] cipherText = cipher.doFinal(plainText.getBytes(CHARSET));
return new String(Base64.getEncoder().encode(cipherText));
} catch (Exception ex) {
LOG.error("Problem encryptingText",ex);
return null;
}
}
public static String decryptText(String cipherText) {
try {
Cipher cipher = getDefaultCipherInstance(Cipher.DECRYPT_MODE);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(cipherText));
return new String(decrypted);
} catch (Exception ex) {
LOG.debug("Problem during decrypt text: " + cipherText, ex);
return null;
}
}
It works fine most of the times but sometimes I see weird characters in the decrypted string like "\u001A=`�["Q�\u001D)��ۉ�d":\ , this is corrupting the json and we are not able to deserialize json to object.
Any idea what could be the problem here?
Update::
I added the following code to test encryption/decryption in a concurrent(multi-threaded) environment:
public class EncryptionTest {
#Test
public void test() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(25);
String text = "Hi there Ithanks for cimngng";
for(int i = 0; i < 5; i++) {
System.out.println("Iteration: " + i);
executorService.submit(new EncryptionRunnable(text));
}
Thread.currentThread().join();
}
static class EncryptionRunnable implements Runnable {
private String text;
public EncryptionRunnable(String text) {
this.text = text;
}
#Override
public void run() {
int i = 0;
while(i < 10) {
String encrypted = encryptText(text);
String prefix = Thread.currentThread().getName() + "::" + i + ":: ";
System.out.println(prefix + "encrypted:: " + encrypted);
try {
System.out.println(prefix + "decrypted:: " + decryptText(encrypted));
} catch (Exception e) {
System.out.println(prefix + "decrypted:: ");
e.printStackTrace();
}
i++;
}
}
}
}
I see that all of the outputs were correct but for one of the output, it produced strange characters like this:
pool-1-thread-5::0:: decrypted:: ȼ����S}�q��j� for cimngng
Even the encrypted string is same for every encryption. Can anybody help now? Note: I am using the same cipher instance for encryption and same for decryption.
Here is a snapshot of the output of the above code.
I have a task where I have to brute force a .enc file encrypted with AES-192 in CBC mode.
So the first thing I've done is trying an offline dictionary attack using Java and the Crypto library, the problem is that an average word in the dictionary is 8 bit long so the password must have been salted in some way.
The problem is that the program that I wrote keep outputting different password at every execution and the output is just unreadable text.
here is the main:
public class main {
public static void main(String[] args) {
bruteForceFile();
}
/*
* Tries to brute force the file reading all the possible keys from a dictionary
* */
private static void bruteForceFile() {
System.out.println("--------------------------------------------------------");
System.out.println("Starting brute force/dictionary attack:");
try {
byte[] file = cipherText.cipherText.getInstance().getFileArray();
bruteForceWrapper enc = new AES(OperatingMode.CBC).bruteForceFile(file);
System.out.println("decription succeded, key : " + enc.key + " elapsed time: " + enc.elapsedSeconds +"s");
System.out.println("--------------------------------------------------------");
System.out.println("Decripted message:\n");
System.out.println(new String(enc.data));
}catch(Exception e) {
e.printStackTrace();
}
}
}
and here is the AES class:
/**
*Advanced Encryption Standard as specified by NIST in FIPS 197. Also known as the Rijndael
*algorithm by Joan Daemen and Vincent Rijmen,
*AES is a 128-bit block cipher supporting keys of 128, 192, and 256 bits.
*/
public class AES extends cipher.AbstractCipher {
public AES(OperatingMode opm) {
super(opm);
super.enablePadding();
}
#Override
protected String getMode() {
if(opm == OperatingMode.CBC) {
if(padding)
return "AES/CBC/PKCS5Padding";
return "AES/CBC/NoPadding";
}
else {
if(padding)
return "AES/ECB/PKCS5Padding";
return "AES/ECB/NoPadding";
}
}
#Override
public encriptionWrapper encript(byte[] plainText,AbstractCipherKey key) {
return null;
}
#Override
public encriptionWrapper decript(byte[]cipherText,AbstractCipherKey key) {
StopWatch timer = new StopWatch();
if(super.print) {
System.out.println("------------------------------------------------------------");
System.out.println("Starting " + this.toString() + " decryption" + " in "
+ opm.toString() + " mode."+ " (" + this.getMode() + ")");
}
try {
Cipher dcipher = Cipher.getInstance("AES");
AESCipherKey aes_key = (AESCipherKey)key;
byte[] b_key = aes_key.getPassword().getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
b_key = sha.digest(b_key);
b_key = Arrays.copyOf(b_key, 16);
SecretKeySpec secretKeySpec = new SecretKeySpec(b_key, "AES");
dcipher.init(Cipher.DECRYPT_MODE, secretKeySpec);// decode with base64 to get bytes
byte[] utf8 = dcipher.doFinal(cipherText);
// create new string based on the specified charset
if(super.print) {
System.out.println("Encryption ended. Elapsed Time: " + timer.getSeconds() + "s");
System.out.println("encrypted message length: " + utf8.length);
System.out.println("------------------------------------------------------------");
}
return new encriptionWrapper(utf8,timer.getSeconds());
} catch (Exception e) {
/*if(e.getClass() == BadPaddingException.class) {
System.out.println("attempt failed....");
}*/
if(super.print) {
System.out.println(this.toString() + " decryption failed. \n");
System.out.println("decryption ended. Elapsed Time: " + timer.getSeconds() + "s");
System.out.println("------------------------------------------------------------\n");
}
return null;
}
}
/*
* Try to brute force an encrypted file with AES
*/
public bruteForceWrapper bruteForceFile(byte[] encrypted) {
StopWatch watch = new StopWatch();
Dictionary dic = new Dictionary();
bruteForceWrapper wrapper;
super.print = false;
System.out.print("Decrypting...");
while(1 == 1) {
if(dic.getProvidedWords().size()%10 == 0) {
System.out.print(".");
}
encriptionWrapper enc = decript(encrypted,new AESCipherKey(dic.getWord()));
if(enc != null) {
wrapper = new bruteForceWrapper(enc.data, watch.getSeconds());
break;
}
}
super.print = true;
wrapper.tried_keys = dic.getProvidedWords();
wrapper.key = dic.getProvidedWords().get(dic.getProvidedWords().size() - 1);
return wrapper;
}
#Override
public String toString() {
return "AES";
}
}
Finally here is the AESCipherKey class:
public class AESCipherKey extends AbstractCipherKey{
private String SHA_TEC = "SHA-1";
public AESCipherKey(String key) {
super(key);
}
/**
*Return the desription of the safeness of the key(unsafe is user generated)
*/
#Override
public String getKeySafenessDescription() {
if(isKeySafe) {
return "(safe key)";
}else
return "(unsafe key)";
}
#Override
public boolean validate() {
if(super.isKeySafe)
return true;
if(super.getByteArray().length != 16) {
System.out.println("Invalid AES key: " + super.key);
return false;
}
return true;
}
#Override
public void generateSecureKey() {
KeyGenerator keyGen;
try {
keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
super.safeKey = keyGen.generateKey();
super.isKeySafe = true;
} catch (NoSuchAlgorithmException e) {
System.out.println("Error generating AES safe key");
e.printStackTrace();
}
}
public String getPassword() {
return super.key;
}
}
So I think that the problem is around here:
byte[] b_key = aes_key.getPassword().getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
b_key = sha.digest(b_key);
b_key = Arrays.copyOf(b_key, 16);
SecretKeySpec secretKeySpec = new SecretKeySpec(b_key, "AES");
but I'm not able to find the error, here some output of the decryption:
--------------------------------------------------------
Starting brute force/dictionary attack:
Decrypting................decription succeded, key : enantiopathia elapsed time: 12.995s
--------------------------------------------------------
Decripted message:
"��t����O����m�V��}s1��i#a7� B<2�B֯�R�E�\!��v���k��WK�m��'hՒ���g�y�$�s�ug���
X��l=qYX�����F%�y)���>��r܅͞��i��L'FG��c6-�}���-�|�L�#�n���Ӧ���)�\�o�2|?7/ə���Lc�����-
�/���*���"sK���*[U�ɮ�����s��ec�P��z�6v�����Ov��1e����w�5����t�{s�%���|��W���'�3�^�H�Td��k1���S���l�8��Žѕ���XZ�X�Eiq��K���|�'�Wi��
E2-�k�Zm��
�͞�+tj��p�o\m���jc\���ؠ_v�F�k;���$\O��JW!�zD3cZ�#���N�T�J!^c��<��+���)[sK�=�Sf���Tm���J>�i�tc���1��`ɱs
,,uO��zt� �Ү>j�6��xe�,�z��l�$jW�����n��g��~M��^�s-����}kDr���`ݶ��4��?��hT�G�߿E�Z�w����&��'��фAz��}�-��r�W�2=����ƛ�i�!��Ⱥu�J�8_d��z���9h�]��yi�A�6D�0H�R����g#��������>rS1�e�供�F����H�E[m�����Syc��糠�)��"��b��0%�¤����
o70T&&�T�06�q�F��X`�V��u{1`&Xkx ��7�����|�v
2_�y��VL6z�xu��95�r�H'g�E�J�(\WY�T������T���kXM�bG�^kppڀ#�h�1�9�[���Ǽ�T<�/Oo�B =�iw����Ef��G�S�c<����������W�
�<�H�N����$�m�-=�;�*��].��v��n���&�V��D����_�{9��+��:����̶F0��|�1�9��p�9�* �Rs�Ͱ�Ckl5ͫ�jGB��!��m�h
/��*г-�z�H�w�)Q����p��!� B�p�H˦eOŹ��������< ��Ǹ��[����uP��q�n�T���Lj����yrЙ-$�i��X����T~�R��4�xό~]��G��e�dÖnI��&b{�=�&��Bi�y���%|���E���H�=�k�~į_�6PӬ��D|~
M ;��BK�'�p����o:8��0]������ً �&�k9��2�0�̟WtFy���t�>?GS��� W.����tG�R��$\V�'�����'�&��a����#�b�9�בȨ�yl�+J�M���rƠ�D�0H��B�w;��8\�!���.%��yc��~�9�X ;hq�)�&E�
�W��?�D�-:��,t�f柟.�-P�f�\˲�=S.�&
���X]�����Z�����������j�A(�]�����m�*U'"6��g��jw��
I want to generate a SAS token for access to my blob container where are some of my media files.
So I created a class SharedAccessSignature.java with this code:
public class SharedAccessSignature
{
private final String signature;
private final String signedPermission;
private final String signedStart;
private final String signedExpiry;
private final String signedIdentifier;
private final String signedIp;
private final String signedProtocol;
private final String signedVersion;
private final String signedResource;
private SharedAccessSignature(SasBuilder builder)
{
signedPermission = formatAsUrlParameter("sp", builder.signedPermission);
signedStart = formatAsUrlParameter("st", builder.signedStart);
signedExpiry = formatAsUrlParameter("se", builder.signedExpiry);
signedIdentifier = formatAsUrlParameter("si", builder.signedIdentifier);
signedIp = formatAsUrlParameter("sip", builder.signedIp);
signedProtocol = formatAsUrlParameter("spr", builder.signedProtocol);
signedVersion = formatAsUrlParameter("sv", builder.signedVersion);
signedResource = formatAsUrlParameter("sr", builder.signedResource);
signature = "sig=" + new SasBuilder().encodeUtf8(builder.signature);
}
private String formatAsUrlParameter(String parameterKey, String parameterValue)
{
if (StringUtils.isNotBlank(parameterValue))
{
return parameterKey + "=" + parameterValue + "&";
}
return "";
}
#Override
public String toString()
{
return new StringBuilder()
.append(signedVersion)
.append(signedResource)
.append(signedStart)
.append(signedExpiry)
.append(signedPermission)
.append(signedIp)
.append(signedProtocol)
.append(signedIdentifier)
.append(signature)
.toString();
}
public static class SasBuilder
{
private String signature = "";
private String signedPermission = "";
private String signedStart = "";
private String signedExpiry = "";
private String canonicalizedResource = "";
private String signedIdentifier = "";
private String signedIp = "";
private String signedProtocol = "";
private String signedVersion = "";
private String signedResource = "";
public SasBuilder signedVersion(String signedVersion)
{
this.signedVersion = signedVersion;
return this;
}
public SasBuilder signedPermission(String signedPermission)
{
this.signedPermission = signedPermission;
return this;
}
public SasBuilder canonicalizedResource(String canonicalizedResource)
{
this.canonicalizedResource = canonicalizedResource;
return this;
}
public SasBuilder signedIp(String signedIp)
{
this.signedIp = signedIp;
return this;
}
public SasBuilder signedProtocol(String signedProtocol)
{
this.signedProtocol = signedProtocol;
return this;
}
public SasBuilder signedIdentifier(String signedIdentifier)
{
this.signedIdentifier = signedIdentifier;
return this;
}
public SasBuilder signedExpiry(String signedExpiry)
{
this.signedExpiry = signedExpiry;
return this;
}
public SasBuilder signedStart(String signedStart)
{
this.signedStart = signedStart;
return this;
}
public SasBuilder signedResource(String signedResource)
{
this.signedResource = signedResource;
return this;
}
public SharedAccessSignature build()
{
String toBeAsEnvironmentVariable_securityKey = "....";
signature = generateSasSignature(toBeAsEnvironmentVariable_securityKey, stringToSign());
checkPreconditions();
return new SharedAccessSignature(this);
}
private String generateSasSignature(String key, String input)
{
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
Encoder encoder = Base64.getEncoder();
Mac sha256_HMAC = null;
String hash = null;
try
{
sha256_HMAC = Mac.getInstance("HmacSHA256");
sha256_HMAC.init(secret_key);
hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));
}
catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | UnsupportedEncodingException e)
{
e.printStackTrace();
}
return hash;
}
private String stringToSign()
{
StringBuilder strToSign = new StringBuilder();
strToSign.append(signedPermission).append("\n");
strToSign.append(signedStart).append("\n");
strToSign.append(signedExpiry).append("\n");
strToSign.append(canonicalizedResource).append("\n");
strToSign.append(signedIdentifier).append("\n");
strToSign.append(signedIp).append("\n");
strToSign.append(signedProtocol).append("\n");
strToSign.append(signedVersion).append("\n");
strToSign.append("").append("\n");
strToSign.append("").append("\n");
strToSign.append("").append("\n");
strToSign.append("").append("\n");
strToSign.append("");
return strToSign.toString();
}
private void checkPreconditions()
{
if (StringUtils.isBlank(signedVersion) || StringUtils.isBlank(signedResource) || StringUtils.isBlank(signedPermission) || StringUtils.isBlank(signedExpiry) || StringUtils.isBlank(signature))
{
throw new IllegalStateException("SAS Builder: SignedVersion, signedResource, SignedPermission, SignedExpiry, Signature must be set.");
}
}
private String encodeUtf8(String textToBeEncoded)
{
try
{
return URLEncoder.encode(textToBeEncoded, "UTF-8");
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
return textToBeEncoded;
}
}
}
And then I try to generate a SAS token like this:
SharedAccessSignature s = new SharedAccessSignature.SasBuilder()
.signedPermission("rwd")
.signedStart("2018-01-31T10:48:41Z")
.signedExpiry("2018-04-06T18:48:41Z")
.signedVersion("2015-04-05")
.signedResource("b")
.canonicalizedResource("/blob/myaccount")
.signedProtocol("https")
.build();
outcome:
sv=2015-04-05&sr=b&st=2018-01-31T10:48:41Z&se=2018-04-06T18:48:41Z&sp=rwd&spr=https&sig=kd09Y%2FTL5V%2F570VWRuEfq7XbEHvcgo4Z%2F2y9t4OswY8%3D
GET request:
https://account.blob.core.cloudapi.de/container/filename.mp4?sv=2015-04-05&sr=b&st=2018-01-31T10:48:41Z&se=2018-04-06T18:48:41Z&sp=rwd&spr=https&sig=kd09Y%2FTL5V%2F570VWRuEfq7XbEHvcgo4Z%2F2y9t4OswY8%3D
But as I am sending that request with this generated token there commes this Error from azure:
<Error>
<Code>AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of
Authorization header is formed correctly including the signature.
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was rwd 2018-01-31T10:48:41Z
2018-04-06T18:48:41Z /blob/globalweb/..... https 2015-04-05
</AuthenticationErrorDetail>
</Error>
EDIT:
I am desperate... I don´t understand it... What is wrong on this "string-to-sign"? Why the "Signature did not match"?
--------
rwd\n
2018-01-31T10:48:41Z\n
2018-04-06T18:48:41Z\n
/blob/globalweb/videos-martindale\n
\n
\n
https\n
2015-04-05\n
\n
\n
\n
\n
-------
//link: https://globalweb.blob.core.cloudapi.de/videos-martindale/somevideo.mp4?sv=2015-04-05&sr=c&st=2018-01-31T10:48:41Z&se=2018-04-06T18:48:41Z&sp=rwd&spr=https&sig=kd09Y%2FTL5V%2F570VWRuEfq7XbEHvcgo4Z%2F2y9t4OswY8%3D
<Error>
<Code>AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:644e47a6-001e-0050-3f20-abc0f0000000 Time:2018-02-21T14:31:10.9429817Z
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was rwd 2018-01-31T10:48:41Z 2018-04-06T18:48:41Z /blob/globalweb/videos-martindale https 2015-04-05
</AuthenticationErrorDetail>
</Error>
The main problem is on you generateSasSignature method. It should decode the key from Base64. Like the following:
public static String generateSasSignature(String key, String input) {
SecretKeySpec secret_key = new SecretKeySpec(Base64.getDecoder().decode(key), "HmacSHA256");
Encoder encoder = Base64.getEncoder();
Mac sha256_HMAC = null;
String hash = null;
try {
sha256_HMAC = Mac.getInstance("HmacSHA256");
sha256_HMAC.init(secret_key);
hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));
}
catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return hash;
}
Then, assuming you're interested in having access to the container called mycontainer, this is how you should do:
SharedAccessSignature s = new SharedAccessSignature.SasBuilder()
.signedPermission("rwd")
.signedStart("2018-01-31T10:48:41Z")
.signedExpiry("2018-04-06T18:48:41Z")
.signedVersion("2015-04-05")
.signedResource("c") // <<---- note here
.canonicalizedResource("/blob/globalweb/mycontainer") // No ending slash!
.signedProtocol("https")
.build();
However, if you want to generate an Account SAS, the following code does the trick:
public static void main(String[] args) throws UnsupportedEncodingException {
String accountName = "globalweb";
String signedPermissions = "rl"; //read and list
String signedService = "b"; //blob
String signedResType = "sco"; //service, container, objects
String start = "2018-02-22T17:16:25Z";
String expiry = "2018-02-28T01:16:25Z";
String signedIp = "";
String protocol = "https";
String signedVersion = "2017-07-29";
String stringToSign =
accountName + "\n" +
signedPermissions + "\n" +
signedService + "\n" +
signedResType + "\n" +
start + "\n" +
expiry + "\n" +
signedIp + "\n" +
protocol + "\n" +
signedVersion + "\n";
//outputs SAS Token
System.out.println(
"?sv="+signedVersion +
"&ss="+signedService +
"&srt="+signedResType +
"&sp="+signedPermissions +
"&st="+start+
"&se="+expiry+
"&spr="+protocol+
"&sig="+
URLEncoder.encode(SasBuilder.generateSasSignature(MY_KEY_BASE64, stringToSign), "UTF-8"));
}
Got this same error which led me to this post:
403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
In my case I had an EncodeURI() on the already encoded uri.
Removing this also fixed the error.
Please try this if you are using 12.5. I was able to get this working with the following:
try {
//Authenticate
StorageSharedKeyCredential credential = new StorageSharedKeyCredential(this.getAzureAccountName(), this.getAzureAccountKey());
//Get the Blob Service Client
BlobServiceClient client = new BlobServiceClientBuilder()
.endpoint(this.getAzureEndPoint())
.credential(credential)
.buildClient();
//Get the blobContainerClient
BlobContainerClient blobContainerClient =
blobServiceClient.get().getBlobContainerClient(containerName);
BlockBlobClient blockBlobClient = blobContainerClient
.getBlobClient(bolbName)
.getBlockBlobClient();
//Setting Account Permission
AccountSasPermission permissions = new AccountSasPermission()
.setListPermission(true)
.setReadPermission(true);
//Following line is required if signature to be generated at container level
//AccountSasResourceType resourceTypes = new AccountSasResourceType().setContainer(true);
//In case you want to generate the signature at the object level use
AccountSasResourceType resourceTypes = new AccountSasResourceType().setObject(true);
AccountSasService services = new AccountSasService().setBlobAccess(true).setFileAccess(true);
//Valid for 2 days starting today
OffsetDateTime expiryTime = OffsetDateTime.now().plus(Duration.ofDays(2));
AccountSasSignatureValues sasValues =
new AccountSasSignatureValues(expiryTime, permissions, services, resourceTypes);
String sasToken = blobServiceClient.get().generateAccountSas(sasValues);
sasToken = blockBlobClient.getBlobUrl()+"?"+sasToken;
System.out.println("URL to get view the Blob in Browser "+sasToken);
} catch (Exception e) {
log.error("Error = {}",e.getMessage());
}
I've programmed the following client-server pair to set up a very simplified version of an IPSec-connection (Cryptography-related).
The problem is, that on the second call to readObject(), i.e.:
// Receive finished message from server
finishedMessage = (BigInteger) inputStream.readObject();
I get a java.io.EOFException.
It should be said, that on most runs the EOFException is thrown, but on some runs it runs flawlessly ?
I've been debugging for hours now, but can't find the error.
If anyone can see the error, please let me know - I will appreciate it !
Error message:
[CLIENT]: Connected...
[CLIENT]: Common key = 33569
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at IPSecClient.SetupSSLConnection(IPSecClient.java:68)
at IPSecClient.main(IPSecClient.java:116)
Client:
import java.math.BigInteger;
import java.net.*;
import java.util.ArrayList;
import java.util.Random;
import java.io.*;
public class IPSecClient {
private Socket socket;
private ObjectInputStream inputStream;
private ObjectOutputStream outputStream;
private IPSec gen;
private ArrayList<BigInteger[]> messages;
private BigInteger[] message;
private final int port, numBits;
private String address;
private Random rand;
private int fixedNumber;
private BigInteger fixedPrime, fixedBase, partialKeyClient,
partialKeyServer, commonKey, publicKeyServer, modulusServer;
public IPSecClient() {
rand = new Random();
numBits = 256;
fixedNumber = rand.nextInt(1000);
fixedPrime = new BigInteger("51803");
fixedBase = new BigInteger("3");
gen = new IPSec();
gen.KeyGen(numBits);
messages = new ArrayList<BigInteger[]>();
port = 5000;
address = "localhost";
}
public void SetupSSLConnection() {
try {
socket = new Socket(address, port);
outputStream = new ObjectOutputStream(socket.getOutputStream());
inputStream = new ObjectInputStream(socket.getInputStream());
System.out.println("[CLIENT]: Connected...");
// Send partial key and certificate (public key) to server
partialKeyClient = fixedBase.pow(fixedNumber).mod(fixedPrime);
message = new BigInteger[] {partialKeyClient, gen.PublicKey(), gen.Modulus()};
messages.add(message);
outputStream.writeObject(message);
outputStream.flush();
// Receive partial key and certificate from server
message = (BigInteger[]) inputStream.readObject();
messages.add(message);
partialKeyServer = message[0];
publicKeyServer = message[1];
modulusServer = message[2];
// Generate common key
commonKey = partialKeyServer.pow(fixedNumber).mod(fixedPrime);
System.out.println("[CLIENT]: Common key = " + commonKey.intValue());
// Send finished message
BigInteger accumulatedMessages = AccumulateMessages(messages).mod(gen.PublicKey());
BigInteger finishedMessage = gen.GenerateRSASignature(accumulatedMessages);
outputStream.writeObject(finishedMessage);
outputStream.flush();
// Receive finished message from server
finishedMessage = (BigInteger) inputStream.readObject();
// Verify finished message
boolean result = gen.VerifyRSASignature(AccumulateMessages(messages).mod(publicKeyServer), finishedMessage, publicKeyServer, modulusServer);
System.out.println("[CLIENT]: Verification of finished message " + (result ? "succeeded" : "failed"));
if (!result) {
System.out.println("[CLIENT]: SSL-connection could not be estasblished...");
CloseConnection(-1);
}
System.out.println("[CLIENT]: SSL-connection estasblished...");
CloseConnection(0);
} catch (SocketException se) {
se.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void CloseConnection(int exitCode) {
try {
socket.close();
outputStream.close();
inputStream.close();
System.exit(exitCode);
} catch (IOException e) {
e.printStackTrace();
}
}
private BigInteger AccumulateMessages(ArrayList<BigInteger[]> messages) {
BigInteger accumulator = new BigInteger("0");
for (BigInteger[] message : messages)
{
for (BigInteger part : message)
{
accumulator = accumulator.add(part);
}
}
return accumulator;
}
public static void main(String[] args) {
IPSecClient client = new IPSecClient();
client.SetupSSLConnection();
}
}
Server:
import java.io.*;
import java.math.BigInteger;
import java.net.*;
import java.util.ArrayList;
import java.util.Random;
public class IPSecServer {
private ServerSocket serverSocket;
private Socket socket;
private ObjectInputStream inputStream;
private ObjectOutputStream outputStream;
private IPSec gen;
private ArrayList<BigInteger[]> messages;
private BigInteger[] message;
private final int port;
private Random rand;
private int fixedNumber;
private BigInteger fixedPrime, fixedBase, partialKeyClient,
partialKeyServer, commonKey, publicKeyClient, modulusClient;
public IPSecServer() {
rand = new Random();
fixedNumber = rand.nextInt(1000);
fixedPrime = new BigInteger("51803");
fixedBase = new BigInteger("3");
gen = new IPSec();
gen.KeyGen(2048);
messages = new ArrayList<BigInteger[]>();
port = 5000;
}
public void SetupSSLConnection() {
try {
serverSocket = new ServerSocket(port);
System.out.println("[SERVER]: Listening...");
socket = serverSocket.accept();
inputStream = new ObjectInputStream(socket.getInputStream());
outputStream = new ObjectOutputStream(socket.getOutputStream());
System.out.println("[SERVER]: Connected... " + "Port/IP: " + socket.getPort() + socket.getInetAddress());
// Receive partial key and certificate from client
message = (BigInteger[]) inputStream.readObject();
messages.add(message);
partialKeyClient = message[0];
publicKeyClient = message[1];
modulusClient = message[2];
// Send partial key and certificate to client
partialKeyServer = fixedBase.pow(fixedNumber).mod(fixedPrime);
message = new BigInteger[] {partialKeyServer, gen.PublicKey(), gen.Modulus()};
messages.add(message);
outputStream.writeObject(message);
outputStream.flush();
// Generate common key
commonKey = partialKeyClient.pow(fixedNumber).mod(fixedPrime);
System.out.println("[SERVER]: Common key = " + commonKey.intValue());
// Receive finished message from client
BigInteger finishedMessage = (BigInteger) inputStream.readObject();
messages.add(new BigInteger[] {finishedMessage});
// Verify finished message
boolean result = gen.VerifyRSASignature(AccumulateMessages(messages).mod(publicKeyClient), finishedMessage, publicKeyClient, modulusClient);
System.out.println("[SERVER]: Verification of finished message " + (result ? "succeeded" : "failed"));
if (!result) {
System.out.println("[SERVER]: SSL-connection could not be estasblished...");
CloseConnection(-1);
}
// Send finished message to client
BigInteger accumulatedMessages = AccumulateMessages(messages).mod(gen.PublicKey());
finishedMessage = gen.GenerateRSASignature(accumulatedMessages);
outputStream.writeObject(finishedMessage);
outputStream.flush();
System.out.println("[SERVER]: SSL-connection estasblished...");
CloseConnection(0);
} catch (SocketException se) {
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void CloseConnection(int exitCode) {
try {
socket.close();
outputStream.close();
inputStream.close();
serverSocket.close();
System.exit(exitCode);
} catch (IOException e) {
e.printStackTrace();
}
}
private BigInteger AccumulateMessages(ArrayList<BigInteger[]> messages) {
BigInteger accumulator = new BigInteger("0");
for (BigInteger[] message : messages)
{
for (BigInteger part : message)
{
accumulator = accumulator.add(part);
}
}
return accumulator;
}
public static void main(String[] args) {
IPSecServer server = new IPSecServer();
server.SetupSSLConnection();
}
}
IPSec:
import java.math.BigInteger;
import java.util.Random;
import java.security.*;
public class IPSec {
private static final BigInteger one = new BigInteger("1");
// private key (n,d)
private BigInteger privateKey;
// public key (n,e)
private BigInteger publicKey = new BigInteger("3");
// modulus n
private BigInteger modulus;
public IPSec() {
}
// PUBLIC KEY
public BigInteger PublicKey() {
return publicKey;
}
public BigInteger Modulus() {
return modulus;
}
// KEY GENERATION
public void KeyGen(int keyLength) {
BigInteger p = BigInteger.probablePrime((int)Math.ceil(keyLength / 2), new Random());
BigInteger q = BigInteger.probablePrime((int)Math.ceil(keyLength / 2), new Random());
while (!(p.subtract(one)).gcd(publicKey).equals(one))
p = p.nextProbablePrime();
while (!(q.subtract(one)).gcd(publicKey).equals(one))
q = q.nextProbablePrime();
BigInteger phi = (p.subtract(one)).multiply(q.subtract(one));
modulus = p.multiply(q);
privateKey = publicKey.modInverse(phi);
}
// ENCRYPT
public BigInteger Encrypt(BigInteger message) {
return message.modPow(publicKey, modulus);
}
public static BigInteger Encrypt(BigInteger message, BigInteger publicKey, BigInteger modulus) {
return message.modPow(publicKey, modulus);
}
// DECRYPT
public BigInteger Decrypt(BigInteger message) {
return message.modPow(privateKey, modulus);
}
// SIGNATURE GENERATION
// Generate RSA-signatures for a message
public BigInteger GenerateRSASignature(BigInteger message) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("SHA-256");
return Decrypt(new BigInteger(1, digest.digest(message.toByteArray())).mod(Modulus()));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.exit(-1);
}
return message;
}
// Verify RSA-signatures for a message
public boolean VerifyRSASignature(BigInteger message, BigInteger signature) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return (new BigInteger(1, digest.digest(message.toByteArray())).mod(Modulus())).equals(Encrypt(signature));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.exit(-1);
}
return false;
}
public boolean VerifyRSASignature(BigInteger message, BigInteger signature,
BigInteger publicKey, BigInteger modulus) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return (new BigInteger(1, digest.digest(message.toByteArray())).mod(Modulus())).equals(Encrypt(signature, publicKey, modulus));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.exit(-1);
}
return false;
}
public static void main(String[] args) {
Testing();
}
// MISC
public void printKeys() {
String s = "";
s += "public = " + publicKey + "\n";
s += "private = " + privateKey + "\n";
s += "modulus = " + modulus;
System.out.println(s);
}
public static void Testing() {
IPSec gen = new IPSec();
gen.KeyGen(128);
BigInteger message = new BigInteger("329");
System.out.println("Verify: " + gen.VerifyRSASignature(message, gen.GenerateRSASignature(message)));
}
}
Your server is barfing at the signature-verifying stage here:
if (!result) {
System.out.println("[SERVER]: SSL-connection could not be established...");
CloseConnection(-1);
}
and closing the socket without sending the FINISHED message. Check its output log. In such a case maybe you should send an error object first. Or else treat EOFException as a handshake failure.
NB:
For safety it is best to contruct the ObjectOutputStream before the ObjectInputStream at both ends.
You should close the ObjectOutputStream, not the socket, or the input stream. That way you can be sure it gets flushed. Closing any of the three closes the other two.
Don't call things 'SSL' when they aren't.