diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2a9f821f4..de6116088 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -563,7 +563,7 @@ jpg(srcfile, destfile, power2=7, password, data="", required, ind=0)\n\ } else if ( strcmp(method,"opreturndecrypt") == 0 ) { - return(LP_opreturn_decrypt(ctx,coin,jbits256(argjson,"txid"),jstr(argjson,"passphrase"))); + return(LP_opreturndecrypt(ctx,coin,jbits256(argjson,"txid"),jstr(argjson,"passphrase"))); } else if ( strcmp(method,"unlockedspend") == 0 ) { diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index d7989991c..5a1f1935e 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -508,6 +508,7 @@ char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,char *base,char *re int32_t LP_merkleproof(struct iguana_info *coin,char *coinaddr,struct electrum_info *ep,bits256 txid,int32_t height); cJSON *electrum_address_gethistory(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *addr,bits256 reftxid); cJSON *LP_myzdebits(); +int32_t LP_opreturn_decrypt(uint16_t *ind16p,uint8_t *decoded,uint8_t *encoded,int32_t encodedlen,char *passphrase); int32_t LP_opreturn_encrypt(uint8_t *dest,int32_t maxsize,uint8_t *data,int32_t datalen,char *passphrase,uint16_t ind16); void LP_pendswap_add(uint32_t expiration,uint32_t requestid,uint32_t quoteid); int32_t _LP_utxos_remove(bits256 txid,int32_t vout); diff --git a/iguana/exchanges/LP_privkey.c b/iguana/exchanges/LP_privkey.c index 64b2c7351..15b629a0d 100644 --- a/iguana/exchanges/LP_privkey.c +++ b/iguana/exchanges/LP_privkey.c @@ -565,6 +565,19 @@ uint8_t *JPG_decrypt(uint16_t *indp,int32_t *recvlenp,uint8_t space[JPG_ENCRYPTE return(extracted); } +int32_t LP_opreturn_decrypt(uint16_t *ind16p,uint8_t *decoded,uint8_t *encoded,int32_t encodedlen,char *passphrase) +{ + bits256 privkey; int32_t msglen; uint8_t *extracted,space[JPG_ENCRYPTED_MAXSIZE + crypto_box_ZEROBYTES]; + vcalc_sha256(0,privkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); + msglen = ((int32_t)encoded[1] << 8) | encoded[0]; + *ind16p = ((int32_t)encoded[3] << 8) | encoded[2]; + if ( msglen < encodedlen && (extracted= JPG_decrypt(ind16p,&msglen,space,encoded,privkey)) != 0 ) + { + memcpy(decoded,extracted,msglen); + return(msglen); + } else return(-1); +} + int32_t LP_opreturn_encrypt(uint8_t *dest,int32_t maxsize,uint8_t *data,int32_t datalen,char *passphrase,uint16_t ind16) { bits256 privkey; int32_t len; uint8_t encoded[JPG_ENCRYPTED_MAXSIZE]; diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 4e990b8cf..0689e1cc6 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1434,9 +1434,9 @@ char *LP_createrawtransaction(cJSON **txobjp,int32_t *numvinsp,struct iguana_inf return(rawtxbytes); } -char *LP_opreturn_decrypt(void *ctx,char *symbol,bits256 utxotxid,char *passphrase) +char *LP_opreturndecrypt(void *ctx,char *symbol,bits256 utxotxid,char *passphrase) { - cJSON *txjson,*vouts,*opret,*sobj,*retjson; uint16_t utxovout; char *opretstr; uint8_t redeemscript[128]; int32_t numvouts,opretlen; struct iguana_info *coin; + cJSON *txjson,*vouts,*opret,*sobj,*retjson; uint16_t utxovout; char *opretstr; uint8_t *opretdata,*databuf,*decoded; uint16_t ind16; uint32_t crc32; int32_t len,numvouts,opretlen,datalen; struct iguana_info *coin; if ( (coin= LP_coinfind(symbol)) == 0 ) return(clonestr("{\"error\":\"cant find coin\"}")); retjson = cJSON_CreateObject(); @@ -1446,7 +1446,7 @@ char *LP_opreturn_decrypt(void *ctx,char *symbol,bits256 utxotxid,char *passphra if ( (vouts= jarray(&numvouts,txjson,"vout")) != 0 && numvouts >= 1 ) { opret = jitem(vouts,numvouts - 1); - jaddstr(retjson,"result","success"); + jaddstr(retjson,"coin",symbol); jaddbits256(retjson,"opreturntxid",utxotxid); if ( (sobj= jobj(opret,"scriptPubKey")) != 0 ) { @@ -1454,9 +1454,54 @@ char *LP_opreturn_decrypt(void *ctx,char *symbol,bits256 utxotxid,char *passphra { jaddstr(retjson,"opreturn",opretstr); opretlen = (int32_t)strlen(opretstr) >> 1; + opretdata = malloc(opretlen); + decode_hex(opretdata,opretlen,opretstr); + databuf = &opretdata[2]; + datalen = 0; + if ( opretdata[0] != 0x6a ) + jaddstr(retjson,"error","not opreturn data"); + else if ( (datalen= opretdata[1]) < 76 ) + { + if ( &databuf[datalen] != &opretdata[opretlen] ) + databuf = 0, jaddstr(retjson,"error","mismatched short opretlen"); + } + else if ( opretdata[1] == 0x4c ) + { + datalen = opretdata[2]; + databuf++; + if ( &databuf[datalen] != &opretdata[opretlen] ) + databuf = 0, jaddstr(retjson,"error","mismatched opretlen"); + } + else if ( opretdata[1] == 0x4d ) + { + datalen = opretdata[3]; + datalen <<= 8; + datalen |= opretdata[2]; + databuf += 2; + if ( &databuf[datalen] != &opretdata[opretlen] ) + databuf = 0, jaddstr(retjson,"error","mismatched big opretlen"); + } + else databuf = 0, jaddstr(retjson,"error","unexpected opreturn data type"); + if ( databuf != 0 ) + { + decoded = calloc(1,opretlen+1); + if ( (len= LP_opreturn_decrypt(&ind16,decoded,databuf,datalen,passphrase)) < 0 ) + jaddstr(retjson,"error","decrypt error"); + else + { + crc32 = calc_crc32(0,decoded,len); + if ( (crc32 & 0xffff) == ind16 ) + { + jaddstr(retjson,"result","success"); + } else jaddstr(retjson,"error","decrypt crc16 error"); + } + free(decoded); + } + free(opretdata); } } } + free_json(txjson); } return(jprint(retjson,1)); }