diff --git a/keys/_private.key b/keys/_private.key deleted file mode 100644 index 98dfd9f..0000000 Binary files a/keys/_private.key and /dev/null differ diff --git a/keys/_public.key b/keys/_public.key deleted file mode 100644 index 859b873..0000000 Binary files a/keys/_public.key and /dev/null differ diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/controller/HDFScontroller.java b/src/main/java/com/skycrate/backend/skycrateBackend/controller/HDFScontroller.java index ddfd29e..54adc74 100644 --- a/src/main/java/com/skycrate/backend/skycrateBackend/controller/HDFScontroller.java +++ b/src/main/java/com/skycrate/backend/skycrateBackend/controller/HDFScontroller.java @@ -1,11 +1,17 @@ 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.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -15,6 +21,7 @@ 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; @@ -22,6 +29,11 @@ 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; @@ -33,6 +45,10 @@ public class HDFScontroller { private final HDFSOperations hdfsOperations; + @Autowired + private UserRepository userRepository; + + @Autowired public HDFScontroller(HDFSOperations hdfsOperations) { this.hdfsOperations = hdfsOperations; @@ -57,12 +73,19 @@ public class HDFScontroller { @RequestParam String uploadedFileName, @RequestParam String username) { try { - // Save file locally first - String localPath = saveFileLocally(file); - System.out.println("File saved locally at: " + localPath); + // 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); - // Upload file to HDFS - hdfsOperations.uploadFile(localPath, hdfsPath, uploadedFileName, username); return new ResponseDTO("File uploaded successfully", true); } catch (IOException e) { e.printStackTrace(); @@ -73,6 +96,41 @@ public class HDFScontroller { } } + // 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); + + // 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 @@ -89,36 +147,108 @@ public class HDFScontroller { return path.toString(); // Return the local path for further processing } - @PostMapping("/downloadFile") - public ResponseEntity downloadFile( - @RequestParam String hdfsPath, + public ResponseEntity downloadFile( + @RequestParam String hdfsEncPath, @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 + // Extract the file name and extension + String encFileName = new File(hdfsEncPath).getName(); + String originalFileName = encFileName.replace(".enc", ""); + String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1); - // Download the file from HDFS to the local path - hdfsOperations.downloadFile(hdfsPath, localPath, username); + // Define local decrypted file path + String localDecryptedPath = "/SkyCrate/downloaded/" + originalFileName; - // 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)); + // 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 a Resource from the file - Resource resource = new FileSystemResource(file); + // 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() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") + .contentLength(decryptedFile.length()) + .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(new ResponseDTO("Failed to download file: " + e.getMessage(), false)); + .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(); + } + } + + @DeleteMapping("/deleteFile") public ResponseDTO deleteFile(@RequestParam String hdfsPath) { try { diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/models/User.java b/src/main/java/com/skycrate/backend/skycrateBackend/models/User.java index f0933c7..c54c66b 100644 --- a/src/main/java/com/skycrate/backend/skycrateBackend/models/User.java +++ b/src/main/java/com/skycrate/backend/skycrateBackend/models/User.java @@ -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,7 +6,6 @@ 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; @@ -15,7 +14,7 @@ import jakarta.persistence.*; @Table(name = "users") @Entity public class User implements UserDetails { - + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(nullable = false) @@ -24,49 +23,38 @@ 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; - - - public User(){ - } + // ✅ Add RSA key fields + @Lob + @Column(name = "public_key", columnDefinition = "BLOB") + private byte[] publicKey; - public User(String firstname,String lastname,String email,String password){ - this.username=firstname+lastname; - this.email=email; - this.password=password; - } + @Lob + @Column(name = "private_key", columnDefinition = "BLOB") + private byte[] privateKey; @CreationTimestamp @Column(updatable = false, name = "created_at") private Date createdAt; - + public User() {} - @Override - public Collection getAuthorities(){ - return List.of(); + public User(String firstname, String lastname, String email, String password) { + this.username = firstname + lastname; + this.email = email; + this.password = password; } - public String getPassword() { - return password; + // ⬇️ Required by Spring Security + @Override + public Collection getAuthorities() { + return List.of(); } @Override @@ -74,6 +62,11 @@ public class User implements UserDetails { return email; } + @Override + public String getPassword() { + return password; + } + @Override public boolean isAccountNonExpired() { return true; @@ -93,6 +86,8 @@ public class User implements UserDetails { public boolean isEnabled() { return true; } + + // ⬇️ Getters and Setters public Integer getId() { return id; } @@ -101,13 +96,11 @@ 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(String firstname,String lastname){ + public String getFullname() { return this.username; } @@ -126,4 +119,21 @@ 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; + } } diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/repository/UserRepository.java b/src/main/java/com/skycrate/backend/skycrateBackend/repository/UserRepository.java index 2305ea2..ef145cb 100644 --- a/src/main/java/com/skycrate/backend/skycrateBackend/repository/UserRepository.java +++ b/src/main/java/com/skycrate/backend/skycrateBackend/repository/UserRepository.java @@ -5,6 +5,8 @@ import org.springframework.data.repository.CrudRepository; import com.skycrate.backend.skycrateBackend.models.User; public interface UserRepository extends CrudRepository { Optional findByEmail(String email); + // Custom query method to find user by username + Optional findByUsername(String username); /* // might use later Optional findByVerificationCode(String verificationCode); diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/services/AuthenticationService.java b/src/main/java/com/skycrate/backend/skycrateBackend/services/AuthenticationService.java index 7031f5e..b64252f 100644 --- a/src/main/java/com/skycrate/backend/skycrateBackend/services/AuthenticationService.java +++ b/src/main/java/com/skycrate/backend/skycrateBackend/services/AuthenticationService.java @@ -9,37 +9,49 @@ 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())); - /* - User user = new User() - .setFullname(inputuser.getFirstname(),inputuser.getLastname()) - .setEmail(inputuser.getEmail()) - .setPassword(passwordEncoder.encode(inputuser.getPassword())); - */ + public User signUp(RegisterUserDto inputUser) { + User user = new User( + inputUser.getFirstname(), + inputUser.getLastname(), + inputUser.getEmail(), + passwordEncoder.encode(inputUser.getPassword()) + ); - return userRepository.save(user) ; + 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); } - public User authenticate(LoginUserDto inputuser){ - authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(inputuser.getEmail() - , inputuser.getPassword())); - return userRepository.findByEmail(inputuser.getEmail()).orElseThrow(); + public User authenticate(LoginUserDto inputUser) { + authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(inputUser.getEmail(), inputUser.getPassword()) + ); + return userRepository.findByEmail(inputUser.getEmail()) + .orElseThrow(() -> new RuntimeException("User not found")); } - -} +} \ No newline at end of file diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/services/EncryptionUtil.java b/src/main/java/com/skycrate/backend/skycrateBackend/services/EncryptionUtil.java index df0bf43..8c53e1e 100644 --- a/src/main/java/com/skycrate/backend/skycrateBackend/services/EncryptionUtil.java +++ b/src/main/java/com/skycrate/backend/skycrateBackend/services/EncryptionUtil.java @@ -23,13 +23,13 @@ public class EncryptionUtil { // Step 1: Generate AES Key SecretKey aesKey = generateAESKey(); - // Step 2: Encrypt data using AES - Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM); + // Encrypt data using AES + Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); aesCipher.init(Cipher.ENCRYPT_MODE, aesKey); byte[] encryptedData = aesCipher.doFinal(data); - // Step 3: Encrypt the AES key with RSA - Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM); + // 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()); @@ -65,13 +65,15 @@ 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_ALGORITHM); + Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); rsaCipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey); - SecretKey aesKey = new SecretKeySpec(aesKeyBytes, AES_ALGORITHM); - // Step 4: Decrypt the data using AES - Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM); + // Create AES key + SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES"); + + // Decrypt the data using AES + Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); aesCipher.init(Cipher.DECRYPT_MODE, aesKey); return aesCipher.doFinal(encryptedData); } diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/services/HDFSOperations.java b/src/main/java/com/skycrate/backend/skycrateBackend/services/HDFSOperations.java index 073556e..ff48ce4 100644 --- a/src/main/java/com/skycrate/backend/skycrateBackend/services/HDFSOperations.java +++ b/src/main/java/com/skycrate/backend/skycrateBackend/services/HDFSOperations.java @@ -1,10 +1,15 @@ package com.skycrate.backend.skycrateBackend.services; import com.skycrate.backend.skycrateBackend.config.HDFSConfig; -import com.skycrate.backend.skycrateBackend.utils.KeyUtil; +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 org.springframework.stereotype.Service; import javax.crypto.Cipher; @@ -12,6 +17,8 @@ import javax.crypto.KeyGenerator; 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; @@ -25,49 +32,91 @@ import java.util.List; @Service public class HDFSOperations { + private final UserRepository userRepository; - public void uploadFile(String localPath, String hdfsPath, String uploadedFileName, String username) { + @Autowired + public HDFSOperations(UserRepository userRepository) { + this.userRepository = userRepository; + } + + public void uploadFile(byte[] fileData, String hdfsPath, String uploadedFileName, String username) { try { 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); + // Create an InputStream from the byte array + ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData); + // Prepare the path for HDFS String finalHdfsPath = hdfsPath.endsWith("/") ? hdfsPath + uploadedFileName : hdfsPath + "/" + uploadedFileName; - fs.copyFromLocalFile(new Path(tempFilePath), new Path(finalHdfsPath)); - Files.delete(Paths.get(tempFilePath)); + // 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); + } 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 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 hdfsPath, String localPath, String username) { + public void downloadFile(String hdfsEncPath, String localPathWithoutExt, String username) { try { FileSystem fs = HDFSConfig.getHDFS(); - String tempFilePath = localPath + ".enc"; - fs.copyToLocalFile(new Path(hdfsPath), new Path(tempFilePath)); + // Extract file name and extension + String encFileName = new File(hdfsEncPath).getName(); + String originalFileName = encFileName.replace(".enc", ""); + String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1); - byte[] encryptedData = Files.readAllBytes(Paths.get(tempFilePath)); - byte[] decryptedData = encryptedData; // Decrypt if needed + 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)); - 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); + throw new RuntimeException("Failed to download or decrypt file: " + e.getMessage(), e); } } diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/utils/KeyUtil.java b/src/main/java/com/skycrate/backend/skycrateBackend/utils/KeyUtil.java index 8f8694b..f75db93 100644 --- a/src/main/java/com/skycrate/backend/skycrateBackend/utils/KeyUtil.java +++ b/src/main/java/com/skycrate/backend/skycrateBackend/utils/KeyUtil.java @@ -3,24 +3,37 @@ package com.skycrate.backend.skycrateBackend.utils; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.security.KeyFactory; -import java.security.PrivateKey; -import java.security.PublicKey; +import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; public class KeyUtil { - public static PrivateKey getPrivateKeyForUser(String username) throws Exception { - 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 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("keys", username + "_public.key"); + 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"); + byte[] bytes = Files.readAllBytes(path); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); + return KeyFactory.getInstance("RSA").generatePrivate(keySpec); + } } \ No newline at end of file diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/utils/RSAKeyUtil.java b/src/main/java/com/skycrate/backend/skycrateBackend/utils/RSAKeyUtil.java new file mode 100644 index 0000000..483d5e6 --- /dev/null +++ b/src/main/java/com/skycrate/backend/skycrateBackend/utils/RSAKeyUtil.java @@ -0,0 +1,70 @@ +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 + } +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 53d9a87..9643e2e 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,6 +3,8 @@ 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 @@ -17,7 +19,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 diff --git a/src/test/java/com/skycrate/backend/skycrateBackend/SkycrateBackendApplicationTests.java b/src/test/java/com/skycrate/backend/skycrateBackend/SkycrateBackendApplicationTests.java deleted file mode 100644 index 8195f98..0000000 --- a/src/test/java/com/skycrate/backend/skycrateBackend/SkycrateBackendApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.skycrate.backend.skycrateBackend; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class SkycrateBackendApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/tmp/Handout-A5.pdf b/tmp/Handout-A5.pdf deleted file mode 100644 index 1660c1f..0000000 Binary files a/tmp/Handout-A5.pdf and /dev/null differ diff --git a/tmp/Handout-A6.pdf b/tmp/Handout-A6.pdf deleted file mode 100644 index 939b1de..0000000 Binary files a/tmp/Handout-A6.pdf and /dev/null differ diff --git a/tmp/Handout-B4.pdf b/tmp/Handout-B4.pdf deleted file mode 100644 index a00bf41..0000000 Binary files a/tmp/Handout-B4.pdf and /dev/null differ diff --git a/tmp/Hello.txt b/tmp/Hello.txt deleted file mode 100644 index f584548..0000000 --- a/tmp/Hello.txt +++ /dev/null @@ -1 +0,0 @@ -Hello World!!! \ No newline at end of file diff --git a/tmp/Rect1.png b/tmp/Rect1.png deleted file mode 100644 index edfedfc..0000000 Binary files a/tmp/Rect1.png and /dev/null differ diff --git a/tmp/test.pptx b/tmp/test.pptx deleted file mode 100644 index d4099ab..0000000 Binary files a/tmp/test.pptx and /dev/null differ