
public void uploadPDF(String binaryPdfString, String key, String secret){
String Date = Datetime.now().formatGMT('EEE, dd MMM yyyy HH:mm:ss z');
String bucketname = 'BucketName';
String method = 'PUT';
String filename = 'FileName';
HttpRequest req = new HttpRequest();
req.setMethod(method);
req.setHeader('Host','s3-us-west-2.amazonaws.com');
req.setEndpoint('https://s3-us-west-2.amazonaws.com' + '/'+ bucketname + '/' + filename);
req.setHeader('Content-Length', string.valueOf(binaryPdfString.length()));
req.setHeader('Content-Encoding', 'base64');
req.setHeader('Content-Type', 'pdf');
req.setHeader('Date', Date);
//get signature string
String stringToSign = 'PUT\n\n\n'+formattedDateString+'\n\n/'+bucketname+'/'+filename;
String encodedStringToSign = EncodingUtil.urlEncode(stringToSign,'UTF-8');
String signed = createSignature(encodedStringToSign,secret);
String authHeader = 'AWS' + ' ' + key + ':' + signed;
req.setHeader('Authorization',authHeader);
req.setBody(binaryPdfString);
Http http = new Http();
try {
//Execute web service call
HTTPResponse res = http.send(req);
System.debug('RESPONSE STRING: ' + res.toString());
System.debug('RESPONSE STATUS: '+res.getStatus());
System.debug('STATUS_CODE: '+res.getStatusCode());
} catch(System.CalloutException e) {
system.debug('AWS Service Callout Exception: ' + e.getMessage());
}
}
public string createSignature(string canonicalBuffer,String secret){
string sig;
Blob mac = Crypto.generateMac('HMacSHA1', blob.valueof(canonicalBuffer),blob.valueof(secret));
sig = EncodingUtil.base64Encode(mac);
return sig;
}

well I guess I should have waited a bit longer to post this question...hahaturns out my signing string didn't need to be UTF-8 encoded (see old code "String encodedStringToSign = EncodingUtil.urlEncode(stringToSign,'UTF-8');" )Amazon's doucmentation mentions "The string to sign (verb, headers, resource) must be UTF-8 encoded", however I removed this piece and just ran my createSignature class using stringToSign (not UTF-8 encoded) and it worked!!Also, it turns out that you can decode the binary stream and use the decoded Blob as the body of the response. Otherwise, Amazon just displays the binary stream text on screen.Here is my final code Hope this helps someone else!
public void uploadPDF(String binaryPdfString, String key, String secret){
String Date = Datetime.now().formatGMT('EEE, dd MMM yyyy HH:mm:ss z');
String bucketname = 'BucketName';
String method = 'PUT';
String filename = 'FileName';
HttpRequest req = new HttpRequest();
req.setMethod(method);
req.setHeader('Host','s3-us-west-2.amazonaws.com');
req.setEndpoint('https://s3-us-west-2.amazonaws.com' + '/'+ bucketname + '/' + filename);
req.setHeader('Content-Length', string.valueOf(binaryPdfString.length()));
req.setHeader('Content-Encoding', 'base64');
req.setHeader('Content-Type', 'pdf');
req.setHeader('Date', Date);
//get signature string
String stringToSign = 'PUT\n\n\n'+formattedDateString+'\n\n/'+bucketname+'/'+filename;
String signed = createSignature(stringToSign,secret);
String authHeader = 'AWS' + ' ' + key + ':' + signed;
req.setHeader('Authorization',authHeader);
Blob PDF = EncodingUtil.base64Decode(binaryPdfString);
req.setBodyAsBlob(PDF);
Http http = new Http();
try {
//Execute web service call
HTTPResponse res = http.send(req);
System.debug('RESPONSE STRING: ' + res.toString());
System.debug('RESPONSE STATUS: '+res.getStatus());
System.debug('STATUS_CODE: '+res.getStatusCode());
} catch(System.CalloutException e) {
system.debug('AWS Service Callout Exception: ' + e.getMessage());
}
}
public string createSignature(string canonicalBuffer,String secret){
string sig;
Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(canonicalBuffer),blob.valueof(secret));
sig = EncodingUtil.base64Encode(mac);
return sig;
}