Cryptopals Set 2 Challenge 13

code repo


Step 1: Don’t Use ECB

Really. Just don’t. This challenge has us make a few functions to simulate a user object in a database, stored with an e-mail, user ID, and a role. We write a parser keyValueParse() to convert a string like into an object like {'email': '', 'uid':10, 'role':'user'} and a function keyValueObjToString to convert the string back to an object. Simple mapping and dictionary stuff.

const isAmpEql = (t) => t.match(/\=\&/) ? true : false;
const keyValueObjToString = (obj) => Object.keys(obj).map(k=>`${k}=${obj[k]}`).join("&");

function keyValueParse(top) {
  let amps=top.split("&");
  if (!amps.length||equals.some(e=>isAmpEql(e.join(""))||e.length!==2)) { throw new Error('Invalid. Keys and values cannot contain metacharacters.'); }
  let dict={};
  return dict;

Then we write a function to encrypt the profile, and one final function that generates a new profile given an e-mail. Using the output of this function profileFor, we are challenged to create a ciphertext in which the role=admin.

const profileFor = (e) => keyValueObjToString(keyValueParse(`email=${e}&uid=10&role=user`));
const decryptAndParse = (eProf) => chopPKCS7(aesDecryptECB(eProf,randomKey,16).map(hexToText)).join("");
function encryptProf(pText) {
  return aesEncryptECB(pText,randomKey,16);

Step 2: Why You Shouldn’t Use ECB

As we’ve seen before, identical plaintexts yield identical ciphertext outputs. All we’ve got to do in order to make our role=admin ciphertext is craft an input to profileFor that will strategically break the parts we’d like to recombine into separate 16 byte blocks. We want a block that has email=, a block that has, a block that has &uid=10&role=, and a block that has admin. There’s a lot of ways you can do this by padding with spacing, but here’s how I did it:

profileFor("     admin           AAAAAAAAAAAAA      ");

gives me the following (broken out into 16-byte blocks):

  • A. email=
  • B.
  • C. admin
  • E. &uid=10&role=

So all that we have to do is to combine A+B+E+C into a ciphertext and decrypt it.

let newCipher=E.slice(0,32).concat(E.slice(64,80),E.slice(32,48)); //A+B, E, C


original padded profile:
email= admin AAAAAAAAAAAAA &uid=10&role=user
manipulated ciphertext:
decrypted manipulation:
email= &uid=10&role=admin

And we’re done. Don’t use ECB.