6 Commits

Author SHA1 Message Date
Kshitij c20b33a305 Deleted tmp folder. This branch is now on hold. tmp folders are no longer being produced. All APIs hopefully work in this one, didn't test tho 🤞 2025-04-17 23:30:52 +05:30
vedang29 a1dc9a840e Removed tmp folder while downloading 2025-04-15 22:47:28 +05:30
vedang29 508405077d Removed tmp folder while uploading 2025-04-15 22:35:44 +05:30
vedang29 36acd75eb3 Merge pull request #2 from kshitij-ka/main 2025-04-15 21:44:05 +05:30
Kshitij 5225174d51 Changed port from 8081 to 8080. 2025-04-15 21:24:17 +05:30
Kshitij 471d03d0b6 Deleted empty test file. 2025-04-15 21:24:02 +05:30
12 changed files with 244 additions and 439 deletions
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+10
View File
@@ -144,6 +144,16 @@
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
<version>2.11.0</version> <version>2.11.0</version>
</dependency> </dependency>
<!-- NEWLY ADDED DEPENDENCY FOR DOWNLOAD ENDPOINT-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@@ -1,15 +1,11 @@
package com.skycrate.backend.skycrateBackend.controller; package com.skycrate.backend.skycrateBackend.controller;
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
import com.skycrate.backend.skycrateBackend.dto.ResponseDTO; import com.skycrate.backend.skycrateBackend.dto.ResponseDTO;
import com.skycrate.backend.skycrateBackend.models.User;
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
import com.skycrate.backend.skycrateBackend.services.EncryptionUtil; import com.skycrate.backend.skycrateBackend.services.EncryptionUtil;
import com.skycrate.backend.skycrateBackend.services.HDFSOperations; import com.skycrate.backend.skycrateBackend.services.HDFSOperations;
import com.skycrate.backend.skycrateBackend.utils.KeyUtil; import com.skycrate.backend.skycrateBackend.utils.KeyUtil;
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
import org.apache.hadoop.fs.FileSystem;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -21,7 +17,6 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.List; import java.util.List;
@@ -29,11 +24,6 @@ import java.util.List;
import org.springframework.core.io.FileSystemResource; // For FileSystemResource import org.springframework.core.io.FileSystemResource; // For FileSystemResource
import org.springframework.core.io.Resource; // For Resource import org.springframework.core.io.Resource; // For Resource
import org.springframework.http.HttpHeaders; // For HttpHeaders import org.springframework.http.HttpHeaders; // For HttpHeaders
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.File; // For java.io.File import java.io.File; // For java.io.File
import static com.skycrate.backend.skycrateBackend.utils.KeyUtil.getPrivateKeyForUser; import static com.skycrate.backend.skycrateBackend.utils.KeyUtil.getPrivateKeyForUser;
@@ -45,10 +35,6 @@ public class HDFScontroller {
private final HDFSOperations hdfsOperations; private final HDFSOperations hdfsOperations;
@Autowired
private UserRepository userRepository;
@Autowired @Autowired
public HDFScontroller(HDFSOperations hdfsOperations) { public HDFScontroller(HDFSOperations hdfsOperations) {
this.hdfsOperations = hdfsOperations; this.hdfsOperations = hdfsOperations;
@@ -65,7 +51,29 @@ public class HDFScontroller {
return new ResponseDTO("Failed to create folder: " + e.getMessage(), false); return new ResponseDTO("Failed to create folder: " + e.getMessage(), false);
} }
} }
//
// @PostMapping("/uploadFile")
// public ResponseDTO uploadFile(
// @RequestParam("file") MultipartFile file,
// @RequestParam String hdfsPath,
// @RequestParam String uploadedFileName,
// @RequestParam String username) {
// try {
// // Save file locally first
// String localPath = saveFileLocally(file);
// System.out.println("File saved locally at: " + localPath);
//
// // Upload file to HDFS
// hdfsOperations.uploadFile(localPath, hdfsPath, uploadedFileName, username);
// return new ResponseDTO("File uploaded successfully", true);
// } catch (IOException e) {
// e.printStackTrace();
// return new ResponseDTO("Failed to upload file locally: " + e.getMessage(), false);
// } catch (Exception e) {
// e.printStackTrace();
// return new ResponseDTO("Failed to upload file to HDFS: " + e.getMessage(), false);
// }
// }
@PostMapping("/uploadFile") @PostMapping("/uploadFile")
public ResponseDTO uploadFile( public ResponseDTO uploadFile(
@RequestParam("file") MultipartFile file, @RequestParam("file") MultipartFile file,
@@ -73,178 +81,77 @@ public class HDFScontroller {
@RequestParam String uploadedFileName, @RequestParam String uploadedFileName,
@RequestParam String username) { @RequestParam String username) {
try { try {
// Retrieve the user from the database using the username // Upload file directly to HDFS without saving locally
User user = userRepository.findByUsername(username).orElseThrow(() -> new RuntimeException("User not found")); hdfsOperations.uploadFile(file, hdfsPath, uploadedFileName, username);
// Get the public key from the user entity
byte[] publicKeyBytes = user.getPublicKey();
PublicKey publicKey = RSAKeyUtil.getPublicKeyFromBytes(publicKeyBytes);
// Encrypt the file content using the public key
byte[] encryptedData = encryptFile(file, publicKey);
// Upload the encrypted file to HDFS
hdfsOperations.uploadFile(encryptedData, hdfsPath, uploadedFileName, username);
return new ResponseDTO("File uploaded successfully", true); return new ResponseDTO("File uploaded successfully", true);
} catch (IOException e) {
e.printStackTrace();
return new ResponseDTO("Failed to upload file locally: " + e.getMessage(), false);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return new ResponseDTO("Failed to upload file to HDFS: " + e.getMessage(), false); return new ResponseDTO("Failed to upload file to HDFS: " + e.getMessage(), false);
} }
} }
// Helper method to encrypt the file content using RSA encryption
private byte[] encryptFile(MultipartFile file, PublicKey publicKey) throws Exception {
// Step 1: Generate a random AES key
SecretKey aesKey = generateAESKey();
// Step 2: Encrypt the file data using AES //
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // private String saveFileLocally(MultipartFile file) throws IOException {
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey); // // Create a temporary directory if it doesn't exist
byte[] fileData = file.getBytes(); // Path tmpDir = Paths.get("tmp");
byte[] encryptedData = aesCipher.doFinal(fileData); // if (!Files.exists(tmpDir)) {
// Files.createDirectories(tmpDir); // Create the directory if it doesn't exist
// }
//
// Path path = tmpDir.resolve(file.getOriginalFilename());
//
// // Copy the file to the local directory
// Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
//
// return path.toString(); // Return the local path for further processing
// }
// Step 3: 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 the encrypted AES key and the encrypted data // @PostMapping("/downloadFile")
byte[] combined = new byte[4 + encryptedAesKey.length + encryptedData.length]; // public ResponseEntity<?> downloadFile(
combined[0] = (byte) (encryptedAesKey.length >> 24); // @RequestParam String hdfsPath,
combined[1] = (byte) (encryptedAesKey.length >> 16); // @RequestParam String username) {
combined[2] = (byte) (encryptedAesKey.length >> 8); // try {
combined[3] = (byte) encryptedAesKey.length; // // Define a temporary local path to download the file
// String localPath = "/app/tmp/downloaded/" + new File(hdfsPath).getName(); // Adjust the path as needed
System.arraycopy(encryptedAesKey, 0, combined, 4, encryptedAesKey.length); //
System.arraycopy(encryptedData, 0, combined, 4 + encryptedAesKey.length, encryptedData.length); // // Download the file from HDFS to the local path
// hdfsOperations.downloadFile(hdfsPath, localPath, username);
return combined; //
} // // Create a File object for the downloaded file
// File file = new File(localPath);
// Generate a random AES key // if (!file.exists()) {
private SecretKey generateAESKey() throws NoSuchAlgorithmException { // return ResponseEntity.status(HttpStatus.NOT_FOUND)
KeyGenerator keyGen = KeyGenerator.getInstance("AES"); // .body(new ResponseDTO("File not found", false));
keyGen.init(256); // Use 256 bits for AES // }
return keyGen.generateKey(); //
} // // Create a Resource from the file
// Resource resource = new FileSystemResource(file);
private String saveFileLocally(MultipartFile file) throws IOException { // return ResponseEntity.ok()
// Create a temporary directory if it doesn't exist // .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
Path tmpDir = Paths.get("tmp"); // .body(resource);
if (!Files.exists(tmpDir)) { // } catch (Exception e) {
Files.createDirectories(tmpDir); // Create the directory if it doesn't exist // return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
} // .body(new ResponseDTO("Failed to download file: " + e.getMessage(), false));
// }
Path path = tmpDir.resolve(file.getOriginalFilename()); // }
// Copy the file to the local directory
Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
return path.toString(); // Return the local path for further processing
}
@PostMapping("/downloadFile") @PostMapping("/downloadFile")
public ResponseEntity<Resource> downloadFile( public ResponseEntity<?> downloadFile(
@RequestParam String hdfsEncPath, @RequestParam String hdfsPath,
@RequestParam String username) { @RequestParam String username) {
try { try {
// Extract the file name and extension String fileName = new File(hdfsPath).getName();
String encFileName = new File(hdfsEncPath).getName(); InputStreamResource resource = hdfsOperations.downloadFile(hdfsPath, username);
String originalFileName = encFileName.replace(".enc", "");
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
// Define local decrypted file path
String localDecryptedPath = "/SkyCrate/downloaded/" + originalFileName;
// Define HDFS paths for encrypted file
String encFilePath = "/SkyCrate/downloaded/" + encFileName;
FileSystem fs = HDFSConfig.getHDFS();
// Download encrypted file from HDFS
fs.copyToLocalFile(new org.apache.hadoop.fs.Path(hdfsEncPath), new org.apache.hadoop.fs.Path(encFilePath));
// Retrieve the RSA private key for the user
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new RuntimeException("User not found"));
PrivateKey privateKey = RSAKeyUtil.getPrivateKeyFromBytes(user.getPrivateKey());
// Read the encrypted file content
byte[] encryptedFileContent = Files.readAllBytes(Paths.get(encFilePath));
// Step 1: Extract the AES key length from the combined data
int aesKeyLength = ((encryptedFileContent[0] & 0xFF) << 24) |
((encryptedFileContent[1] & 0xFF) << 16) |
((encryptedFileContent[2] & 0xFF) << 8) |
(encryptedFileContent[3] & 0xFF);
// Step 2: Extract the encrypted AES key and encrypted data
byte[] encryptedAesKey = new byte[aesKeyLength];
byte[] encryptedData = new byte[encryptedFileContent.length - 4 - aesKeyLength];
System.arraycopy(encryptedFileContent, 4, encryptedAesKey, 0, aesKeyLength);
System.arraycopy(encryptedFileContent, 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 the AES key
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES");
// Step 4: Decrypt the data using AES
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
// Decrypt the file content using the provided decrypt method
// byte[] decryptedFileContent = RSAKeyUtil.decrypt(encryptedFileContent, privateKey);
byte[] decryptedFileContent = aesCipher.doFinal(encryptedData);
// Write the decrypted content to the original file
Files.write(Paths.get(localDecryptedPath + "." + fileExtension), decryptedFileContent);
// Log the file creation
if (Files.exists(Paths.get(localDecryptedPath + "." + fileExtension))) {
System.out.println("File created successfully at: " + localDecryptedPath + "." + fileExtension);
} else {
System.out.println("Failed to create file at: " + localDecryptedPath + "." + fileExtension);
}
// Create the decrypted file resource
File decryptedFile = new File(localDecryptedPath + "." + fileExtension);
Resource resource = new FileSystemResource(decryptedFile);
// Return the file as a response
return ResponseEntity.ok() return ResponseEntity.ok()
.contentLength(decryptedFile.length()) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.contentType(MediaType.APPLICATION_OCTET_STREAM) .contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + decryptedFile.getName() + "\"")
.body(resource); .body(resource);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null); .body(new ResponseDTO("Failed to download file: " + e.getMessage(), false));
}
}
public void initializeKeysForUser(String username) {
try {
// Check if the public key file exists
Path publicKeyPath = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_public.key");
if (!Files.exists(publicKeyPath)) {
// Generate and store keys if they do not exist
KeyUtil.generateAndStoreKeyPair(username);
}
} catch (Exception e) {
e.printStackTrace();
} }
} }
@@ -6,6 +6,7 @@ import java.util.Date;
import java.util.List; import java.util.List;
import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
@@ -23,27 +24,28 @@ public class User implements UserDetails {
@Column(nullable = false) @Column(nullable = false)
private String username; private String username;
/*
//Optional feature might add later
@Column(name = "verification_code")
private String verificationCode;
@Column(name ="verification_expiry")
private LocalDateTime verificationExpiry;
*/
@Column(unique = true, nullable = false) @Column(unique = true, nullable = false)
private String email; private String email;
@Column(nullable = false) @Column(nullable = false)
private String password; private String password;
// ✅ Add RSA key fields
@Lob
@Column(name = "public_key", columnDefinition = "BLOB")
private byte[] publicKey;
@Lob
@Column(name = "private_key", columnDefinition = "BLOB")
private byte[] privateKey;
@CreationTimestamp public User(){
@Column(updatable = false, name = "created_at") }
private Date createdAt;
public User() {}
public User(String firstname,String lastname,String email,String password){ public User(String firstname,String lastname,String email,String password){
this.username=firstname+lastname; this.username=firstname+lastname;
@@ -51,20 +53,25 @@ public class User implements UserDetails {
this.password=password; this.password=password;
} }
// ⬇️ Required by Spring Security
@CreationTimestamp
@Column(updatable = false, name = "created_at")
private Date createdAt;
@Override @Override
public Collection<? extends GrantedAuthority> getAuthorities(){ public Collection<? extends GrantedAuthority> getAuthorities(){
return List.of(); return List.of();
} }
@Override public String getPassword() {
public String getUsername() { return password;
return email;
} }
@Override @Override
public String getPassword() { public String getUsername() {
return password; return email;
} }
@Override @Override
@@ -86,8 +93,6 @@ public class User implements UserDetails {
public boolean isEnabled() { public boolean isEnabled() {
return true; return true;
} }
// ⬇️ Getters and Setters
public Integer getId() { public Integer getId() {
return id; return id;
} }
@@ -96,11 +101,13 @@ public class User implements UserDetails {
this.id = id; this.id = id;
} }
public void setFullname(String firstname,String lastname) { public void setFullname(String firstname,String lastname) {
this.username=firstname+lastname; this.username=firstname+lastname;
} }
public String getFullname() { public String getFullname(String firstname,String lastname){
return this.username; return this.username;
} }
@@ -119,21 +126,4 @@ public class User implements UserDetails {
public void setCreatedAt(Date createdAt) { public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt; this.createdAt = createdAt;
} }
// ✅ Getters and setters for RSA keys
public byte[] getPublicKey() {
return publicKey;
}
public void setPublicKey(byte[] publicKey) {
this.publicKey = publicKey;
}
public byte[] getPrivateKey() {
return privateKey;
}
public void setPrivateKey(byte[] privateKey) {
this.privateKey = privateKey;
}
} }
@@ -5,8 +5,6 @@ import org.springframework.data.repository.CrudRepository;
import com.skycrate.backend.skycrateBackend.models.User; import com.skycrate.backend.skycrateBackend.models.User;
public interface UserRepository extends CrudRepository<User,Integer> { public interface UserRepository extends CrudRepository<User,Integer> {
Optional<User> findByEmail(String email); Optional<User> findByEmail(String email);
// Custom query method to find user by username
Optional<User> findByUsername(String username);
/* /*
// might use later // might use later
Optional<User> findByVerificationCode(String verificationCode); Optional<User> findByVerificationCode(String verificationCode);
@@ -9,10 +9,6 @@ import com.skycrate.backend.skycrateBackend.dto.LoginUserDto;
import com.skycrate.backend.skycrateBackend.dto.RegisterUserDto; import com.skycrate.backend.skycrateBackend.dto.RegisterUserDto;
import com.skycrate.backend.skycrateBackend.models.User; import com.skycrate.backend.skycrateBackend.models.User;
import com.skycrate.backend.skycrateBackend.repository.UserRepository; import com.skycrate.backend.skycrateBackend.repository.UserRepository;
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
@Service @Service
public class AuthenticationService { public class AuthenticationService {
@@ -27,31 +23,23 @@ public class AuthenticationService {
this.authenticationManager=authenticationManager; this.authenticationManager=authenticationManager;
} }
public User signUp(RegisterUserDto inputUser) { public User signUp(RegisterUserDto inputuser){
User user = new User( User user=new User(inputuser.getFirstname(),inputuser.getLastname(),inputuser.getEmail(),passwordEncoder.encode(inputuser.getPassword()));
inputUser.getFirstname(), /*
inputUser.getLastname(), User user = new User()
inputUser.getEmail(), .setFullname(inputuser.getFirstname(),inputuser.getLastname())
passwordEncoder.encode(inputUser.getPassword()) .setEmail(inputuser.getEmail())
); .setPassword(passwordEncoder.encode(inputuser.getPassword()));
*/
try {
KeyPair keyPair = RSAKeyUtil.generateKeyPair();
user.setPublicKey(keyPair.getPublic().getEncoded());
user.setPrivateKey(keyPair.getPrivate().getEncoded());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Failed to generate RSA key pair", e);
}
return userRepository.save(user) ; return userRepository.save(user) ;
} }
public User authenticate(LoginUserDto inputUser) { public User authenticate(LoginUserDto inputuser){
authenticationManager.authenticate( authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(inputuser.getEmail()
new UsernamePasswordAuthenticationToken(inputUser.getEmail(), inputUser.getPassword()) , inputuser.getPassword()));
); return userRepository.findByEmail(inputuser.getEmail()).orElseThrow();
return userRepository.findByEmail(inputUser.getEmail())
.orElseThrow(() -> new RuntimeException("User not found"));
} }
} }
@@ -23,13 +23,13 @@ public class EncryptionUtil {
// Step 1: Generate AES Key // Step 1: Generate AES Key
SecretKey aesKey = generateAESKey(); SecretKey aesKey = generateAESKey();
// Encrypt data using AES // Step 2: Encrypt data using AES
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM);
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey); aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encryptedData = aesCipher.doFinal(data); byte[] encryptedData = aesCipher.doFinal(data);
// Encrypt the AES key with RSA // Step 3: Encrypt the AES key with RSA
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM);
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey); rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded()); byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded());
@@ -65,15 +65,13 @@ public class EncryptionUtil {
System.arraycopy(encryptedCombined, 4 + aesKeyLength, encryptedData, 0, encryptedData.length); System.arraycopy(encryptedCombined, 4 + aesKeyLength, encryptedData, 0, encryptedData.length);
// Step 3: Decrypt the AES key using RSA // Step 3: Decrypt the AES key using RSA
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM);
rsaCipher.init(Cipher.DECRYPT_MODE, privateKey); rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey); byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey);
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, AES_ALGORITHM);
// Create AES key // Step 4: Decrypt the data using AES
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES"); Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM);
// Decrypt the data using AES
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
aesCipher.init(Cipher.DECRYPT_MODE, aesKey); aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
return aesCipher.doFinal(encryptedData); return aesCipher.doFinal(encryptedData);
} }
@@ -1,16 +1,12 @@
package com.skycrate.backend.skycrateBackend.services; package com.skycrate.backend.skycrateBackend.services;
import com.skycrate.backend.skycrateBackend.config.HDFSConfig; import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
import com.skycrate.backend.skycrateBackend.models.User; import com.skycrate.backend.skycrateBackend.utils.KeyUtil;
import com.skycrate.backend.skycrateBackend.repository.UserRepository; import org.apache.commons.io.IOUtils;
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil; import org.apache.hadoop.fs.*;
import org.apache.hadoop.fs.FSDataOutputStream; import org.springframework.core.io.InputStreamResource;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.KeyGenerator; import javax.crypto.KeyGenerator;
@@ -18,7 +14,6 @@ import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
@@ -32,94 +27,98 @@ import java.util.List;
@Service @Service
public class HDFSOperations { public class HDFSOperations {
private final UserRepository userRepository;
@Autowired // public void uploadFile(String localPath, String hdfsPath, String uploadedFileName, String username) {
public HDFSOperations(UserRepository userRepository) { // try {
this.userRepository = userRepository; // FileSystem fs = HDFSConfig.getHDFS();
} // byte[] data = Files.readAllBytes(Paths.get(localPath)); // Read file as bytes
//
// // Encrypt file (consider adding encryption here as needed)
// byte[] encryptedData = data;
//
// String tempFilePath = localPath + ".enc";
// Files.write(Paths.get(tempFilePath), encryptedData);
//
// String finalHdfsPath = hdfsPath.endsWith("/") ? hdfsPath + uploadedFileName : hdfsPath + "/" + uploadedFileName;
// fs.copyFromLocalFile(new Path(tempFilePath), new Path(finalHdfsPath));
//
// Files.delete(Paths.get(tempFilePath));
// } catch (IOException e) {
// // Handle I/O exception and log the error
// throw new RuntimeException("Failed to upload file due to I/O issue: " + e.getMessage(), e);
// } catch (Exception e) {
// // Catch any other exceptions
// throw new RuntimeException("Failed to upload file: " + e.getMessage(), e);
// }
// }
public void uploadFile(byte[] fileData, String hdfsPath, String uploadedFileName, String username) { public void uploadFile(MultipartFile file, String hdfsPath, String uploadedFileName, String username) {
try { try {
FileSystem fs = HDFSConfig.getHDFS(); FileSystem fs = HDFSConfig.getHDFS();
// Create an InputStream from the byte array // Encrypt file data if needed (currently direct pass-through)
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData); byte[] fileBytes = file.getBytes(); // directly get bytes from MultipartFile
byte[] encryptedData = fileBytes;
// Prepare the path for HDFS // Define final HDFS file path
String finalHdfsPath = hdfsPath.endsWith("/") ? hdfsPath + uploadedFileName : hdfsPath + "/" + uploadedFileName; String finalHdfsPath = hdfsPath.endsWith("/") ? hdfsPath + uploadedFileName : hdfsPath + "/" + uploadedFileName;
// Upload the file directly to HDFS from the InputStream // Write encrypted bytes directly to HDFS
Path hdfsFilePath = new Path(finalHdfsPath); Path hdfsDestPath = new Path(finalHdfsPath);
FSDataOutputStream outputStream = fs.create(hdfsFilePath); try (FSDataOutputStream outputStream = fs.create(hdfsDestPath, true)) {
IOUtils.copyBytes(inputStream, outputStream, 4096, true); outputStream.write(encryptedData);
}
} catch (IOException e) { } catch (IOException e) {
// Handle I/O exception and log the error throw new RuntimeException("Failed to upload file due to I/O issue: " + e.getMessage(), e);
throw new RuntimeException("Failed to upload file to HDFS: " + e.getMessage(), e);
} catch (Exception e) { } catch (Exception e) {
// Catch any other exceptions throw new RuntimeException("Failed to upload file: " + e.getMessage(), e);
throw new RuntimeException("Failed to upload file to HDFS: " + e.getMessage(), e);
} }
} }
public void downloadFile(String hdfsEncPath, String localPathWithoutExt, String username) {
// public void downloadFile(String hdfsPath, String localPath, String username) {
// try {
// FileSystem fs = HDFSConfig.getHDFS();
// String tempFilePath = localPath + ".enc";
//
// fs.copyToLocalFile(new Path(hdfsPath), new Path(tempFilePath));
//
// byte[] encryptedData = Files.readAllBytes(Paths.get(tempFilePath));
// byte[] decryptedData = encryptedData; // Decrypt if needed
//
// Files.write(Paths.get(localPath), decryptedData);
// Files.delete(Paths.get(tempFilePath));
// } catch (IOException e) {
// // Handle I/O exception and log the error
// throw new RuntimeException("Failed to download file due to I/O issue: " + e.getMessage(), e);
// } catch (Exception e) {
// // Catch any other exceptions
// throw new RuntimeException("Failed to download file: " + e.getMessage(), e);
// }
// }
public InputStreamResource downloadFile(String hdfsPath, String username) {
try { try {
FileSystem fs = HDFSConfig.getHDFS(); FileSystem fs = HDFSConfig.getHDFS();
// Extract file name and extension // Read encrypted file directly from HDFS
String encFileName = new File(hdfsEncPath).getName(); FSDataInputStream hdfsInputStream = fs.open(new Path(hdfsPath));
String originalFileName = encFileName.replace(".enc", "");
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
String fullDecryptedPath = localPathWithoutExt + "/" + originalFileName; // Optional: If decryption is needed, read bytes, decrypt, and wrap in ByteArrayInputStream
String encFilePath = fullDecryptedPath + ".enc"; byte[] encryptedData = IOUtils.toByteArray(hdfsInputStream);
String keyFilePath = fullDecryptedPath + ".key"; byte[] decryptedData = encryptedData; // Apply decryption if needed
// Download encrypted file and AES key from HDFS return new InputStreamResource(new ByteArrayInputStream(decryptedData));
fs.copyToLocalFile(new Path(hdfsEncPath), new Path(encFilePath));
fs.copyToLocalFile(new Path(hdfsEncPath.replace(".enc", ".key")), new Path(keyFilePath));
// Read the encrypted AES key
byte[] encryptedAesKey = Files.readAllBytes(Paths.get(keyFilePath));
System.out.println("Length of encrypted AES key: " + encryptedAesKey.length);
// Retrieve the RSA private key for the user
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new RuntimeException("User not found"));
PrivateKey privateKey = RSAKeyUtil.getPrivateKeyFromBytes(user.getPrivateKey());
Cipher rsaCipher = Cipher.getInstance("RSA");
rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey);
// Ensure valid AES key length
if (aesKeyBytes.length != 16 && aesKeyBytes.length != 24 && aesKeyBytes.length != 32) {
throw new RuntimeException("Invalid AES key length: " + aesKeyBytes.length + " bytes");
}
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, 0, aesKeyBytes.length, "AES");
// Read the encrypted file content
byte[] encryptedFileContent = Files.readAllBytes(Paths.get(encFilePath));
// Decrypt the file content using AES
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // Specify padding
aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
byte[] decryptedFileContent = aesCipher.doFinal(encryptedFileContent);
// Write the decrypted content to the original file
Files.write(Paths.get(fullDecryptedPath + "." + fileExtension), decryptedFileContent);
// Cleanup temporary files
Files.deleteIfExists(Paths.get(encFilePath));
Files.deleteIfExists(Paths.get(keyFilePath));
} catch (IOException e) {
throw new RuntimeException("Failed to stream file due to I/O issue: " + e.getMessage(), e);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Failed to download or decrypt file: " + e.getMessage(), e); throw new RuntimeException("Failed to stream file: " + e.getMessage(), e);
} }
} }
public void createFolder(String hdfsPath) { public void createFolder(String hdfsPath) {
try { try {
FileSystem fs = HDFSConfig.getHDFS(); FileSystem fs = HDFSConfig.getHDFS();
@@ -3,37 +3,24 @@ package com.skycrate.backend.skycrateBackend.utils;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.security.*; import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec; import java.security.spec.X509EncodedKeySpec;
public class KeyUtil { public class KeyUtil {
public static void generateAndStoreKeyPair(String username) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048); // Key size
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// Store the public key
Path publicKeyPath = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_public.key");
Files.write(publicKeyPath, keyPair.getPublic().getEncoded());
// Store the private key
Path privateKeyPath = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_private.key");
Files.write(privateKeyPath, keyPair.getPrivate().getEncoded());
}
public static PublicKey getPublicKeyForUser(String username) throws Exception {
Path path = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_public.key");
byte[] bytes = Files.readAllBytes(path);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
return KeyFactory.getInstance("RSA").generatePublic(keySpec);
}
public static PrivateKey getPrivateKeyForUser(String username) throws Exception { public static PrivateKey getPrivateKeyForUser(String username) throws Exception {
Path path = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_private.key"); Path path = Paths.get("keys", username + "_private.key");
byte[] bytes = Files.readAllBytes(path); byte[] bytes = Files.readAllBytes(path);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
return KeyFactory.getInstance("RSA").generatePrivate(keySpec); return KeyFactory.getInstance("RSA").generatePrivate(keySpec);
} }
public static PublicKey getPublicKeyForUser(String username) throws Exception {
Path path = Paths.get("keys", username + "_public.key");
byte[] bytes = Files.readAllBytes(path);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
return KeyFactory.getInstance("RSA").generatePublic(keySpec);
}
} }
@@ -1,70 +0,0 @@
package com.skycrate.backend.skycrateBackend.utils;
import javax.crypto.*;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class RSAKeyUtil {
// Generate RSA Key Pair
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048); // Key size
return generator.generateKeyPair();
}
// Convert byte array to PublicKey
public static PublicKey getPublicKeyFromBytes(byte[] publicKeyBytes) throws Exception {
X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
}
// Convert byte array to PrivateKey
public static PrivateKey getPrivateKeyFromBytes(byte[] privateKeyBytes) throws Exception {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(spec);
}
// Encrypt data using RSA (with padding)
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // Specify padding
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
// Decrypt data using RSA (with padding)
public static byte[] decrypt(byte[] encryptedData, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // Specify padding
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(encryptedData);
}
// Generate AES Key (128, 192, or 256 bits)
public static SecretKey generateAESKey(int keySize) throws NoSuchAlgorithmException {
if (keySize != 128 && keySize != 192 && keySize != 256) {
throw new IllegalArgumentException("Invalid AES key size. Must be 128, 192, or 256 bits.");
}
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(keySize); // Specify the key size
return keyGenerator.generateKey();
}
// Encrypt AES Key using RSA
public static byte[] encryptAESKey(SecretKey aesKey, PublicKey publicKey) throws Exception {
return encrypt(aesKey.getEncoded(), publicKey); // Encrypt the AES key using RSA
}
// Decrypt AES Key using RSA
public static SecretKey decryptAESKey(byte[] encryptedAESKey, PrivateKey privateKey, int keySize) throws Exception {
byte[] decryptedKey = decrypt(encryptedAESKey, privateKey); // Decrypt with RSA
// Ensure that the decrypted key length matches the expected AES key size
if (decryptedKey.length != keySize / 8) {
throw new IllegalArgumentException("Decrypted key size does not match expected AES key size.");
}
return new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES"); // Convert to AES Key
}
}
@@ -3,8 +3,6 @@ spring.application.name=skycrateBackend
spring.servlet.multipart.max-file-size=1000MB spring.servlet.multipart.max-file-size=1000MB
spring.servlet.multipart.max-request-size=1000MB spring.servlet.multipart.max-request-size=1000MB
spring.servlet.multipart.enabled=true
security.jwt.secret-key=3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b security.jwt.secret-key=3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b
security.jwt.expiration-time=3600000 security.jwt.expiration-time=3600000