I have a Java Project to Authenticate images over a wireless network. I am using blowfish for encryption of images. The problem I am facing is how to send the blowfish symmetric key to the receiver so that he can decrypt the image. I am relatively new to cryptography.Please include the code snippet to illustrate the same.
package ClientModule;
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.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.swing.*;
public class ImageEncryption_Client
{
KeyGenerator keyGenerator = null;
public static SecretKey secretKey = null;
public static Cipher cipher = null;
ImageEncryption_Client(){
try {
/**
* Create a Blowfish key
*/
keyGenerator = KeyGenerator.getInstance("Blowfish");
secretKey = keyGenerator.generateKey();
System.out.println(secretKey.toString());
/**
* Create an instance of cipher mentioning the name of algorithm
* - Blowfish
*/
cipher = Cipher.getInstance("Blowfish");
System.out.println(cipher.toString());
} catch (NoSuchPaddingException ex) {
System.out.println(ex);
} catch (NoSuchAlgorithmException ex) {
System.out.println(ex);
}
}
private void encrypt(String srcPath, String destPath)
{
File rawFile = new File(srcPath);
File encryptedFile = new File(destPath);
InputStream inStream = null;
OutputStream outStream = null;
try {
/**
* Initialize the cipher for encryption
*/
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
/**
* Initialize input and output streams
*/
inStream = new FileInputStream(rawFile);
outStream = new FileOutputStream(encryptedFile);
byte[] buffer = new byte[1024];
int len;
while ((len = inStream.read(buffer)) > 0) {
outStream.write(cipher.update(buffer, 0, len));
outStream.flush();
}
outStream.write(cipher.doFinal());
inStream.close();
outStream.close();
} catch (IllegalBlockSizeException ex) {
JOptionPane.showMessageDialog(null,"An Exception Occurred","Exception",JOptionPane.ERROR_MESSAGE);
System.out.println(ex);
} catch (BadPaddingException ex) {
JOptionPane.showMessageDialog(null,"An Exception Occurred","Exception",JOptionPane.ERROR_MESSAGE);
System.out.println(ex);
} catch (InvalidKeyException ex) {
JOptionPane.showMessageDialog(null,"An Exception Occurred","Exception",JOptionPane.ERROR_MESSAGE);
System.out.println(ex);
} catch (FileNotFoundException ex) {
JOptionPane.showMessageDialog(null,"An Exception Occurred","Exception",JOptionPane.ERROR_MESSAGE);
System.out.println(ex);
} catch (IOException ex) {
JOptionPane.showMessageDialog(null,"An Exception Occurred","Exception",JOptionPane.ERROR_MESSAGE);
System.out.println(ex);
}
}
void enc(String filename)//, String dir)
{
String fileToEncrypt = filename;
String arr[]=filename.split("\\.");
String encryptedFile = arr[0]+"_encrypted."+arr[1];
String directoryPath = "C:\\Users\\Public\\Pictures\\Sample Pictures\\";
encrypt(directoryPath + fileToEncrypt,
directoryPath + encryptedFile);
}
public static void main(String... kkk)
{
new ImageEncryption_Client().enc("Koala.jpg");//,"");
}
}
First off, I wouldn't tread into this area without doing a bit more research or consulting a security expert.
One really good resource on crypto specifically targeted at developers is: https://www.schneier.com/books/cryptography_engineering/
Now on to answering your question. I would first question whether you actually need to do key-exchange or whether you could get away with setting up a pre-shared secret / key pair on both sides.
Key Exchange
Key exchange is the class of problem you're asking about. There are many implementations:
http://en.wikipedia.org/wiki/Key_exchange
Diffie Hellman is a classic approach which is popular in SSL and TLS:
http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
A java implementation example of Diffie Hellman can be found here:
http://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/CryptoSpec.html#DH2Ex
Pre-shared Key
Key exchange is complex and requires that you own both sides of the communication. Another approach would be to place a shared secret on both ends of the communication. The simplest approach would be to share a symmetric key. http://en.wikipedia.org/wiki/Shared_secret
A slightly more secure approach would be to use asymmetric keys (public key crypto) where each side generates it's own public private key pair and then you pre-share the public key with the other end. So in the classic example where Alice and Bob want to communicate securely, Alice would give Bob her public key and Bob would encrypt all data sent to Alice with her public key. She could then decrypt it with her private key. This approach has the advantage where if any one side is compromised the attacker can't read messages encrypted for the other side. More details are outlined here:
http://en.wikipedia.org/wiki/Public-key_cryptography
A third and slightly more granular approach building on the last one would be to generate a symmetric key per image and encrypt the image with that key. Then encrypt the symmetric key with the public key of the party you're sending the data to. When sending the image over the wire you'd include the encrypted key and the encrypted image. This model is useful because symmetric encryption is faster and better suited for large files like images but combining them in this way you still get the benefits of using public key crypto to protect the transport.
If you happen to be doing this up on AWS, their KMS service would make it very easy to have a shared encryption key across servers. They also use a multi-level crypto approach similar to the last model but in this case the master key is stored on a hardware security module (HSM), which has the added benefit that the master key is never known and can never be pulled off the chip it lives on:
http://aws.amazon.com/kms/
Related
I am new to JavaFX and cryptography. In this project I need to select a file with file chooser and encrypt it with private key. I have 2 buttons;chooseFileBtn and sendFileBtn. When I click chooseFileBtn, I choose a file and then with clicking sendFileBtn, it should encrypt it with private key. I tried this code below but I got some errors.
Controller:
package com.example.demo1;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.stage.FileChooser;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
public class HelloController {
#FXML
private Label chooseFileBtn;
#FXML
private Label sendFileBtn;
#FXML
private ListView listView;
File selectedFile;
#FXML
public void chooseFileButtonClick(ActionEvent event) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
FileChooser fc = new FileChooser();
File selectedFile = fc.showOpenDialog(null);
if( selectedFile != null)
{
listView.getItems().add(selectedFile.getPath());
}
else {
System.out.println("File is now valid");
}
}
#FXML
public void sendFileButtonClick(ActionEvent event)throws Exception{
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
KeyPair pair = generator.generateKeyPair();
PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
try (FileOutputStream fos = new FileOutputStream("private.key")) {
fos.write(privateKey.getEncoded());
}
File privateKeyFile = new File("private.key");
byte[] privateKeyBytes = Files.readAllBytes(privateKeyFile.toPath());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new X509EncodedKeySpec(privateKeyBytes);
keyFactory.generatePublic(privateKeySpec);
byte[] fileBytes = Files.readAllBytes(selectedFile.toPath());
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] encryptedFileBytes = encryptCipher.doFinal(fileBytes);
try (FileOutputStream stream = new FileOutputStream(selectedFile)) {
stream.write(encryptedFileBytes);
}
}
}
fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<VBox alignment="CENTER" prefHeight="327.0" prefWidth="323.0" spacing="20.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demo1.HelloController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
<children>
<Label prefHeight="127.0" prefWidth="276.0" text="File Transfer Application">
<font>
<Font name="American Typewriter" size="23.0" />
</font>
</Label>
<Button fx:id="chooseFileBtn1" mnemonicParsing="false" onAction="#chooseFileButtonClick" text="Choose A File" />
<ListView fx:id="listView" prefHeight="28.0" prefWidth="283.0" />
<Button fx:id="sendFileBtn1" mnemonicParsing="false" onAction="#sendFileButtonClick" text="Send The File" />
</children>
</VBox>
Errors:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
Caused by: java.lang.reflect.InvocationTargetException
Caused by: java.security.spec.InvalidKeySpecException
Caused by: java.security.InvalidKeyException
Why do I get these errors and how can I fix it?
I don't know what the actual issue with your code is (I didn't try to debug it). But your code is pretty close to what you need.
I implemented some basic crypto functions in the JavaFX sample app below and it worked fine for me (OpenJDK 19 + JavaFX 19, OS X 13). It doesn't use file operations, so it is not exactly what you are trying to implement. Perhaps try it and check that it works in your environment, then compare the implementation to yours and change what you need to solve your exact problem.
Study:
https://crypto.stackexchange.com/questions/2123/rsa-encryption-with-private-key-and-decryption-with-a-public-key
and some other external crypto resources, to better understand the subject field.
There is some jargon and terms in this solution, if you don't understand any of them, run some independent research.
The example encrypts with a public key and decrypts with a private key because, generally, that makes more sense for most operations as noted in the linked question. There is no technical issue in encrypting with a private key and decrypting with a public key (it works, you can try it by modifying the sample code), it just makes less sense to do so.
If you encrypt with the private key, the encrypted text can only be decrypted with the public key, but the public key is public, so anybody could have that and anybody could decrypt the file. This is why such encryption and decryption techniques are used as a step in signature generation and verification, rather than encryption of text for confidentiality. By comparison, if you encrypt with the public key and decrypt with the private key, only somebody with whom the private key has been shared can decrypt the text, thus confidentiality is preserved.
The example also just straight-up encrypts and decrypts the file with the RSA pair. Often in an actual application, a more complex approach is used. The asymmetric key might be used to encrypt a symmetric key which is actually used to encrypt or decrypt the document text (or password-based encryption, PBE may be used). The encrypted symmetric key may or may not be stored in the encrypted document together with some packaging metadata in ASN.1 notation describing the algorithms (name, cipher mode, padding method, etc) used in encrypting the document. For instance in a PKCS 7 or PKCS 12 or PGP encrypted format. Demonstration of these more complex cases is beyond the scope of this answer.
Crypto.java
Generates a new RSA key in the constructor.
The algorithm used and keysize are hardcoded, in an actual app, you would make such information configurable.
The encryption block and padding settings are left as default for the algorithm rather than being explictly provided.
UTF-8 is used as the character encoding for the translation of plain text to and from bytes.
You will want to save the private key if you wish to be able to decrypt the encrypted data after the app has shut down.
You will also want to save the public key if you wish to be able to encrypt new data with the same key after the app has shut down.
You would also need to add functionality to initialize the crypto functions with saved keys rather than generated ones.
The additional persistence management functions for keys are not in scope for this answer.
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
class Crypto {
private final PrivateKey privateKey;
private final PublicKey publicKey;
public Crypto() throws NoSuchAlgorithmException {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
KeyPair pair = generator.generateKeyPair();
privateKey = pair.getPrivate();
publicKey = pair.getPublic();
}
public String encrypt(String plainText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = encryptCipher.doFinal(
plainText.getBytes(StandardCharsets.UTF_8)
);
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public String decrypt(String cipherText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] encryptedBytes = decryptCipher.doFinal(
Base64.getDecoder().decode(cipherText.getBytes(StandardCharsets.UTF_8))
);
return new String(encryptedBytes, StandardCharsets.UTF_8);
}
}
EncryptApp.java
Encrypts plain text in a text area using the crypto functions (RSA public key).
Decrypts cipher text in a text area using the crypto functions (RSA private key).
For display, the cipher text is base 64 encoded.
Using file handling, you can adapt this solution to persist the plain text and cipher text. This persistence is out of the scope of this answer.
The UI is coded inline in the application in order not to complicate the solution, but the UI can be defined in CSS and FXML and UI binding and action handling moved to an FXML controller if desired.
import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class EncryptApp extends Application {
private static final String SAMPLE_TEXT = """
There once was a man from Nantucket,
Who kept all his cash in a bucket.
But his daughter, named Nan,
Ran away with a man,
And as for the bucket, Nantucket.
""";
#Override
public void start(Stage stage) {
final Crypto crypto;
try {
crypto = new Crypto();
} catch (Exception e) {
System.err.println("Unable to initialize crypto functions");
e.printStackTrace();
Platform.exit();
return;
}
TextArea plainTextArea = new TextArea(SAMPLE_TEXT);
plainTextArea.setStyle("-fx-font-family: monospace;");
Button encryptButton = new Button("Encrypt");
Button clearButton = new Button("Clear");
clearButton.setOnAction(e -> plainTextArea.clear());
clearButton.disableProperty().bind(
plainTextArea.textProperty().isEmpty()
);
VBox encryptSection = new VBox(10,
new HBox(10, encryptButton, clearButton),
plainTextArea
);
TextArea cipherTextArea = new TextArea();
cipherTextArea.setStyle("-fx-font-family: monospace;");
cipherTextArea.setEditable(false);
cipherTextArea.setWrapText(true);
Button decryptButton = new Button("Decrypt");
decryptButton.disableProperty().bind(
cipherTextArea.textProperty().isEmpty()
);
VBox decryptSection = new VBox(10, decryptButton, cipherTextArea);
encryptButton.setOnAction(e ->
encrypt(crypto, plainTextArea, cipherTextArea)
);
decryptButton.setOnAction(e ->
decrypt(crypto, plainTextArea, cipherTextArea)
);
HBox layout = new HBox(
10,
encryptSection,
decryptSection
);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
}
private static void decrypt(Crypto crypto, TextArea plainTextArea, TextArea cipherTextArea) {
try {
plainTextArea.setText(
crypto.decrypt(cipherTextArea.getText())
);
} catch (Exception ex) {
String msg = "Unable to decrypt cipher text";
plainTextArea.setText(msg);
System.err.println(msg);
ex.printStackTrace();
}
}
private static void encrypt(Crypto crypto, TextArea plainTextArea, TextArea cipherTextArea) {
try {
cipherTextArea.setText(
crypto.encrypt(plainTextArea.getText())
);
} catch (Exception ex) {
String msg = "Unable to encrypt plain text";
cipherTextArea.setText(msg);
System.err.println(msg);
ex.printStackTrace();
}
}
public static void main(String[] args) {
launch();
}
}
module-info.java
The module-info.java requires jdk.crypto.cryptoki, which provides the sun crypto provider for the RSA algorithms. That will already be in a standard JDK distribution. But, if you jlink this application, by default, it will only link the minimum modules it thinks it needs and the linker won't know to include the sun crypto provider. That is why the cryptoki module is explicitly required.
module com.example.fxencrypt {
requires javafx.controls;
requires jdk.crypto.cryptoki;
exports com.example.fxencrypt;
}
java version 1.8
import java.io.ByteArrayInputStream;
import java.security.KeyFactory;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;
/**
*
* #author user
*/
public class Test {
public static void main(String[] args) throws Exception {
String publicKeyB64 = "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";
String data = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjU2MzU4ODUyMzRCOTI1MkRERTAwNTc2NkQ5RDlGMjc2NTY1RjYzRTIiLCJ4NXQiOiJWaldJVWpTNUpTM2VBRmRtMmRueWRsWmZZLUkiLCJ0eXAiOiJKV1QifQ.eyJhcHBjdHhzZW5kZXIiOiIwMDAwMDAwMi0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDBAOGU5MDAzNTgtOWJjMC00YmQyLTlmMzQtNDU5OTY3ODk5MDVkIiwiaXNicm93c2VyaG9zdGVkYXBwIjoiVHJ1ZSIsImFwcGN0eCI6IntcIm1zZXhjaHVpZFwiOlwiYTVkYWY0YzItZTdiYS00NDE5LTljYmUtYjQ4NWE2ZTNiNGQ1XCIsXCJ2ZXJzaW9uXCI6XCJFeElkVG9rLlYxXCIsXCJhbXVybFwiOlwiaHR0cHM6Ly9vdXRsb29rLm9mZmljZTM2NS5jb206NDQzL2F1dG9kaXNjb3Zlci9tZXRhZGF0YS9qc29uLzFcIn0iLCJuYmYiOjE1OTMwMjA4MzAsImV4cCI6MTU5MzA0OTYzMCwiaXNzIjoiMDAwMDAwMDItMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwQDhlOTAwMzU4LTliYzAtNGJkMi05ZjM0LTQ1OTk2Nzg5OTA1ZCIsImF1ZCI6Imh0dHBzOi8vbWFpbGFwcC5mb3JjZS5jb20vY2xpZW50cy9tYWlsYXBwL2FjdGl2YXRpb24ifQ";
String signature = "oifeWN-wnci-WCS6XPLC-74ynG9rmXdePVfMMxX9WsAXOK5tvRpNmNsPqu9bllufAIUhgpNIYtHEB39-_o2pzpugyfkohLJfPovEQa-1X8zzudjxY3j5tRyISzVuwL9l6zROhJIdOvXsoarzcuQ38j492H7ol7auTvfDI4Mwu4Ri_e2rbiFYWsYU36Htj39DEiOvpQ12z7Onu-Yrj1inICTDtJsOdv9HWrO2nZ5IwRdl45Tt0Ks3ZrBeStleNVCXQdU_xKvYtbO02fUfgkFrIzEUZYHgXbK8sE2m0phmeU7Wp-KdW4jVVl9yLQtB98_FJJfw9tI4Oys2NBBY2sLyhQ";
RSAPublicKey secret = null;
try {
secret = null;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(new ByteArrayInputStream(Base64.getMimeDecoder().decode(publicKeyB64)));
secret = (RSAPublicKey) cert.getPublicKey();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
KeyFactory kf = KeyFactory.getInstance("RSA");
Signature privateSignature = Signature.getInstance("SHA256withRSA");
privateSignature.initVerify(secret);
privateSignature.update(data.getBytes("UTF-8"));
System.out.println(privateSignature.verify(Base64.getMimeDecoder().decode(signature.getBytes())));
}
}
Getting the following exception:
Exception in thread "main" java.security.SignatureException: Signature length not correct: got 248 but was expecting 256
at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:211)
at java.security.Signature$Delegate.engineVerify(Signature.java:1394)
at java.security.Signature.verify(Signature.java:771)
at com.ciphercloud.plugin.salesforce.rewriters.Test.main(Test.java:35)
One more question:
Earlier, I used the Base64.getDecoder().decode(signature.getBytes())) but it's throwing an error, so I changed to Base64.getMimeDecoder().decode(signature.getBytes())). May I know why it faild with Base64.getDecoder().decode()?
The problem here is the wrong decoding.
Neither Mime (Base64.getMimeDecoder().decode()) nor Base64 (Base64.getDecoder().decode()) are correct.
JWT uses Base64url encoding, not Base64. The difference are the - and _ characters, which are used in base64url to replace the + and / of the Base64 standard. Also the padding = is omitted in Base64url encoding.
The correct way to decode the JWT header, payload and signature is to use the Base64url decoder:
Base64.getUrlDecoder().withoutPadding().decode()
I am trying to write a ssl decryption program. I found some old code from 2010 and have tried to get it to run. After finally being able to compile it I now get this error:
Exception in thread "main" java.lang.IllegalAccessError: tried to access class sun.security.ssl.CipherSuite from class sun.security.ssl.decrypt at sun.security.ssl.decrypt.main(decrypt.java:36)
which is the line where I call CipherSuite.valueOf(0x00, 0x2f); (deleted some comment lines that's why it might be another line number here)
Now I have read that it would probably be a problem with the method valueOf() being private. Since I am a newbie to java I don't know how to handle that, because the code I would need to change is in a jar. (Using openjdk-1.7)
On the other hand, it says here
that the method is just static. Also checking with .isAvailable() like recommended in the link above (at the .valueOf method) does not help.
Any suggestions?
Here is the code I got so far:
package sun.security.ssl;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.SecretKey;
import javax.xml.bind.DatatypeConverter;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.security.internal.spec.TlsKeyMaterialParameterSpec;
import sun.security.internal.spec.TlsKeyMaterialSpec;
import sun.security.ssl.CipherSuite.BulkCipher;
public class decrypt {
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException {
byte[] clrnd = DatatypeConverter.parseHexBinary("be9b706c800f93526913732a356c7e7fe9383ace52f5ed120d38a81db07e903d");
byte[] srvrnd = DatatypeConverter.parseHexBinary("56af786428bc3e0c69ef2fdd9f6e3456ceae660a323d6109e9554b4af7fe6652");
ProtocolVersion pv = ProtocolVersion.valueOf(0x03, 0x03);
CipherSuite cipher_suite = CipherSuite.valueOf(0x00, 0x2f);
String KeyAlgo = cipher_suite.cipher.algorithm;
String Master_Key = "c55ca8dd56fa59b80b8ff01d9a1d4f04251aec41ab6340e8db118b3d4d2ef895cc51592f9bcd5dbde5eda9d5ad386f34";
byte[] master_secret = DatatypeConverter.parseBase64Binary(Master_Key);
byte[] client_app_data = DatatypeConverter.parseHexBinary("715e388b6ed9339faa6fc640f329c358");
SecretKey masterkey = new SecretKeySpec(master_secret, 0, master_secret.length, KeyAlgo);
//Calculate connection keys
BulkCipher cipher = cipher_suite.cipher;
int expandedKeySize = cipher_suite.exportable ? cipher.expandedKeySize : 0;
KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsKeyMaterial");
int pv_major = pv.major;
int pv_minor = pv.minor;
try {
kg.init(new TlsKeyMaterialParameterSpec(masterkey, pv_major, pv_minor, clrnd, srvrnd, cipher.algorithm, cipher.keySize, expandedKeySize, cipher.ivSize, cipher_suite.macAlg.size, cipher_suite.prfAlg.getPRFHashAlg(), cipher_suite. prfAlg.getPRFHashLength(), cipher_suite.prfAlg.getPRFBlockSize()));
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(decrypt.class.getName()).log(Level.SEVERE, null, ex);
}
TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey();
SecretKey clntWriteKey = keySpec.getClientCipherKey();
IvParameterSpec clntWriteIV = keySpec.getClientIv();
SecureRandom clientrandom = new SecureRandom(clrnd);
CipherBox svbox = cipher_suite.cipher.newCipher(pv, clntWriteKey, clntWriteIV, clientrandom, false);
try {
svbox.decrypt(client_app_data, 5, client_app_data.length-5, 0);
} catch (BadPaddingException ex) {
Logger.getLogger(decrypt.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(svbox);
}
}
Thanks!
I guess because it uses the default access modifier.
Java Access Modifiers
The class sun.security.ssl.CipherSuite uses the default access modifier. This means that you can only access this class from the same package, which is not the case in your project.
CipherSuite class definition
"TLS_RSA_WITH_AES_128_CBC_SHA256" cipher suite is supported by java 8 default providers. Ref - https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SunJSSEProvider.
Also I have following program to verify that.
But when I try to get the cipher for the same algorithm it gives error.
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
public class CipherSuitesInfoGenerator {
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException {
SSLContext context = SSLContext.getDefault();
SSLSocketFactory sf = context.getSocketFactory();
String[] cipherSuites = sf.getSupportedCipherSuites();
String cipherName = "TLS_RSA_WITH_AES_128_CBC_SHA256";
for (String s : cipherSuites) {
if (s.equals(cipherName)) {
System.out.println(cipherName + " is supported");
try {
Cipher cipher = Cipher.getInstance(cipherName);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
}
}
}
}
The output is:
TLS_RSA_WITH_AES_128_CBC_SHA256 is supported
Cannot find any provider supporting TLS_RSA_WITH_AES_128_CBC_SHA256
A ciphersuite is something that is used internally in a JSSE provider, it defines the primitives used within the TLS protocol. It's not a Cipher, a Cipher instance in Java represents one primitive used for encryption/decryption such as AES or RSA.
I am working on an application that uploads a file to amazon s3(part of the application). But when I generate the URL of the files, it shows the authentication key, file name and etc. I need to encrypt the URL. Also I am using tiny url to shorten the URL but when I put the curser on the link it shows the real URL. I looked for md5 but I couldn't make it work. Is there any suggestion?
I will try to explain how MD5 works
import java.math.*;
import java.security.*;
public class testMain {
/**
* #param args
*/
public static void main(String[] args) {
String stringThatNeedsToBeEncrpyted = "yourURL"; // Value to encrypt
MessageDigest mdEnc = null;
try {
mdEnc = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // Encryption algorithm
mdEnc.update(stringThatNeedsToBeEncrpyted.getBytes(), 0, stringThatNeedsToBeEncrpyted.length());
String md5 = new BigInteger(1, mdEnc.digest()).toString(16); //Make the Encrypted string
System.out.println(md5); //print the string in the console
}
}
The output is : 7f5976785d03c60f9fd4b08fb78e72ce
This is your message digest.
EDIT
Hashing a username and password should always be done with an appropriate hashing algorithm like PBKDF2, bcrypt or scrypt. Furthermore always use SSL to transfer confidential data.