While writing a hunk of sample code to demonstrate the issue, I found a work around (a bit clumsy, but it works).
The concise issue:
Using CryptoJS JavaScript as encryption library.
If mobile Safari in iOS 6.1.3 downloads an AES encrypted file of more than roughly 200KB-300KB, the decryption fails 100% of the time.
(Decryption is 100% successful if using a locally stored AES encrypted files, or if the iOS device is connected to the Web Inspector for debugging.)
The work-around:
download aes file.
Attempt to decrypt.
On failure to decrypt:
repeat above until successful.
Just re-sending the original downloaded file back for decryption does not work. The file must be re-downloaded.
This has proven 100% successful on iPhone 4, iPhone 5, iPad 2, The New iPad.
Will test on iPhone 4S as soon as I upgrade to 6.1.3.
Once mobile Safari has successfully decrypted a file of this size, all following files will decrypt first time through.
My iPad 2 requires 2 downloads, the second successfully decrypting.
My iPhone 5 requires 3 downloads, the third successfully decrypting.
sample code below:
<!DOCTYPE html>
<html>
<head>
<title>CryptoJS Large File Workaround</title>
<meta name="viewport"content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta charset="UTF-8">
<meta name="apple-mobile-web-app-capable"content="yes" />
<meta name="apple-touch-fullscreen"content="yes" />
<script type="text/javascript"src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript"src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/jquery-ui.min.js"></script>
<script type="text/javascript"src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
</head>
<body style="margin:0px; padding:0px;"link="black">
<div id="data">Loading
<br>
</div>
<div></div>
<script>
function parseData(response) {
var offset;
var dec;
var data = null;
dec = CryptoJS.AES.decrypt(response, "Not a really super secret password.");
try {
data = dec.toString(CryptoJS.enc.Utf8);
$("div").append(data);
alert("Successful decryption of file. " + data.length + " bytes long.");
} catch (err) {
alert("Failure in toString(CryptoJS.enc.Utf8): " + err.message);
}
return data;
}
function loadInitDoc(baseUrl, fName, async) {
var result = null;
jQuery.ajax({
url: baseUrl + fName,
method: 'GET',
dataType: 'text',
cache: false,
async: async
}).done(function (response) {
result = parseData(response);
});
return result;
}
function tryData() {
var decData = null;
var baseUrl = "http://www.mydomain.com/";
var eName = "sampleenc.txt";
while (decData === null) {
alert("Click OK to try getting " + baseUrl + eName);
decData = loadInitDoc(baseUrl, eName, false);
}
}
tryData();
</script>
</body>
</html>