def tweetnacl_crypto_sign(max_messagelength=256, with_hash_stub=True): """ max_messagelength: maximum length of the message, in bytes. i.e., the symbolic execution will not consider messages longer than max_messagelength with_hash_stub: if True, then use a stub for the SHA512 hash function rather than trying to analyze it directly """ proj = tweetnaclProject() if with_hash_stub: addHashblocksStub(proj) state = funcEntryState( proj, "crypto_sign_ed25519_tweet", [ ( "sm", pointerToUnconstrainedPublic() ), # signed message: Output parameter, buffer of at least size [length m] + 64 ( "smlen", pointerTo(publicValue(), 8) ), # signed message length: Output parameter where the actual length of sm is written ("m", pointerToUnconstrainedPublic()), # message: unconstrained length ("mlen", publicValue()), # message length: length of m. Not a pointer. ("sk", pointerTo(secretArray(64), 64)), # secret key: size 64 bytes ]) state.add_constraints(getArgBVS(state, 'mlen') <= max_messagelength) addDevURandom(state) return (proj, state)
def tweetnacl_crypto_sign_open(max_messagelength=256, with_hash_stub=True): """ note that this function *does not handle any secret inputs* so it probably isn't necessary to analyze. Still included for completeness. max_messagelength: maximum length of the message, in bytes. i.e., the symbolic execution will not consider messages longer than max_messagelength with_hash_stub: if True, then use a stub for the SHA512 hash function rather than trying to analyze it directly """ proj = tweetnaclProject() if with_hash_stub: addHashblocksStub(proj) state = funcEntryState( proj, "crypto_sign_ed25519_tweet_open", [ ("m", pointerToUnconstrainedPublic() ), # Output parameter: message, buffer of at least size 'smlen' ("mlen", pointerTo(publicValue(), 8) ), # Output parameter where the actual length of m is written ("sm", pointerToUnconstrainedPublic()), # Signed message: length 'smlen' ("smlen", publicValue() ), # signed message length: length of 'sm'. Not a pointer. ("pk", pointerTo(publicArray(32), 32) ) # public key: size crypto_sign_PUBLICKEYBYTES ]) state.add_constraints(getArgBVS(state, 'smlen') <= max_messagelength) addDevURandom(state) return (proj, state)
def tweetnacl_crypto_box_open(max_messagelength=256): """ max_messagelength: maximum length of the message, in bytes. i.e., the symbolic execution will not consider messages longer than max_messagelength """ proj = tweetnaclProject() state = funcEntryState( proj, "crypto_box_curve25519xsalsa20poly1305_tweet_open", [ ("m", pointerToUnconstrainedPublic() ), # Output parameter, will hold plaintext, length 'clen' ("c", pointerToUnconstrainedPublic()), # ciphertext: length 'clen' ("clen", publicValue()), # length of ciphertext. Not a pointer ("n", pointerTo(secretArray(24), 24)), # nonce, size crypto_box_NONCEBYTES ("pk", pointerTo( publicArray(32), 32)), # public key, size crypto_box_PUBLICKEYBYTES ("sk", pointerTo(secretArray(32), 32) ) # secret key, size crypto_box_SECRETKEYBYTES ]) state.add_constraints(getArgBVS(state, 'clen') <= max_messagelength) addDevURandom(state) return (proj, state)
def donna_lfence(): proj = donnaProject() state = funcEntryState(proj, "crypto_scalarmult_lfence", [("mypublic", pointerTo(publicArray(32), 32)), ("secret", pointerTo(secretArray(32), 32)), ("basepoint", pointerTo(publicArray(32), 32))]) addDevURandom(state) return (proj, state)
def c_donna(args, generating_fname=False): parser = argparse.ArgumentParser('c_donna') args = parser.parse_args(args) if generating_fname: return '' proj = angr.Project('fact-eval/c_donna') state = funcEntryState(proj, "curve25519_donna", [ ("mypublic", pointerTo(secretArray(32), 32)), ("_secret", pointerTo(secretArray(32), 32)), ("basepoint", pointerTo(publicArray(32), 32)), ]) return proj, state, "C donna", None
def tweetnacl_crypto_sign_keypair(with_hash_stub=True): """ with_hash_stub: if True, then use a stub for the SHA512 hash function rather than trying to analyze it directly """ proj = tweetnaclProject() if with_hash_stub: addHashblocksStub(proj) state = funcEntryState(proj, "crypto_sign_ed25519_tweet_keypair", [("pk", pointerTo(publicArray(32), 32)), ("sk", pointerTo(secretArray(64), 64))]) addDevURandom(state) return (proj, state)
def tweetnacl_crypto_hash(max_messagelength=256, with_hashblocks_stub=True): """ note that this function *does not handle any secret inputs* so it probably isn't necessary to analyze. Still included for completeness, and because it is a building block of some of the other functions that might be useful to test alone. max_messagelength: maximum length of the message, in bytes. i.e., the symbolic execution will not consider messages longer than max_messagelength with_hash_stub: if True, then use a stub for the crypto_hashblocks function rather than trying to analyze it directly """ proj = tweetnaclProject() if with_hashblocks_stub: addHashblocksStub(proj) state = funcEntryState( proj, "crypto_hash_sha512_tweet", [ ("h", pointerTo( publicArray(64), 64)), # Output parameter: where to put the hash. 64 bytes. ("m", pointerToUnconstrainedPublic()), # message: length 'mlen' ("mlen", publicValue() ) # message length: length of m. Not a pointer. ]) state.add_constraints(getArgBVS(state, 'mlen') <= max_messagelength) addDevURandom(state) return (proj, state)
def openssl_EVP_PKEY2PKCS8(): proj = opensslProject() state = funcEntryState( proj, "EVP_PKEY2PKCS8", [("pkey", pointerTo(abstractEVP_PKEY(), 128, cannotPointSecret=True))]) addDevURandom(state) addEVPStubs(proj) return (proj, state)
def tweetnacl_crypto_onetimeauth_verify(max_messagelength=256): """ max_messagelength: maximum length of the message, in bytes. i.e., the symbolic execution will not consider messages longer than max_messagelength """ proj = tweetnaclProject() state = funcEntryState( proj, "crypto_onetimeauth_poly1305_tweet_verify", [ ("a", pointerTo( publicArray(16), 16)), # authenticator, size crypto_onetimeauth_BYTES ("m", pointerToUnconstrainedPublic()), # message: unconstrained length ("mlen", publicValue()), # length of message. Not a pointer ("k", pointerTo(secretArray(32), 32)) # secret key: size 32 bytes ]) state.add_constraints(getArgBVS(state, 'mlen') <= max_messagelength) addDevURandom(state) return (proj, state)
def tweetnacl_crypto_stream_salsa20(max_outputbytes=128): """ crypto_stream_salsa20 produces a continuous stream of output. max_outputbytes: maximum value of the 'clen' parameter which determines the output size i.e., the symbolic execution will not consider values of 'clen' larger than max_outputbytes """ proj = tweetnaclProject() state = funcEntryState( proj, "crypto_stream_salsa20_tweet", [ ("c", pointerToUnconstrainedPublic() ), # Output parameter, buffer of size clen ("clen", publicValue()), # length of the 'c' output buffer ("n", pointerTo(secretArray(8), 8) ), # nonce, buffer of size crypto_stream_salsa20_tweet_NONCEBYTES ("k", pointerTo(secretArray(32), 32)) # secret key: size 32 bytes ]) state.add_constraints(getArgBVS(state, 'clen') <= max_outputbytes) addDevURandom(state) return (proj, state)
def c_ssl3(args, generating_fname=False): parser = argparse.ArgumentParser('c_ssl3') args = parser.parse_args(args) if generating_fname: return '' proj = angr.Project('fact-eval/c_s3_cbc.O3') thing = publicValue(value=4) ctx_struct = [ pointerTo(thing), publicArray(256), ] ctx = struct(ctx_struct) state = funcEntryState( proj, "ssl3_cbc_digest_record", [ ("ctx", pointerTo(ctx)), ("md_out", pointerTo(secretArray(64), 64)), ("md_out_size", publicValue(64)), ("header", pointerTo(secretArray(16), 16)), ("data", pointerTo(secretArray(256), 256)), # XXX should be unconstrained ("data_plus_mac_size", secretValue()), ("data_plus_mac_plus_padding_size", publicValue(256)), ("mac_secret", pointerTo(secretArray(32), 32)), ("mac_secret_length", publicValue(32)), ("is_sslv3", publicValue(0, bits=8)), ]) # XXX add constraints return proj, state, "C ssl3", None, '0011001000100010101000'
def fact_ssl3(args, generating_fname=False): parser = argparse.ArgumentParser('fact_ssl3') args = parser.parse_args(args) if generating_fname: return '' proj = angr.Project('fact-eval/fact_s3_cbc.O3') state = funcEntryState( proj, "__ssl3_cbc_digest_record", [ ("md_state", pointerTo(secretArray(216), 216)), ("mac_out", pointerTo(secretArray(64), 64)), ("basepoint", pointerTo(publicArray(32), 32)), ("header", pointerTo(secretArray(16), 16)), ("__header_len", publicValue(16)), ("data", pointerTo(secretArray(256), 256)), # XXX should be unconstrained ("__data_len", publicValue(256)), ("data_plus_mac_size", secretValue()), ]) # XXX add constraints return proj, state, "FaCT ssl3", None
def tweetnacl_crypto_secretbox(max_messagelength=256): """ max_messagelength: maximum length of the message, in bytes. i.e., the symbolic execution will not consider messages longer than max_messagelength """ proj = tweetnaclProject() state = funcEntryState( proj, "crypto_secretbox_xsalsa20poly1305_tweet", [ ("c", pointerToUnconstrainedPublic() ), # Output parameter, will hold ciphertext, length 'mlen' ("m", pointerToUnconstrainedPublic()), # message: length 'mlen' ("mlen", publicValue()), # length of message. Not a pointer ("n", pointerTo( secretArray(24), 24)), # nonce, buffer of size crypto_secretbox_NONCEBYTES ("k", pointerTo(secretArray(32), 32)) # secret key: size 32 bytes ]) state.add_constraints(getArgBVS(state, 'mlen') <= max_messagelength) addDevURandom(state) return (proj, state)
def openssl_ASN1_item_sign(): proj = opensslProject() state = funcEntryState( proj, "ASN1_item_sign", [("it", pointerToUnconstrainedPublic()), ("algor1", pointerToUnconstrainedPublic()), ("algor2", pointerToUnconstrainedPublic()), ("signature", pointerToUnconstrainedPublic()), ("asn", pointerToUnconstrainedPublic()), ("pkey", pointerTo(abstractEVP_PKEY(), 128, cannotPointSecret=True)), ("type", pointerToUnconstrainedPublic())]) addDevURandom(state) addEVPStubs(proj) return (proj, state)
def abstractEVP_PKEY(engineNull=True): """ Abstract representation of an EVP_PKEY aka struct evp_pkey_st engineNull: if True, then the 'engine' field will be forced to NULL rather than unconstrained """ return struct([ publicValue(bits=32), # type publicValue(bits=32), # save_type publicValue( bits=64), # references (experimentally seems to be 64 bits?) pointerToUnconstrainedPublic(maxPointeeSize=36 * 8, cannotPointSecret=True), # ameth publicValue(0) if engineNull else pointerToUnconstrainedPublic( cannotPointSecret=True), # engine pointerToUnconstrainedPublic(cannotPointSecret=True), # pmeth_engine pointerTo( secretArray(512), 512 ), # pkey union. Conservatively estimated to definitely fit within 512 bytes publicValue(), # save_parameters pointerToUnconstrainedPublic(cannotPointSecret=True), # attributes pointerToUnconstrainedPublic(cannotPointSecret=True) # lock ])
def c_mee(args, generating_fname=False): if generating_fname: return '' binary = 'fact-eval/c_mee.O3' declassified_load = 0x516c5f proj = angr.Project(binary) proj.hook_symbol("aesni_cbc_encrypt", AesStub()) aes_key_ks = [ [secretValue(bits=32) for _ in range(60)], # 0..ef publicValue(bits=32), # f0..f3 ] sha_ctx_head = [ [secretValue(bits=32) for _ in range(5)], # f4..107 publicValue(bits=32), # 108..10b publicValue(bits=32), # 10c..10f secretArray(64), # 110..14f publicValue(bits=32), # 150..153 ] sha_ctx_tail = [ [secretValue(bits=32) for _ in range(5)], # 154..167 publicValue(bits=32), # 168..16b publicValue(bits=32), # 16c..16f secretArray(64), # 170..1af publicValue(bits=32), # 1b0..1b3 ] sha_ctx_md = [ [secretValue(bits=32) for _ in range(5)], # 1b4 publicValue(bits=32), publicValue(bits=32), secretArray(64), publicValue(bits=32), ] evp_aes_hmac_sha1 = [ aes_key_ks, sha_ctx_head, sha_ctx_tail, sha_ctx_md, publicValue(bits=32), # [pad] 214..217 publicValue(13, bits=64), # 218..21f [publicValue(bits=8) for _ in range(16)], #[publicValue(bits=8) for _ in range(9)] + [publicValue(0x0302, bits=16), publicValue(bits=16)], secretArray(16), ] evp_cipher_ctx_st = [ pointerToUnconstrainedPublic(), # cipher pointerToUnconstrainedPublic(), # engine publicValue(0, bits=32), # encrypt publicValue(bits=32), # buf_len publicArray(16), # oiv publicArray(16), # iv publicArray(32), # buf publicValue(bits=32), # num publicValue(bits=32), # [padding] pointerToUnconstrainedPublic(), # app_data publicValue(bits=32), # key_len publicValue(bits=32), # [padding] publicValue(bits=64), # flags pointerTo(struct(evp_aes_hmac_sha1)), # cipher_data publicValue(bits=32), # final_used publicValue(bits=32), # block_mask publicArray(32), # final ] ctx = struct(evp_cipher_ctx_st) state = funcEntryState( proj, "aesni_cbc_hmac_sha1_cipher", [ ("ctx", pointerTo(ctx)), ("out", pointerTo(secretArray(1024), 1024)), # XXX should be unconstrained ("in", pointerTo(publicArray(1024), 1024)), # XXX should be unconstrained ("len", publicValue(1024, bits=64)), ]) return proj, state, "mee", [declassified_load], '00110010011001111011'
def fact_mee(args, generating_fname=False): parser = argparse.ArgumentParser('fact_mee') parser.add_argument('--unopt', action='store_true') args = parser.parse_args(args) if generating_fname: fname = '' argsd = dict(vars(args)) for arg in sorted(argsd): val = argsd[arg] sarg = '' if arg == 'unopt': if val: sarg = 'unopt' else: sarg = 'O3' elif arg == 'mod': if val: sarg = 'mod' else: sarg = arg_to_fname(arg, val) if sarg: fname += '.' + sarg return fname print(args, flush=True) binary = 'fact-eval/fact_mee' declassified_load = 0x401cf3 if not args.unopt: binary += '.O3' declassified_load = 0x401854 proj = angr.Project(binary) aes_key_ks = [ [secretValue(bits=32) for _ in range(60)], # 0..ef publicValue(bits=32), # f0..f3 ] sha_ctx_head = [ [secretValue(bits=32) for _ in range(5)], # f4..107 publicValue(bits=32), # 108..10b publicValue(bits=32), # 10c..10f secretArray(64), # 110..14f publicValue(bits=32), # 150..153 ] sha_ctx_tail = [ [secretValue(bits=32) for _ in range(5)], # 154..167 publicValue(bits=32), # 168..16b publicValue(bits=32), # 16c..16f secretArray(64), # 170..1af publicValue(bits=32), # 1b0..1b3 ] sha_ctx_md = [ [secretValue(bits=32) for _ in range(5)], # 1b4..1c7 publicValue(bits=32), # 1c8..1cb publicValue(bits=32), # 1cc..1cf secretArray(64), # 1d0..20f publicValue(bits=32), # 210..213 ] evp_aes_hmac_sha1 = [ aes_key_ks, sha_ctx_head, sha_ctx_tail, sha_ctx_md, publicValue(bits=64), # 218 secretArray(16), ] evp_aes_hmac_sha1 = struct(evp_aes_hmac_sha1) state = funcEntryState( proj, "_aesni_cbc_hmac_sha1_cipher", [ ("iv", pointerTo(publicArray(16), 16)), ("key", pointerTo(evp_aes_hmac_sha1)), ("out", pointerTo(secretArray(1024), 1024)), # XXX should be unconstrained ("out_len", publicValue(1024, bits=64)), ("in", pointerTo(publicArray(1024), 1024)), # XXX should be unconstrained ("in_len", publicValue(1024, bits=64)), ("tls_ver", publicValue(0x0302, bits=16)), ]) return proj, state, "mee", [declassified_load]
def c_secretbox(args, generating_fname=False): parser = argparse.ArgumentParser('c_secretbox') parser.add_argument('--asm', action='store_true') parser.add_argument('--open', action='store_true') args = parser.parse_args(args) if generating_fname: fname = '' argsd = dict(vars(args)) if argsd['open']: fname += '_open' del argsd['open'] argsd['opt'] = 'O2' for arg in sorted(argsd): val = argsd[arg] sarg = '' if arg == 'asm': if val: sarg = 'asm' else: sarg = 'cref' else: sarg = arg_to_fname(arg, val) if sarg: fname += '.' + sarg return fname print(args, flush=True) binary = 'fact-eval/c_secretbox' if args.asm: binary += '.asm' else: binary += '.cref' binary += '.O2' proj = angr.Project(binary) fname = 'crypto_secretbox' path = '' declassified_verify_branch = [] if args.open: fname += '_open' params = [ ("m", pointerTo(secretArray(1024), 1024)), # XXX should be unconstrained ("c", pointerTo(publicArray(1024), 1024)), # XXX should be unconstrained ("clen", publicValue(1024, bits=64)), ] declassified_verify_branch = 0x401d80 path = '1011001000100010101000' else: params = [ ("c", pointerTo(secretArray(1024), 1024)), # XXX should be unconstrained ("m", pointerTo(secretArray(1024), 1024)), # XXX should be unconstrained ("mlen", publicValue(1024, bits=64)), ] if args.asm: path = '0100000000011001011001000100010101000' else: path = '01000000000110110010011001111011' params += [ ("n", pointerTo(publicArray(24), 24)), ("k", pointerTo(secretArray(32), 32)), ] state = funcEntryState(proj, fname, params) return proj, state, fname, [declassified_verify_branch], path
def fact_secretbox(args, generating_fname=False): parser = argparse.ArgumentParser('fact_secretbox') parser.add_argument('--asm', action='store_true') parser.add_argument('--unopt', action='store_true') parser.add_argument('--open', action='store_true') args = parser.parse_args(args) if generating_fname: fname = '' argsd = dict(vars(args)) if argsd['open']: fname += '_open' del argsd['open'] for arg in sorted(argsd): val = argsd[arg] sarg = '' if arg == 'unopt': if val: sarg = 'unopt' else: sarg = 'O2' elif arg == 'asm': if val: sarg = 'asm' else: sarg = 'cref' else: sarg = arg_to_fname(arg, val) if sarg: fname += '.' + sarg return fname print(args, flush=True) binary = 'fact-eval/fact_secretbox' if args.asm: binary += '.asm' else: binary += '.cref' if not args.unopt: binary += '.O2' proj = angr.Project(binary) if args.unopt: if not args.asm: declassified_verify_branch = 0x403075 else: declassified_verify_branch = 0x404095 else: if not args.asm: declassified_verify_branch = 0x4020be else: declassified_verify_branch = 0x40237e fname = '_crypto_secretbox' if args.open: fname += '_open' params = [ ("m", pointerTo(secretArray(1024), 1024)), # XXX should be unconstrained ("m_len", publicValue(1024, bits=64)), ("c", pointerTo(publicArray(1024), 1024)), # XXX should be unconstrained ("c_len", publicValue(1024, bits=64)), ] else: params = [ ("c", pointerTo(secretArray(1024), 1024)), # XXX should be unconstrained ("c_len", publicValue(1024, bits=64)), ("m", pointerTo(secretArray(1024), 1024)), # XXX should be unconstrained ("m_len", publicValue(1024, bits=64)), ] params += [ ("n", pointerTo(publicArray(24), 24)), ("k", pointerTo(secretArray(32), 32)), ] state = funcEntryState(proj, fname, params) return proj, state, fname, [declassified_verify_branch]