11#import " AESCrypto.h"
22#import " CryptoUtils.h"
3+ #import " FileUtils.h"
34#import < CommonCrypto/CommonCryptor.h>
45
56#import < MobileCrypto/MobileCrypto-Swift.h>
@@ -87,15 +88,36 @@ + (nullable NSString *)processFile:(NSString *)filePath operation:(CCOperation)o
8788 NSData *keyData = [CryptoUtils decodeBase64: keyBase64];
8889 NSData *ivData = [CryptoUtils decodeBase64: base64Iv];
8990
90- NSString *normalizedFilePath = [filePath stringByReplacingOccurrencesOfString: @" file://" withString: @" " ];
91+ NSString *normalizedFilePath = [FileUtils normalizeFilePath: filePath];
92+
93+ // Check if input file exists
94+ NSFileManager *fileManager = [NSFileManager defaultManager ];
95+ if (![fileManager fileExistsAtPath: normalizedFilePath]) {
96+ return nil ;
97+ }
98+
9199 NSString *outputFileName = [@" processed_" stringByAppendingString: [normalizedFilePath lastPathComponent ]];
92100 NSString *outputFilePath = [[normalizedFilePath stringByDeletingLastPathComponent ] stringByAppendingPathComponent: outputFileName];
93-
101+
94102 NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath: normalizedFilePath];
95103 NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath: outputFilePath append: NO ];
104+
105+ // Validate stream creation
106+ if (!inputStream || !outputStream) {
107+ return nil ;
108+ }
109+
96110 [inputStream open ];
97111 [outputStream open ];
98112
113+ // Validate stream opening
114+ if ([inputStream streamStatus ] != NSStreamStatusOpen || [outputStream streamStatus ] != NSStreamStatusOpen) {
115+ [inputStream close ];
116+ [outputStream close ];
117+ [fileManager removeItemAtPath: outputFilePath error: nil ];
118+ return nil ;
119+ }
120+
99121 size_t bufferSize = 4096 ;
100122 uint8_t buffer[bufferSize];
101123 CCCryptorRef cryptor = NULL ;
@@ -104,68 +126,79 @@ + (nullable NSString *)processFile:(NSString *)filePath operation:(CCOperation)o
104126 NSLog (@" Failed to create cryptor: %d " , status);
105127 [inputStream close ];
106128 [outputStream close ];
129+ [fileManager removeItemAtPath: outputFilePath error: nil ];
107130 return nil ;
108131 }
109132
133+ BOOL loopSuccess = YES ;
134+
110135 while ([inputStream hasBytesAvailable ]) {
111136 NSInteger bytesRead = [inputStream read: buffer maxLength: sizeof (buffer)];
112137 if (bytesRead > 0 ) {
138+
113139 size_t dataOutMoved;
114140 status = CCCryptorUpdate (cryptor, buffer, bytesRead, buffer, bufferSize, &dataOutMoved);
115141 if (status == kCCSuccess ) {
116- [outputStream write: buffer maxLength: dataOutMoved];
142+ NSInteger bytesWritten = [outputStream write: buffer maxLength: dataOutMoved];
143+ if (bytesWritten != (NSInteger )dataOutMoved) {
144+ loopSuccess = NO ;
145+ break ;
146+ }
117147 } else {
118148 NSLog (@" Cryptor update failed: %d " , status);
119- CCCryptorRelease (cryptor);
120- [inputStream close ];
121- [outputStream close ];
122- return nil ;
149+ loopSuccess = NO ;
150+ break ;
123151 }
124152 } else if (bytesRead < 0 ) {
125153 NSLog (@" Input stream read error" );
126- CCCryptorRelease (cryptor);
127- [inputStream close ];
128- [outputStream close ];
129- return nil ;
154+ loopSuccess = NO ;
155+ break ;
130156 }
131157 }
132158
133- if (status == kCCSuccess ) {
159+ if (loopSuccess ) {
134160 size_t finalBytesOut;
135161 status = CCCryptorFinal (cryptor, buffer, bufferSize, &finalBytesOut);
136- if (status == kCCSuccess ) {
137- [outputStream write: buffer maxLength: finalBytesOut];
138- } else {
162+ if (status == kCCSuccess && finalBytesOut > 0 ) {
163+ NSInteger finalBytesWritten = [outputStream write: buffer maxLength: finalBytesOut];
164+ if (finalBytesWritten != (NSInteger )finalBytesOut) {
165+ NSLog (@" Output stream write error on final block" );
166+ loopSuccess = NO ;
167+ }
168+ } else if (status != kCCSuccess ) {
139169 NSLog (@" Cryptor final failed: %d " , status);
140- CCCryptorRelease (cryptor);
141- [inputStream close ];
142- [outputStream close ];
143- return nil ;
144170 }
145171 }
146172
147173 CCCryptorRelease (cryptor);
148174 [inputStream close ];
149175 [outputStream close ];
150176
151- if (status == kCCSuccess ) {
177+ if (status != kCCSuccess || !loopSuccess) {
178+ [[NSFileManager defaultManager ] removeItemAtPath: outputFilePath error: nil ];
179+ return nil ;
180+ }
181+
182+ if (operation == kCCDecrypt ) {
183+ // For decrypt: atomically replace the original file with decrypted content
152184 NSURL *originalFileURL = [NSURL fileURLWithPath: normalizedFilePath];
153185 NSURL *outputFileURL = [NSURL fileURLWithPath: outputFilePath];
154186 NSError *error = nil ;
155- [[NSFileManager defaultManager ] replaceItemAtURL: originalFileURL
156- withItemAtURL: outputFileURL
157- backupItemName: nil
158- options: NSFileManagerItemReplacementUsingNewMetadataOnly
159- resultingItemURL: nil
160- error: &error];
161- if (error ) {
187+ BOOL success = [[NSFileManager defaultManager ] replaceItemAtURL: originalFileURL
188+ withItemAtURL: outputFileURL
189+ backupItemName: nil
190+ options: NSFileManagerItemReplacementUsingNewMetadataOnly
191+ resultingItemURL: nil
192+ error: &error];
193+ if (!success ) {
162194 NSLog (@" Failed to replace original file: %@ " , error);
195+ [[NSFileManager defaultManager ] removeItemAtPath: outputFilePath error: nil ];
163196 return nil ;
164197 }
165198 return [NSString stringWithFormat: @" file://%@ " , normalizedFilePath];
166199 } else {
167- [[ NSFileManager defaultManager ] removeItemAtPath: outputFilePath error: nil ];
168- return nil ;
200+ // For encrypt: return the processed file path
201+ return [ NSString stringWithFormat: @" file:// %@ " , outputFilePath] ;
169202 }
170203}
171204
0 commit comments