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 440 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,187 +51,107 @@ 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") // @PostMapping("/uploadFile")
public ResponseDTO uploadFile( // public ResponseDTO uploadFile(
@RequestParam("file") MultipartFile file, // @RequestParam("file") MultipartFile file,
@RequestParam String hdfsPath, // @RequestParam String hdfsPath,
@RequestParam String uploadedFileName, // @RequestParam String uploadedFileName,
@RequestParam String username) { // @RequestParam String username) {
try { // try {
// Step 1: Retrieve the user and their RSA public key // // Save file locally first
User user = userRepository.findByUsername(username) // String localPath = saveFileLocally(file);
.orElseThrow(() -> new RuntimeException("User not found")); // System.out.println("File saved locally at: " + localPath);
byte[] publicKeyBytes = user.getPublicKey(); //
PublicKey publicKey = RSAKeyUtil.getPublicKeyFromBytes(publicKeyBytes); // // Upload file to HDFS
// hdfsOperations.uploadFile(localPath, hdfsPath, uploadedFileName, username);
// Step 2: Encrypt the file content using hybrid encryption (AES + RSA) // return new ResponseDTO("File uploaded successfully", true);
byte[] fileBytes = file.getBytes(); // } catch (IOException e) {
byte[] encryptedData = EncryptionUtil.encrypt(fileBytes, publicKey); // e.printStackTrace();
// return new ResponseDTO("Failed to upload file locally: " + e.getMessage(), false);
// Step 3: Upload encrypted data to HDFS // } catch (Exception e) {
hdfsOperations.uploadFile(encryptedData, hdfsPath, uploadedFileName, username); // e.printStackTrace();
// return new ResponseDTO("Failed to upload file to HDFS: " + e.getMessage(), false);
return new ResponseDTO("File uploaded successfully", true); // }
} catch (IOException e) { // }
e.printStackTrace(); @PostMapping("/uploadFile")
return new ResponseDTO("Failed to read file: " + e.getMessage(), false); public ResponseDTO uploadFile(
} catch (Exception e) { @RequestParam("file") MultipartFile file,
e.printStackTrace(); @RequestParam String hdfsPath,
return new ResponseDTO("Failed to upload file to HDFS: " + e.getMessage(), false); @RequestParam String uploadedFileName,
} @RequestParam String username) {
try {
// Upload file directly to HDFS without saving locally
hdfsOperations.uploadFile(file, hdfsPath, uploadedFileName, username);
return new ResponseDTO("File uploaded successfully", true);
} catch (Exception e) {
e.printStackTrace();
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 { // private String saveFileLocally(MultipartFile file) throws IOException {
// Step 1: Generate a random AES key // // Create a temporary directory if it doesn't exist
SecretKey aesKey = generateAESKey(); // Path tmpDir = Paths.get("tmp");
// 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 2: Encrypt the file data using AES
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] fileData = file.getBytes();
byte[] encryptedData = aesCipher.doFinal(fileData);
// Step 3: Encrypt the AES key with RSA // @PostMapping("/downloadFile")
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // public ResponseEntity<?> downloadFile(
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey); // @RequestParam String hdfsPath,
byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded()); // @RequestParam String username) {
// try {
// Step 4: Combine the encrypted AES key and the encrypted data // // Define a temporary local path to download the file
byte[] combined = new byte[4 + encryptedAesKey.length + encryptedData.length]; // String localPath = "/app/tmp/downloaded/" + new File(hdfsPath).getName(); // Adjust the path as needed
combined[0] = (byte) (encryptedAesKey.length >> 24); //
combined[1] = (byte) (encryptedAesKey.length >> 16); // // Download the file from HDFS to the local path
combined[2] = (byte) (encryptedAesKey.length >> 8); // hdfsOperations.downloadFile(hdfsPath, localPath, username);
combined[3] = (byte) encryptedAesKey.length; //
// // Create a File object for the downloaded file
System.arraycopy(encryptedAesKey, 0, combined, 4, encryptedAesKey.length); // File file = new File(localPath);
System.arraycopy(encryptedData, 0, combined, 4 + encryptedAesKey.length, encryptedData.length); // if (!file.exists()) {
// return ResponseEntity.status(HttpStatus.NOT_FOUND)
return combined; // .body(new ResponseDTO("File not found", false));
} // }
//
// Generate a random AES key // // Create a Resource from the file
private SecretKey generateAESKey() throws NoSuchAlgorithmException { // Resource resource = new FileSystemResource(file);
KeyGenerator keyGen = KeyGenerator.getInstance("AES"); // return ResponseEntity.ok()
keyGen.init(256); // Use 256 bits for AES // .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
return keyGen.generateKey(); // .body(resource);
} // } catch (Exception e) {
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
private String saveFileLocally(MultipartFile file) throws IOException { // .body(new ResponseDTO("Failed to download file: " + e.getMessage(), false));
// Create a temporary directory if it doesn't exist // }
Path tmpDir = Paths.get("tmp"); // }
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
}
@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();
} }
} }
@@ -1,4 +1,4 @@
package com.skycrate.backend.skycrateBackend.models; package com.skycrate.backend.skycrateBackend.models;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
@@ -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,38 +24,49 @@ 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") public User(){
private byte[] privateKey; }
public User(String firstname,String lastname,String email,String password){
this.username=firstname+lastname;
this.email=email;
this.password=password;
}
@CreationTimestamp @CreationTimestamp
@Column(updatable = false, name = "created_at") @Column(updatable = false, name = "created_at")
private Date createdAt; private Date createdAt;
public User() {}
public User(String firstname, String lastname, String email, String password) {
this.username = firstname + lastname; @Override
this.email = email; public Collection<? extends GrantedAuthority> getAuthorities(){
this.password = password; return List.of();
} }
// ⬇️ Required by Spring Security public String getPassword() {
@Override return password;
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
} }
@Override @Override
@@ -62,11 +74,6 @@ public class User implements UserDetails {
return email; return email;
} }
@Override
public String getPassword() {
return password;
}
@Override @Override
public boolean isAccountNonExpired() { public boolean isAccountNonExpired() {
return true; return true;
@@ -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) {
this.username = firstname + lastname;
public void setFullname(String firstname,String 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 {
@@ -21,37 +17,29 @@ public class AuthenticationService {
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final AuthenticationManager authenticationManager; private final AuthenticationManager authenticationManager;
public AuthenticationService(UserRepository userRepository, AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder) { public AuthenticationService( UserRepository userRepository, AuthenticationManager authenticationManager , PasswordEncoder passwordEncoder){
this.userRepository = userRepository; this.userRepository=userRepository;
this.passwordEncoder = passwordEncoder; this.passwordEncoder=passwordEncoder;
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 { return userRepository.save(user) ;
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);
} }
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