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
16 changed files with 271 additions and 578 deletions
-3
View File
@@ -31,6 +31,3 @@ build/
### VS Code ###
.vscode/
### apach-maven binary ###
apache-maven-3.9.6
-30
View File
@@ -1,30 +0,0 @@
## BACKEND ##
# Base image
FROM debian:12-slim
# Metadata
LABEL maintainer="kshitijka"
LABEL version=1.0
LABEL description="Skycrate is a web based file management system that uses Hadoop as filesystem."
# Update & upgrade & install & rm
RUN apt-get update && apt-get upgrade -y && \
apt-get install -y openjdk-17-jdk && \
rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN useradd -s /bin/bash skycrateBack
# Create work dir
RUN mkdir /app
RUN chown -R skycrateBack:skycrateBack /app
COPY ./target/ /app
WORKDIR /app
# Switch user
USER skycrateBack
EXPOSE 8081
CMD ["java", "-jar", "/app/skycrateBackend-0.0.1-SNAPSHOT.jar"]
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>
<version>2.11.0</version>
</dependency>
<!-- NEWLY ADDED DEPENDENCY FOR DOWNLOAD ENDPOINT-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
<build>
@@ -12,8 +12,8 @@ import java.security.PrivilegedExceptionAction;
public class HDFSConfig {
public static FileSystem getHDFS() throws Exception {
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://namenode:9000");
return FileSystem.get(new URI("hdfs://namenode:9000"), conf);
conf.set("fs.defaultFS", "hdfs://192.168.29.56:9000");
return FileSystem.get(new URI("hdfs://192.168.29.56:9000"), conf);
}
@@ -36,6 +36,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
}
@Override
protected void doFilterInternal(
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@@ -59,6 +60,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
);
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
@@ -1,15 +1,11 @@
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.models.User;
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
import com.skycrate.backend.skycrateBackend.services.EncryptionUtil;
import com.skycrate.backend.skycrateBackend.services.HDFSOperations;
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.core.io.InputStreamResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -21,7 +17,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
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.Resource; // For Resource
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 static com.skycrate.backend.skycrateBackend.utils.KeyUtil.getPrivateKeyForUser;
@@ -45,10 +35,6 @@ public class HDFScontroller {
private final HDFSOperations hdfsOperations;
@Autowired
private UserRepository userRepository;
@Autowired
public HDFScontroller(HDFSOperations hdfsOperations) {
this.hdfsOperations = hdfsOperations;
@@ -65,186 +51,107 @@ public class HDFScontroller {
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 {
// Retrieve the user from the database using the username
User user = userRepository.findByUsername(username).orElseThrow(() -> new RuntimeException("User not found"));
// 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);
} 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")
// 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")
public ResponseDTO uploadFile(
@RequestParam("file") MultipartFile file,
@RequestParam String hdfsPath,
@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 {
// 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");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] fileData = file.getBytes();
byte[] encryptedData = aesCipher.doFinal(fileData);
//
// private String saveFileLocally(MultipartFile file) throws IOException {
// // 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
// }
// 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
byte[] combined = new byte[4 + encryptedAesKey.length + encryptedData.length];
combined[0] = (byte) (encryptedAesKey.length >> 24);
combined[1] = (byte) (encryptedAesKey.length >> 16);
combined[2] = (byte) (encryptedAesKey.length >> 8);
combined[3] = (byte) encryptedAesKey.length;
System.arraycopy(encryptedAesKey, 0, combined, 4, encryptedAesKey.length);
System.arraycopy(encryptedData, 0, combined, 4 + encryptedAesKey.length, encryptedData.length);
return combined;
}
// Generate a random AES key
private SecretKey generateAESKey() throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // Use 256 bits for AES
return keyGen.generateKey();
}
private String saveFileLocally(MultipartFile file) throws IOException {
// 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")
// public ResponseEntity<?> downloadFile(
// @RequestParam String hdfsPath,
// @RequestParam String username) {
// try {
// // Define a temporary local path to download the file
// String localPath = "/app/tmp/downloaded/" + new File(hdfsPath).getName(); // Adjust the path as needed
//
// // Download the file from HDFS to the local path
// hdfsOperations.downloadFile(hdfsPath, localPath, username);
//
// // Create a File object for the downloaded file
// File file = new File(localPath);
// if (!file.exists()) {
// return ResponseEntity.status(HttpStatus.NOT_FOUND)
// .body(new ResponseDTO("File not found", false));
// }
//
// // Create a Resource from the file
// Resource resource = new FileSystemResource(file);
// return ResponseEntity.ok()
// .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
// .body(resource);
// } catch (Exception e) {
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
// .body(new ResponseDTO("Failed to download file: " + e.getMessage(), false));
// }
// }
@PostMapping("/downloadFile")
public ResponseEntity<Resource> downloadFile(
@RequestParam String hdfsEncPath,
public ResponseEntity<?> downloadFile(
@RequestParam String hdfsPath,
@RequestParam String username) {
try {
// Extract the file name and extension
String encFileName = new File(hdfsEncPath).getName();
String originalFileName = encFileName.replace(".enc", "");
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
String fileName = new File(hdfsPath).getName();
InputStreamResource resource = hdfsOperations.downloadFile(hdfsPath, username);
// 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()
.contentLength(decryptedFile.length())
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + decryptedFile.getName() + "\"")
.body(resource);
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
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();
.body(new ResponseDTO("Failed to download file: " + e.getMessage(), false));
}
}
@@ -279,25 +186,4 @@ public class HDFScontroller {
.body("Failed to list files: " + e.getMessage());
}
}
@GetMapping("/getUsernameByEmail")
public ResponseEntity<?> getUsernameByEmail(@RequestParam String email) {
try {
// Fetch user from the database using the provided email
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new RuntimeException("User not found with email: " + email));
// // Log the retrieved user object to verify the username
// System.out.println("Retrieved user: " + user.getFullname());
// Return the username as the response
return ResponseEntity.ok(user.getFullname()); // Return the username
} catch (Exception e) {
// Handle error if user is not found or other exceptions occur
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to fetch username: " + e.getMessage());
}
}
}
@@ -1,4 +1,4 @@
package com.skycrate.backend.skycrateBackend.models;
package com.skycrate.backend.skycrateBackend.models;
import java.time.LocalDateTime;
import java.util.Collection;
@@ -6,6 +6,7 @@ import java.util.Date;
import java.util.List;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
@@ -14,7 +15,7 @@ import jakarta.persistence.*;
@Table(name = "users")
@Entity
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
@@ -23,38 +24,49 @@ public class User implements UserDetails {
@Column(nullable = false)
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)
private String email;
@Column(nullable = false)
private String password;
// ✅ Add RSA key fields
@Lob
@Column(name = "public_key", columnDefinition = "BLOB")
private byte[] publicKey;
public User(){
}
@Lob
@Column(name = "private_key", columnDefinition = "BLOB")
private byte[] privateKey;
public User(String firstname,String lastname,String email,String password){
this.username=firstname+lastname;
this.email=email;
this.password=password;
}
@CreationTimestamp
@Column(updatable = false, name = "created_at")
private Date createdAt;
public User() {}
public User(String firstname, String lastname, String email, String password) {
this.username = firstname + lastname;
this.email = email;
this.password = password;
@Override
public Collection<? extends GrantedAuthority> getAuthorities(){
return List.of();
}
// ⬇️ Required by Spring Security
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
public String getPassword() {
return password;
}
@Override
@@ -62,11 +74,6 @@ public class User implements UserDetails {
return email;
}
@Override
public String getPassword() {
return password;
}
@Override
public boolean isAccountNonExpired() {
return true;
@@ -86,8 +93,6 @@ public class User implements UserDetails {
public boolean isEnabled() {
return true;
}
// ⬇️ Getters and Setters
public Integer getId() {
return id;
}
@@ -96,11 +101,13 @@ public class User implements UserDetails {
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;
}
@@ -119,21 +126,4 @@ public class User implements UserDetails {
public void setCreatedAt(Date 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;
public interface UserRepository extends CrudRepository<User,Integer> {
Optional<User> findByEmail(String email);
// Custom query method to find user by username
Optional<User> findByUsername(String username);
/*
// might use later
Optional<User> findByVerificationCode(String verificationCode);
@@ -9,49 +9,37 @@ import com.skycrate.backend.skycrateBackend.dto.LoginUserDto;
import com.skycrate.backend.skycrateBackend.dto.RegisterUserDto;
import com.skycrate.backend.skycrateBackend.models.User;
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
@Service
public class AuthenticationService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final AuthenticationManager authenticationManager;
public AuthenticationService(UserRepository userRepository, AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.authenticationManager = authenticationManager;
public AuthenticationService( UserRepository userRepository, AuthenticationManager authenticationManager , PasswordEncoder passwordEncoder){
this.userRepository=userRepository;
this.passwordEncoder=passwordEncoder;
this.authenticationManager=authenticationManager;
}
public User signUp(RegisterUserDto inputUser) {
User user = new User(
inputUser.getFirstname(),
inputUser.getLastname(),
inputUser.getEmail(),
passwordEncoder.encode(inputUser.getPassword())
);
public User signUp(RegisterUserDto inputuser){
User user=new User(inputuser.getFirstname(),inputuser.getLastname(),inputuser.getEmail(),passwordEncoder.encode(inputuser.getPassword()));
/*
User user = new User()
.setFullname(inputuser.getFirstname(),inputuser.getLastname())
.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) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(inputUser.getEmail(), inputUser.getPassword())
);
public User authenticate(LoginUserDto inputuser){
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(inputuser.getEmail()
, inputuser.getPassword()));
return userRepository.findByEmail(inputuser.getEmail()).orElseThrow();
return userRepository.findByEmail(inputUser.getEmail())
.orElseThrow(() -> new RuntimeException("User not found"));
}
}
}
@@ -1,10 +1,9 @@
package com.skycrate.backend.skycrateBackend.services;
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.Arrays;
public class EncryptionUtil {
private static final String RSA_ALGORITHM = "RSA";
@@ -20,57 +19,36 @@ public class EncryptionUtil {
}
// 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;
// }
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);
}
// Step 1: Generate AES Key
SecretKey aesKey = generateAESKey();
private static byte[] encryptDataWithAES(byte[] data, SecretKey aesKey) throws Exception {
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// Step 2: Encrypt data using AES
Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM);
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
return aesCipher.doFinal(data);
}
byte[] encryptedData = aesCipher.doFinal(data);
private static byte[] combineEncryptedData(byte[] encryptedAesKey, byte[] encryptedData) {
// Step 3: Encrypt the AES key with RSA
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM);
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;
}
// 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
@@ -87,16 +65,21 @@ public class EncryptionUtil {
System.arraycopy(encryptedCombined, 4 + aesKeyLength, encryptedData, 0, encryptedData.length);
// 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);
byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey);
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, AES_ALGORITHM);
// Create AES key
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES");
// Decrypt the data using AES
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// Step 4: Decrypt the data using AES
Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM);
aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
return aesCipher.doFinal(encryptedData);
}
// Generate a random AES key
private static SecretKey generateAESKey() throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance(AES_ALGORITHM);
keyGen.init(AES_KEY_SIZE);
return keyGen.generateKey();
}
}
@@ -1,16 +1,12 @@
package com.skycrate.backend.skycrateBackend.services;
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
import com.skycrate.backend.skycrateBackend.models.User;
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
import org.apache.hadoop.fs.FSDataOutputStream;
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 com.skycrate.backend.skycrateBackend.utils.KeyUtil;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.fs.*;
import org.springframework.core.io.InputStreamResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
@@ -18,7 +14,6 @@ import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
@@ -32,129 +27,97 @@ import java.util.List;
@Service
public class HDFSOperations {
private final UserRepository userRepository;
@Autowired
public HDFSOperations(UserRepository userRepository) {
this.userRepository = userRepository;
}
// public void uploadFile(byte[] fileData, String hdfsPath, String uploadedFileName, String username) {
// public void uploadFile(String localPath, String hdfsPath, String uploadedFileName, String username) {
// try {
// FileSystem fs = HDFSConfig.getHDFS();
// byte[] data = Files.readAllBytes(Paths.get(localPath)); // Read file as bytes
//
// // Create an InputStream from the byte array
// ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData);
// // Encrypt file (consider adding encryption here as needed)
// byte[] encryptedData = data;
//
// String tempFilePath = localPath + ".enc";
// Files.write(Paths.get(tempFilePath), encryptedData);
//
// // Prepare the path for HDFS
// String finalHdfsPath = hdfsPath.endsWith("/") ? hdfsPath + uploadedFileName : hdfsPath + "/" + uploadedFileName;
// fs.copyFromLocalFile(new Path(tempFilePath), new Path(finalHdfsPath));
//
// // Upload the file directly to HDFS from the InputStream
// Path hdfsFilePath = new Path(finalHdfsPath);
// FSDataOutputStream outputStream = fs.create(hdfsFilePath);
// IOUtils.copyBytes(inputStream, outputStream, 4096, true);
//
// Files.delete(Paths.get(tempFilePath));
// } catch (IOException e) {
// // Handle I/O exception and log the error
// throw new RuntimeException("Failed to upload file to HDFS: " + e.getMessage(), e);
// 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 to HDFS: " + e.getMessage(), e);
// throw new RuntimeException("Failed to upload file: " + e.getMessage(), e);
// }
// }
//
// public void downloadFile(String hdfsEncPath, String localPathWithoutExt, String username) {
public void uploadFile(MultipartFile file, String hdfsPath, String uploadedFileName, String username) {
try {
FileSystem fs = HDFSConfig.getHDFS();
// Encrypt file data if needed (currently direct pass-through)
byte[] fileBytes = file.getBytes(); // directly get bytes from MultipartFile
byte[] encryptedData = fileBytes;
// Define final HDFS file path
String finalHdfsPath = hdfsPath.endsWith("/") ? hdfsPath + uploadedFileName : hdfsPath + "/" + uploadedFileName;
// Write encrypted bytes directly to HDFS
Path hdfsDestPath = new Path(finalHdfsPath);
try (FSDataOutputStream outputStream = fs.create(hdfsDestPath, true)) {
outputStream.write(encryptedData);
}
} catch (IOException e) {
throw new RuntimeException("Failed to upload file due to I/O issue: " + e.getMessage(), e);
} catch (Exception e) {
throw new RuntimeException("Failed to upload file: " + e.getMessage(), e);
}
}
// public void downloadFile(String hdfsPath, String localPath, String username) {
// try {
// FileSystem fs = HDFSConfig.getHDFS();
// String tempFilePath = localPath + ".enc";
//
// // Extract file name and extension
// String encFileName = new File(hdfsEncPath).getName();
// String originalFileName = encFileName.replace(".enc", "");
// String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
// fs.copyToLocalFile(new Path(hdfsPath), new Path(tempFilePath));
//
// String fullDecryptedPath = localPathWithoutExt + "/" + originalFileName;
// String encFilePath = fullDecryptedPath + ".enc";
// String keyFilePath = fullDecryptedPath + ".key";
//
// // Download encrypted file and AES key from HDFS
// 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));
// 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) {
// throw new RuntimeException("Failed to download or decrypt file: " + e.getMessage(), e);
// // Catch any other exceptions
// throw new RuntimeException("Failed to download file: " + e.getMessage(), e);
// }
// }
public void uploadFile(byte[] fileData, String hdfsPath, String uploadedFileName, String username) {
public InputStreamResource downloadFile(String hdfsPath, String username) {
try {
FileSystem fs = HDFSConfig.getHDFS();
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData);
String finalHdfsPath = hdfsPath.endsWith("/") ? hdfsPath + uploadedFileName : hdfsPath + "/" + uploadedFileName;
Path hdfsFilePath = new Path(finalHdfsPath);
try (FSDataOutputStream outputStream = fs.create(hdfsFilePath)) {
IOUtils.copyBytes(inputStream, outputStream, 4096, true);
}
// Read encrypted file directly from HDFS
FSDataInputStream hdfsInputStream = fs.open(new Path(hdfsPath));
// Optional: If decryption is needed, read bytes, decrypt, and wrap in ByteArrayInputStream
byte[] encryptedData = IOUtils.toByteArray(hdfsInputStream);
byte[] decryptedData = encryptedData; // Apply decryption if needed
return new InputStreamResource(new ByteArrayInputStream(decryptedData));
} catch (IOException e) {
throw new RuntimeException("Failed to upload file to HDFS: " + e.getMessage(), e);
throw new RuntimeException("Failed to stream file due to I/O issue: " + e.getMessage(), e);
} catch (Exception e) {
throw new RuntimeException(e);
throw new RuntimeException("Failed to stream file: " + e.getMessage(), e);
}
}
public void downloadFile(String hdfsEncPath, String localPathWithoutExt, String username) {
try {
FileSystem fs = HDFSConfig.getHDFS();
String encFilePath = localPathWithoutExt + ".enc";
fs.copyToLocalFile(new Path(hdfsEncPath), new Path(encFilePath));
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new RuntimeException("User not found"));
PrivateKey privateKey = RSAKeyUtil.getPrivateKeyFromBytes(user.getPrivateKey());
byte[] encryptedFileContent = Files.readAllBytes(Paths.get(encFilePath));
byte[] decryptedFileContent = RSAKeyUtil.decrypt(encryptedFileContent, privateKey);
Files.write(Paths.get(localPathWithoutExt), decryptedFileContent);
Files.deleteIfExists(Paths.get(encFilePath));
} catch (Exception e) {
throw new RuntimeException("Failed to download or decrypt file: " + e.getMessage(), e);
}
}
public void createFolder(String hdfsPath) {
try {
@@ -3,37 +3,24 @@ package com.skycrate.backend.skycrateBackend.utils;
import java.nio.file.Files;
import java.nio.file.Path;
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.X509EncodedKeySpec;
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 {
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);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
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,80 +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
// }
public static byte[] encryptAESKey(SecretKey aesKey, PublicKey publicKey) throws Exception {
return encrypt(aesKey.getEncoded(), publicKey);
}
public static SecretKey decryptAESKey(byte[] encryptedAESKey, PrivateKey privateKey, int keySize) throws Exception {
byte[] decryptedKey = decrypt(encryptedAESKey, privateKey);
return new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES");
}
}
+4 -6
View File
@@ -3,15 +3,13 @@ spring.application.name=skycrateBackend
spring.servlet.multipart.max-file-size=1000MB
spring.servlet.multipart.max-request-size=1000MB
spring.servlet.multipart.enabled=true
security.jwt.secret-key=3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b
security.jwt.expiration-time=3600000
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.datasource.username=skycrateDB
spring.datasource.password=${MYSQL_PASSWORD}
spring.datasource.url=jdbc:mysql://db:3306/skycrate
spring.datasource.username=kshitij
spring.datasource.password=loa_dngLLA8729
spring.datasource.url=jdbc:mysql://192.168.29.55:3306/skycrate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
@@ -19,7 +17,7 @@ spring.jpa.properties.hibernate.format_sql=true
spring.jpa.open-in-view=false
logging.level.org.springframework.security.config.annotation.authentication.configuration.InitializeUserDetailsBeanManagerConfigurer=ERROR
server.port=8081
server.port=8080