Ceci est un puzzle de golf de code avec une application du monde réel. Certains navigateurs actuels, si vous saisissez une URL qui ressemble à
data:text/html,<script>alert("hi")</script>
exécutera le code JavaScript donné. Supposons maintenant que vous ayez une URL qui ressemble à (pseudocode):
data:text/html,<script>
myPublicKey="12345678";
cryptoLib=download("http://example.com/somecryptolib.js");
if(sha256sum(cryptoLib) == "12345678")
eval(cryptoLib)
</script>
Si vous imprimiez cela sur des cartes de visite sous forme de code QR , toute personne qui se rendrait à cette URL avec un navigateur approprié obtiendrait un client de chiffrement à clé publique, avec votre clé publique préchargée, sans avoir à installer quoi que ce soit. En raison de la vérification du hachage, vous pouvez être sûr qu'ils ont obtenu le vrai logiciel de cryptage, même si leur FAI se mêle du trafic.
Malheureusement, la vraie version de ce pseudocode est assez longue pour un code QR. Mon défi est: combien de temps pouvez-vous le faire? Une mise en œuvre:
- Soyez une donnée: ... URL qui s'exécute correctement à partir de la barre d'adresse de Chrome et Firefox. (Pour créer des données valides: URL, vous devrez encoder% en% 25 et supprimer les retours à la ligne)
- Ayez une URL et un hachage SHA-256 intégrés, de préférence sous forme de littéraux de chaîne de texte brut vers le début
- Télécharger un fichier à partir d'une URL à l'aide de XMLHttpRequest (ou d'une API similaire). (Notez que le serveur devra inclure un en-tête Access-Control-Allow-Origin: * pour que cela fonctionne.)
- Si cette URL a été chargée avec succès et que le résultat est un fichier avec le hachage attendu, évaluez-le. Sinon, ne faites rien ou affichez un message d'erreur.
- Toutes les fonctions JavaScript intégrées présentes dans Chrome et Firefox sont équitables, mais le chargement des bibliothèques est impossible.
- Utilisez le moins d'octets possible
J'ai fait une version naïve en utilisant CryptoJS ( version minifiée ):
data:text/html,<script>
u = 'http://localhost:8000'
h = '5e3f73c606a82d68ef40f9f9405200ce24adfd9a4189c2bc39015345f0ee46d4'
// Insert CryptoJS here
r = new XMLHttpRequest;
r.open('GET', u, false);
r.send();
if(CryptoJS.SHA256(r.response) == h)
eval(r.response);
</script>
Qui sort du minifier comme:
data:text/html,<script>u="http://localhost:8000";h="5e3f73c606a82d68ef40f9f9405200ce24adfd9a4189c2bc39015345f0ee46d4";var CryptoJS=CryptoJS||function(k,w){var f={},x=f.lib={},g=function(){},l=x.Base={extend:function(a){g.prototype=this;var c=new g;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},t=x.WordArray=l.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=w?c:4*a.length},toString:function(a){return(a||y).stringify(this)},concat:function(a){var c=this.words,d=a.words,b=this.sigBytes;a=a.sigBytes;this.clamp();if(b%254)for(var e=0;e<a;e++)c[b+e>>>2]|=(d[e>>>2]>>>24-8*(e%254)&255)<<24-8*((b+e)%254);else if(65535<d.length)for(e=0;e<a;e+=4)c[b+e>>>2]=d[e>>>2];else c.push.apply(c,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<32-8*(c%254);a.length=k.ceil(c/4)},clone:function(){var a=l.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],d=0;d<a;d+=4)c.push((1<<30)*4*k.random()|0);return new t.init(c,a)}}),z=f.enc={},y=z.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++){var e=c[b>>>2]>>>24-8*(b%254)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b+=2)d[b>>>3]|=parseInt(a.substr(b,2),16)<<24-4*(b%258);return new t.init(d,c/2)}},m=z.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++)d.push(String.fromCharCode(c[b>>>2]>>>24-8*(b%254)&255));return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b++)d[b>>>2]|=(a.charCodeAt(b)&255)<<24-8*(b%254);return new t.init(d,c)}},n=z.Utf8={stringify:function(a){try{return decodeURIComponent(escape(m.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return m.parse(unescape(encodeURIComponent(a)))}},B=x.BufferedBlockAlgorithm=l.extend({reset:function(){this._data=new t.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=n.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,d=c.words,b=c.sigBytes,e=this.blockSize,f=b/(4*e),f=a?k.ceil(f):k.max((f|0)-this._minBufferSize,0);a=f*e;b=k.min(4*a,b);if(a){for(var p=0;p<a;p+=e)this._doProcessBlock(d,p);p=d.splice(0,a);c.sigBytes-=b}return new t.init(p,b)},clone:function(){var a=l.clone.call(this);a._data=this._data.clone();return a},_minBufferSize:0});x.Hasher=B.extend({cfg:l.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){B.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(c,d){return(new a.init(d)).finalize(c)}},_createHmacHelper:function(a){return function(c,d){return(new A.HMAC.init(a,d)).finalize(c)}}});var A=f.algo={};return f}(Math);(function(k){for(var w=CryptoJS,f=w.lib,x=f.WordArray,g=f.Hasher,f=w.algo,l=[],t=[],z=function(a){return (1<<30)*4*(a-(a|0))|0},y=2,m=0;64>m;){var n;a:{n=y;for(var B=k.sqrt(n),A=2;A<=B;A++)if(!(n%25A)){n=!1;break a}n=!0}n&&(8>m&&(l[m]=z(k.pow(y,0.5))),t[m]=z(k.pow(y,1/3)),m++);y++}var a=[],f=f.SHA256=g.extend({_doReset:function(){this._hash=new x.init(l.slice(0))},_doProcessBlock:function(c,d){for(var b=this._hash.words,e=b[0],f=b[1],p=b[2],k=b[3],s=b[4],l=b[5],m=b[6],n=b[7],q=0;64>q;q++){if(16>q)a[q]=c[d+q]|0;else{var v=a[q-15],g=a[q-2];a[q]=((v<<25|v>>>7)^(v<<14|v>>>18)^v>>>3)+a[q-7]+((g<<15|g>>>17)^(g<<13|g>>>19)^g>>>10)+a[q-16]}v=n+((s<<26|s>>>6)^(s<<21|s>>>11)^(s<<7|s>>>25))+(s&l^~s&m)+t[q]+a[q];g=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&f^e&p^f&p);n=m;m=l;l=s;s=k+v|0;k=p;p=f;f=e;e=v+g|0}b[0]=b[0]+e|0;b[1]=b[1]+f|0;b[2]=b[2]+p|0;b[3]=b[3]+k|0;b[4]=b[4]+s|0;b[5]=b[5]+l|0;b[6]=b[6]+m|0;b[7]=b[7]+n|0},_doFinalize:function(){var a=this._data,d=a.words,b=8*this._nDataBytes,e=8*a.sigBytes;d[e>>>5]|=128<<24-e%2532;d[(e+64>>>9<<4)+14]=k.floor(b/(1<<30)*4);d[(e+64>>>9<<4)+15]=b;a.sigBytes=4*d.length;this._process();return this._hash},clone:function(){var a=g.clone.call(this);a._hash=this._hash.clone();return a}});w.SHA256=g._createHelper(f);w.HmacSHA256=g._createHmacHelper(f)})(Math);r=new XMLHttpRequest;r.open("GET",u,!1);r.send();CryptoJS.SHA256(r.response)==h&&eval(r.response)</script>
Testé avec ce serveur Python minimal:
import BaseHTTPServer
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_HEAD(s):
s.send_response(200)
s._sendHeaders()
s.end_headers()
def do_GET(s):
s.send_response(200)
s._sendHeaders()
s.end_headers()
s.wfile.write('alert("Success!")')
def _sendHeaders(s):
s.send_header("Content-type", "script/javascript");
s.send_header("Access-Control-Allow-Origin", "*");
def run(server_class=BaseHTTPServer.HTTPServer,
handler_class=RequestHandler):
server_address = ('', 8000)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
run()
La partie JavaScript est de 4700 octets, mais elle peut être beaucoup plus petite. Comment peut-il devenir petit?
la source
eval
, puis faire une deuxième demande avec la bibliothèque de chiffrement chargée irait à l'encontre du point de ce correct? J'ai passé du temps à travailler sur une solution et j'ai fini par faire exactement cela, mais j'ai réalisé que cela signifie faire confiance au FAI pour ne pas jouer avec la bibliothèque de cryptographie, ce qui est un problème.script
élément, en définissant saasync
propriété surfalse
et en l'insérant dans le document?script/javascript
? Tu veux diretext/javascript
.Réponses:
844 caractères
Les valeurs URL et Hash sont codées en dur. Le hachage est encodé en double mot décimal, les valeurs de mon code correspondent au script de l'exemple de serveur Python.
Je n'ai pas non plus pris la peine de faire l'encodage d'URL, mais cela fonctionne lorsque vous tapez
javascript:
manuellement dans la barre d'URL, puis collez le code (et également dans la console).L'implémentation n'est pas conforme, mais elle devrait fonctionner pour les fichiers inférieurs à 512 Mo.
la source