CryptEncrypt fails with NTE_BAD_LEN - winapi

I need to encrypt message with X.509 RSA public key. I successfully imported 1024-bit public key in DER format, but my program fails with message longer than about 110 bytes. I'm calling CryptEncrypt function with pbData set to NULL, because I need to calculate size of output buffer first.
This is the source code:
Plain text version of the same:
bool CCrypt::RSAEncrypt() {
HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
if (CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
CParam *pubKey = coreData.local.overlay->getItem(3);
// Decode the binary key blob in DER format into a CERT_PUBLIC_KEY_INFO
CERT_PUBLIC_KEY_INFO* publicKeyInfo = NULL;
DWORD publicKeyInfoSize;
if (CryptDecodeObjectEx(
X509_ASN_ENCODING,
X509_PUBLIC_KEY_INFO,
(LPBYTE) pubKey->getVal(),
pubKey->getLength(),
CRYPT_DECODE_ALLOC_FLAG/* | CRYPT_DECODE_NOCOPY_FLAG*/,
NULL, // TODO: Pass a CRYPT_DECODE_PARA to use own heap management to allocate memory
&publicKeyInfo,
&publicKeyInfoSize
)) {
// Import the public using the context
if (CryptImportPublicKeyInfo(
hProv,
X509_ASN_ENCODING,
publicKeyInfo,
&hKey
)) {
// Get the size of a key
DWORD dwBlockLen = NULL;
DWORD dwValLen = sizeof(DWORD);
if (CryptGetKeyParam(hKey, KP_BLOCKLEN, (LPBYTE) &dwBlockLen, &dwValLen, 0)) {
dwBlockLen = (dwBlockLen + 7) / 8; // Transform to bytes legth
BYTE msg[] = "Lorem ipsum dolor sit .... [3000+ characters here]";
DWORD dwMsgLen = I(str)->lengthA((LPSTR) msg);
//dwMsgLen = 110;
DBG(C_INFO, "CryptGetKeyParam succeed. dwMsgLen: %d, dwBlockLen: %d", dwMsgLen, dwBlockLen);
// pbData [in, out] set to NULL to calculate actual size of a buffer required
if (CryptEncrypt(hKey, 0, TRUE, CRYPT_OAEP, NULL, &dwMsgLen, 0)) {
DBG(C_INFO, "CryptEncrypt succeed. dwMsgLen: %d", dwMsgLen);
// TODO: Fails here
} else {
DBG(C_ERROR, "CryptEncrypt error.");
}
} else {
DBG(C_ERROR, "CryptGetKeyParam error.");
}
CryptDestroyKey(hKey);
}
LocalFree(publicKeyInfo);
}
CWA(advapi32, CryptReleaseContext)(hProv, 0);
}
return false;
}
Output from my debugger:
[16:08:14] TC=1093889010, PID=25484(0x638C), TID=26340(0x66E4), LE=0(0x0), F=CCrypt::RSAEncrypt, FL=d:\c\source\client\../common/Crypt.cpp (62)
INFO: CryptGetKeyParam succeed. dwMsgLen: 2175, dwBlockLen: 128
[16:08:14] TC=1093889010, PID=25484(0x638C), TID=26340(0x66E4), LE=2148073476(0x80090004), F=CCrypt::RSAEncrypt, FL=d:\c\source\client\../common/Crypt.cpp (69)
ERROR: CryptEncrypt error.
As you can see, this function fails at CryptEncrypt with error NTE_BAD_LEN (0x80090004). However when I manually set dwMsgLen to 110 [see line 61], it works correctly. When I set this variable to 120, it fails.
Can someone tell me where the problem can be?

Related

Transmitting 1500KB (hex files )data over UDS using CAPL test module

I am trying to download my hex file of size 1500KB via UDS with CAPL test module,
p2 timer = 50ms
p2* timer = 5000ms
Here is snippet of my code for data transfer :
void TS_transferData()
{
byte transferData_serviceid = 0x36;
byte blockSequenceCounter = 0x1;
byte buffer[4093];
byte binarydata[4095];
long i,ret1,ret2,ret3,temp,timeout = 0,Counter = 0;
char filename[30] = "xxx.bin";
dword readaccess_handle;
diagrequest ECU_QUALIFIER.* request;
long valueleft;
readaccess_handle = OpenFileRead(filename,1);
if (readaccess_handle != 0 )
{
while( (valueleft = fileGetBinaryBlock(buffer,elcount(buffer),readaccess_handle))==4093 )
{
binarydata[0] = transferData_serviceid;
binarydata[1] = blockSequenceCounter;
for(i=0;i<elcount(buffer);i++)
{
binarydata[i+2] = buffer[i];
}
diagResize(request, elCount(binarydata));
DiagSetPrimitiveData(request,binarydata,elcount(binarydata));
DiagSendRequest(request);
write("length of binarydata %d ",elcount(binarydata));
// Wait until the request has been completely sent
ret1 = TestWaitForDiagRequestSent(request, 20000);
if(ret1 == 1) // Request sent
{
ret2=TestWaitForDiagResponse(request,50);
if(ret2==1) // Response received
{
ret3=DiagGetLastResponseCode(request); // Get the code of the response
if(ret3==-1) // Is it a positive response?
{
;
}
else
{
testStepFail(0, "4.0","Binary Datatransfer on server Failed");
break;
}
}
else if(ret2 == timeout)
{
testStepFail(0, "4.0","Binary Datatransfer on server Failed");
write("timeout occured while TestWaitForDiagResponse with block %d ",blockSequenceCounter);
}
}
else if(ret1 == timeout)
{
testStepFail(0, "4.0","Binary Datatransfer on server Failed");
write("timeout occured while TestWaitForDiagRequestSent %d ",blockSequenceCounter);
}
if(blockSequenceCounter == 255)
blockSequenceCounter = 0;
else
++blockSequenceCounter;
}
}
//handle the rest of the bytes to be transmitted
fileClose (readaccess_handle);
}
The software downloading is happening but it is taking a long.... time for download.
For TestWaitForDiagRequestSent() function any value for timeout less than 20000 is giving me timeout error.
Is there any other way I can reduce the software transfer time or where am I going wrong with calculation?
Is there any example I can refer to see How to transmit such a long data using CAPL ?
Sorry, I am a beginner to CAPL and UDS protocol.

SetPerTcpConnectionEStats and GetPerTcpConnectionEStats is returning error code 1214 (invalid NETNAME)

I am trying to get stats similar to the ones shown in "Resource Monitor" in windows in a my c++ service. For that I have used the example shown at https://learn.microsoft.com/en-gb/windows/win32/api/iphlpapi/nf-iphlpapi-getpertcp6connectionestats?redirectedfrom=MSDN. But I am stuck because SetPerTcpConnectionEStats and GetPerTcpConnectionEStats is returning with error code 1214. The only difference btn. the code in the example at above mentioned link and mine is that I am not working on a particular local and remote port but on all the entries in the tcp table, but I don't think that should make any difference.
Can somebody help me out here?
I can reproduce this error if I work with all the entries. According to the sample you linked, in addition to local and remote port, GetTcpRow has a search parameter MIB_TCP_STATE_ESTAB. The state is the normal state for the data transfer phase of the TCP connection.
The following sample works for me.
DWORD RunEstatsTest(bool v6) //set as IPv4(FALSE)
{
PMIB_TCPTABLE tcpTable = NULL;
DWORD status, size = 0;
status = GetTcpTable(tcpTable, &size, TRUE);
if (status != ERROR_INSUFFICIENT_BUFFER) {
return status;
}
tcpTable = (PMIB_TCPTABLE)malloc(size);
if (tcpTable == NULL) {
return ERROR_OUTOFMEMORY;
}
status = GetTcpTable(tcpTable, &size, TRUE);
if (status != ERROR_SUCCESS) {
free(tcpTable);
return status;
}
for (int i = 0; i < tcpTable->dwNumEntries; i++) {
if (MIB_TCP_STATE_ESTAB == tcpTable->table[i].State)
{
ToggleAllEstats(&tcpTable->table[i], TRUE, v6);
GetAllEstats(&tcpTable->table[i], v6);
ToggleAllEstats(&tcpTable->table[i], FALSE, v6);
}
}
free(tcpTable);
return ERROR_SUCCESS;
}

How to deserialize the IPXDefaultLibraryURLBookmark of the Photos plist

So, I've been trying to deserialize the IPXDefaultLibraryURLBookmark of the com.apple.Photos defaults (defaults read com.apple.Photos IPXDefaultLibraryURLBookmark) but no luck. Ideally I'd like a programmatic way in c++ to deserialize that value to retrieve the last known location of the photo
bookd0xUsersmateuscbPicturesPhotos Library.photoslibrary 0#˜ì5$r$Éò|åú¨A∫˙æJ file:///Macintosh HDÇ1tA∫‘}•$6465C0A4-1771-3C89-9055-147CEDFBBF2EÅÔ/∆72cd528f2dcfb4b3434986cf3caa02cc946333b8;00000000;00000000;0000000000000020;com.apple.app-sandbox.read-write;00000001;01000004;0000000002980783;/users/mateuscb/pictures/photos library.photoslibrary¥˛ˇˇˇdº‰#‘ î  H ( 8 t0 †–Ä®
I know its not a bplist, since the first format specifier denotes bookd.
But I have no clue what that is. I'm somewhat new to OSX development, so this may be something very basic I'm missing.
I want to retrieve the: /users/mateuscb/pictures/photos library.photoslibrary portion so I can find the defaults photoslibrary.
Unless there is another way to retrieve the default photoslibrary path?
I figured out how to retrieve the path to the .photoslibrary. I used CFURLCreateByResolvingBookmarkData to get a CFURLRef from the plist then used CFURLGetFileSystemRepresentation to get the full path as a string.
Help from this sample to retrieve sandbox preferences: https://gist.github.com/glebd/4759724
Here is my full solution:
int main(int argc, const char * argv[]) {
bool success = FALSE;
UInt8 photosUrlString[PATH_MAX];
struct passwd *pwd = getpwuid(getuid());
if (pwd == NULL){
Log("Unable to retrieve current user");
return 0;
}
const char *home = pwd->pw_dir;
if (home == NULL){
Log("Unable to retrieve current user directory");
return 0;
}
CFMutableStringRef preferencesPath = CFStringCreateMutable(NULL, 0);
if (preferencesPath) {
CFStringAppend(preferencesPath, CFStringCreateWithCStringNoCopy(NULL, home, kCFStringEncodingUTF8, NULL));
CFStringAppend(preferencesPath, CFSTR("/Library/Containers/com.apple.Photos/Data/Library/Preferences/com.apple.Photos"));
} else {
Log("Unable to create CFString of user directory");
return 0;
}
CFPropertyListRef photosUrlPrefs = CFPreferencesCopyValue(CFSTR("IPXDefaultLibraryURLBookmark"), preferencesPath, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
CFRelease(preferencesPath);
if (photosUrlPrefs) {
CFTypeID prefsType = CFGetTypeID(photosUrlPrefs);
if (CFDataGetTypeID() == prefsType) {
CFDataRef photosUrlData = (CFDataRef) photosUrlPrefs;
CFErrorRef urlResolveError = nil;
CFURLRef photosUrl = CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, photosUrlData, NULL, NULL, NULL, NULL, &urlResolveError);
if (photosUrl == NULL) {
if(urlResolveError != NULL) {
CFStringRef resolveErrorString = CFErrorCopyDescription(urlResolveError);
if (resolveErrorString != NULL) {
char resolveErrorCString[PATH_MAX];
if (CFStringGetCString((CFStringRef) resolveErrorString, resolveErrorCString, sizeof(resolveErrorCString), kCFStringEncodingUTF8)) {
Log("Error resolving URL: %s", resolveErrorCString);
}
CFRelease(resolveErrorString);
}
} else {
Log("Error resolving URL, no resolveError");
}
} else {
success = CFURLGetFileSystemRepresentation(photosUrl, false, photosUrlString, sizeof(photosUrlString));
CFRelease(photosUrl);
}
} else {
Log("Url plist value is not CFData");
}
if (photosUrlPrefs != NULL) {
CFRelease(photosUrlPrefs);
}
}
if(success) {
Log("path: %s", photosUrlString);
}
return 0;
}

How to stream a video or a file considering request and response range headers?

I am now using FileStreamResult and it works to stream a video, but can't seek it. It always starts again from the beginning.
I was using ByteRangeStreamContent but it seems that it is not available anymore with dnxcore50.
So how to proceed ?
Do i need to manually parse the request range headers and write a custom FileResult that sets the response Content-Range and the rest of the headers and writes the buffer range to the response body or is there something already implemented and i'm missing it ?
Here is a naive implementation of a VideoStreamResult. I am using at the moment (the multipart content part is not tested):
public class VideoStreamResult : FileStreamResult
{
// default buffer size as defined in BufferedStream type
private const int BufferSize = 0x1000;
private string MultipartBoundary = "<qwe123>";
public VideoStreamResult(Stream fileStream, string contentType)
: base(fileStream, contentType)
{
}
public VideoStreamResult(Stream fileStream, MediaTypeHeaderValue contentType)
: base(fileStream, contentType)
{
}
private bool IsMultipartRequest(RangeHeaderValue range)
{
return range != null && range.Ranges != null && range.Ranges.Count > 1;
}
private bool IsRangeRequest(RangeHeaderValue range)
{
return range != null && range.Ranges != null && range.Ranges.Count > 0;
}
protected async Task WriteVideoAsync(HttpResponse response)
{
var bufferingFeature = response.HttpContext.Features.Get<IHttpBufferingFeature>();
bufferingFeature?.DisableResponseBuffering();
var length = FileStream.Length;
var range = response.HttpContext.GetRanges(length);
if (IsMultipartRequest(range))
{
response.ContentType = $"multipart/byteranges; boundary={MultipartBoundary}";
}
else
{
response.ContentType = ContentType.ToString();
}
response.Headers.Add("Accept-Ranges", "bytes");
if (IsRangeRequest(range))
{
response.StatusCode = (int)HttpStatusCode.PartialContent;
if (!IsMultipartRequest(range))
{
response.Headers.Add("Content-Range", $"bytes {range.Ranges.First().From}-{range.Ranges.First().To}/{length}");
}
foreach (var rangeValue in range.Ranges)
{
if (IsMultipartRequest(range)) // I don't know if multipart works
{
await response.WriteAsync($"--{MultipartBoundary}");
await response.WriteAsync(Environment.NewLine);
await response.WriteAsync($"Content-type: {ContentType}");
await response.WriteAsync(Environment.NewLine);
await response.WriteAsync($"Content-Range: bytes {range.Ranges.First().From}-{range.Ranges.First().To}/{length}");
await response.WriteAsync(Environment.NewLine);
}
await WriteDataToResponseBody(rangeValue, response);
if (IsMultipartRequest(range))
{
await response.WriteAsync(Environment.NewLine);
}
}
if (IsMultipartRequest(range))
{
await response.WriteAsync($"--{MultipartBoundary}--");
await response.WriteAsync(Environment.NewLine);
}
}
else
{
await FileStream.CopyToAsync(response.Body);
}
}
private async Task WriteDataToResponseBody(RangeItemHeaderValue rangeValue, HttpResponse response)
{
var startIndex = rangeValue.From ?? 0;
var endIndex = rangeValue.To ?? 0;
byte[] buffer = new byte[BufferSize];
long totalToSend = endIndex - startIndex;
int count = 0;
long bytesRemaining = totalToSend + 1;
response.ContentLength = bytesRemaining;
FileStream.Seek(startIndex, SeekOrigin.Begin);
while (bytesRemaining > 0)
{
try
{
if (bytesRemaining <= buffer.Length)
count = FileStream.Read(buffer, 0, (int)bytesRemaining);
else
count = FileStream.Read(buffer, 0, buffer.Length);
if (count == 0)
return;
await response.Body.WriteAsync(buffer, 0, count);
bytesRemaining -= count;
}
catch (IndexOutOfRangeException)
{
await response.Body.FlushAsync();
return;
}
finally
{
await response.Body.FlushAsync();
}
}
}
public override async Task ExecuteResultAsync(ActionContext context)
{
await WriteVideoAsync(context.HttpContext.Response);
}
}
And parse request headers range:
public static RangeHeaderValue GetRanges(this HttpContext context, long contentSize)
{
RangeHeaderValue rangesResult = null;
string rangeHeader = context.Request.Headers["Range"];
if (!string.IsNullOrEmpty(rangeHeader))
{
// rangeHeader contains the value of the Range HTTP Header and can have values like:
// Range: bytes=0-1 * Get bytes 0 and 1, inclusive
// Range: bytes=0-500 * Get bytes 0 to 500 (the first 501 bytes), inclusive
// Range: bytes=400-1000 * Get bytes 500 to 1000 (501 bytes in total), inclusive
// Range: bytes=-200 * Get the last 200 bytes
// Range: bytes=500- * Get all bytes from byte 500 to the end
//
// Can also have multiple ranges delimited by commas, as in:
// Range: bytes=0-500,600-1000 * Get bytes 0-500 (the first 501 bytes), inclusive plus bytes 600-1000 (401 bytes) inclusive
// Remove "Ranges" and break up the ranges
string[] ranges = rangeHeader.Replace("bytes=", string.Empty).Split(",".ToCharArray());
rangesResult = new RangeHeaderValue();
for (int i = 0; i < ranges.Length; i++)
{
const int START = 0, END = 1;
long endByte, startByte;
long parsedValue;
string[] currentRange = ranges[i].Split("-".ToCharArray());
if (long.TryParse(currentRange[END], out parsedValue))
endByte = parsedValue;
else
endByte = contentSize - 1;
if (long.TryParse(currentRange[START], out parsedValue))
startByte = parsedValue;
else
{
// No beginning specified, get last n bytes of file
// We already parsed end, so subtract from total and
// make end the actual size of the file
startByte = contentSize - endByte;
endByte = contentSize - 1;
}
rangesResult.Ranges.Add(new RangeItemHeaderValue(startByte, endByte));
}
}
return rangesResult;
}
FYI, built-in support for range requests will be present in .NET Core 2.1
https://github.com/aspnet/Mvc/pull/6895

Posting file on Background Agent / HttpWebRequest stream buffer keeps growing?

I need to POST a 5MB file from within a ResourceIntensiveTask, where the OS sets a max memory usage of 5MB.
So trying to stream the file directly from storage, but the Stream associated to the HttpWebRequest keeps growing in size. This is the code:
public void writeStream(Stream writer, string filesource, string filename)
{
var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication();
var f = store.OpenFile(filesource, FileMode.Open, FileAccess.Read);
store.Dispose();
byte[] buffer = Encoding.UTF8.GetBytes(String.Format(#"Content-Disposition: form-data; name=""file""; filename=""{0}""\n", filename));
writer.Write(buffer, 0, buffer.Length);
buffer = Encoding.UTF8.GetBytes("Content-Type: application/octet-stream\n");
writer.Write(buffer, 0, buffer.Length);
long initialMemory = Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage;
buffer = new byte[2048];
int DataRead = 0;
do
{
DataRead = f.Read(buffer, 0, 2048);
if (DataRead > 0)
{
writer.Write(buffer, 0, DataRead);
Array.Clear(buffer, 0, 2048);
}
} while (DataRead > 0);
double increasedMemory = ((double)Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage - initialMemory) / 1000000;
buffer = Encoding.UTF8.GetBytes("\n--" + boundary + "\n--");
writer.Write(buffer, 0, buffer.Length);
writer.Flush();
}
increasedMemory debug variable is used to get the differential memory before and after the file is read and streamed to the HttpWebRequest, and it gives almost the exact size of the file (5MB) which means the process memory is increasing 5MB.
I am also setting AllowReadStreamBuffering=false to the HttpWebRequest.
How to keep memory low? How to upload large files when memory usage limit is 5MB?
The problem is that without being able to turn off write buffering, the connection to the server is not even made until BeginGetResponse() is called after closing the request stream (verified with WireShark).
The only way I can think of to get around this would be to use sockets directly (although that will be way more complicated if using an SSL connection).
This code works for me and doesn't increase memory usage while sending data to the server. I haven't tested it in a background task but don't see any reason it wouldn't work.
Socket _socket;
const int BUFFERSIZE = 4096;
byte[] writebuffer = new byte[BUFFERSIZE];
string hostName = "www.testdomain.com";
string hostPath = "/test/testupload.aspx";
IsolatedStorageFileStream isoFile;
public void SocketPOST(string hostName, string filesource)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists(filesource))
{
isoFile = store.OpenFile(filesource, FileMode.Open, FileAccess.Read);
}
}
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.SetNetworkRequirement(NetworkSelectionCharacteristics.NonCellular);
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = new DnsEndPoint(hostName, 80);
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(Socket_Completed);
_socket.ConnectAsync(socketEventArg);
}
private void Socket_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Connect: // Connected so started sending data, headers first
if (e.ConnectSocket.Connected)
{
StringBuilder sbHeaders = new StringBuilder("POST " + hostPath + " HTTP/1.1\r\n");
sbHeaders.Append("HOST: " + hostName + "\r\n");
sbHeaders.Append("USER-AGENT: MyWP7App/1.0\r\n");
sbHeaders.Append("Content-Type: text/plain; charset=\"utf-8\"\r\n");
sbHeaders.Append("Content-Length: " + isoFile.Length.ToString() + "\r\n\r\n");
byte[] headerBuffer = Encoding.UTF8.GetBytes(sbHeaders.ToString());
e.SetBuffer(headerBuffer, 0, headerBuffer.Length);
if (!e.ConnectSocket.SendAsync(e)) Socket_Completed(e.ConnectSocket, e);
}
break;
case SocketAsyncOperation.Send:
case SocketAsyncOperation.SendTo: // Previous buffer sent so send next one if stream not finished
Array.Clear(writebuffer, 0, BUFFERSIZE);
int DataRead = 0;
DataRead = isoFile.Read(writebuffer, 0, BUFFERSIZE);
if (DataRead > 0)
{
e.SetBuffer(writebuffer, 0, DataRead);
if (!_socket.SendAsync(e)) Socket_Completed(e.ConnectSocket, e);
}
else
{
isoFile.Dispose();
if (!_socket.ReceiveAsync(e)) Socket_Completed(e.ConnectSocket, e);
}
break;
case SocketAsyncOperation.Receive:
case SocketAsyncOperation.ReceiveFrom:
if (e.BytesTransferred > 0)
{
string response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred).Trim('\0');
// Check response if necessary
e.ConnectSocket.Shutdown(SocketShutdown.Both);
e.ConnectSocket.Dispose();
}
break;
default:
break;
}
}
}
Note: I've left a lot of the error handling out to keep the example short.
SSL Note: Because SSL works at the TCP level and WP7 doesn't currently support SSL sockets (SslStream) you would need to handle the certificate handshake, cipher exchange, etc yourself to set up the SSL connection on the socket and then encrypt everything being sent (and decrypt everything received) with the agreed algorithms. There has been some success using the Bouncy Castle API so that could be possible (see this blog post).
One thing I noticed: you forgot to dispose f!
I personally would use the code like this:
public void writeStream(Stream writer, string filesource, string filename)
{
using (var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
{
long initialMemory = Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage;
using (var f = store.OpenFile(filesource, FileMode.Open, FileAccess.Read))
{
byte[] buffer = Encoding.UTF8.GetBytes(string.Format(#"Content-Disposition: form-data; name=""file""; filename=""{0}""\n", filename));
writer.Write(buffer, 0, buffer.Length);
buffer = Encoding.UTF8.GetBytes("Content-Type: application/octet-stream\n");
writer.Write(buffer, 0, buffer.Length);
buffer = new byte[2048];
int DataRead = 0;
do
{
DataRead = f.Read(buffer, 0, 2048);
if (DataRead > 0)
{
writer.Write(buffer, 0, DataRead);
}
} while (DataRead > 0);
buffer = Encoding.UTF8.GetBytes("\n--" + boundary + "\n--");
writer.Write(buffer, 0, buffer.Length);
writer.Flush();
}
double increasedMemory = ((double)Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage - initialMemory) / 1000000;
}
}
The boundary var seems to be missing, so a coding error still remains here!

Resources