Refactor file upload/download with service layer and secure encryption
- Replaced direct encryption logic in FileController with FileService delegation - Added JWT-based username extraction in file operations - Updated FileMetadata entity to include `uploadedAt` field and removed redundant getters/setters - Refactored EncryptionUtil: - Switched to AES-CBC with PBKDF2 key derivation - Removed RSA-based encryption logic - Added salt and IV generation helpers - Changed JwtAuthenticationFilter to fetch user by username (not email) - Renamed method in FileMetadataRepository to match new parameter order FILE UPLOAD NOW WORKS! TESTED USING CURL.
This commit is contained in:
@@ -1,79 +1,70 @@
|
||||
package com.skycrate.backend.skycrateBackend.controller;
|
||||
|
||||
import com.skycrate.backend.skycrateBackend.entity.FileMetadata;
|
||||
import com.skycrate.backend.skycrateBackend.repository.FileMetadataRepository;
|
||||
import com.skycrate.backend.skycrateBackend.security.EncryptionService;
|
||||
import org.apache.hadoop.fs.FSDataInputStream;
|
||||
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import com.skycrate.backend.skycrateBackend.services.FileService;
|
||||
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.io.OutputStream;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/files")
|
||||
public class FileController {
|
||||
|
||||
@Autowired
|
||||
private FileSystem hdfs;
|
||||
private final FileService fileService;
|
||||
private final JwtService jwtService;
|
||||
|
||||
@Autowired
|
||||
private FileMetadataRepository metadataRepo;
|
||||
public FileController(FileService fileService, JwtService jwtService) {
|
||||
this.fileService = fileService;
|
||||
this.jwtService = jwtService;
|
||||
}
|
||||
|
||||
@PostMapping("/upload")
|
||||
public String upload(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("password") String password,
|
||||
Authentication auth) throws Exception {
|
||||
public ResponseEntity<String> uploadFile(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("password") String password,
|
||||
HttpServletRequest request
|
||||
) {
|
||||
try {
|
||||
String token = extractToken(request);
|
||||
String username = jwtService.extractUsername(token);
|
||||
|
||||
byte[] fileBytes = file.getBytes();
|
||||
byte[] salt = EncryptionService.generateSalt();
|
||||
byte[] iv = new byte[12];
|
||||
new SecureRandom().nextBytes(iv);
|
||||
SecretKey key = EncryptionService.deriveKey(password, salt);
|
||||
fileService.uploadEncryptedFile(username, password, file.getBytes(), file.getOriginalFilename());
|
||||
|
||||
byte[] encrypted = EncryptionService.encrypt(fileBytes, key, iv);
|
||||
String pathStr = "/user/" + auth.getName() + "/" + file.getOriginalFilename();
|
||||
Path hdfsPath = new Path(pathStr);
|
||||
|
||||
try (FSDataOutputStream out = hdfs.create(hdfsPath, true)) {
|
||||
out.write(encrypted);
|
||||
return ResponseEntity.ok("File uploaded and encrypted successfully.");
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.status(500).body("File upload failed: " + e.getMessage());
|
||||
}
|
||||
|
||||
FileMetadata metadata = new FileMetadata();
|
||||
metadata.setUsername(auth.getName());
|
||||
metadata.setFilePath(pathStr);
|
||||
metadata.setSalt(salt);
|
||||
metadata.setIv(iv);
|
||||
metadataRepo.save(metadata);
|
||||
|
||||
return "File uploaded and encrypted successfully!";
|
||||
}
|
||||
|
||||
@GetMapping("/download")
|
||||
public void download(@RequestParam("path") String path,
|
||||
@RequestParam("password") String password,
|
||||
Authentication auth,
|
||||
OutputStream responseStream) throws Exception {
|
||||
@GetMapping("/download/{filename}")
|
||||
public ResponseEntity<?> downloadFile(
|
||||
@PathVariable String filename,
|
||||
@RequestParam("password") String password,
|
||||
HttpServletRequest request
|
||||
) {
|
||||
try {
|
||||
String token = extractToken(request);
|
||||
String username = jwtService.extractUsername(token);
|
||||
|
||||
Optional<FileMetadata> optional = metadataRepo.findByFilePathAndUsername(path, auth.getName());
|
||||
if (optional.isEmpty()) {
|
||||
throw new SecurityException("You are not authorized to access this file.");
|
||||
byte[] decryptedData = fileService.downloadDecryptedFile(username, password, filename);
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.body(decryptedData);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.status(500).body("File download failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
FileMetadata metadata = optional.get();
|
||||
SecretKey key = EncryptionService.deriveKey(password, metadata.getSalt());
|
||||
|
||||
try (FSDataInputStream input = hdfs.open(new Path(path))) {
|
||||
byte[] encrypted = input.readAllBytes();
|
||||
byte[] decrypted = EncryptionService.decrypt(encrypted, key, metadata.getIv());
|
||||
responseStream.write(decrypted);
|
||||
private String extractToken(HttpServletRequest request) {
|
||||
String authHeader = request.getHeader("Authorization");
|
||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||
throw new RuntimeException("Missing or invalid Authorization header");
|
||||
}
|
||||
return authHeader.substring(7);
|
||||
}
|
||||
}
|
||||
@@ -30,14 +30,7 @@ public class FileMetadata {
|
||||
@Column(nullable = false)
|
||||
private byte[] iv;
|
||||
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
public void setFilePath(String filePath) { this.filePath = filePath; }
|
||||
public void setSalt(byte[] salt) { this.salt = salt; }
|
||||
public void setIv(byte[] iv) { this.iv = iv; }
|
||||
|
||||
public String getUsername() { return this.username; }
|
||||
public String getFilePath() { return this.filePath; }
|
||||
public byte[] getSalt() { return this.salt; }
|
||||
public byte[] getIv() { return this.iv; }
|
||||
@Column(nullable = false)
|
||||
private long uploadedAt;
|
||||
|
||||
}
|
||||
+1
-1
@@ -6,5 +6,5 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface FileMetadataRepository extends JpaRepository<FileMetadata, Long> {
|
||||
Optional<FileMetadata> findByFilePathAndUsername(String filePath, String username);
|
||||
Optional<FileMetadata> findByUsernameAndFilePath(String username, String filePath);
|
||||
}
|
||||
+5
-4
@@ -45,7 +45,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
final String authHeader = request.getHeader("Authorization");
|
||||
final String jwt;
|
||||
final String userEmail;
|
||||
final String username;
|
||||
|
||||
if (!StringUtils.hasText(authHeader) || !authHeader.startsWith("Bearer ")) {
|
||||
filterChain.doFilter(request, response);
|
||||
@@ -62,15 +62,16 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
}
|
||||
|
||||
try {
|
||||
userEmail = jwtService.extractUsername(jwt);
|
||||
username = jwtService.extractUsername(jwt); // This is actually the `username`, not email
|
||||
} catch (Exception e) {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
response.getWriter().write("Invalid JWT token");
|
||||
return;
|
||||
}
|
||||
|
||||
if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
User user = userRepository.findByEmail(userEmail).orElse(null);
|
||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
// ❗ Use username to find the user
|
||||
User user = userRepository.findByUsername(username).orElse(null);
|
||||
|
||||
if (user != null && jwtService.isTokenValid(jwt, user)) {
|
||||
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
|
||||
|
||||
@@ -1,102 +1,79 @@
|
||||
package com.skycrate.backend.skycrateBackend.services;
|
||||
|
||||
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
public class EncryptionUtil {
|
||||
private static final String RSA_ALGORITHM = "RSA";
|
||||
private static final String AES_ALGORITHM = "AES";
|
||||
private static final int RSA_KEY_SIZE = 2048;
|
||||
private static final int AES_KEY_SIZE = 256;
|
||||
|
||||
// Generate RSA Key Pair (Public & Private)
|
||||
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(RSA_ALGORITHM);
|
||||
keyGen.initialize(RSA_KEY_SIZE);
|
||||
return keyGen.generateKeyPair();
|
||||
private static final int SALT_LENGTH = 16; // in bytes
|
||||
private static final int IV_LENGTH = 16; // for AES CBC
|
||||
private static final int ITERATIONS = 65536;
|
||||
private static final int KEY_LENGTH = 256; // bits
|
||||
|
||||
// --- AES key derivation using PBKDF2 ---
|
||||
public static SecretKey deriveAESKey(char[] password, byte[] salt)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
|
||||
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||
|
||||
KeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
|
||||
byte[] keyBytes = factory.generateSecret(spec).getEncoded();
|
||||
|
||||
return new SecretKeySpec(keyBytes, "AES");
|
||||
}
|
||||
|
||||
// Encrypt data using AES (AES Key is encrypted using RSA)
|
||||
// public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
|
||||
// // Step 1: Generate AES Key
|
||||
// SecretKey aesKey = generateAESKey();
|
||||
//
|
||||
// // Encrypt data using AES
|
||||
// Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
// aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
|
||||
// byte[] encryptedData = aesCipher.doFinal(data);
|
||||
//
|
||||
// // Encrypt the AES key with RSA
|
||||
// Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
// rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
// byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded());
|
||||
//
|
||||
// // Step 4: Combine encrypted AES key and encrypted data into one array
|
||||
// byte[] combined = new byte[4 + encryptedAesKey.length + encryptedData.length];
|
||||
//
|
||||
// // First 4 bytes indicate the length of the AES encrypted key
|
||||
// combined[0] = (byte) (encryptedAesKey.length >> 24);
|
||||
// combined[1] = (byte) (encryptedAesKey.length >> 16);
|
||||
// combined[2] = (byte) (encryptedAesKey.length >> 8);
|
||||
// combined[3] = (byte) encryptedAesKey.length;
|
||||
//
|
||||
// // Copy AES Key and Encrypted Data into the combined array
|
||||
// System.arraycopy(encryptedAesKey, 0, combined, 4, encryptedAesKey.length);
|
||||
// System.arraycopy(encryptedData, 0, combined, 4 + encryptedAesKey.length, encryptedData.length);
|
||||
//
|
||||
// return combined;
|
||||
// }
|
||||
// --- Encrypt data using AES-CBC ---
|
||||
public static byte[] encrypt(byte[] data, SecretKey key, byte[] iv)
|
||||
throws GeneralSecurityException {
|
||||
|
||||
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
|
||||
SecretKey aesKey = RSAKeyUtil.generateAESKey(256); // Ensure 256 bits
|
||||
byte[] encryptedData = encryptDataWithAES(data, aesKey);
|
||||
byte[] encryptedAesKey = RSAKeyUtil.encryptAESKey(aesKey, publicKey);
|
||||
return combineEncryptedData(encryptedAesKey, encryptedData);
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
|
||||
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
private static byte[] encryptDataWithAES(byte[] data, SecretKey aesKey) throws Exception {
|
||||
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
|
||||
return aesCipher.doFinal(data);
|
||||
// --- Decrypt data using AES-CBC ---
|
||||
public static byte[] decrypt(byte[] encryptedData, SecretKey key, byte[] iv)
|
||||
throws GeneralSecurityException {
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
|
||||
|
||||
return cipher.doFinal(encryptedData);
|
||||
}
|
||||
|
||||
private static byte[] combineEncryptedData(byte[] encryptedAesKey, byte[] encryptedData) {
|
||||
byte[] combined = new byte[4 + encryptedAesKey.length + encryptedData.length];
|
||||
System.arraycopy(encryptedAesKey, 0, combined, 4, encryptedAesKey.length);
|
||||
System.arraycopy(encryptedData, 0, combined, 4 + encryptedAesKey.length, encryptedData.length);
|
||||
return combined;
|
||||
// --- Generate random salt ---
|
||||
public static byte[] generateSalt() {
|
||||
byte[] salt = new byte[SALT_LENGTH];
|
||||
new SecureRandom().nextBytes(salt);
|
||||
return salt;
|
||||
}
|
||||
|
||||
// --- Generate random IV ---
|
||||
public static byte[] generateIV() {
|
||||
byte[] iv = new byte[IV_LENGTH];
|
||||
new SecureRandom().nextBytes(iv);
|
||||
return iv;
|
||||
}
|
||||
|
||||
// Decrypt data using RSA (AES Key is decrypted using RSA, then used for AES decryption)
|
||||
public static byte[] decrypt(byte[] encryptedCombined, PrivateKey privateKey) throws Exception {
|
||||
// Step 1: Extract AES Key length from the combined data
|
||||
int aesKeyLength = ((encryptedCombined[0] & 0xFF) << 24) |
|
||||
((encryptedCombined[1] & 0xFF) << 16) |
|
||||
((encryptedCombined[2] & 0xFF) << 8) |
|
||||
(encryptedCombined[3] & 0xFF);
|
||||
// --- Optional: Utility to base64 encode data ---
|
||||
public static String encodeBase64(byte[] data) {
|
||||
return Base64.getEncoder().encodeToString(data);
|
||||
}
|
||||
|
||||
// Step 2: Extract the encrypted AES key and encrypted data
|
||||
byte[] encryptedAesKey = new byte[aesKeyLength];
|
||||
byte[] encryptedData = new byte[encryptedCombined.length - 4 - aesKeyLength];
|
||||
|
||||
System.arraycopy(encryptedCombined, 4, encryptedAesKey, 0, aesKeyLength);
|
||||
System.arraycopy(encryptedCombined, 4 + aesKeyLength, encryptedData, 0, encryptedData.length);
|
||||
|
||||
// Step 3: Decrypt the AES key using RSA
|
||||
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey);
|
||||
|
||||
// Create AES key
|
||||
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES");
|
||||
|
||||
// Decrypt the data using AES
|
||||
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
|
||||
return aesCipher.doFinal(encryptedData);
|
||||
public static byte[] decodeBase64(String base64) {
|
||||
return Base64.getDecoder().decode(base64);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.skycrate.backend.skycrateBackend.services;
|
||||
|
||||
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
|
||||
import com.skycrate.backend.skycrateBackend.entity.FileMetadata;
|
||||
import com.skycrate.backend.skycrateBackend.repository.FileMetadataRepository;
|
||||
import com.skycrate.backend.skycrateBackend.utils.EncryptionUtil;
|
||||
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class FileService {
|
||||
|
||||
private final FileMetadataRepository fileMetadataRepository;
|
||||
|
||||
public FileService(FileMetadataRepository fileMetadataRepository) {
|
||||
this.fileMetadataRepository = fileMetadataRepository;
|
||||
}
|
||||
|
||||
public void uploadEncryptedFile(String username, String password, byte[] fileContent, String filename) throws Exception {
|
||||
// Generate salt and IV
|
||||
byte[] salt = EncryptionUtil.generateSalt();
|
||||
byte[] iv = EncryptionUtil.generateIv();
|
||||
|
||||
// Derive AES key
|
||||
SecretKey key = EncryptionUtil.deriveKey(password.toCharArray(), salt);
|
||||
|
||||
// Encrypt file content
|
||||
byte[] encryptedData = EncryptionUtil.encrypt(fileContent, key, iv);
|
||||
|
||||
// Prepare HDFS path
|
||||
Path userDir = new Path("/" + username);
|
||||
Path filePath = new Path(userDir, filename);
|
||||
FileSystem fs = HDFSConfig.getHDFS();
|
||||
|
||||
// Ensure user directory exists
|
||||
if (!fs.exists(userDir)) {
|
||||
fs.mkdirs(userDir);
|
||||
}
|
||||
|
||||
// Write encrypted file to HDFS
|
||||
try (FSDataOutputStream outputStream = fs.create(filePath, true);
|
||||
InputStream in = new ByteArrayInputStream(encryptedData)) {
|
||||
in.transferTo(outputStream);
|
||||
}
|
||||
|
||||
// Save metadata
|
||||
FileMetadata metadata = FileMetadata.builder()
|
||||
.username(username)
|
||||
.filePath(filePath.toString())
|
||||
.salt(salt)
|
||||
.iv(iv)
|
||||
.build();
|
||||
|
||||
fileMetadataRepository.save(metadata);
|
||||
}
|
||||
|
||||
public byte[] downloadDecryptedFile(String username, String password, String filename) throws Exception {
|
||||
Path filePath = new Path("/" + username + "/" + filename);
|
||||
FileSystem fs = HDFSConfig.getHDFS();
|
||||
|
||||
Optional<FileMetadata> metadataOpt = fileMetadataRepository.findByUsernameAndFilePath(username, filePath.toString());
|
||||
if (metadataOpt.isEmpty()) {
|
||||
throw new RuntimeException("File metadata not found");
|
||||
}
|
||||
|
||||
FileMetadata metadata = metadataOpt.get();
|
||||
|
||||
// Derive key
|
||||
SecretKey key = EncryptionUtil.deriveKey(password.toCharArray(), metadata.getSalt());
|
||||
|
||||
// Read file from HDFS
|
||||
byte[] encryptedData = Files.readAllBytes(
|
||||
new java.io.File(filePath.toString()).toPath()
|
||||
);
|
||||
|
||||
// Decrypt
|
||||
return EncryptionUtil.decrypt(encryptedData, key, metadata.getIv());
|
||||
}
|
||||
}
|
||||
@@ -63,4 +63,4 @@ public class JwtService {
|
||||
public String generateToken(User user) {
|
||||
return generateToken((UserDetails) user);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.skycrate.backend.skycrateBackend.utils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.*;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EncryptionUtil {
|
||||
|
||||
private static final int SALT_LENGTH = 16; // 128 bits
|
||||
private static final int IV_LENGTH = 16; // 128 bits for AES
|
||||
private static final int ITERATIONS = 65536;
|
||||
private static final int KEY_LENGTH = 256; // AES-256
|
||||
|
||||
private static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA256";
|
||||
private static final String AES_CIPHER = "AES/CBC/PKCS5Padding";
|
||||
|
||||
private static final SecureRandom secureRandom = new SecureRandom();
|
||||
|
||||
public static byte[] generateSalt() {
|
||||
byte[] salt = new byte[SALT_LENGTH];
|
||||
secureRandom.nextBytes(salt);
|
||||
return salt;
|
||||
}
|
||||
|
||||
public static byte[] generateIv() {
|
||||
byte[] iv = new byte[IV_LENGTH];
|
||||
secureRandom.nextBytes(iv);
|
||||
return iv;
|
||||
}
|
||||
|
||||
public static SecretKey deriveKey(char[] password, byte[] salt) throws Exception {
|
||||
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
|
||||
PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
|
||||
SecretKey tmp = factory.generateSecret(spec);
|
||||
return new SecretKeySpec(tmp.getEncoded(), "AES");
|
||||
}
|
||||
|
||||
public static byte[] encrypt(byte[] plaintext, SecretKey key, byte[] iv) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(AES_CIPHER);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
|
||||
return cipher.doFinal(plaintext);
|
||||
}
|
||||
|
||||
public static byte[] decrypt(byte[] ciphertext, SecretKey key, byte[] iv) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(AES_CIPHER);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
|
||||
return cipher.doFinal(ciphertext);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user