Customise NSLog so it shows less info - cocoa

by default NSLog outputs a long string before the requested output,
e.g:
NSLog(#"Log message");
Outputs to the console:
2011-04-15 11:23:01.692 MyAppName[23160:903] Log message
I know I can add the filename and line number to the log, but how do I get rid of all the date, time and app name that appears before the message?
I find it really clutters the console in Xcode making it harder to find the information I'm after.

This is definitely the FIRST thing I do on a new project. NSLog(…) has diarrhea of the mouth. Here is a basic macro that lets you get some peace and quiet.. AND log basic objects without the annoying NSLog(#"%#", xYz); syntax (instead you just NSLog(xYz);).
#define NSLog(fmt...) NSShutUp(__PRETTY_FUNCTION__,fmt)
#define UTF8FMT(fmt,argL) \
[NSString.alloc initWithFormat:fmt arguments:argL].UTF8String
void NSShutUp(const char*func, id fmt, ...) {
if (![fmt isKindOfClass:NSString.class])
// it's not a string (aka. the formatter), so print it)
fprintf (stderr, "%s: %s\n", func,
[[NSString stringWithFormat:#"%#",fmt,nil]UTF8String]);
else { va_list argList; va_start (argList, fmt);
fprintf (stderr, "%s: %s\n", func, UTF8FMT(fmt,argList));
va_end (argList);
} }
/* SAMPLE RUN */
int main (void) { NSString *a; NSNumber *b; NSArray *c;
NSLog(a = #"Ahh, silence." );
NSLog(b = #(M_PI) );
NSLog(c = #[#"Arrays, baby!"] );
// Old syntax still works.
NSLog(#"%# * %# * %#",a,b,c);
return 0;
}
OUTPUT
int main(): Ahh, silence.
int main(): 3.141592653589793
int main(): (
"Arrays, baby!"
)
int main(): Ahh, silence. * 3.141592653589793 * (
"Arrays, baby!"
)

i would recommend that you start using a better alternatives to NSlog like SOSMAX or NSLogger.
Here is a bit overview of both of them
http://learning-ios.blogspot.com/2011/05/better-nslog-ing.html

Related

lldb printf in xcode 12

XCode 12.4 , lldb debug on one IOS app
using command 'expression'
(int) printf("hello world\n");
no output ,but
(void) NSLog(#"hello world\n");
it did work , why ? can I change to C/C++ mode ?
enter image description here
also, I find that
(void) NSLog(#"number = %i", 123);
result is "number = 307823584".
i don't know what it means. it seem that only objc object is allowed ?
SString* temp = #"yuv";
(void) NSLog(#"str = %#", temp);
output is "str = yuv" (corret)
but
(void) NSLog(#"str = %s", "123456");
output is "str = »¡#" (error)

WinAPI C++ client detect write on anonymous pipe before reading

I am writing a C++ (Windows) client console application which reads from an anonymous pipe on STDIN. I would like to be able to use my program as follows:
echo input text here | my_app.exe
and do something in the app with the text that is piped in
OR
my_app.exe
and then use some default text inside of the app instead of the input from the pipe.
I currently have code that successfully reads from the pipe on STDIN given the first situation:
#include <Windows.h>
#include <iostream>
#include <string>
#define BUFSIZE 4096
int main(int argc, const char *argv[]) {
char char_buffer[BUFSIZE];
DWORD bytes_read;
HANDLE stdin_handle;
BOOL continue_reading;
unsigned int required_size;
bool read_successful = true;
stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
if (stdin_handle == INVALID_HANDLE_VALUE) {
std::cout << "Error: invalid handle value!\n\n";
} else {
continue_reading = true;
while (continue_reading) {
continue_reading = ReadFile(stdin_handle, char_buffer, BUFSIZE,
&bytes_read, NULL);
if (continue_reading) {
if (bytes_read != 0) {
// Output what we have read so far
for (unsigned int i = 0; i < bytes_read; i++) {
std::cout << char_buffer[i];
}
} else {
continue_reading = false;
}
}
}
}
return 0;
}
I know that my only option with anonymous pipes is to do a blocking read with ReadFile. If I understand correctly, in regard to how I am invoking it, ReadFile will continue to read from the buffer on STDIN until it detects an end of write operation on the other end of the pipe (perhapse reads some sort of "end of write" token??). I would like to know if there is some sort of "beginning write" token that will be in the buffer if something is being piped in which I can check on STDIN BEFORE I call ReadFile. If this were the case I could just skip calling ReadFile and use some default text.
If there is not a way to do this, I can always pass in a command line argument that denotes that I should not check the pipe and just use the default text (or the other way around), but I would much prefer to do it the way that I specified.
Look at PeekNamedPipe(). Despite its name, it works for both named and anonymous pipes.
int main(int argc, const char *argv[])
{
char char_buffer[BUFSIZE];
DWORD bytes_read;
DWORD bytes_avail;
DWORD dw;
HANDLE stdin_handle;
bool is_pipe;
stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
is_pipe = !GetConsoleMode(stdin_handle, &dw);
if (stdin_handle == INVALID_HANDLE_VALUE) {
std::cout << "Error: invalid handle value!\n\n";
} else {
while (1) {
if (is_pipe) {
if (PeekNamedPipe(stdin_handle, NULL, 0, NULL, &bytes_avail, NULL)) {
if (bytes_avail == 0) {
Sleep(100);
continue;
}
}
}
if (!ReadFile(stdin_handle, char_buffer, min(bytes_avail, BUFSIZE), &bytes_read, NULL)) {
break;
}
if (bytes_read == 0) {
break;
}
// Output what we have read so far
for (unsigned int i = 0; i < bytes_read; i++) {
std::cout << char_buffer[i];
}
}
}
return 0;
}
It looks like what you're really trying to do here is to determine whether you've got console input (where you use default value) vs pipe input (where you use input from the pipe).
Suggest testing that directly instead of trying to check if there's input ready: the catch with trying to sniff whether there's data in the pipe is that if the source app is slow in generating output, your app might make an incorrect assumption just because there isn't input yet available. (It might also be possible that, due to typeahead, there's a user could have typed in characters that area ready to be read from console STDIN before your app gets around to checking if input is available.)
Also, keep in mind that it might be useful to allow your app to be used with file redirection, not just pipes - eg:
myapp.exe < some_input_file
The classic way to do this "interactive mode, vs used with redirected input" test on unix is using isatty(); and luckily there's an equivalent in the Windows CRT - see function _isatty(); or use GetFileType() checking for FILE_TYPE_CHAR on GetStdHandle(STD_INPUT_HANDLE) - or use say GetConsoleMode as Remy does, which will only succeed on a real console handle.
This also works without overlapped I/O while using a second thread, that does the synchronous ReadFile-call. Then the main thread waits an arbitrary amount of time and acts like above...
Hope this helps...

NSString pointer passed to function... not keeping the value I set

I'm not sure what I'm doing wrong here. I've also tried setting s1..3 in foo by using:
s1 = [[NSString alloc] initWithString:[filepaths objectAtIndex:0]];
Context below:
void foo(NSString *s1, NSString *s2, NSString *s3){
//assign long string to NSString *fps
//...
//break fps into smaller bits
NSArray *filepaths = [fps componentsSeparatedByString:#"\n"];
//the above worked! now let's assign them to the pointers
s1 = [filepaths objectAtIndex:0];
//repeat for s2 and s3
NSLog(#"%#",s1); //it worked! we're done in this function
}
int main(int argc, const char * argv[]){
NSString *s1 = nil; //s2 and s3 as well
foo(s1,s2,s3); //this should work
NSLog(#"%#",s1); //UH OH, this is null!
return 0;
}
No.
You are passing in pointers to objects which can be mutated locally. You are not changing the original objects, as you might think from plain C.
If you want to use this method (which I would not recommend - it's really odd to see in Cocoa except in the case of NSError), you would have something like:
void foo(NSString **s1, NSString **s2, NSString **s3) {
*s1 = [filepaths objectAtIndex:0]; // etc.
}
You would then pass in &s1 as the argument.
This will, of course, clobber whatever was in s1, potentially cause memory leaks, thread unsafety, etc., unless you are really careful. Which is why I say you usually won't do this.
Functions take a local copy of their arguments, so you're modifying a copy of the NSString* not the original. This is called "pass by value". What you want is "pass by reference," which looks like this:
void foo(NSString** s1) {
if(s1) *s1 = #"Different string";
}
int main(int argc, const char* argv[]){
NSString* s1 = nil;
foo(&s1);
NSLog(#"%#", s1);
return EXIT_SUCCESS;
}
It boils down to how well you understand pointers in C. It would be a good idea to read up on the "address of" operator &, and the dereference operator *, and just C pointers in general.

Encrypt NSString using AES-128 and a key

I have a basic notes app, and I want to allow the user to have encrypted or secure notes. I have an UI whipped up, but right now, I can't seem to get encryption working. Either it returns me a bunch of garbage or nothing at all. This is what I use to en/decrypt:
- (BOOL) encryptWithAES128Key: (NSString *) key {
// 'key' should be 16 bytes for AES128, will be null-padded otherwise
char * keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
// encrypts in-place, since this is a mutable data object
size_t numBytesEncrypted = 0;
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128 , kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self mutableBytes], [self length], /* input */
[self mutableBytes], [self length] + kCCBlockSizeAES128, /* output */
&numBytesEncrypted);
return (result == kCCSuccess);
}
- (NSMutableData *) decryptWithAES128Key: (NSString *) key {
// 'key' should be 16 bytes for AES128, will be null-padded otherwise
char * keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
// encrypts in-place, since this is a mutable data object
size_t bufferSize = [self length] + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus result = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self bytes], [self length], /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if(result == kCCSuccess || result == kCCParamError) {
return [[NSMutableData dataWithBytesNoCopy:buffer length:numBytesEncrypted] retain];
}
return nil;
}
Does anyone have any idea why this might be going wrong?
Edit 1:
I've revised my en/decryption code to be the same. Here is how it looks right now:
- (BOOL) encryptWithAES128Key: (NSString *) key {
CCCryptorStatus ccStatus = kCCSuccess;
// Symmetric crypto reference.
CCCryptorRef thisEncipher = NULL;
// Cipher Text container.
NSData * cipherOrPlainText = nil;
// Pointer to output buffer.
uint8_t * bufferPtr = NULL;
// Total size of the buffer.
size_t bufferPtrSize = 0;
// Remaining bytes to be performed on.
size_t remainingBytes = 0;
// Number of bytes moved to buffer.
size_t movedBytes = 0;
// Length of plainText buffer.
size_t plainTextBufferSize = 0;
// Placeholder for total written.
size_t totalBytesWritten = 0;
// A friendly helper pointer.
uint8_t * ptr;
// Initialization vector; dummy in this case 0's.
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
plainTextBufferSize = [self length];
ccStatus = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, (const void *)[key UTF8String], kCCKeySizeAES128, (const void *)iv, &thisEncipher);
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Allocate buffer.
bufferPtr = [self mutableBytes];
// Zero out buffer.
//memset((void *)bufferPtr, 0x0, bufferPtrSize);
// Initialize some necessary book keeping.
ptr = bufferPtr;
// Set up initial size.
remainingBytes = bufferPtrSize;
// Actually perform the encryption or decryption.
ccStatus = CCCryptorUpdate(thisEncipher, (const void *) [self bytes], plainTextBufferSize, ptr, remainingBytes, &movedBytes);
ptr += movedBytes;
remainingBytes -= movedBytes;
totalBytesWritten += movedBytes;
// Finalize everything to the output buffer.
ccStatus = CCCryptorFinal(thisEncipher, ptr, remainingBytes, &movedBytes);
cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten];
NSLog(#"data: %#", cipherOrPlainText);
NSLog(#"buffer: %s", bufferPtr);
CCCryptorRelease(thisEncipher);
thisEncipher = NULL;
if(bufferPtr) free(bufferPtr);
}
- (NSMutableData *) decryptWithAES128Key: (NSString *) key {
CCCryptorStatus ccStatus = kCCSuccess;
// Symmetric crypto reference.
CCCryptorRef thisEncipher = NULL;
// Cipher Text container.
NSData * cipherOrPlainText = nil;
// Pointer to output buffer.
uint8_t * bufferPtr = NULL;
// Total size of the buffer.
size_t bufferPtrSize = 0;
// Remaining bytes to be performed on.
size_t remainingBytes = 0;
// Number of bytes moved to buffer.
size_t movedBytes = 0;
// Length of plainText buffer.
size_t plainTextBufferSize = 0;
// Placeholder for total written.
size_t totalBytesWritten = 0;
// A friendly helper pointer.
uint8_t * ptr;
// Initialization vector; dummy in this case 0's.
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
plainTextBufferSize = [self length];
ccStatus = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, (const void *)[key UTF8String], kCCKeySizeAES128, (const void *)iv, &thisEncipher);
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Allocate buffer.
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t) );
// Zero out buffer.
memset((void *)bufferPtr, 0x0, bufferPtrSize);
// Initialize some necessary book keeping.
ptr = bufferPtr;
// Set up initial size.
remainingBytes = bufferPtrSize;
// Actually perform the encryption or decryption.
ccStatus = CCCryptorUpdate(thisEncipher, (const void *) [self bytes], plainTextBufferSize, ptr, remainingBytes, &movedBytes);
ptr += movedBytes;
remainingBytes -= movedBytes;
totalBytesWritten += movedBytes;
// Finalize everything to the output buffer.
ccStatus = CCCryptorFinal(thisEncipher, ptr, remainingBytes, &movedBytes);
cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten];
NSLog(#"data: %#", cipherOrPlainText);
NSLog(#"buffer: %s", bufferPtr);
CCCryptorRelease(thisEncipher);
thisEncipher = NULL;
if(bufferPtr) free(bufferPtr);
return [NSMutableData dataWithData:cipherOrPlainText];
}
This code somewhat works. If I encrypt this string with the passphrase '1234567890123456':
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>dict</key>
<dict>
<key>device</key>
<string>Tristan's Magical Macbook of Death</string>
<key>text</key>
<string>e1xydGYxXGFuc2lcYW5zaWNwZzEyNTJcY29jb2FydGYxMDM4XGNvY29hc3VicnRm
MzYwCntcZm9udHRibFxmMFxmc3dpc3NcZmNoYXJzZXQwIEhlbHZldGljYTt9Cntc
Y29sb3J0Ymw7XHJlZDI1NVxncmVlbjI1NVxibHVlMjU1O30KXHBhcmRcdHg1NjBc
dHgxMTIwXHR4MTY4MFx0eDIyNDBcdHgyODAwXHR4MzM2MFx0eDM5MjBcdHg0NDgw
XHR4NTA0MFx0eDU2MDBcdHg2MTYwXHR4NjcyMFxxbFxxbmF0dXJhbFxwYXJkaXJu
YXR1cmFsCgpcZjBcZnMyNCBcY2YwIFx1bCBcdWxjMCBCTEFILn0=
</string>
<key>title</key>
<string>Welcome to Notepaddy!</string>
<key>uuid</key>
<string>5yvghz9n4ukgefnbx0qa2xne3nxeebcmcvpci9j5lwpncul1asftdayjv8a</string>
</dict>
<key>text</key>
<string>e1xydGYxXGFuc2lcYW5zaWNwZzEyNTJcY29jb2FydGYxMDM4XGNvY29hc3VicnRm
MzYwCntcZm9udHRibFxmMFxmc3dpc3NcZmNoYXJzZXQwIEhlbHZldGljYTt9Cntc
Y29sb3J0Ymw7XHJlZDI1NVxncmVlbjI1NVxibHVlMjU1O30KXHBhcmRcdHg1NjBc
dHgxMTIwXHR4MTY4MFx0eDIyNDBcdHgyODAwXHR4MzM2MFx0eDM5MjBcdHg0NDgw
XHR4NTA0MFx0eDU2MDBcdHg2MTYwXHR4NjcyMFxxbFxxbmF0dXJhbFxwYXJkaXJu
YXR1cmFsCgpcZjBcZnMyNCBcY2YwIFx1bCBcdWxjMCBCTEFILn0=
</string>
<key>title</key>
<string>Welcome to Notepaddy!</string>
<key>uuid</key>
<string>5yvghz9n4ukgefnbx0qa2xne3nxeebcmcvpci9j5lwpncul1asftdayjv8a</string>
</dict>
</plist>
I get the same text back, but the entire </plist> is missing and the </dict> is cut off. Decrypting and printing the result string out gives me complete garbage when encrypted with the passphrase '0987654321123456' or any other passphrase, or the same as above when copied into the password field.
Both versions have the same problem: You tell CommonCrypto to write past the end of your buffer, and then you ignore the result.
The first version:
[self mutableBytes], [self length] + kCCBlockSizeAES128, /* output */
The second version:
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Allocate buffer.
bufferPtr = [self mutableBytes];
That's not right. You're not allocating anything. You're telling it to write bufferPtrSize bytes to a buffer of size [self length]!
You want to do something more like this (if you really want to encrypt in-place):
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Increase my size if necessary:
if (bufferPtrSize > self.length) {
self.length = bufferPtrSize;
}
I'm also not sure why encrypting is in-place while decrypting is not; the latter is, if anything, easier to do.
Your second version has an additional problems:
You free something you didn't allocate: if(bufferPtr) free(bufferPtr);
You potentially read past the end of the string: (const void *)[key UTF8String], kCCKeySizeAES128
Additional crypto problems:
Keys are supposed to be fixed-size and have a decent amount of entropy. Naively converting a string to bytes does not a good key make (for one, keys longer than 16 bytes are effectively truncated). The least you could do is hash it. You might also want to iterate the hash, or just use PBKDF2 (admittedly I haven't found the spec/test vectors for PBKDF2...)
You almost certainly want to use a random IV too (see SecRandomCopyBytes).
Addendum:
The reason why you're seeing a truncated result is because you're returning a truncated answer (with PKCS7 padding, the encrypted result is always bigger than the original data). Chances (about 255/256) are that the last ciphertext block was incorrectly padded (because you gave CCryptor truncated data), so ccStatus says an error happened but you ignored this and returned the result anyway. This is incredibly bad practice. (Additionally, you really want to use a MAC with CBC to avoid the padding oracle security hole.)
EDIT:
Some code that seems to work looks something like this (complete with test cases):
Notes:
Not actually tested on iOS (though the non-iOS code should work on iOS; it's just that SecRandomCopyBytes is a slightly nicer interface but not available on OS X).
The read() loop might be right, but is not thoroughly tested.
The ciphertext is prefixed with the IV. This is the "textbook" method, but makes ciphertexts bigger.
There is no authentication, so this code can act as a padding oracle.
There is no support for AES-192 or AES-256. It would not be difficult to add (you'd just need to switch on the key length and pick the algorithm appropriately).
The key is specified as a NSData, so you'll need to do something like [string dataUsingEncoding:NSUTF8StringEncoding]. For bonus points, run it through CC_SHA256 and take the first 16 output bytes.
There's no in-place operation. I didn't think it was worth it.
.
#include <Foundation/Foundation.h>
#include <CommonCrypto/CommonCryptor.h>
#if TARGET_OS_IPHONE
#include <Security/SecRandom.h>
#else
#include <fcntl.h>
#include <unistd.h>
#endif
#interface NSData(AES)
- (NSData*) encryptedDataUsingAESKey: (NSData *) key;
- (NSData*) decryptedDataUsingAESKey: (NSData *) key;
#end
#implementation NSData(AES)
- (NSData*) encryptedDataUsingAESKey: (NSData *) key {
uint8_t iv[kCCBlockSizeAES128];
#if TARGET_OS_IPHONE
if (0 != SecRandomCopyBytes(kSecRandomDefault, sizeof(iv), iv))
{
return nil;
}
#else
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) { return nil; }
ssize_t bytesRead;
for (uint8_t * p = iv; (bytesRead = read(fd,p,iv+sizeof(iv)-p)); p += (size_t)bytesRead) {
// 0 means EOF.
if (bytesRead == 0) { close(fd); return nil; }
// -1, EINTR means we got a system call before any data could be read.
// Pretend we read 0 bytes (since we already handled EOF).
if (bytesRead < 0 && errno == EINTR) { bytesRead = 0; }
// Other errors are real errors.
if (bytesRead < 0) { close(fd); return nil; }
}
close(fd);
}
#endif
size_t retSize = 0;
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[key bytes], [key length],
iv,
[self bytes], [self length],
NULL, 0,
&retSize);
if (result != kCCBufferTooSmall) { return nil; }
// Prefix the data with the IV (the textbook method).
// This requires adding sizeof(iv) in a few places later; oh well.
void * retPtr = malloc(retSize+sizeof(iv));
if (!retPtr) { return nil; }
// Copy the IV.
memcpy(retPtr, iv, sizeof(iv));
result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[key bytes], [key length],
iv,
[self bytes], [self length],
retPtr+sizeof(iv),retSize,
&retSize);
if (result != kCCSuccess) { free(retPtr); return nil; }
NSData * ret = [NSData dataWithBytesNoCopy:retPtr length:retSize+sizeof(iv)];
// Does +[NSData dataWithBytesNoCopy:length:] free if allocation of the NSData fails?
// Assume it does.
if (!ret) { free(retPtr); return nil; }
return ret;
}
- (NSData*) decryptedDataUsingAESKey: (NSData *) key {
const uint8_t * p = [self bytes];
size_t length = [self length];
if (length < kCCBlockSizeAES128) { return nil; }
size_t retSize = 0;
CCCryptorStatus result = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[key bytes], [key length],
p,
p+kCCBlockSizeAES128, length-kCCBlockSizeAES128,
NULL, 0,
&retSize);
if (result != kCCBufferTooSmall) { return nil; }
void * retPtr = malloc(retSize);
if (!retPtr) { return nil; }
result = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[key bytes], [key length],
p,
p+kCCBlockSizeAES128, length-kCCBlockSizeAES128,
retPtr, retSize,
&retSize);
if (result != kCCSuccess) { free(retPtr); return nil; }
NSData * ret = [NSData dataWithBytesNoCopy:retPtr length:retSize];
// Does +[NSData dataWithBytesNoCopy:length:] free if allocation of the NSData fails?
// Assume it does.
if (!ret) { free(retPtr); return nil; }
return ret;
}
#end
void test(NSData * data, NSData * key)
{
NSLog(#"%#, %#", data, key);
NSData * enc = [data encryptedDataUsingAESKey:key];
NSLog(#"%#", enc);
NSData * dec = [enc decryptedDataUsingAESKey:key];
NSLog(#"%#", dec);
NSLog((data == dec || [data isEqual:dec]) ? #"pass" : #"FAIL");
}
int main()
{
#define d(x) [NSData dataWithBytesNoCopy:("" x) length:sizeof("" x)-1 freeWhenDone:0]
[NSAutoreleasePool new];
NSData * key = d("0123456789abcdef");
test([NSData data], key);
test(d(""), key);
test(d("a"), key);
test(d("0123456789abcde"), key);
test(d("0123456789abcdef"), key);
test(d("0123456789abcdef0"), key);
test(d("0123456789abcdef0123456789abcde"), key);
test(d("0123456789abcdef0123456789abcdef"), key);
test(d("0123456789abcdef0123456789abcdef0"), key);
}
Regarding your *de*cryption code
kCCParamError is, as its name says, an error. Why are you treating it as success? If you get that error, it means you did something wrong; look at the parameters you passed and figure out what.
This is probably why you're getting “garbage”: CCCrypt (decrypting) never actually gave you anything, because it could not work with whatever values you gave it. What you're getting is whatever was lying around in the output buffer when you allocated it.
If you switch to calloc or to creating the NSMutableData object before calling CCCrypt and using its mutableBytes as the buffer, I think you'll find that the buffer then always contains all zeroes. Same reason: CCCrypt is not filling it out, because it's failing, because you passed one or more wrong values (parameter error).
You need to fix the parameter error before you can expect this to work.
You might try breaking the CCCrypt call into calls to CCCryptorCreate, CCCryptorUpdate, CCCryptorFinal, and CCCryptorRelease, at least temporarily, to see where it's going wrong.
Encryption: The same problem, or no problem at all
Is your encryption method returning YES or NO? I'm guessing it returns NO, because the code appears to be mostly the same between the encryption and decryption methods, so whatever you have wrong in your decryption code is probably wrong in your encryption code as well. See what CCCrypt is returning and, if it's failing, get it working.
If it is returning YES (CCCrypt is succeeding), then I wonder what you mean by “returns me a bunch of garbage”. Are you referring to the contents of the data object you sent the encryptWithAES128Key: message to?
If that's the case, then that is the expected result. Your code encrypts the contents of the data object in place, overwriting the cleartext with the ciphertext. What you're seeing isn't pure “garbage”—it's the ciphertext! Decrypting it (successfully) will reveal the cleartext again.
By the way, you have the “encrypts in-place, since this is a mutable data object” comment on the creation of an output buffer in order to not work in-place in the decryption code. It should be in the encryption method, where you are working in-place. I suggest making either both work in-place or neither work in-place; consistency is a virtue.
If you have following padding changes in your code remove it and always keep kCCOptionPKCS7Padding on, this should solve your issue.
if (encryptOrDecrypt == kCCEncrypt) {
if (*pkcs7 != kCCOptionECBMode) {
if ((plainTextBufferSize % kChosenCipherBlockSize) == 0) {
*pkcs7 = 0x0000;
} else {
*pkcs7 = kCCOptionPKCS7Padding;
}
}
}
You should use RNCryptor, it's high level encryption opensource api around CommonCrypto, and high level encryption API's are the best practice for cryptography these days, because it's easy for experts to make mistakes in the implementations using crypto primatives, and there are alot of side channel attacks out there that take advantage of those mistakes.
For example, you code says /* initialization vector (optional) * / 100% not true, thus you've totally crippled AES-CBC, and that's just the most obvious issue.
In your case RNCryptor is ideal, I'd strongly suggest you don't roll your own implementation.

Program received signal from GDB: EXC_BAD_ACCESS

Well, I'm starting development on the Mac OS X this code that you'll see is in a book that I bought, really basic like Chapter 3. And I can't run it. PLEASE HELP ME:
C301.m :
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
if (argc == 1) {
NSLog (#"You need to provide a file name");
return -1;
}
FILE *wordFile = fopen("tmp/words.txt", "r");
char word[100];
while (fgets(word, 100, wordFile)) {
word[strlen(word) - 1] = '\0';
NSLog(#"%s is %d characters long", word, strlen(word));
}
fclose(wordFile);
return 0;
} //main
The file is in its place.
Thank you so much!
I am guessing wordFile is NULL (you should check for this); that you are mistaken: the file in fact does not exist, and finally that you really meant "/tmp/words.txt" instead of "tmp/words.txt"

Resources