HOME/Articles/

Reverse engineering Blind's API and client side encryption

Article Outline

Blind is an app that provides an anonymous forum and community for verified employees to discuss issues, interact with people of similar professions and lifestyles, and discuss normally taboo topics like compensation, company policies, or political issues du jour. Users on Blind are grouped by topics, company and their broader industry.

Around a year ago they introduced their webapp - before this, they were just a mobile app.

{% include image.html footnote="Blinds current web homepage (teamblind.com)" file="blindhomepage" alt="blind homepage" %}

I decided to poke around and see how they decided to implement their routing and webpage.

Loading into their homepage I was happy to see infinite scrolling and inline comments - this usually means they aren't server side rendering everything, and have pure API routes setup just to fetch these things. It's trivial to find and reverse these client side requests - no HTML scraping is needed.

As a side note, this is probably one of the main redeeming factors for people that still use PHP to generate their HTML. It's significantly more work to scrape HTML than to use client side routes that (usually) return JSON.

Looking into the requests we see POST requests to https://www.teamblind.com/api/article/list.

{% include image.html footnote="POST requests to retrieve additional posts on the homepage" file="blindnetwork" alt="blind network" %}

The response, however, wasn't what I was hoping for.

{
  "payload": "A3gsuMXojEEYlVQHu2ld18xcBQjIrtI5Cm7Ly054pm7xyRXEpltmAQbbfSeNqY7Ii3xqKwZf2/JU4gcQIJcBG2yx6T6LZtXwB5Xgr8rgBciCrIxv4tPAglYvv/V32zm3it02VIaP+YhLN/4oJAsCIIdu/EScOfXYkyvtwHg73wg4b4oCgUPD8wQuFMsPoNvuETrgKVbLAuKZqKqYPBqIj0TaAqxi1I6zP9Oy5EbT73DgbWbrLq8DaUyGZdMqE1k/RsnKOemC3yuW5AKk9K1UeeWOtTfNpHBTNUa2R72kVmfRqm+QizQb/yqMIkgzCvz+bbQPQtIQ2QxcuoZvKp7mfditpXBvTHzrDd80WdTAhJ/B6Gh4LouB5UAsKjMngdDhQPLY4neOjlHL97GZm4eXeCtcOMK182cmBLMWgwtNNRDoiQV3bP8t1s9ziRW4v+InvXOyXy03KMmvphKhc+iqlEgiGSeNMSgq+n8MLAWGSLkgkxbl/SD4WYNsEEBgVDhv71kAaZwAVwFGEw7WEhy1XVklD1SklbF/a0NQY5rdp36HshtEiOCsU/fjSFuXcCCYff+zOs42tzviZx6cVHZwJI3v8HYM8UQyEs32dY7HpRGQMnN20fiuS1y4R8Ch1XrYWRmj9nc9+ew8yazoiSVBpXh09vBPH8yqd9dUyw6zteTFoNIX5inwdlBLd/x2ZAVwlYPg1ZAOiAgdjXGrBtLC2mHlY/k2nj/ntaZUh7EfHPbptlT13fv0ZwFZGKqnHLlXUdtJVa4mTDJdoW5ECl+MdQeNtMkUra5/FCIR4iKf23NLsOZwV1wrVw/gy82Euy9N0mgBAEvkEsIW7kDq9qicHVmCfcfdvsKXc7tlMyHDQ0B4UiRG2W7J1d9yuHj1/VdtaedubbE4H7AVUZKUTmQDcSDVpQEZkPmjIaCthIZAPPlRLdwapCAsaxHt0h7bDuiOBlD2uHTPmP/EqJxr1TP2/mMC9ohDTffWRD5jx0eUg1lYpE+lOsv1eJdIegYg+M9lnXq6u5iyqtI9EGH4QXAjQFZknY4F/JGBmcwZB4LCgdPv60s9KHvfapEioAOj02QsQzg6SDuZywSWhhw4MaBaQuDqryT/scACT1ng9N6WZUvu0C3nlA9HtQ/+q3/2QUuGxjeFxh1uHSXC5mLzJujjzUgn/sEPQrS/krL8+eR9KcnVt8/3tvCv3RWXoA4DDEcxckuf3AAhHPkSA5ySPePVpEvCxF2SilPHh13pUH4H/u4JpWPlL5TMa3BBFwHKvtVfmnr6nIqzWVBX3lLK7kpYHzFBCrgIqZRlpQ2dFyaV0W1D8kADqmRX7IRVFnX4Z8UP/zb1lPGFH3w8m+Z2K8r6Fpqk0ytfrU/5vhTYd9ECyupvtejTh8vrGRUx64Niv91QlmrGbmZkrcgCWnMs3nJSF+yfVXQ1DA0Wx7G43NY6VoObP86JfK0giGF4FyMk+bJBE25ggs9drN/yHvwtiWu6BjwFpWHu4E7HvL3GkaV/SfkiPWu1dyLbU3GLElJ4/VAUaJFttI8B5TmBN5X70GtKE4vlSVGe2RHFoMJ0YGYjYbYYcVI92Dh8zaOS0mzximVyO5sdY+HoH8PXBeSe9YtVzMAxJYeNpSl/HqJWylpi7grAOMUQ/Flw1fOEdL1iFYZlQpHUP7pVU44vdLl1zd4Ub6Jt8itgI3rYsmcT1wkxu2s9T3DeegHQNaL30te7k7Q/Fi5gKCrbfmT7vqHpTfBY6KKGh7OVlDCyxLQzU1zVKnHD6dBYv0FlfZojDReaZzkdSUAMXEgLf4B1aCdZ15vv1QkL9B0R8IYq1Py1vAZFcguCBCSDYwALBAuWOq9kiN3K6s5IeILIDeDEnQQeJWXsag8MOJG7T61f0G99N5rv+mFgqjzk2iY554c8ytHjO1n1/BjwqTE4gHAZOX6835cL71lYEhea5kqL6KHSytM5CPKhlapu/E7s5GEXYbQKSrmAVOlzrUUK9zm63JV2AzX6CYWXI+f3ua9eCDBIHn6MZ+6c/5sExyyn4FPdvyN6fl5/afAE5vFV0OYA9cOVdlFSuRSa8vno2TfPrQgUbIYehM7fihcClnqyRX80YjzBE2LWdMJKcUs37kxwY/6nQGvnloSpdDwplhbGmQBqLC5p2/ZkzV88j3pxD3XC6Ola47AdOqF5YCiIeLSVpC1hhxDHiYnFDgHO/ahq0A27jJbZmpe7q9O615kF4DgHGbdi1yiNonNWAdH9V69Ba6rtw+PHsDViPtf6Ao/LQI/8HvJn/N0RDA+cjwgnE86+lIfmVK02wlt6jIGQS5H5UnnaTI7fDBIMiJO/M+TgVP0s5Imm5f2iaInaVuJQMGUVZLetxH2ijVeTmKvj86Kls3uC4Mi/qLJoHTU4pEvvwMC3oZTc+3Hu149DihpDamCr1dBFkXq/FlNaYc1ot6XWdPefvFSv+O+dbHgLa59+UdTLQzjd3EU+bIHo6+WksEEicytu5FH7gZVAFwVqh0psXUcrUacRyKo/+saWR/2Ly2xoXw9mae/oJWoYTyjw9G0YRf1IYtqaw6DvxN5fnEBWW4wf8QmMezyhI4H6Jwsbg1hMhRbGRzrd34rFV4kRc9lIfIzgB00uhnhEEWiFcEcSM2NJp2fEuBTw7FZ1SltwedzHUrmhW4P8kgl8pWRLwv5zURpqSnB3f6SLf6FUh91TQIgS7RuLl9kvjca5uxi34CFK9a3RV4DB/jm7FFvU4Pb1O2cl0rqNXpU/TgC98yn0c9eRQetAsu2Nkd2n3n8gM8I23y05PMPazMECmZNG5GgLJdghCdUmGety7EcgFbnfIYqCBfehEtn9IVkWoRrYKFW9TtRmRkcUE2uu2BLxec1jKKPn6vUfWWFcH5Vs+PtWBBXnuOU2HenosB0lTitPqGI59R+T8EqS4pHsAtvcOEs3Qc3SrQKPjKfpfRKUXQ5V9/vijt9Da1ovho80qBybhMmtzBR77LYwUS7yyQEREEHYBBycTqJgbXJSnXztgRy07T2jZ53rFv1sYujDKTAoy+ys+rAp+3gOzxJpQAp8Zlv94I2ev2V8AA56HsonLvXOyirT1JuKLrx1n5LWRA5/8DE9TP4OaMzeBxWb1QNobbV9eOo4OhYqIDSp31fwEOvokuNuz/r9Dp5fZs8GDXoFaLSe/M+Htgz53WojPfxebEThS+1e/9oKioHV8FnlkyhEDh1I124gLDqR1CphEv3ZRKCGkH5HuizdjMSk+ez/uhtixIZ3ZZGOiYRCltwNKn0rcuKjZjNdmfzxww3++PPvO6GgKLZ2VLY000o9BFSynyiwQyG83RqQUVE5fhAuB7HOP+d8L6a6ZOdQYGYpNLg5zp1CF/Kp2WHdnSwiFevle70ZOM2XS1rVtjiQRet8fZHCx+YHAujNijx2g6GiWHVI/pp2zvf6vQ+nDE31i6qLBm7W9MU/P5vqlgJEkUT+oFmHhvsCGH+aBhwaGBFRFbGjSV4pat09yn+XLfxJ0dXPLnHY0CSiUIOxa/nmrOe0ocDQaVH1XecJ19L1lUR4wM0erNh3P8xv7umRKAdxx+P9OUGQmufsKoOut4wCyKu+Zao9nwgOI/lOI7b4UGH91xx+X7XLIWk/ENLi3AkcqMF1i2IwNvmvpx1vR9vBl4AtIpKRDEv/VzjTF3LpoW7te/LW1WG3R0m5Wtz5T4H9ymar1tE3DbcZDsD7oBDB3ChjpeO+SR0PzlYBAM2AHLqsm7De/JWX8b1npEQ7/KS8tSEAezOdqhXV6szGxK04L21MarpZx42hxgduRwXNvjrFCV3jMMpnfVJqquwnCs7wqNYjRJtt5zt+hzvRn4diFvijhIf4t7QXGkJtKl/d04EdW08ZxiddXXHKjq+5WDIrMxbOb/aiCA3xCavqLjzZ91JVjUvEbPyU0U157zv5h6GytK6+jjozuBwjgZLrWEdXbcBPg1/Sg0T/zoPm4TP7nqHLdoNW7+rFsxKBtKppLxSUAIY/PRu7PVQGs3S2vgF8HfRz/vzdI7LhThNZJRN/8/BjDZEPIwWrZNiMAq8+6nQAnFDOeiLDiVS0HHrjcjBCMYgyz/dqA1+bkZ8xMjhAFfbwHO7t/1X18lCMSgy3vHiNl+qiYCb/bHA03pp3T2yPVajUpOtHcsv3KrhaTsaMQPQUpuLTq+u/6u7eWF/JsCWj45RYBE/DoxbtDlJ01TGUZA0Ya7cjUUixfp3eXevWa1goojx8N1s68vXcdl0xz86nO7kaK3TmV2cSFjjEjA8DgB7LU8zPuIKt8l5y9nXeO9rcrMJ0ghaEsOwr56xc8v9z7rJxB/nCIH5iDQOhUf8/AaqBsH/WfPABqvlQ1NgTFHgtnV9DpjUH9M+6jr0pOvyNf7Z6Chj5cdMfCwStatlKhZN6QKlCnVLw93vBVuuSBTKDygo91JOiyWBW9xONJPiM2r6cLipqfyYa4oHrG1ciHX1CVJgCO4Aiw7qLfDJQWv/4jvIllXk5+Mupal4Zv5VQO8JSzGXA2f2RmdyalViMWFYyWb23lmIsMvYktgLX3GrG2QjyEP4AtO4lYRHyVzeqdd9YYP31Qf8UxnXMbTF0CbV5d9j6bsHeMIDc58tCSq0JXHQdNsLKddgoiYTxy/t3qbDwFz61jB29EWk0Uk7hgV1yTYilWDtNqo3Y/SjjRLN4cr14OzeC4hdlJdJ6inIp5sOEJwWzNH6JiXlWDoq/siwdhpBJrIzmcl0utimDgVR0JUs07k6HoeUsnryj4vcPhmsDJ61suxbwnDHWMgLrmZ+LsIVDweh/OL7H5fGI3QXe3aBFaMITy7xzjWTeATFeww5wv3YatI3blCLGtFOhjnClPeNJGslRagMm8MhMv/W52uqfcIc2pedgra/fdbMpQ94EnkKrsRJroLdH4zJLPdLhUnw5s5k8rTNPV7dpdEA9d7Y3xQyfc8f8aQwjKBzv0uku/QCyR0C+zqu33gCdrLNXOnS7YsN/7Wt/DEMMMuikVEowW1nf7cVrWkzhuAKt+QnEi/uWSKqJTyAvmXOBgoD07v3wulgxWPuYGz+uG3sssukOrJjz1LF1LhvgB5JP9DVs8iti9UxqMdX5Wzc/IneEXaqshl4wMax3wSnR3so6QsRLQsbRrKR6B4B7YxywBwr7vdAhCOdYQoJS/oCWxGydNiAZrPH9M1Qhv7E8owAfHBn2qVzN61i6N+WHrDfRd1nrT4wiwjyVDBwQD2fbunSreWMpZEXIqIQvPv2enPcIBzHzjNpeKGN9cP1FjHbUCKrsvNfEH+xNoc10/lfm7DkJ0GdavMs1eTiJRc7KM169auhHDXfQhQTs+pGUzk2AXuhHkC1choAw+pn3NViIv4qszf4tr9QcYltkJGScG/ncKuLz61lWVH8kEb9dRAnnwmlJ9rO7uuAOqlfwGgX/Np4lZ97l0fUudBjG2sBYVJ94Y7S96HcnMBEZ/ErM49STyahu0hfhnCP+IDTtBlcVWGfim2UYKP6qi4RduXzyxYQbSlrEPJZjK2NwCvffgYIidHd1Z/P4YIUzXo20PEvA5HnIUtwQ9es6ezQvfzN+aSPe6M/W0A2xg7yCLjBTKHIIXSLrQBQMqrEOp0z4mVVBlRfhF7LEJpfNz5iQQJdVh7R3cyL19NbHDtMMcgvMzVdmipwfcbgpl8TI1bDn99QyxqFLxiXLMVmxH76w/q65wF0E+6tYUKKxHFBRzA6f+ZGdt2qD9DyZmUkUcltB8h4emGlcjbbqoCexhuzSh4XQueYSVnovYaRpZmIoqYXef+2z4R263ym9r7Cf4P9v9wi1ej8MfC26UX5BTIyd/cT5EznVX4snPEtn61E/Y/D+n7sPfZe+DhxeU2FLPscEqBD2QKcSsXxvmNd4qUndgeGzoI1a+REt2hbWuYfFAL0X0DKtsME2uM4krOcp7PgsnaXVdcvVISsmUTjDvgzjrmAxKKeyEDtc7dJCHqUUrr7eCWEL7FjZH2/IE2O/pFMQDbMsOk97yAxHUxb8XAutnmauWY6g1rnfVhu3S0FG5sPjklRYmAICvKOyX1d9+nsvwtMRucXhpKaAcwA5iOgdVzHxk4g+uhxLEwyoDCT1ourCl3ExrwFkHs1UiBtSmRBbAXnHNDBnEgee22YPrFz7QUvTb3iUFZP4R/qUxh24ZCx7hdgNXlin45DsR/rM0bbv1sBv3XUQ6gJsbtmyewg/M4a0SLYcuYWptTo0nqELGd2K0CLF+bdZGnLAvOULkY8U26GH1vWCpd4JSPGJcNCvaMnnyLNdArA5ybs7Zn6gH7L3AZQRUSyx/Zwfpb/bK/db9KhT9NV6fMKrrdZLXUPhTHKk451+6sMpz1WWI9s+Oeq73TlJ0YeVDS5X2JaweXzJ13XHDSq0qQnjFbfHmObo7lz6Csy5P+ypjCq9+fKJzbU7PuH32eYTRlH3dE2L1gnX5lvOvWcC5PtW9AEgwDOuVprky6sZdQmvxYsCuTjEX5yPMrW/7lXk6/i91t6/q67i8AbBumKwW8rtfRHfg7por1b3X/LASxAfJBtEjl5zod5jHGFrc9JR54S5qYcIarsMLzy0cTBpt0KhWa6+Oj0ECkJu4jrPYYRQsMZjm07SYSe9yk86BKqDGgjwfwYCCJ+WUWrZ7VvQHDN9P5cHbfR1iQU/Oz4yqj3xsFulw+CdwmJbzWkMNxp7pLWlnd/Mi2HD3M+lgUiAUz7mk8ZzAPCI+4UaaPoUItjLdEIYtkSum6nEl9+Q+huJsaNMSM+rup5hZfgzD1TxouAIe73HczSmwlQxz5Ytx01ABlO6ZO1juGMG4h8N1kTlRqJhGUQF2GNdx0dpMltX62ubhCeO75RUwhSo11y6v0mK9CZkTO+OpsEu2Lo0Yy38WHlJ5+OSO77fhwarsuAq6W/z6gJ6dS0Cuymhy9pZy3gLKj8oiIFpUgTjRLuNxXd58XzIvv/XpGq0iMM8W1qc0ML5z7W9D6gvXRRzvl2iXUmvt05VNyYlzD9sD1SuR9w6o3VyygKL3ZX5CPMEBcfyeMZa6JaT6f0s2zoiFwfnwWEVjo4+mcQsjzYtMC1r87M02uodVyojdVIbWEAyEolUC741J0h9q6ZFEbk0PrGah9tafIATX+emfWEA4YNo+AWHyxMigCBGN86HoCnG4FRGN3d8dUhDnil0KjXwSrcVf7T8AzkaodIoHcACm3TG8sTtlzd6XH5YXTiFbwlnaxcnygANZQ8UunZcc0wouIByptthnbAh+CjvoCW9LsrR0gFlHj5ob+KYTmhnW3Q9rcmD11qOtAqjaqdPIcY/2u/DWzYrYHMeZWxGNqvUt+PczJS9GN2Q99eBfjktBH6o2x71QPUWYlaHerkGhAOe+YK5iG57lJFXLYAloKlMn1nRKBCY7254xtlWICVDYufxG3mQp4FSj7BCNtBN8hkRadXHEJpMbBE4rbojT5ptvQt7ETXY1BaS/ORdU88KesTz2L2qzfjpI3hK35HVLoFiAr29uyT6rd+qBnsuJ7AooSE3yLh/LeKF1WDrPTvZZlzoOsOrmzceLD6H9MDW53Qx07b35tLXruLVzcSy2UNbHEexvOq+w7jdCQvtrKwE9lSy7VabvQW9ztMikKwhCuDy4QK7lXLiJJ/6jw5yFMLcqDyz/1fi85Ehc253dinlK02+OC0ok5E/PyvWNyhpCerNj/UkUweV+jYfKdgpK7l77yQK/V9jnQbWz6Bm1LNldpUsXwnbcMjk1BgbN6YJ6qxJOeghai0B3ZGVMJLqc10wMTfVtQNsh/ol3azQtuoWVkRT+9bK4vpc16QQzjgfxFJgFj2CyPLG+bERezdB7YUYt4vKzKHCDdScDWxAMb1U3vo0zPhxW2+J8yd+6cn3p53qGpj6Fz2KPcdIiFu7o7ijL/nOzN0vrrQOB2U1M6sigyt+Cwcj/23USWV1uoXx/O0NSrlwAE+Wfdn+3kmbthpV8JKL1ujMVgb3RORZz4O7hFtm/uDmpcJh2xiOSh7CkOqqHjFjKs9SSGtCwDb4R8zRsYyesfMcgci5rhf9W6eHJashxGikLuCMmt76W1sBgI1BDOYCGDhL3N5oeezF7cBzNKpuxIv/xwIkK+K/SPxar8VzFIDEV2YcWiYr4064BWAnhfFgXQYN3b23kTjSnd8EzQnXareIwzwDHwF2yYs2OAqlCG18K7C9KrfmnB0QQCiDoFHua2guZonRKS/qyZxpzHgewfDJ9mokisEK+5YY7K3hsRImch4AJOQvvHQMHsC0O75dE+eBvs4k8wb6Wo8qZMEpnrrW8OGW70vzeSDI8G5qC6n/6HIzv2o2Cf4fDR0TyydSUphryYyuawH1ge1oAKL42xnQwljlwuORHql0IBOEgAG0VdfUDE8UObPFmaTdCJaCiS0Jf92ZkYbfrhckw5dsVoZMrnK3whph9dxctAfcBwd4SIw8lpC+cIZFcmFigetpFJffozsOjL1Y6YO9zPV7QRp2SqFVLQvgvFB0cLhvdQE2SOJ5fU3ncJZVKXbgwMO0wMTtmnpD5GgTMa1KP6GIqqxbgJeIY4Lh5zpECXOaX7MTp6T1XMPTtZuspvfAd92BYz5FHxXPIxnT1vrRi1eTROTNSWSqCvsAYvvu8VUBGX8cyT++1Mq+T/WATPbl2JEdJKlqwod/e4OWaGxFZy2ENwhaW3wnKB4+qZTcxWqIFXws+i2yQpZXZ8lM/zg+OYs/rUNhNhFE/6fFhm+iO6Ydishrl5fxKVRl+sGnccbScpZOULolFV/l0t+HnLrCsnEX9QMXnrYqHnUw/EhmHXYFkgt4Mnv/cImD2Itrk91/szAyOfDFrd2E5a4xcSN5znPr3RuEHXmL4pTpaY2ePC2wNR4/1GN1fg2Uj9/ZdN8HOe8ZEe84lH6ONwNEObJRTNqlbDiRxPb9sKg40BbSes9FVe247cxqopPkb9W9DuRYSXyspF6/vX7knrlJgViW0aUsLtQiy7zm3SQEAbwE0fzxxBhJ28BVgmbhHq1l1T26h2E+M2W09DcxeaugHbzQAkBuGjK31RHX0gPAQvbSaZQJP5t8kXX3f+S6p/b0oZpBmSP4QA1nIRzG6g8WCmmA5dkLZoaRHU6DV+vt97XM4lb6P4X4WIHl/egVX/TNEpH9ppue+IKbG8IcCp2xSE2I5a2I/6Jk1QIyZ03KCYsBaGSmaRChRmwf4S1xtgundK3j1+jJHlt1dF40PpGQsy+nrj5tvhY493Tc/eUiwHjU6pdHsFQXCHbLvKcWvFWzk3uGa6cCKz1IwyRA368O0R1kUSymXt4aELxRLgBda23hxksZKnxq01YIVrfnudocZsotJOGwhv+nN/oaCo7iYxQpaYViOWoRdJpv3ISwkotado2/Ae8SL/2u9GgqQsp3ZveNopu2b9kttPkZYMNIX6cHCyhnFWTAqVzqEJbLU4ow2yWG9ts8byS7w3PrAnmBzi4eHLuiR62J0+bA5M9Cm6axbTQkezgFwjJuY1jYsACPI4lslNiaX7kpSk2gRFVdL7gX2E1cX61Eo8sBaB7TkVFjsBBhAhI5aGM/tDTbGuinkWLLJGNRFTukigw02SfpTZR+VLY1U0SW2hGBu7iuH+EeqVNxCc7uAo6fC4ps6u6MH1rlNkz7Ci0Otz4ozhw6INOAIEzQzKy+S4YC43m2CmgH71XaNEAakEyFOKw+HfW43ZEyMXgg1uJxFEbN3odPaDNUMFDvv/b13ws7yHER6U5XR+JA1RbPFsdJIf+vwnU/1PPj9TI9O0mYL1CtE5GBxcKG3JmCOzh3Dcsu/zy0Sy9DJ5B6HtJ7mWnIVj6YHfQ1GyvlnYWGOSOCUGtOeO8KADnObzRcE3jkm4cSKl1yybAWuF7TuZ6bKDl1KqaPUr708xN+KMkLr39YhGBXROwBF8HZRXvAzmL4df41uIx6uajAz9o1rU+PZLGWqLN3+JSZIzeDVBG2Z3hujgcvCsD9Ik5xU/MJgrByznNW3RSStwhlZZdlzEshgYbYvmf/nwSapcMq1QHT3SgLXz8YXxdtIUi4EzZ/eDHV+R8kcfhimnMT2a9y5acFo9WqzKqbJZcUH2zI+uqR/1OkHrHdTbnXEF/0nq4QmIVGAIbYqTsscQEMNyrTynKALNzf4dmhhKavgWfQdyzpIg81v2hmNN4XxU+lKtA7VLsVbJwCaw4BDcKMIRitsYbsE9tdXqOTXCyz21WCSncp3ae1uvSThmNCU0YQKj3Yq5HDH9S6pM4YAH1hU25U5mN41RyuapM4C70Gxl2KGOh2exoWl1TY5KIfGqbRuqHQay3poISTxYVUKZnSuL8IPe8YZjh9nqmxV1eYsKgHGJZhprOWLjlcOhMTzz8Pb8Fenec8JR+ML6USP4jZbdLySDZ7pofxoppGEI4MfqbkzaWNOFlGMIQ8JL9W0+3haPp+xnObBfweYPuQ8eTQF9aUUpcU9XZRzCa6Y33mSv9W/eLGlNqwNNNSYpjdWF2ZO9VqsE4Se+j/vRoY7kD9WZJetQbWHKg/gwf5fKJd+pBCsoW/fPsXiqMNpWcenWs1sDP6BFKSoTesilNN7+qvrCCSj+INliVABdzT5yTS7pPQYTtRLCuF4gGVBQeZkHiYBjR+oE4OWwbeKxPILkflmCkPWxkuYO7nzetsF1d2XqME6/nsOFPOsZlLZcrOlFOgql4CM/Cno6Vv8QfCqTv78GVIk+ES8i1Xdhfobw+NFJec8ukey5LodXXrJh/JOPdhUwPhlKedtTnbT1g2ZgadjXVsNdfn5bfteyYBGfXZKtR4r21uVkCEsjkOw941CcjQXzTCHVKi2qWtFqL9LOfo57K2LS6NFyxznrOFyiYBvbR1xPDhiSkDMnkuWASBwh5CdEl8nUbrRjrGr7bxjg92Yk5/9cpf0YQho1TTTSApbMd9iIBIiXj+CXRjXVj+YFLhX96uqBrNVgG3ZvWSF6CIBW4f6jAxEBae8HQ6QFsx8MkdxBOOVyALc4ZRMImTxKZYWmLNMG5QIe732OA/bcY7rZIEqwZjZEUbZdQ0l4qF3lrFVQUhGLnnV61nfODqvBK0F2HhINH9rUckRXPk3jur22mDLviJ+dHpoLDQVa/CahuD1FhZ+a6nqXVCrLvymDrK+gwb9Di08hFvx0dQWDPQjSySGl8xkFB9IuIHxakukX84JrEwZQOaHUzTT4gglYnBse/ipaFTTIh3BaxVGH7RahB6ak+UUfYV6KbWxYp0CNvl2cdgwK8leniGpuPqcXIx2+CV9KLuDK/cWx03B5N+sWCY0rLhDXuO+ZbU2cA87rP7Y1G7jyMaucid77upWBCSlFvdPibMKIq5W0Yl+cGaUnvPK+rR+HxjVRpMsCQHOysvM3Rc+bOe5j0Cqni79mcdVAHQF0wAPxAPsxCvP86WubcLlQMoaxZSGuEMIzUtOFUKmI89Pi5K1kBAHdZOHcE3WdvTJ0mjsdknXiTZ5fidtlSzPVPS6PaLR1y76Ej+ex5CnFlONtoMTBEMppu+6aROoYpzPIVFo8Zw77ME2X3RsMQ+fEDMmgrGP4U/rZesZLQQZJhciJjLa5hJjLCvmvoD5gDk8H3n67F7eajZ0EeIWdsuZ3umgEFV31MJT3fRvEEeUaPAdM6GlS9lif1ltkv1NyavbNkF5Ih03uZ2caFR59EfAGmxY9U4zrVZSa0y+fdejAfJohm2D49faQKvUarUR+5EE6XkwHOk1qQLqwq57AnjiwWEMdudKNmXSGU1Iv34Jcdh/CrIS2CTBG3+LH+kuS82eaOSKAx3bDKbEvqixSf602KM9kfuZI/R3C9d0yMSundIQQ9LDKnexPQHllbLvmV2Uzyw2ofPAdnz1cLc1JGEoZ4OOW++NBP7FRStjSHT/vE1P4JWkenETfY/L2yhyWDB5wUIrZpipz57G4evvSL8fyUkVSldC42YJ2JFqsMrj0C6uWo+2HFZOBUNEgOLDHPaTKpNCYHWNL4uspnidAlqy55p344rSQ3/k4fy2kMtzSO0DbjqtFblZ2QoDMoZ6MaTj1FFL63eFGdVmYyBBFyDXC/ohQnEzsn5B/qG1Q3l339DoJzBIJU/eXqBSmiHvFZ92KnLXkVoC+WovjHYtf/N3fNCP9TAcLWlcA+S1tmNHCyKrVD/Bi1g1bEM2OXAluSI1hFgHYo9dj+OrDiBy/rjWZioKfVNXfuUzf26F17jWoRjLQU1Yw94UJBJGUtpd9cXXsJPrn0xSQWcfG4H+t5xIADgw81/eQjivFNY3VQIpd5C16peGPutYSom/Ztgw0Te+1ckwf3PiJzdty17mrO1Q+pQ7hWSSywEQR+vYbW1SXMDG3Ic67MV4EA2dEpBvRq6HeQ2euGBxjq1hRtmVXdO+wcOYAX5e7m80nZRipTq1VgZp38Rp4AlhXoWrDYbZl5ng9DBLNOCqmcCGCF6q1XC14fH9Ler2Z+6JPBSltZ7McZx+HM3/hw5CEtejFMfWsk7bGQv45A38s0joZgYbtOqekAcKM7jj2BMTuw9hgSJrdtIVIEXpVq5t7E9nsDQeVvJ4kFJv3IvK4UsXVbUXv/SLN2IoM2uk51oSSdCibkY17BUxON78qir4A33PLXrfDXvCe4ZnTBclPDXso7g3BJYC+Rn4TYo+VhiBxKrG4gcaYvRJ9d5AVHoWVcKvnMNcT2LxdRF4+cSZ/LSHLBP39pJMfx5mDpfp1i/NFJkeY4YnN1YnBuxh8AwZdJP6zLJyyMTOnVHfzVeT8vmbWmWxNwDvDgFYpvawqxGIjgzIXizV2VDED6ranil65XWL15VfJk9yaVdrkuDHuIGlgR9t5kH2ZSNTTpST9Kn1/0nqLH5TtAWOeUnc/MU3npO0EzGlc3mMx+LL6s+uuPYgIRHWuz7SVIFhbItHEw+Fymit05oaQ7+FRJj+AEmubtuVKTwjicibKuwR3oqab1kKohyLnjsDdT+nUlMKVUZSjkavMqiKsuc9v2wnsWLYhhazR0HzojmPly1G2SW6ewmeUc26UJSSscvLIT+WkQUoGZ4AcVgWHGLoGymfMIZqsDBe7SDfdhoRlAp5e/vT3KrD1ETopo8A91p3lkL/vQ2Jx17TyGYxJwCqpEfTWmImHwWXXstCCDQ+QBeH0fu0Gxt1xNwUaaP3aXpQONWWW6BsO9jjQdL7L9LSNx4x3vpdiNpQ9yPa0i/QDdLRJCEKwuGZ78jDRj4QB9K5+w2naYQ4Ks3U9MZ8u4fx3RVVm/BuxP+U3Wmbp2d2IkrrO7Uc+yJzPkPZvvbXBjk/Paw6B5dr6OHgValRpp9OBD8p0Pkw73yqHJeTrSfZvYH47TE0Z8gUaAr7FcnK+KPMoFoXhpTK4sqKYNy4133nkI4C3a4WkEbPl/wwLDeGMZebwSoU2bojJJSbaADBvTZR14dPsZRfNU4JlOS3qNJHkEz7D/lz+yh/PvuYGYfu2I96xLI3iT6uzZtI6WSS57R4v7PbPlXgplpaKNa7OaS97TMxm/1Mbpp8X8AgzA6eYgK6zAb0sojWtFhh4L/K3dFNRp7wjNhX+WROn1fVn4fPqmTf8xFW5WpWWap4Tn2TDk/ct5bHSl9iX6vAMpwpwEFc1lwjLtsZaZUs7orVwlfkXsqIvnT72D5V3Ef7kjl7Ml1PmVljtxuFdILX3ELLPugR1LJ1n82GVVqxxCDkTLF2utM7qbYIZn8DKyL9gYvpZKDkpnjWYxG8B/Z7aUex4bAK/wYhl6eyjKdpiNNM7E+0DHNZP5aodxZppEjGjgmPM8IcTgzNj0kL/UDQ40IyvI3AbYuq3GKdoXEYFpfa8iEwjy3eHc7APtkfyUDBQHwrD5b6c1Adr8V36bInGwWD7yCc/1oALzWm7KKGIMsGx0nz5phjs+LLUeFuxMR4aG+xVccojZZdaQTzhI6a9rpWRgYY4xsKqlzZ1QPLQSa0Ox0u/U52Oz5vsDbOvVPv4x33huaJ7Btug1MFBVRhllzRtKIVaDg0XaD/WXrEpXuBifGiBJFfHorEz0FQkyqJ4RiZt+ZVSVuw6kGOt2W7+q9DqiSarnpsCPHNBzYZIEnaqtgGndK//6MWw7yyZVETk45KWEaWN5pdP9Nlx1lbmAKOAiG2Rf0cpi8QbqpP9Wbei4E4RiYdkJcm+8/aAgpmes/M3PHawYru0aj3Xw4uDeID/AKHx0tU/gJdnZAdGShgf0/gNoM0E3k0E/7lQOvW9kAIzgqYjGZajQPRhb9OKsEL6hx531IMJWgxu/k6ezL88BJPF8AHaq3LuVASKHhmPIfD/VkOu1a1frP04xoVx40ibDsvp1rVRALGZXPP/7nf8b5b0xZcQRaWsR7tdR+EMMc/CtGHIWs4ELKft7/Y1lhWEHCR8g6UBFNAv08AhlJqLWLrXID3TM1wDY0MkSzkTKTFpKSzl4KUWXUjflyj7iUFpZNYhL4mYnQOplvX5AhTrMDCsnUhVBNR6Atg5MWmconVcRdwp9mmOHd9jctFrJtbvigVEtIClRv5KXgZvDGQLaCRA6jN4qOJmrulFRDDNXV1Zgm2ZhLPHH0XlelRC6h31w6UN1Lqt9kZ5HRnOiuaWEisB8QdGVD40XlUEe+R+tNTnHFz7vj7orOZEp/Q9TEIATg7g4i/bNxa3X6+MkmjlpauuwDTNqHFZYNN6m8rCnvjvSauA+4JU58t1xWxWP5ONuuN1m7oO77wucZT5Y+ClvfouuXaF2qapvy03eHcYW2IM6sHI0C7RyTHJ0MuaNuXfA5pTKnxwz8yQELrQraJ8KO23RGRh9xoczT1Okfv9eIqK8t0d72G/3hde3Nd3LvmbwRXdqC7FkV5k6R5uWYY/GV4i5iIxo9GVD4VuGH5hphjX4/8fNGou2fo+7sbjiwXLLj8xaHamviOCBfsBPnXKO0ZLp3jK/rqckvQzIYZGTVzTjCZYx+QznQWF2brb5GyKQ32CZzaKcbi/Eh1N31Q2mMKqW7V0htaCtI1lFX0JuRt3jrwVgymHS/qiipKwTjaHus3ovfUBN1XKu1503y/+WEUNvKNLbsY3Vqk8PG5iSM2zKCnUbpGJi3wK1WDczemfCrVTi0NNKElXqvvoj33SPL3gepn3NGQAEtJvitdky9wMsNWjTJbR1+mPLnsjMh7oGkWVAoguj/ShAYMsCl0egX9mu6hUj3KC9kPlc06VeBk4dLE4vlqZymnWgwgeIlfBse9mrwqq25QyVazr4chr2w5LEhVmWA6acTC/wgKV1YpvVbtMaxQ/NFeNy31R8Xo7OdvPWEGv157WEfrsmH9TWhLViHiZiA3uXSbvNVVDGwCi3PVaFyhTt2fJtso16vY33Y/8jjPwh8kqVu5oGha8qSKPz+VDcslHDHajk4eA/AOAwZmwNnKNxHhBrJLJBGNgJjqrfXqe+fW04k7iRm5bJFQNxLVXke7xUcGBJsZd7LI7vLbtRquoHYgcfT1UVjj7dYWyI9XKABbGVd68Fba0mHvK8N2qplKNBc/V0lOHTxTSGtUUPc244rPLH1S7AKf64jhAB2XvjgPCwAiu8pNNoHiwBT4uvD3YEbtNMBvAeVbcibAM0AdnIZ6iV03w3b4K1gI0rtxXg72FHSzXNZ1uaiQ6H3yyV+Mrv2V46MOqT18gywdxq3k4gtFIP4FRHLdpPAXLkQjL/K5ws3pQ4PCL25fK9DRIM+SzI/+8mjXbyGYAHVsEhCrueHo4z273hCN/cBzn0QSal2lnCMC56jBYAmRsEXNuikEerH6vRmmudBcD82/eht4ig4GFYibpxDs5rBjGb5MYi4axEYSEyRjKinGWbAEIK7vLxf4h5xX6tKBV/8sTsuTvGOMdPJDFzhR1e84n/3rrzMUIjb7zqbshKb2te7nyh7eAumvJSgxJmjmD85p29YlHh+v9eCY+Y68VT3krK6/gD2ALoeCQoGhSUBA++tYQ8tg8TnX64pkcP9RjDRsBC3/V/S4EDD2/k4xJqtRYmEVokLcPrm7hNPPc4eI7LiEPWg1pRY/D2b5EX0v4WRXcmVJc3IsQp8nWEyLCD8vW/Wa+d7wmmC0V+Cmnjd0JDio8bVe+OWRmj+Xh+eWpTe3qWL2G+B0Rnn1PHB/J8pu4UjhNtocSyxRpWwsr3kyHIskLc7vRqp97RIo5FrNWwJDh0T2Lh7lmMTaMe5uQBwxWj/VYtI40ZbPiDjv9jS2Sb82AMBL9ugPYQBXFoSZvqo8EbRbVLKQhoQejFfw0IyPwnLBDMheMk1DmN4sY4CN+obVkX3TVqdSoy9zKTBjA65t3NOwzKXRjdQTQiVjLfK34+L1du1LANOX3EfKmO5IHXYGbHigeVRHk8fVQUK7HgVUFBBgNGnqFkXkK2c5tZl0Titd9j58EFVG+2I9fdrJhg4E0WoLqN2Eqa2RVWsl7VQN1WRZUFVD1X3J88IaiPNL63Z+IucOuvzitaDspDnfVH/Inkpd5O0wxlfA18hdML/YaQbAM0cKENxfgHCxEd+PgXTr7ecHJXzYBiIRol0Rhea4UoAKWTMDMKvwiVAyWj8eBEMwrQejmxSvwHDpInZn8Q2Rwp6Rqhzbqvig3kVNLWydKwCGExVxXlAPWVWkh5sGsYtOF93u8xJQCldvawm6Rf/hzV5ui66bTVOlNOefv2psAQgGQiSryea5gqy9xsgPNOqZXPU4jqCYfuJtIVA7edLPmhKlnL2DUALKx1nCUOJ4zGgGCFCu/2yIUkkj11rcLwFw1nI2clmDtwE/XY9IoTUT/WvxoIDghJU1j7NMwvsewKv3xgUNPSHslBdPKzUjV6/+GgT2ZUUhusTbb+6mV03BCenLYOabFzbVZPIgh3b5C2PbqjDRDqLo0QPXDw/7/n2kqkn0mwsMl4dtGQBU7wYimwcxy/5TbfKjCFhkxZM4bKdtaeTyAn9sorPD3L8wB16UvN2LAYMGSvuGlLN1F5erslLCEBLODCLLTEtyFhh/V3WfmYOch/mRpqvKVsmj5H1DuspQW9osCwey9N315h885IRd+69wlhkqdQ8AK5AGLWZKmT1q2ZHQoQigU+unnO2BJsUyGsJ3IgUlUj/i86cFr0LlpVZsFNzb1LHqEPG2gQxozYfIiwItgbm0V1URn87FH/+3rQg77dEDU31wrUiXdEqY/OPzi9B2Rog7t6NJ0oM3BcppDkE9VDsMdGb88sxqhK5zg4typ+Y67lOdJmYUG8gLdVlMxgXAOP9rDOjaf0UOjeZGXDvHO7ejuMA94XJWD3lxIG9cutl3nU/Kn0ngQZkUS9CuhRZKvsh4nxsDUya1MbfhnpdWPoxhTPapJQKqWb9Hs6oExxZDI/6eunkflTrfWWONlMZsSKr9WW5c8hZIYN+7gknb0cWwwTeYulOmyVHG6FHd8FzW8w6XbeK6qSYikfWD5w4rti2r7IEKUWTSXH3zCaGB8nt/NzCuwxmGeLXL/ZMNhTqradmWDHYWWbGBAVrXtYfgqv+ykh+thD6aT50D2qnaE5fcrpJkn6fiN9L9jusu4m/MH2Fr5E1jgeDnlqUPk1bjXHkNfm+IPZHh5wQ05prrFDl7Gn65f3rx4QnHqJKrCouF1Bsw8scdOhG8u4gn84pE85MYoA6Xuo99HgbzeBo5nPxi01qrT4+6Tsk+/fUlVD/69Ab2Osv/v6W2o/wrXUVb2fZo6BxU0QyshFGuC121qBKiZLYjX+xsXs3VVipJPMyDsj5PhjtMVX3IgKcH39jUOFuthbNIq21eLa/ZERJgpZL6frS+upwhseg6OZLphSwQobjoS9IDcwXyEigFrDRH5/fe8yyRlfJNvJ8LzEr16llIv66QVG8qxkTpOLQWhPNGna8aRoacxipA4KzqYDsnUUOA0CisbkJa3LDZToh0nF/ScowRpX9VaBBAzbIDGQ+ClLfDFx2TlMDIWXkYFAef9cpLWGEWuuCLKqqi+iC2uMkp8tTImfIpEKowpCB0t3izviwS2dpq84H757tL0z+xS8yTLSuVjrJkgWq0OuKDsGGfY6V3uHcCKiob6bmh2yHBT8M4avlMnLCSjGCLNnxsDyUw8EQuH9LXOwayGTF24p3G/C2kWhvnErVBRXovSvY98+p9eggIL53SkjL8g1vjDao3jdaA1cUMxfJA5/FKeuzx3ZnjBx929KAfSSXAe0lxLg0d7imCKSWNshgl+Hczb8T8+tkx8RgIpDuem7UhwR5kEt7PdDqfoau4/kVC/YLYjMf1ePPMbQQZ2lBjEpGofmFSEGy4uilk4TWFYaULjurK1tfGAl8J9N3lROtnJBdavF4LUqS/4Ga/3SA7oN6V4SO77mRs9AWYGBLUIru1rI5EwgTvAGl+M86xl3USjML0TjJMiS/deuzFbTUyBlqmNcsPiZCup60QI5NzAAZ3bbRt32RgvKeVAYK+6wJXfcsQu/p3KZioObC7hh88FfB14gl5SnnXLYDO215L+klXjrCA7dbu5GAvEPiXIh88lsvffYZY/hS0/nJyJtBeJEUOav1Vs1m7eqGgBRiEBGwamWLAx2Gg2wLubiUbseCK8B2M3mBgZoLNRr1HCCSYZfqicccCk6cCu9Qrb54eJaFteiQBr6+hq1l2Wnik7q0f+S1Gomf4p5kEifMh8a8gtP/Kl/pgcWBZuClVe2l0mHHz7dNBfQZh3m/ZUdIwm0NxU5YS9RInGv/MkwxKLJbOQOJyXXIM92rOYwprda3YEaaRaxAshE2RhXJQx4uAgllg9lCQjHrF0bQiiWQk9iev8OfTpMus7DyTe3ZJPrn+VCFR4efHUmOgREPaXdraTNOMfqigKBP66l3dKvGlLRjgu5QyXdUxZ4F1kprtnVLZQX9mtAe1vw0ZWd28fdRoXNRgIDJFB/9BBGIiJ1FL0PIjmsbmkHe/UKnG938Re5h7TyhLyr/u7UAW+m5MIZQt68cLTIvXFJxbV/f3yZjsLhm1D8ZN37XUzu/Do2FrLukHXsQMUQc4s7ahzCvTxdt9hJjZ4SFrM1jm2I36PyusqBedk1qlk4cWhAU9vpzXkFs+VGBcCBKUWYSzACZeHe0SVqTcxiy0CbJtkliNcVeYluvmSF60Ikq2IUQOTIjojZLEAODNogQanOOKHim+EaBv8jodAW+Dqgv0rX6HhBp+c3a3Irn0uK46CFM36uZs/9/nbBxKzXdpECIdxZvWhQj+NyAsvCqylJLpTdb7zkQuHF3vDVFDqZ8mtsaidGOCIf1+g3eqtBcw6NuCZZfJyvS2BcZ7w2HlJly062tttMy1wMpajQgfl82oKregmN1I9Gwg92BmY3UhuGVy91U4sIZFCye1wv8a61MtWRd2gBaMETYKOvFy73gLwz+a526WY2pb39AYpKhUycR6YcG3BlwpT/1aAtQ5ri7e/4gmqpz6TnaJXOJjjG02hHKyCe8NzDEdLmf8BZdg/e1XIlf3PI4JK4q8cXbmTeTqx4rXvuzmKiHh8lKAU9VQLNTEM2cWk1E+Ew+n64ZBhdgfktxm2i1nQLgNzr5DEmj8wVAxKvyEFmLGH+gO+fTbl1h6wYoujVMFBsAbFO/0JxJk2x/RtAbP8gy/2jysEL2qeorBbmpFHitK+dihT37gXHGNXm3p8k2r3cLv4XGK9sDocbDJN1pWEwAFakW41T2BVq64tqxUtzSM+aXj1rGEZIppFIlx4Q7es7kFvy7RCtpySJUn6K94WK6C0/JvFPatSJ2nHaJ4UYMCcQIjZzyzPgS3wkHjqV7f85msAkwS8jYHTCur3C/GIxUlM+myI24qtLn0pxb9LwrC4iwNsJw4kjICnxtilteWH6LKasIQ68ViUzyzWGj/m699AR8dIzqyU8mC3tzDQvV3sDpZw1Dx/JNckFy+hRfyeNbWyD52Azmn4jOt4JAWO/7h6I8T10awqAPfp4EDe+nhk/zI5r1N5ajRyss8C485aVjvM3Cpny2cvtxZ7ptgMmke4YVka34+b1YLgXdliLyW/NPv1YtnTC2wJQGRZuwVadrSGlFiTNCfBT5HU9/kgYp1WTnoIo2T4wb3YXJY6rKqCmo8t3dGh2fay34ttXUa8f4kQiFdO5sIJKnf4ovEI0mobU2VDbO9UIuoHMHjgpnaD/5vi9zZqFmx3stH7qUOp0QYKOOFedOV+6EnSyirV2/4mNRfc1r3Zu7zfSpJlNyr9SydqGMCjGxh9EY3qWSw1THQkgMDWaUtkdRlRR5qgSiKX95YveVmCtu89kNewVgmOhVSqp1dH6bV5LbfrnGfx7HP/ZuTxL7ZawPJDF59OOlLFoTEcNYzHKpz54H1mqgXOHx3NIOdMYNLD+4JM+T9Qjsk/dzxhlrR7brQP3HqqcrLAHOulJHUd0a5LzOGHjpFBG/C3tpIOlbCnKNaPr7Y4XTSpCSiNCChMGJjrXBoS4ol+y4oD+ryThFbGx+ZmhJBdOfb5cbJDU8WTLQ4RWnVrU/mW1hhkSz1aBEoWfjk9xMsy74NntsFd8tQVHNev5x6KJHQR3Jdq8T/2XU8inOuYHWTRxEvDMHOXOLop2GFWKL0TySjMkPt9VSRKeBHysi0aOzYfvaL+iaVNzO2GgEJQSYckC2XYQZ87PIzRA3cSeMgzTjUmUqtzIoNem9lDjeMto53yyIs7rWKj0HysFzwQmkLv29VCGdU0htiFDq+2towHRu2KGUxu3rWFSw6TorhCMjDZ3A926By99BvgFLm2awILJAwHsWf5uuvJVVmmqE9uwyHZwapIyEnB0jac8VF+neYfFnhFoqAp0CY8/EPwd5NtlOpI39klsEQAITayhWSgCON+epYyEq8BdsWjkMO4jYjXrGpcRKxhaVUDR2/WMLlvyd9qq1SJchkYB6JEnpIiZtaRFkBC8Qlp3GkP80J+mXkAu4KkQQ50XYKokLVFj7OcB9Mlr7pGXZ7RVOz3+/wMSeuLALhegB8OFfL1ezTP/F5b5o022SzWHfNbftMFA8odg+yG8rE0TOx9S9p/WFvYq2cckJGDo0945oQF+7Qk7THEFSLqzqFEtkxHoYFXOFYwedpxdj+ANzsy45ORfeifmOm2kx6I6UctItkaBuzjR0js7mh566pdIhrBhjgsNhIWt5AMHVP1Wr8reSAosGmch8FRudzoVFn+40tCeoQdoT0lbXdbBTfwUOHaL4UABGN4QrUT2HyvQwTaasU/VqniXTrxviDvEzqqSBZAMZrUUI6LzPUTp2jkxKQiPTdQ+MLZOfmF+xAWX9LeUZJ0GXJggjuT5dYTMC586Qpd6LnkQkqqYS3hCIPKRs+jnxtvCld+o94+NQ5+cHAdROZObcJ3BuzX5yiVoOcCxiHsZhtxlB0qw36bUYN/n4Y5mm85UhzinmuAiN1TIIalWyjXknJI6u8b/rs/cXPZHTSSnPqM6wpavVLDLpQKFh8HmG9CreJgJCzbd8QF1uHtQoTA9WLGRtZnySAN/ac7Xgk5nZACLh6jDj+RHTJXvFAuJq15I1fB9Gv2UW4qhir5KV/5uqpNaubD9Ee1/GOpMVH53N+zvTt5RwkqkuMaRbsMyd8w0o4e4WbyAMC8/fTFO99aIWRTznlqWAO7V86jJAUFHoUFjEaCd0g+FzpgTKfqUEmWn/bvUtQK5fOnoU1qMWR+XI2TRK7wgf4+M1g3QcCd0FnUsMmkOfa+92W1rz1M480/yrYxgAG6tWSjGgp7BtGU4p/u1z6GsjotTn2qQ/xpDMQSHDRpZXubJVrMLmQx8F/Tq0gfBpNtHJRG7WAw6GC92CLnINMBxuFbYkQol/l2HGJ10Ov3Xk2iB/7ig0diLeLv2FeCQBpWgGxLM4bl89lFBM2Py3nTligVgqgCWFkFZmvK+j2N4PdisQ4oNSYYpS2jfRbQ0fZLKwcAitk7ippC3XZzRCR+kjwxgmyzzCbvt30yx4LVYekGjWxUQF5axmgS9ir8AogFF/BdlI1S3Al2xylX9wwBnzGo+r+lN3ZtAGWKf1MR94MB9P4SbvqjrV1mV8Bg713/pAIhmq6BfpE1nlw8OvM+JTiEqV5hT/HOuptxoolapL4HL2Yl5PqdrPlOzTh8XpGjIbNr31WdSVsuYBQOBsw1XyMiHpH51qxH/g22u0Lk9cDmo3mxUAWXeZGigiSsZ0Y1701ZAPK2AKT98QSRyxVLpVnZM9UHr9XOkjRR/6L0pbgk+s+krPb3NvEDzjwldgaebxKETeGx8it2ImNh0r7bfippNNYUeyyYR4FjSNElqNjph0icxXM8bGCNMWXKe/Y4B/DO8UGnc4CsvoZYrUCtl6ZDn2gDGSrXVT4MLTI4B64t7n6CAvnQHRhJgeOEYJTimh5YUjmC932MDQkYhRI8vmoPamqHmSH+g8oqjmxm64VxRZq74Oe1HLtKLSomS+y/pOF+9v/Gret9nyqG/LHZMDvmFFHgpgpqSOtakNboVu7Kg6ETSi/USldsZjoqs2rMJVhX6p4CASob3VE4fe0QC8XTKzdh7/xxDGZ2bWxrM1r1QW9c9Kmg2gkRLc1WMzw1KuXOCVsQOdNTEgFsiPx5VNoh2r3z57Hqc6AVCIYxrT43J1vvyIqB27NO0XBKRRVKcRmU6NogWqjJ59LaZocMNPWA1bizcP5qjUjCAwGnT4XEHdHr8JwTDFLYiS1akt1GexHF+L9MYEK3cSDxX6x7HF7rVL/RS475W/2/kCQggilSJspCcPABwxdkLUSGShMLHQpEGx7NU7C1t2ZjFCyLNulApK3fLlgj0tTTg5+zk7+eS7d4UK8WMfJXlz1O+RQGqJ2Heh0HAWYAMNJjnM2YPTIVe8AMoviTxIKTmAooNiI5k+aUznZiQ7qBiKl2qHU1EUYQebHY0RaSUQ4r4qZ/eHsB/kXXsd9NusMHZYtJ1wxa1Qkr4y6aZr3JbpRRlS0jgt04bO6J95tA9R2CS+qIS6TErCrZvNvC0sXfeYd4pYLP+g8OuN7rATMyBVwsIHp1VaFjsw7L842/3GzavdfPDuNLLMPgd2bmgl/exYNYjTbADqiiOTEIagaLwZ9P+DX0RiRB/ywXNgR37q94DsF790yQY0HRSaq6UferkaHra+Od1TfztlnZEwqzc7h805j6lpp1St6d/mby6rkimmMmFBC/AD4bVQr9ZuhHsxX0A5pThLqb6t6K5GzXwBwVGk6oxI+Uvkz2c60+Hxcymp9LR+quwB74JT5ZNeVp1vc4Y+C1MRixn7wps8/8+sKgiqrbwzi8kgD/Bkpymx2KFMukDTgCPeaC2EtObDNdvMxbWCau0xU9MTA4IfCOZ9ffcoF6mCcEWWQakYH4W0W2OHgf8WYx16YQYbEnnk8R6l1oeidmDI/3jEljO0AqJyN7uo+MvIGS7fmnhxmJ4M09O2+H3jc/i3qfeVivkkTXNFtcRCIUJ1AHNTVikoM50rK8XUpGzplEzVd7UkTNHNK9KG1Mba4qhRH5AVZWScMYnuWFfe6oUJnrYaO9RQ4oefv1w49+V7eZbkMIjcfMyroXnzUfdIidlr7CAhnStkgDw691JPzuc9DUffZ3pRRhSXiVK8uR1Y/262tVjDyv/rmQO62cCQouZmQwRPlTi/rOW4C+TKz03Konl//yB4XKtbJut171aJZxvePyAnlPERPMw1ov2c0paZkoNMdrF3nRWvxdT24GUF4wsBKZ6iFR5oVMx/F5oHnHOg3/YhEPNHjD5ryfM20suDDjGdg4puAfhwju6RAKWe401RBWDt6l/WOYSFv/GZ6wNi3TdSP5aVIAu+cVNlXiTLMcNaxBJXq2ivofeoGJmlw6hiL46C5oLvSKAxq1UXYHYMXSUKzdiuIqSW7eD+ElrOIxlBu4csxo7ILGZite9v35XWL5nV8DbPaG2IKAhIKTair0JREcl9IP/kN/5Yhw9dSF00KS19GUqT2G7qCQf7LdjFz3JQBkyK6/GXInwjyrXtplavu3diCeWwvBZ10uTkMTrQ6/EfOrYb4WDp+yyAz6HRq333Nc5o0uFFI26/BTFeVjVjAZqR+os6s4KNlAXaPckyfN9ptjC2jLwo/D0TzCu82r6v5Ud2GoS04PK6ZpCTGneR8HbyQabhODjShedw761jJCfg4n/ndMXIyyuq9qv3eKX7S0Qa3FghtT605L/R0f1NHmXemDaqZvST0HcBkdXruRaOTxvmoPI+cztXaOcymVenTVVdEjcB6wC+qRkno2Bpij3rmZUXXxtBOSSXMDSSjrLo+q4AJ3a8SrT9VWRzr2fNr9t2Pea8G0lGlixXrc8KQWWriDnjAiRxfVBiqvveshbqpzRoz6XZXn5BcKqhJtdNaW3VGRTRt+1Dq5XBAZQgW3a4jxSy0/rZhQI+KPATETqdQhIjj9JRY6G7zt6cNXNFqkEh4LG1UHEOslT1nPKeVZN2/NWRfJ4wjh717eznjo3GP8VTP+CXBoEIYZ2tzeyGqrXuv2U/c+p9xmkXDM+MBM92fMZx7kx7y6aHBmzfAedpQ44xvXNcbm28fUVwPTLX/0HClQbEciJp905EULw2X1mma3yo1yiO1mocThUt7TlwHUNz1FX/X0TE4+/KmFg7cZT+adqG+JpFz+RCwHKzSgot9RsirnsxxP5BmAZzDckr/47v2GXRPJg3CSvX1JBvHm2zcxf8AN5+2Ox0Bs/CBp0P/xqcLkPy4G2TmTg/AtYMYZJ24hQKrO5rMn++gl544vSJzdzOAUHXpW90sMKhCo0humuSWdxkyG9AtfHLVr0KxPf/VUcVMIfgVCwSxiQihndwGALC2BjZqOTdX5bE7qSjhl5oZHnFUx7kd1oE/spwJuJ6uqHjDJ0sMhipj8uivWV3gqxUexAHDH4NTiJ34fQPfgHhgMRtY2L0ViVCYtYEJZjUjbpy6vJBvVNumJ2Z8BoskSU99fx3H5LOYQOQqFop3GGdn9121VRuZVYogfRDnyHMaP3zHQCvOzuSIs7ez/GVqQyx4IKjimJO5CDLUO3syu/wIoeOoEU+NbkAjMyV6Odi+QquIY+9yCBx4+q9xK6u/rerYhtefQUL24UQgb+pqPnc7P9QiDrfM+sJfghxWGIl1EGKF+sUgSPFEpQLfNj6IJyBZyYT6FnEEyx4hRLLjyfLzGqjHvGilduQUDrFmBqVCcDDYcFERZJObDiCvHAfZhXzMst5YxLOEtcEVu/BcU3cIB6HFjzZtY77D1xpj6SQZQQ3UOoAJHICfodvn+A1UKnqxks89ZeBcLMORix4pDxO7A/5sPNK70ydOJIhiW/Oi0Xe4I6Jc9iSeB/ALsbX7hlMXHx8NwOk4l6KcJvyouWdUkbH0/kR87dZXRIrf6ei52wu7nHgq3/jsU7xjGoPLO1XywIjmotfp61ChcseYK8o9GSJIg9lP9cgEgh2NsVEzqRKSh4YYVb+eR6HHVVm4SkQxCxT3iM8BDQE1zHU142RNt4sA9lQrMMsYrhGxtfOu7SIaQR2g+lRqqMkSRgxwIO4demERJcDBC8hqW5UzbybRndcfKS+LkN2RUqJvqxbaHtfLW+rPnmP7MhvnhSHM2ecpc1syv2tUfncKSKXgPNGfsR/lGeNP9Wp18qZl/fjSSD4nlOKXKw5y3M3FL/zI7hU4dFMzb11GsdCvhQSHvgZ4d7i3RVcKUvXoUcgmNtr4WeaM9roHIw5xNeJS3T1ONtN6u+pizzvQCJ0b46t3UXBI1RcnHqGwKd4aqTvH5snoaxTFHqPvoPUjzGvhK3gRDGj4jBV9VMFdFxSiTiK/4fdD0/3FAkubEERwnk+oDcT3vTgl7xLzSYTKJe72q2hAL94dm36/16i9HpitMixFf0wfKtrjoD9lgoZJxf182GA5LllLL/3PSQ0tftWIVUx5Iw3Bf9rDXvUpuaS6uHNDyhw3jBcxiBYbguRQzZlNL/qbjDlXku5iWUWiS31yYqyI9ygfzhvWReITSNu3CbwET6rt4/QzJbr8TB5Z94YuzcncBpEoulsbabBXaNuJcpTlFtU3qNU6oggTbGp3LFcYjejFp6RHxCu+9Nzix8l3q6r+GPhBaItZvZou3a6/8bmz8bHfbj+gq6pTwc7aXmmLFkUaTaQSRLIP94B67lXQZcQpiLcdMqkRuy703rcnsywCU2Bpt5/BeBIphG3GBJMmLRTcZpMtMhVw9edHJekAGa2JO0FE+DcXHmOk1Znp1P7a+ZOS3DZM0FMIaSzBCNPWmwKo4Vyyc9YUbFx6XzAPiZmKP9vYlUYU+qdZwvuQ5YGeHG/f146sFGPj+f+7l7M/v2XvFhish/OGGkD0kUqkInXL5SBjjuB33qSHkWjNlcQJDEbOGSKxryWGhwp1Nh2cgp2mLWaentCv578h5rYMKPCMAXcTbNjlXUM8I1IEgK+eTEIM/XEoV0IDKSXVel2rec67HAEi6ffFCN7pf1xX1Z/sGBrqsLmGvxmVoM4IpXOgTAYYfJgpFYKErj2z7Guo0iIhyQKuBaLnfyJsi2exNCED9BvNSRhuAmNT631xd5u0VR9HuDwQnJqCepey3aAWWaeCioxdqPl+LbixqAa/yIhS8CJurlil28Khm85eDSzKNbbHcz2SpVqGsEanbqpKJgBVjPEmorFfYw0XA0Ow05OOk9wyZj+zhzbGXP+dBpiJyFoNchld8ZYjVix1Ct4AFvL1sha5hhWxrCvEcsygNRprRIQW3uwa6NHqQ0gmdLjjv/FKnpekpOITjKR/kGBaSGxj++Y42l2alpEHTd+Bef9MiqeAdlPHNx2BZAdJHMjHbBtWoWniC/FjEzaNlZX3m9bPhy8r3EsiDif0CWpTH9AYHJYhMNTE4Ua68C+fxfiwNIvAuLmhRrF6bXREwxfqXIdxQf2qsduXnWJylDpziQoiaFrcxD3k4U+YG7iHCFT71qs5pmOxQWQI31Ew4fvX7BrnZ1D3mcbX2k4hTwlKiRx6MvTkp+UDSGWf4yF5hOdwEteHWexDkMIbaR7rK1gG/Iz40FrEcId5iqqLXAo/5TipwDcJw99zCr2wfY+hmeFZjYTh56XZ6awxpHuyjEvqanwf44uyns0gYVqs91mPpuATIo9qs1lZpci8mMVsOvpqmHxfGYEy6YBO5UGAad71h93wuTx/P/NkYmkcrow4e+pWOdlHIAa407Oio0uTfE2cc+txRSmoXF32hpBS1mB24h8cl7h8PUBlzpiApJGR3RGrNAIhu5WGb2lQB8tECEEKBNI28zj25gqfi1ZVrAejYAlWUKBHtuRoLzRb/FHlqpcZbV6w89WrLutyupKhQw9Cz3BRnYuFFM+FgliyMISUILsyJjJC0m8GQSnJf0uopRY4U1dAHO5xr6mXozhZXTtlhxh4/Zv011YY7A/DEwlAw+oc9MesVr04+PID9jz5X23VrhvV3B5/z+XuH5njV1RST9gTsKFl9WHtdwoCkiHcm3AqUxpf8sz6f4suJehBDyKHW6ZYTJWVb7BQn+3yVi29SGI0JDNA9rwteeq3c7KDfFAY5R9Oc70uq2RqGVnweX5WHQbuRpGfJIwHwF6lmYUvUC3iNHI6fnyUzyk3ojgqdUCPGRUFb8cejNsqfUdJZ+D04tOBJj7f9zOWAE5riYvLYdauLfpMMw1Q92Ulx1q5zN7hprUEEjNsiLh5FqwrcfjNFl6IebLktiXVdPyRL6jRm4dct+obLo90a7fbgWFjy8LrHu4qScolk+9IlhrkSf+TfICanQHEONxG9ybw3VBKY6SGtaydablL5gDV1qQBe8hBLtioL3f2upW962naJXdlOvY27E/VZ/WbAFliAkjl6VkmqsCfV1/TRcfsOf3Z73yykA0r39LLaAJ8BakTKfFnzFwYb1Mom58QrOD7dwPKlzRYnpDdREdsmpFbRsj10X6Ukp7VSnrVwIQMqOVWRLJZPnSAaWFf11zAE0yCKAVUt9CJR1SkV7zGD34+m2Sik3QSM3fI8oJaz/mG8RrYLFFsDK05R3FaD+bSnilfPE9B633cy/5H1rz7kL7JInxhAF+RtOyR7j+1s7Rc0Y6LtUU4zgTXo90w+nzfVXB23EoHWR4WATIpTC8T1xLqeDPmP/K2+5bj3YtQ/svrUrAG2Nwd7OrFppg7cV6yj1DU4yecU2kq2APbFchlh+0RqZm+jvfEcwbVnmlHHsFmFKIZp5i//1YCrx6XW9O7ItR9mDN5/1y8nr7I3g3cErrdjIiFJ+h5N8tb/ppgHVYd0emnaIEdKyO4kPs38iH5W4no5P/7wrFqsJceGYRpK7gpBYSlBEJgVZ7Wy5cRzXok2xmyQ5smh7DVA2Hk+jdmr9O+8FSN9FEJwpTB7rnLf7GHHE27q4v52qRXb3dG0tRdbMFQalRsbiEhZSgJtM6UvSascg3MK3Vd9Ahdl41bETuEkwW05+NGA3OTiegnYT3qfkc4VDrh4Yp9va9mZieUHDdMM7T5RIcG3220SCpAkyW4u7uQryJ06VbKJR6F6D16ScLIUSMyuAJC7eMRsVGhbyWyF3bMLhFAgSEblmDYXoUyR7u3i7fA1tztpBNi1pU4m0Egyqel3JdjuGknjNIH1Yd25SJAVNC3ylbM/FhedoW7SMSP9GTVbjG4I6f2+eCXQf5SFsQnGQkaGOsctQpq7Gog8I0trBFcrabdDt9YQUjXKzvbX14vZHo1Ix2kDErE6za/+HVp08hdwH6XVhVkBnLfh7R815rt5LU8LXS3v7RfLRQZTZjaHnRbfMdOcXqghNVVeBx2O4p5TebHXjCgHsl/j/HZrw1Hqn6AuhAZ/ey4g5j4fpkDZZRJeyDB6NfHV04NGvROYvS7XoEu72lKjHXjVdfE/R0yAuz3Avk+JVmwpNe+VZI/q7EUogdftA5bDQ6OxPgUdiWLN1PmmGW1YdNN/P8n6xBi8FJ1Ov6fX5A9j8h1+0XCXQ3Eyn4zUWybjdN2eaIfVwNPIN0Web13OEKVNzvQ2s5ZhnPz1PXv+8YptvVrXXblqfx0VSzYeR2kG1MdYfhfXd/nit9VHJdEnjnu25pHk0YRvbglNsqVLoCOSCjO73AWwFl1E7m38zliUsgqDB7jW2EjlDr1vsg1bSWKzpZLpeXVwgiClsVd6urDzRvZPcTP8WnqfvqYWpBO3RY3OdNXWYb+99XyrJVrZgaRq2U3wzULjTWPGEKRpA64HBP7x/qyjwA0UDlR/NyARj05HKmJuvyrdqFn1m/p31zZ88/8d0EuGZFsNMZMerSRJeS+9uSA6DKt17Arc/qiBKGiJ2VQnzI/vLFVRuvvJ7o9YSuFDrLmRFoTQI+mPY/yMir6hKpKHKMbNzZJz4nRbDHTOQssgGUq9iQkdM4k8DnFsiJ82C8f8TBYgVVO0hBKl1inDmhLIgRWh8R7UugyvVbCE77WX4wiKIxQ5ry50MoyTFpIJtOwFgy7Jcc8B+k7j9y2BExB3FZ3XkRgkBWI3l6Rqj1NN6mzwxkY7XmLcpPFaZZEPbwkhXHvhA7AEYXs1Gs/d57gjxlntO5/eEWXsFwbjGaYmghZCn/QAHSZg3RgDQNoY8AZ4kaKFtjFldrXCKn5EUWqy6luzKnlXhPUhaxMa9vhV4EaaMT6qDHy38rpcxaW3nBtg8OExhfHb+KYFv72oJL0lNSULQou8/B0XEhhVRUIO4m5AYUgO4sEazonO/eShtixitZukj1iBy2C29tTM2/Uf1yrHzZdsO994fso3EXvcIktL2mJeBCRNO4S8hD4VM6bcTdA+gHNWDt9EveBYboJovJLBzGOVD8FtzUAVYkvlTxp+b3jgKYHWh9nTVg4OUWADeq07D6SXWmTWedReA+95cLvjPxqXtCZGVD0kK293meuOM7Jiynw1edhExSxwQseUd0qUzSZM/iB2yQd+mgJGv7Ajy06Ag6+Y/DsnDTc8I3A2g2/yL3v8ELiV6++nMg6jkxYhdZVlsXPUYi5HoJRr1hSjdLuvFRty1vl7/KNN1HZz64+yR5u/6VJz+JksBRkFa97ZoyvQlgCEJrykXHYo3UfDTHLbBKWk+Vi9HTZntLScxDDP98SBoXkxaeZg1L1WsfGYzpedf3zJzFk/jDZejdDcUr7nt3gwhmZRYP5swks8KOiaVGAvELk1pVd5KiHgGAUtRATwUeHQ9AwOPTc0luoNGS7CyjcER0vCwxyGoQPGfIDiGm1kOA6gF+Tq4DsU0wcGosOu+aU4Xi5KjptD/nnzFQYKcXGvZjuTeeg9l2hcLS6mlpEn3tN3L67BQaT85GiF0SvLHzN4lCJMePNEg4ZTUT9Ud1s/2E2029gwBC/o0ZB7VdyRoJ+G9M6jIN4ZDXjHVw3A2QZSX7nI/qOYaruAdaAKG5Q45i3zEJ1oEFu+Qfr17wM/h2u4eqK/GMDqmJZ7k0b+5MSejrgiL/vmGGAFwhdzGS4pDp+0q4WdiJWx24WxUpukHHgksh+9ccsgz/oE5Fi65mnXpFj8CKPCbYMCd2kPoXQXebgNafmEt4uY3U7FOipiC49WzAbWZ+L6vR2m9ENLeDjhYRWTsoRC8iDMebXeK01HNJu02Rkxgo1Zq5QNNaLJTNlOno7W2dUlUalNlhtWhpt4hShy0ui4uBhbWlOlF/caCcono85vPZWwRvhXGrzhBnXAgrTmO+QGcHpRO++hSWzDI7HYuWmXRxXtsfp07qP/5hJpBuwJCVQtF/CNolGib9rJgfvmdRwbkLgaHdvGiSo7AYmsKW6itI7A6l3PiU5aG1g8/3i2V/KYKV9KS2ppGlLfpGchTll19j3qoqtJOdsnXeEmKaYLHWGAKB7O+U8Q=="
}

The request was also formatted this way, but we'll get to it later.

{% include image.html footnote="Blinds API request format" file="blindreq" alt="blind request blob" %}

It was a JSON object with a single key - payload. It had the telltale signs of base64, though (any string ending with = should set off your base64 detector).

{
  "payload": "A3gsuMXojEEY...<omitted for brevity>...HWGAKB7O+U8Q=="
}

I was hoping this was a custom text format encoded in base64, but unfortunately decrypting it lead to garbage.

{% include image.html footnote="Decoding the base64 lead to garbled text" file="blindenc" alt="blind encrypted blob" %}

It was clearly decrypting this into legible content, though, so I wanted to figure out how it was formatted and how easy it would be reverse.

Decryption

The javascript that was making the request was minified through webpack, and chunked.

{% include image.html footnote="Stepping through the minified javascript" file="blindcode" alt="blind minified js" %}

Stepping through wasn't particularly useful, though, as it seemed like a custom HTTP library that was just a thin wrapper around fetch and XMLHttpRequest.

I assumed that they were probably using an open source library for their encryption - they are still a startup, afterall, and I doubt they'd roll their own encryption library.

I started looking for strings in the code that would be helpful - a lot of minification can't know what a string contains, and as such won't strip things like library version numbers and names, URLs, and other things that would give a hint of how it's being done.

{% include image.html footnote="References to GitHub in the minified codebase" file="blindgit" alt="blind git" %}

There were quite a few references to GitHub (Always a good keyword to search for - package authors will often link to the open source code for issues in strings that are included in the minified library).

{% include image.html footnote="The open source library they were using for their encryption" file="blindbrowserify" alt="blind encryption library" %}

Bingo.

    throw new Error(["sorry, createCredentials is not implemented yet", "we accept pull requests", "https://github.com/crypto-browserify/crypto-browserify"].join("\n"))

This library had a function called createCredentials that hadn't been implemented yet, and had the helpful comment saying "We accept pull requests!"

This section of the code was clearly the minified version of the open source library.

    var p = n(342);
    t.pbkdf2 = p.pbkdf2,
    t.pbkdf2Sync = p.pbkdf2Sync;
    var d = n(519);
    t.Cipher = d.Cipher,
    t.createCipher = d.createCipher,
    t.Cipheriv = d.Cipheriv,
    t.createCipheriv = d.createCipheriv,
    t.Decipher = d.Decipher,
    t.createDecipher = d.createDecipher,
    t.Decipheriv = d.Decipheriv,
    t.createDecipheriv = d.createDecipheriv,
    t.getCiphers = d.getCiphers,
    t.listCiphers = d.listCiphers;
    var f = n(534);
    t.DiffieHellmanGroup = f.DiffieHellmanGroup,
    t.createDiffieHellmanGroup = f.createDiffieHellmanGroup,
    t.getDiffieHellman = f.getDiffieHellman,
    t.createDiffieHellman = f.createDiffieHellman,
    t.DiffieHellman = f.DiffieHellman;
    var l = n(539);
    t.createSign = l.createSign,
    t.Sign = l.Sign,
    t.createVerify = l.createVerify,
    t.Verify = l.Verify,
    t.createECDH = n(573);
    var h = n(574);
    t.publicEncrypt = h.publicEncrypt,
    t.privateEncrypt = h.privateEncrypt,
    t.publicDecrypt = h.publicDecrypt,
    t.privateDecrypt = h.privateDecrypt;
    var M = n(577);
    t.randomFill = M.randomFill,
    t.randomFillSync = M.randomFillSync,
    ...

The description of the library is "The goal of this module is to reimplement node's crypto module, in pure javascript so that it can run in the browser."

It looks like they're using Node on their backend with the crypto module, and want to use the same features on their front end in exactly the same way.

Nice way to reuse code, but it also means that they have to pass their shared secret key to the client.

I assumed that they wouldn't include the secret key in the client - they'd create one adhoc per session, and renew it every X minutes, through a websocket perhaps.

I assumed wrong.

{% include image.html footnote="Blinds shared AES secret key" file="blindkey" alt="blind encryption key" %}

They kept the static shared key as a string in the minified JS. They also helpfully named these functions dataDec and dataEnc.

At this point it looked like we have everything we need to decrypt their data.

We don't even need to download the library they used, since it's just a reimplementation of the crypto module.

30 seconds in an editor later and we have the following:

const text = `<blob from above>`;
const crypto = require('crypto');

const t = crypto.createDecipher("aes-256-cbc", "5d860d3eb8e4a271309c0e4c001fafcc7cc80277e5238d9796a810a93ffa27d3")
let e = t.update(text, "base64", "utf8");
e += t.final("utf8")


console.log(JSON.parse(e))

I just copy and pasted their minified implementation and swapped out the crypto module.

{% include image.html footnote="The API decrypted API response" file="blinddecrypted" alt="blind decrypted" %}

This worked out of the box - no additional required. The most interesting part of the response was the article_list. These were formatted as follows:

{
    "alias": "b6WJEDTp",
    "member_nickname": "faRw33",
    "created_at": "4d",
    "is_auth": "Y",
    "board_id": 114961,
    "member_company_id": 109330,
    "images": [],
    "group_name": null,
    "channel_name": "Misc.",
    "board_name": "Misc.",
    "title": "Is an extreme work ethic required to reach the absolute top of your potential?",
    "content": "I was never a huge basketball fan, but after Kobe's death I spent more time into his background. He was an absolute machine in how hard/how long he worked and the results showed. It's seems like its like that with so many great people who are just so passionate about one thing they will work their b",
    "content_length": 300,
    "like_cnt": 2,
    "comment_cnt": 22,
    "view_cnt": 1337,
    "is_liked": false,
    "is_bookmarked": false,
    "is_multi_poll": false,
    "is_multi": false,
    "is_poll": true,
    "is_mine": false,
    "last_comment_cnt": null,
    "has_comment_update": false,
    "is_hot": false,
    "is_now": false,
    "is_company_tagged": false,
    "is_wormhole": false,
    "job_title": null,
    "is_read": false,
    "report_msg": null,
    "is_top_contributor": false,
    "is_show_holic": false,
    "mention": null,
    "was_companies": null,
    "bio": null,
    "tags": [],
    "article_tags": null,
    "is_hidden_company": false,
    "is_show_company": true,
    "member_company_name": "Greenhouse Software",
    "is_best_company": false,
    "poll": {
        "id": 47176,
        "article_id": 553156,
        "is_multi": false,
        "cnt": 108,
        "polled": 0
    },
    "link": null,
    "label": null
}

We get the users alias as well as their nickname, which isn't shown on the actual posts, as well as some other information about the post.

We can now successfully decrypt every response from Blind. But how about making these requests adhoc in the first place?

Encryption

Back to making the requests that we alluded to earlier - it looks like the request also follows the same format, with a payload.

{% include image.html footnote="Blinds API request" file="blindreq" alt="blind request blob" %}

The natural assumption would be that they follow the exact same format as above - use that same AES key to encrypt the request payload.

First we need to figure out what the non-encrypted request looks like.

Looking back above at the decryption process, there was another function called dataEnc. This is probably how they encrypt their requests. Putting a breakpoint there before the function is executed shows us the format.

{% include image.html footnote="Blinds API request format" file="blindrequnenc" alt="blind request" %}

The encryption is different this time, though - it's using an asymmetrical public key instead of the AES key from earlier. I'm not entirely sure why they do this - if someone is sniffing traffic, and they're able to see the encrypted request object, they would've been able to see the minified JS and do the same thing I'm doing right now. It does prevent an attacker from decrypting the request, since they don't have the private key, but it doesn't prevent them from just recreating the request in the first place.

Regardless, their implementation looks like this:

return new Jt("-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhRvQEkqodGnJ9ap47FiF\nNwMTpdqUbfWyzecgJBxjWwWYwMYxpnde0WNjpzpdz9PMKLdFAg0UH1u32Y2xK/Bq\n/L8F2f+djLwGxszjTZwGGPiQxNWyDRI/In8T3S3dVqfr0QPirKsoy2OxgnbC7+BE\nH0ZN6Y4Sax588Uq+9M1Wz7ct60EZjLO9RLS/qH+t1ZBpQ/p3Ddkm/yCDvixyctvd\nGTbWUVFxtsqdTQjy8OcnQo2y1v6NUeZRqoKsk7LVmkYk3HjggDkBOZk8h1xRuCch\nkY1ix5jjArG645y863N6R+EQ9ShHZnwbVpsy47Vo8zigfk2RKl8ksxvstLrtABfW\nDQIDAQAB\n-----END PUBLIC KEY-----").encrypt(t, "base64")

Looking at the function signature (.encrypt(t, "base64")) and code it wasn't immediately obvious what library they were using (they weren't using the same library as earlier).

Actually stepping into the code this time helped.

{% include image.html footnote="Stepping into the minified third party library for public key encryption" file="blindstepinto" alt="blind stepping into code" %}

Googling around for the this.$options had a nearly perfect match on the node-rsa module.

{% include image.html footnote="Google results for the JSON options object of the library" file="blindgoogle" alt="blind googling for options" %}

Minification will often not rewrite variable names for certain classes due to potential issues with string based references (options['mystring'] needs to work, so you can't rewrite certain variables. Thanks compilers class!). Because of this you can pretty easily find 3rd party libraries even without a source map or any understanding of what the code is doing (which is fairly frequent when dealing with minified JS).

I do the same as we did above and create a simple wrapper for this library:

const NodeRSA = require('node-rsa');
const key = new NodeRSA(`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhRvQEkqodGnJ9ap47FiF
NwMTpdqUbfWyzecgJBxjWwWYwMYxpnde0WNjpzpdz9PMKLdFAg0UH1u32Y2xK/Bq
/L8F2f+djLwGxszjTZwGGPiQxNWyDRI/In8T3S3dVqfr0QPirKsoy2OxgnbC7+BE
H0ZN6Y4Sax588Uq+9M1Wz7ct60EZjLO9RLS/qH+t1ZBpQ/p3Ddkm/yCDvixyctvd
GTbWUVFxtsqdTQjy8OcnQo2y1v6NUeZRqoKsk7LVmkYk3HjggDkBOZk8h1xRuCch
kY1ix5jjArG645y863N6R+EQ9ShHZnwbVpsy47Vo8zigfk2RKl8ksxvstLrtABfW
DQIDAQAB
-----END PUBLIC KEY-----`);

const toenc = {
  "channelId": "Careers",
  "childchannelIds": [
    120565
  ],
  "offset": 0,
  "limit": 50,
  "orderBy": "pop"
}

const encrypted = key.encrypt(toenc, 'base64');
console.log('encrypted: ', encrypted);

I was a little thrown off at first because what I got didn't match what my browser was saying, but then I realized that this library actually produces a different output on every decryption.

{% include image.html footnote="Different results on every encryption" file="blindmulti" alt="blind different outputs for the same input" %}

I took my request and replaced the encrypted blob from their version of the library and replaced it with mine, and got back a valid response.

We are now able to generate requests and decrypt the responses.

The offset and limit are also interesting, but I'll leave that as an exercise for the reader 😉.

Conclusion

Blind is encrypting their requests and responses locally. While not a good solution to network sniffing and interception by any means, this isn't as dumb as it initially looks - it prevents anyone who is only looking at their API route from being able to decrypt it.

It also prevents any automated tools from harvesting the data; you'd need to do a fairly deep analysis of their libraries and keys to figure out how it was encrypted. Additionally, by encrypting the requests with the public key, you couldn't decrypt them unless you had the corresponding private key. This is less true for the AES key (but probably makes sense based on relative sizes of the requests - public/private key encryption is much more computationally expensive than AES, and the requests seem to be a few orders of magnitude smaller than the responses).

Overall a pretty fun weekend afternoon!