Skip to content

Instantly share code, notes, and snippets.

@alibitek
Last active March 30, 2017 15:29
Show Gist options
  • Save alibitek/6fa778086b4fcadafe57118f79b84c43 to your computer and use it in GitHub Desktop.
Save alibitek/6fa778086b4fcadafe57118f79b84c43 to your computer and use it in GitHub Desktop.
/* Pretty printing styles. Used with prettify.js. */
.str { color: #080; }
.kwd { color: #008; }
.com { color: #800; }
.typ { color: #606; }
.lit { color: #066; }
.pun { color: #660; }
.pln { color: #000; }
.tag { color: #008; }
.atn { color: #606; }
.atv { color: #080; }
.dec { color: #606; }
@media print {
.str { color: #060; }
.kwd { color: #006; font-weight: bold; }
.com { color: #600; font-style: italic; }
.typ { color: #404; font-weight: bold; }
.lit { color: #044; }
.pun { color: #440; }
.pln { color: #000; }
.tag { color: #006; font-weight: bold; }
.atn { color: #404; }
.atv { color: #060; }
}
(function(){
var o=true,r=null,z=false;window.PR_SHOULD_USE_CONTINUATION=o;window.PR_TAB_WIDTH=8;window.PR_normalizedHtml=window.PR=window.prettyPrintOne=window.prettyPrint=void 0;window._pr_isIE6=function(){var N=navigator&&navigator.userAgent&&/\bMSIE 6\./.test(navigator.userAgent);window._pr_isIE6=function(){return N};return N};
var aa="!",ba="!=",ca="!==",F="#",da="%",ea="%=",G="&",fa="&&",ja="&&=",ka="&=",H="(",la="*",ma="*=",na="+=",oa=",",pa="-=",qa="->",ra="/",sa="/=",ta=":",ua="::",va=";",I="<",wa="<<",xa="<<=",ya="<=",za="=",Aa="==",Ba="===",J=">",Ca=">=",Da=">>",Ea=">>=",Fa=">>>",Ga=">>>=",Ha="?",Ia="@",L="[",M="^",Ta="^=",Ua="^^",Va="^^=",Wa="{",O="|",Xa="|=",Ya="||",Za="||=",$a="~",ab="break",bb="case",cb="continue",db="delete",eb="do",fb="else",gb="finally",hb="instanceof",ib="return",jb="throw",kb="try",lb="typeof",
mb="(?:^^|[+-]",nb="\\$1",ob=")\\s*",pb="&amp;",qb="&lt;",rb="&gt;",sb="&quot;",tb="&#",ub="x",vb="'",wb='"',xb=" ",yb="XMP",zb="</",Ab='="',P="",Q="\\",Bb="b",Cb="t",Db="n",Eb="v",Fb="f",Gb="r",Hb="u",Ib="0",Jb="1",Kb="2",Lb="3",Mb="4",Nb="5",Ob="6",Pb="7",Qb="\\x0",Rb="\\x",Sb="-",Tb="]",Ub="\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]",R="g",Vb="\\B",Wb="\\b",Xb="\\D",Yb="\\d",Zb="\\S",$b="\\s",ac="\\W",bc="\\w",cc="(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)",
dc="(?:",ec=")",fc="gi",gc="PRE",hc='<!DOCTYPE foo PUBLIC "foo bar">\n<foo />',ic="\t",jc="\n",kc="[^<]+|<!--[\\s\\S]*?--\>|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>|</?[a-zA-Z][^>]*>|<",lc="nocode",mc=' $1="$2$3$4"',S="pln",nc="string",T="lang-",oc="src",U="str",pc="'\"",qc="'\"`",rc="\"'",V="com",sc="lang-regex",tc="(/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/)",uc="kwd",vc="^(?:",wc=")\\b",xc=" \r\n\t\u00a0",yc="lit",zc="typ",Ac="0123456789",Y="pun",Bc="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try debugger eval export function get null set undefined var with Infinity NaN caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END break continue do else for if return while case done elif esac eval fi function in local set then until ",
Cc="</span>",Dc='<span class="',Ec='">',Fc="$1&nbsp;",Gc="&nbsp;<br />",Hc="<br />",Ic="console",Jc="cannot override language handler %s",Kc="default-markup",Lc="default-code",Mc="dec",Z="lang-js",$="lang-css",Nc="lang-in.tag",Oc="htm",Pc="html",Qc="mxml",Rc="xhtml",Sc="xml",Tc="xsl",Uc=" \t\r\n",Vc="atv",Wc="tag",Xc="atn",Yc="lang-uq.val",Zc="in.tag",$c="uq.val",ad="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where ",
bd="c",cd="cc",dd="cpp",ed="cxx",fd="cyc",gd="m",hd="null true false",id="json",jd="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var ",
kd="cs",ld="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient ",md="java",nd="break continue do else for if return while case done elif esac eval fi function in local set then until ",
od="bsh",pd="csh",qd="sh",rd="break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None ",sd="cv",td="py",ud="caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END ",vd="perl",wd="pl",xd="pm",yd="break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END ",
zd="rb",Ad="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try debugger eval export function get null set undefined var with Infinity NaN ",Bd="js",Cd="regex",Dd="pre",Ed="code",Fd="xmp",Gd="prettyprint",Hd="class",Id="br",Jd="\r";
(function(){var N=function(){for(var a=[aa,ba,ca,F,da,ea,G,fa,ja,ka,H,la,ma,na,oa,pa,qa,ra,sa,ta,ua,va,I,wa,xa,ya,za,Aa,Ba,J,Ca,Da,Ea,Fa,Ga,Ha,Ia,L,M,Ta,Ua,Va,Wa,O,Xa,Ya,Za,$a,ab,bb,cb,db,eb,fb,gb,hb,ib,jb,kb,lb],b=mb,c=0;c<a.length;++c)b+=O+a[c].replace(/([^=<>:&a-z])/g,nb);b+=ob;return b}(),Ja=/&/g,Ka=/</g,La=/>/g,Kd=/\"/g;function Ld(a){return a.replace(Ja,pb).replace(Ka,qb).replace(La,rb).replace(Kd,sb)}function ga(a){return a.replace(Ja,pb).replace(Ka,qb).replace(La,rb)}var Md=/&lt;/g,Nd=/&gt;/g,
Od=/&apos;/g,Pd=/&quot;/g,Qd=/&amp;/g,Rd=/&nbsp;/g;function Sd(a){var b=a.indexOf(G);if(b<0)return a;for(--b;(b=a.indexOf(tb,b+1))>=0;){var c=a.indexOf(va,b);if(c>=0){var d=a.substring(b+3,c),g=10;if(d&&d.charAt(0)===ub){d=d.substring(1);g=16}var i=parseInt(d,g);isNaN(i)||(a=a.substring(0,b)+String.fromCharCode(i)+a.substring(c+1))}}return a.replace(Md,I).replace(Nd,J).replace(Od,vb).replace(Pd,wb).replace(Qd,G).replace(Rd,xb)}function Ma(a){return yb===a.tagName}function W(a,b){switch(a.nodeType){case 1:var c=
a.tagName.toLowerCase();b.push(I,c);for(var d=0;d<a.attributes.length;++d){var g=a.attributes[d];if(g.specified){b.push(xb);W(g,b)}}b.push(J);for(var i=a.firstChild;i;i=i.nextSibling)W(i,b);if(a.firstChild||!/^(?:br|link|img)$/.test(c))b.push(zb,c,J);break;case 2:b.push(a.name.toLowerCase(),Ab,Ld(a.value),wb);break;case 3:case 4:b.push(ga(a.nodeValue));break}}function Na(a){for(var b=0,c=z,d=z,g=0,i=a.length;g<i;++g){var m=a[g];if(m.ignoreCase)d=o;else if(/[a-z]/i.test(m.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,
P))){c=o;d=z;break}}function l(j){if(j.charAt(0)!==Q)return j.charCodeAt(0);switch(j.charAt(1)){case Bb:return 8;case Cb:return 9;case Db:return 10;case Eb:return 11;case Fb:return 12;case Gb:return 13;case Hb:case ub:return parseInt(j.substring(2),16)||j.charCodeAt(1);case Ib:case Jb:case Kb:case Lb:case Mb:case Nb:case Ob:case Pb:return parseInt(j.substring(1),8);default:return j.charCodeAt(1)}}function n(j){if(j<32)return(j<16?Qb:Rb)+j.toString(16);var f=String.fromCharCode(j);if(f===Q||f===Sb||
f===L||f===Tb)f=Q+f;return f}function q(j){for(var f=j.substring(1,j.length-1).match(new RegExp(Ub,R)),s=[],k=[],h=f[0]===M,e=h?1:0,p=f.length;e<p;++e){var t=f[e];switch(t){case Vb:case Wb:case Xb:case Yb:case Zb:case $b:case ac:case bc:s.push(t);continue}var u=l(t),x;if(e+2<p&&Sb===f[e+1]){x=l(f[e+2]);e+=2}else x=u;k.push([u,x]);if(!(x<65||u>122)){x<65||u>90||k.push([Math.max(65,u)|32,Math.min(x,90)|32]);x<97||u>122||k.push([Math.max(97,u)&-33,Math.min(x,122)&-33])}}k.sort(function(Oa,Pa){return Oa[0]-
Pa[0]||Pa[1]-Oa[1]});var B=[],E=[NaN,NaN];for(e=0;e<k.length;++e){var A=k[e];if(A[0]<=E[1]+1)E[1]=Math.max(E[1],A[1]);else B.push(E=A)}var D=[L];h&&D.push(M);D.push.apply(D,s);for(e=0;e<B.length;++e){A=B[e];D.push(n(A[0]));if(A[1]>A[0]){A[1]+1>A[0]&&D.push(Sb);D.push(n(A[1]))}}D.push(Tb);return D.join(P)}function v(j){var f=j.source.match(new RegExp(cc,R)),s=f.length,k=[],h,e=0;for(h=0;e<s;++e){var p=f[e];if(p===H)++h;else if(Q===p.charAt(0)){var t=+p.substring(1);if(t&&t<=h)k[t]=-1}}for(e=1;e<k.length;++e)if(-1===
k[e])k[e]=++b;for(h=e=0;e<s;++e){p=f[e];if(p===H){++h;if(k[h]===undefined)f[e]=dc}else if(Q===p.charAt(0))if((t=+p.substring(1))&&t<=h)f[e]=Q+k[h]}for(h=e=0;e<s;++e)if(M===f[e]&&M!==f[e+1])f[e]=P;if(j.ignoreCase&&c)for(e=0;e<s;++e){p=f[e];var u=p.charAt(0);if(p.length>=2&&u===L)f[e]=q(p);else if(u!==Q)f[e]=p.replace(/[a-zA-Z]/g,function(x){var B=x.charCodeAt(0);return L+String.fromCharCode(B&-33,B|32)+Tb})}return f.join(P)}var w=[];g=0;for(i=a.length;g<i;++g){m=a[g];if(m.global||m.multiline)throw new Error(P+
m);w.push(dc+v(m)+ec)}return new RegExp(w.join(O),d?fc:R)}var ha=r;function Td(a){if(r===ha){var b=document.createElement(gc);b.appendChild(document.createTextNode(hc));ha=!/</.test(b.innerHTML)}if(ha){var c=a.innerHTML;if(Ma(a))c=ga(c);return c}for(var d=[],g=a.firstChild;g;g=g.nextSibling)W(g,d);return d.join(P)}function Ud(a){var b=0;return function(c){for(var d=r,g=0,i=0,m=c.length;i<m;++i){var l=c.charAt(i);switch(l){case ic:d||(d=[]);d.push(c.substring(g,i));var n=a-b%a;for(b+=n;n>=0;n-=" ".length)d.push(" ".substring(0,
n));g=i+1;break;case jc:b=0;break;default:++b}}if(!d)return c;d.push(c.substring(g));return d.join(P)}}var Vd=new RegExp(kc,R),Wd=/^<\!--/,Xd=/^<\[CDATA\[/,Yd=/^<br\b/i,Qa=/^<(\/?)([a-zA-Z]+)/;function Zd(a){var b=a.match(Vd),c=[],d=0,g=[];if(b)for(var i=0,m=b.length;i<m;++i){var l=b[i];if(l.length>1&&l.charAt(0)===I){if(!Wd.test(l))if(Xd.test(l)){c.push(l.substring(9,l.length-3));d+=l.length-12}else if(Yd.test(l)){c.push(jc);++d}else if(l.indexOf(lc)>=0&&$d(l)){var n=l.match(Qa)[2],q=1,v;v=i+1;a:for(;v<
m;++v){var w=b[v].match(Qa);if(w&&w[2]===n)if(w[1]===ra){if(--q===0)break a}else++q}if(v<m){g.push(d,b.slice(i,v+1).join(P));i=v}else g.push(d,l)}else g.push(d,l)}else{var j=Sd(l);c.push(j);d+=j.length}}return{source:c.join(P),tags:g}}function $d(a){return!!a.replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,mc).match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/)}function ia(a,b,c,d){if(b){var g={source:b,b:a};c(g);d.push.apply(d,g.c)}}function K(a,b){var c={},d;(function(){for(var m=a.concat(b),
l=[],n={},q=0,v=m.length;q<v;++q){var w=m[q],j=w[3];if(j)for(var f=j.length;--f>=0;)c[j.charAt(f)]=w;var s=w[1],k=P+s;if(!n.hasOwnProperty(k)){l.push(s);n[k]=r}}l.push(/[\0-\uffff]/);d=Na(l)})();var g=b.length,i=function(m){for(var l=m.source,n=m.b,q=[n,S],v=0,w=l.match(d)||[],j={},f=0,s=w.length;f<s;++f){var k=w[f],h=j[k],e,p;if(typeof h===nc)p=z;else{var t=c[k.charAt(0)];if(t){e=k.match(t[1]);h=t[0]}else{for(var u=0;u<g;++u){t=b[u];if(e=k.match(t[1])){h=t[0];break}}e||(h=S)}if((p=h.length>=5&&T===
h.substring(0,5))&&!(e&&e[1])){p=z;h=oc}p||(j[k]=h)}var x=v;v+=k.length;if(p){var B=e[1],E=k.indexOf(B),A=E+B.length,D=h.substring(5);ia(n+x,k.substring(0,E),i,q);ia(n+x+E,B,Ra(D,B),q);ia(n+x+A,k.substring(A),i,q)}else q.push(n+x,h)}m.c=q};return i}function C(a){var b=[],c=[];if(a.tripleQuotedStrings)b.push([U,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,r,pc]);
else a.multiLineStrings?b.push([U,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,r,qc]):b.push([U,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,r,rc]);if(a.hashComments)a.cStyleComments?b.push([V,/^#(?:[^\r\n\/]|\/(?!\*)|\/\*[^\r\n]*?\*\/)*/,r,F]):b.push([V,/^#[^\r\n]*/,r,F]);if(a.cStyleComments){c.push([V,/^\/\/[^\r\n]*/,r]);c.push([V,/^\/\*[\s\S]*?(?:\*\/|$)/,r])}a.regexLiterals&&c.push([sc,new RegExp(M+N+tc)]);var d=
a.keywords.replace(/^\s+|\s+$/g,P);d.length&&c.push([uc,new RegExp(vc+d.replace(/\s+/g,O)+wc),r]);b.push([S,/^\s+/,r,xc]);c.push([yc,/^@[a-z_$][a-z_$@0-9]*/i,r,Ia],[zc,/^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/,r],[S,/^[a-z_$][a-z_$@0-9]*/i,r],[yc,/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,r,Ac],[Y,/^.[^\s\w\.$@\'\"\`\/\#]*/,r]);return K(b,c)}var ae=C({keywords:Bc,hashComments:o,cStyleComments:o,multiLineStrings:o,regexLiterals:o});function be(a){var b=a.source,c=a.f,d=a.c,
g=[],i=0,m=r,l=r,n=0,q=0,v=Ud(window.PR_TAB_WIDTH),w=/([\r\n ]) /g,j=/(^| ) /gm,f=/\r\n?|\n/g,s=/[ \r\n]$/,k=o;function h(p){if(p>i){if(m&&m!==l){g.push(Cc);m=r}if(!m&&l){m=l;g.push(Dc,m,Ec)}var t=ga(v(b.substring(i,p))).replace(k?j:w,Fc);k=s.test(t);var u=window._pr_isIE6()?Gc:Hc;g.push(t.replace(f,u));i=p}}for(;1;){var e;if(e=n<c.length?q<d.length?c[n]<=d[q]:o:z){h(c[n]);if(m){g.push(Cc);m=r}g.push(c[n+1]);n+=2}else if(q<d.length){h(d[q]);l=d[q+1];q+=2}else break}h(b.length);m&&g.push(Cc);a.a=g.join(P)}
var X={};function y(a,b){for(var c=b.length;--c>=0;){var d=b[c];if(X.hasOwnProperty(d))Ic in window&&console.i(Jc,d);else X[d]=a}}function Ra(a,b){a&&X.hasOwnProperty(a)||(a=/^\s*</.test(b)?Kc:Lc);return X[a]}y(ae,[Lc]);y(K([],[[S,/^[^<?]+/],[Mc,/^<!\w[^>]*(?:>|$)/],[V,/^<\!--[\s\S]*?(?:-\->|$)/],[T,/^<\?([\s\S]+?)(?:\?>|$)/],[T,/^<%([\s\S]+?)(?:%>|$)/],[Y,/^(?:<[%?]|[%?]>)/],[T,/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],[Z,/^<script\b[^>]*>([\s\S]+?)<\/script\b[^>]*>/i],[$,/^<style\b[^>]*>([\s\S]+?)<\/style\b[^>]*>/i],
[Nc,/^(<\/?[a-z][^<>]*>)/i]]),[Kc,Oc,Pc,Qc,Rc,Sc,Tc]);y(K([[S,/^[\s]+/,r,Uc],[Vc,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,r,rc]],[[Wc,/^^<\/?[a-z](?:[\w:-]*\w)?|\/?>$/],[Xc,/^(?!style\b|on)[a-z](?:[\w:-]*\w)?/],[Yc,/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[Y,/^[=<>\/]+/],[Z,/^on\w+\s*=\s*\"([^\"]+)\"/i],[Z,/^on\w+\s*=\s*\'([^\']+)\'/i],[Z,/^on\w+\s*=\s*([^\"\'>\s]+)/i],[$,/^sty\w+\s*=\s*\"([^\"]+)\"/i],[$,/^sty\w+\s*=\s*\'([^\']+)\'/i],[$,/^sty\w+\s*=\s*([^\"\'>\s]+)/i]]),[Zc]);y(K([],[[Vc,/^[\s\S]+/]]),
[$c]);y(C({keywords:ad,hashComments:o,cStyleComments:o}),[bd,cd,dd,ed,fd,gd]);y(C({keywords:hd}),[id]);y(C({keywords:jd,hashComments:o,cStyleComments:o}),[kd]);y(C({keywords:ld,cStyleComments:o}),[md]);y(C({keywords:nd,hashComments:o,multiLineStrings:o}),[od,pd,qd]);y(C({keywords:rd,hashComments:o,multiLineStrings:o,tripleQuotedStrings:o}),[sd,td]);y(C({keywords:ud,hashComments:o,multiLineStrings:o,regexLiterals:o}),[vd,wd,xd]);y(C({keywords:yd,hashComments:o,multiLineStrings:o,regexLiterals:o}),
[zd]);y(C({keywords:Ad,cStyleComments:o,regexLiterals:o}),[Bd]);y(K([],[[U,/^[\s\S]+/]]),[Cd]);function Sa(a){var b=a.e,c=a.d;a.a=b;try{var d=Zd(b),g=d.source;a.source=g;a.b=0;a.f=d.tags;Ra(c,g)(a);be(a)}catch(i){if(Ic in window){console.log(i);console.h()}}}function ce(a,b){var c={e:a,d:b};Sa(c);return c.a}function de(a){for(var b=window._pr_isIE6(),c=[document.getElementsByTagName(Dd),document.getElementsByTagName(Ed),document.getElementsByTagName(Fd)],d=[],g=0;g<c.length;++g)for(var i=0,m=c[g].length;i<
m;++i)d.push(c[g][i]);c=r;var l=Date;l.now||(l={now:function(){return(new Date).getTime()}});var n=0,q;function v(){for(var j=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;n<d.length&&l.now()<j;n++){var f=d[n];if(f.className&&f.className.indexOf(Gd)>=0){var s=f.className.match(/\blang-(\w+)\b/);if(s)s=s[1];for(var k=z,h=f.parentNode;h;h=h.parentNode)if((h.tagName===Dd||h.tagName===Ed||h.tagName===Fd)&&h.className&&h.className.indexOf(Gd)>=0){k=o;break}if(!k){var e=Td(f);e=e.replace(/(?:\r\n?|\n)$/,
P);q={e:e,d:s,g:f};Sa(q);w()}}}if(n<d.length)setTimeout(v,250);else a&&a()}function w(){var j=q.a;if(j){var f=q.g;if(Ma(f)){for(var s=document.createElement(gc),k=0;k<f.attributes.length;++k){var h=f.attributes[k];if(h.specified){var e=h.name.toLowerCase();if(e===Hd)s.className=h.value;else s.setAttribute(h.name,h.value)}}s.innerHTML=j;f.parentNode.replaceChild(s,f);f=s}else f.innerHTML=j;if(b&&f.tagName===gc)for(var p=f.getElementsByTagName(Id),t=p.length;--t>=0;){var u=p[t];u.parentNode.replaceChild(document.createTextNode(Jd),
u)}}}v()}window.PR_normalizedHtml=W;window.prettyPrintOne=ce;window.prettyPrint=de;window.PR={combinePrefixPatterns:Na,createSimpleLexer:K,registerLangHandler:y,sourceDecorator:C,PR_ATTRIB_NAME:Xc,PR_ATTRIB_VALUE:Vc,PR_COMMENT:V,PR_DECLARATION:Mc,PR_KEYWORD:uc,PR_LITERAL:yc,PR_NOCODE:lc,PR_PLAIN:S,PR_PUNCTUATION:Y,PR_SOURCE:oc,PR_STRING:U,PR_TAG:Wc,PR_TYPE:zc}})();
})()
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>XEP-0384: OMEMO Encryption</title><link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/mnemonicflow/6fa778086b4fcadafe57118f79b84c43/raw/b13faa72055c5dc2ce1e13068a3adc6a82d83de6/xmpp.css" /><link href="https://cdn.rawgit.com/mnemonicflow/6fa778086b4fcadafe57118f79b84c43/raw/b13faa72055c5dc2ce1e13068a3adc6a82d83de6/prettify.css" type="text/css" rel="stylesheet" /><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" /><script type="text/javascript" src="https://cdn.rawgit.com/mnemonicflow/6fa778086b4fcadafe57118f79b84c43/raw/b13faa72055c5dc2ce1e13068a3adc6a82d83de6/prettify.js"></script><meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=2.0" /><meta name="DC.Title" content="OMEMO Encryption" /><meta name="DC.Creator" content="Andreas Straub" /><meta name="DC.Description" content="This specification defines a protocol for end-to-end encryption in one-on-one chats that may have multiple clients per account." /><meta name="DC.Publisher" content="XMPP Standards Foundation" /><meta name="DC.Contributor" content="XMPP Extensions Editor" /><meta name="DC.Date" content="2017-03-25" /><meta name="DC.Type" content="XMPP Extension Protocol" /><meta name="DC.Format" content="XHTML" /><meta name="DC.Identifier" content="XEP-0384" /><meta name="DC.Language" content="en" /><meta name="DC.Rights" content="This XMPP Extension Protocol is copyright &#xA9; 1999 &#x2013; 2017 by the XMPP Standards Foundation (XSF)." /></head><body onload="prettyPrint()"><h1>XEP-0384: OMEMO Encryption</h1><table><tr valign="top"><td><strong>Abstract:</strong></td><td>This specification defines a protocol for end-to-end encryption in one-on-one chats that may have multiple clients per account.</td></tr><tr valign="top"><td><strong>Author:</strong></td><td>Andreas Straub</td></tr><tr valign="top"><td><strong>Copyright:</strong></td><td>© 1999 – 2017 XMPP Standards Foundation. <a href="#appendix-legal">SEE LEGAL NOTICES</a>.</td></tr><tr valign="top"><td><strong>Status:</strong></td><td>Experimental</td></tr><tr valign="top"><td><strong>Type:</strong></td><td>Standards Track</td></tr><tr valign="top"><td><strong>Version:</strong></td><td>0.2</td></tr><tr valign="top"><td><strong>Last Updated:</strong></td><td>2017-03-25</td></tr></table><hr /><p style="color:red">WARNING: This Standards-Track document is Experimental. Publication as an XMPP Extension Protocol does not imply approval of this proposal by the XMPP Standards Foundation. Implementation of the protocol described herein is encouraged in exploratory implementations, but production systems are advised to carefully consider whether it is appropriate to deploy implementations of this protocol before it advances to a status of Draft.</p><hr /><h2>Table of Contents</h2><div class="indent"><p><br />1. <a href="#intro">Introduction</a><br />   
1.1. <a href="#intro-motivation">Motivation</a><br />   
1.2. <a href="#intro-overview">Overview</a><br />2. <a href="#reqs">Requirements</a><br />3. <a href="#glossary">Glossary</a><br />   
3.1. <a href="#glossary-general">General Terms</a><br />   
3.2. <a href="#glossary-odr">ODR-specific</a><br />4. <a href="#odr">OMEMO Double Ratchet</a><br />   
4.1. <a href="#odr-parameters">Parameters</a><br />   
4.2. <a href="#odr-wire">Wire format</a><br />5. <a href="#usecases">Use Cases</a><br />   
5.1. <a href="#usecases-setup">Setup</a><br />   
5.2. <a href="#usecases-discovering">Discovering peer support</a><br />   
5.3. <a href="#usecases-announcing">Announcing support</a><br />   
5.4. <a href="#usecases-building">Building a session</a><br />   
5.5. <a href="#usecases-messagesend">Sending a message</a><br />   
5.6. <a href="#usecases-keysend">Sending a key</a><br />   
5.7. <a href="#usecases-receiving">Receiving a message</a><br />      
5.7.1. <a href="#usecase-receiving-keys">Processing the matching elements</a><br />   
5.8. <a href="#uninstall">Removing OMEMO support</a><br />6. <a href="#rules">Business Rules</a><br />7. <a href="#impl">Implementation Notes</a><br />8. <a href="#security">Security Considerations</a><br />9. <a href="#iana">IANA Considerations</a><br />10. <a href="#registrar">XMPP Registrar Considerations</a><br />   
10.1. <a href="#namespaces">Protocol Namespaces</a><br />   
10.2. <a href="#versioning">Protocol Versioning</a><br />11. <a href="#schema">XML Schema</a><br />12. <a href="#ack">Acknowledgements</a></p><p><a href="#appendices">Appendices</a><br />    <a href="#appendix-docinfo">A: Document Information</a><br />    <a href="#appendix-authorinfo">B: Author Information</a><br />    <a href="#appendix-legal">C: Legal Notices</a><br />    <a href="#appendix-xmpp">D: Relation to XMPP</a><br />    <a href="#appendix-discuss">E: Discussion Venue</a><br />    <a href="#appendix-conformance">F: Requirements Conformance</a><br />    <a href="#appendix-notes">G: Notes</a><br />    <a href="#appendix-revs">H: Revision History</a></p></div><hr /><h2>1.
<a name="intro" id="intro">Introduction</a></h2>
<div class="indent"><h3>1.1 <a name="intro-motivation" id="intro-motivation">Motivation</a></h3>
<p class="" style="">
There are two main end-to-end encryption schemes in common use in the XMPP
ecosystem, Off-the-Record (OTR) messaging (<span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0364.html">Current Off-the-Record Messaging Usage (XEP-0364)</a></span> [<a href="#nt-idm46032767451904">1</a>]) and OpenPGP
(<span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0027.html">Current Jabber OpenPGP Usage (XEP-0027)</a></span> [<a href="#nt-idm46032766467360">2</a>]). OTR has significant usability drawbacks for inter-client
mobility. As OTR sessions exist between exactly two clients, the chat
history will not be synchronized across other clients of the involved
parties. Furthermore, OTR chats are only possible if both participants are
currently online, due to how the rolling key agreement scheme of OTR
works. OpenPGP, while not suffering from these mobility issues, does not
provide any kind of forward secrecy and is vulnerable to replay attacks.
Additionally, PGP over XMPP uses a custom wireformat which is defined by
convention rather than standardization, and involves quite a bit of
external complexity.
</p>
<p class="" style="">
This XEP defines a protocol that leverages <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">Double Ratchet</a></span> [<a href="#nt-idm46032766461408">3</a>] encryption
with <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/x3dh/x3dh.pdf">X3DH</a></span> [<a href="#nt-idm46032766452112">4</a>] Key Agreement to provide
multi-end to multi-end encryption, allowing messages to be synchronized
securely across multiple clients, even if some of them are offline. <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">Double Ratchet</a></span> [<a href="#nt-idm46032766461408">3</a>]
and <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/x3dh/x3dh.pdf">X3DH</a></span> [<a href="#nt-idm46032766452112">4</a>] are cryptographic protocols designed by Trevor Perrin
and Moxie Marlinspike and were first published under the name Axolotl.
</p>
</div>
<div class="indent"><h3>1.2 <a name="intro-overview" id="intro-overview">Overview</a></h3>
<p class="" style="">
The general idea behind this protocol is to maintain separate,
long-standing <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">Double Ratchet</a></span> [<a href="#nt-idm46032766461408">3</a>] sessions with each device of each contact
(as well as with each of our own other devices), which are used as secure key
transport channels. In this scheme, each message is encrypted with a
fresh, randomly generated encryption key. An encrypted header is added to
the message for each device that is supposed to receive it. These headers
simply contain the key that the payload message is encrypted with, and
they are separately encrypted using the session corresponding to the
counterpart device. The encrypted payload is sent together with the
headers as a &lt;message&gt; stanza. Individual recipient devices can
decrypt the header item intended for them, and use the contained payload
key to decrypt the payload message.
</p>
<p class="" style="">
As the encrypted payload is common to all recipients, it only has to be
included once, reducing overhead. Furthermore, <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">Double Ratchet</a></span> [<a href="#nt-idm46032766461408">3</a>]'s transparent handling
of messages that were lost or received out of order, as well as those sent
while the recipient was offline, is maintained by this protocol. As a
result, in combination with <span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0280.html">Message Carbons (XEP-0280)</a></span> [<a href="#nt-idm46032766437136">5</a>] and <span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0313.html">Message Archive Management (XEP-0313)</a></span> [<a href="#nt-idm46032766431856">6</a>], the desired property
of inter-client history synchronization is achieved.
</p>
<p class="" style="">
The cryptographic algorithms used by OMEMO are collectively referred to as
the OMEMO Double Ratchet (ODR). In order to make the protocol independent
from specific server-side support, <span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0163.html">Personal Eventing Protocol (XEP-0163)</a></span> [<a href="#nt-idm46032766425856">7</a>] (PEP) is used to fill the 'server'
role of <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/x3dh/x3dh.pdf">X3DH</a></span> [<a href="#nt-idm46032766452112">4</a>].
</p>
</div>
<h2>2.
<a name="reqs" id="reqs">Requirements</a></h2>
<ul class="" style="">
<li class="" style="">Provide forward secrecy</li>
<li class="" style="">Ensure chat messages can be deciphered by all (capable) clients of both parties</li>
<li class="" style="">Be usable regardless of the participants' online statuses</li>
<li class="" style="">Provide a method to exchange auxilliary keying material. This could for example be used to secure encrypted file transfers.</li>
</ul>
<h2>3.
<a name="glossary" id="glossary">Glossary</a></h2>
<div class="indent"><h3>3.1 <a name="glossary-general" id="glossary-general">General Terms</a></h3>
<div class="indent"><dl>
<di>
<dt><strong>
Device
</strong></dt><dd>
A communication end point, i.e. a specific client instance
</dd>
</di>
<di>
<dt><strong>
OMEMO element
</strong></dt><dd>
An &lt;encrypted&gt; element in the urn:xmpp:omemo:1 namespace. Can be
either MessageElement or a KeyTransportElement
</dd>
</di>
<di>
<dt><strong>
OMEMO Message Element
</strong></dt><dd>
An OMEMO Element that contains a chat message. Its &lt;payload&gt;,
when decrypted, corresponds to a &lt;message&gt;'s &lt;body&gt;.
</dd>
</di>
<di>
<dt><strong>
OMEMO Key Transport Element
</strong></dt><dd>
An OMEMO Element that does not have a &lt;payload&gt;. It contains a
fresh encryption key, which can be used for purposes external to this
XEP.
</dd>
</di>
<di>
<dt><strong>
OMEMO Ratchet Update Message
</strong></dt><dd>
A &lt;message&gt; containing an OMEMO Key Transport Element but no
other payload or reference to a payload.
</dd>
</di>
<di>
<dt><strong>
matching element
</strong></dt><dd>
An &lt;envelope&gt; or &lt;init-envelope&gt; element with an rid matching our own
device ID
</dd>
</di>
<di>
<dt><strong>
Bundle
</strong></dt><dd>
A collection of publicly accessible data that can be used to build a
session with a device, namely its public Identity-key, a signed-pre-key
with corresponding signature, and a list of (single use) pre-keys.
</dd>
</di>
<di>
<dt><strong>
active device
</strong></dt><dd>
Any device whose ID is currently announced in the devicelist
</dd>
</di>
<di>
<dt><strong>
inactive device
</strong></dt><dd>
Any device whose ID is NOT currently announced in the devicelist
</dd>
</di>
<di>
<dt><strong>
rid
</strong></dt><dd>
The device id of the intended recipient of the containing envelope
</dd>
</di>
<di>
<dt><strong>
sid
</strong></dt><dd>
The device id of the sender of the containing OMEMO element
</dd>
</di>
</dl></div>
</div>
<div class="indent"><h3>3.2 <a name="glossary-odr" id="glossary-odr">ODR-specific</a></h3>
<p class="" style="">
The terminology of ODR is chosen to be analogous to the <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">Double Ratchet</a></span> [<a href="#nt-idm46032766461408">3</a>]
and <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/x3dh/x3dh.pdf">X3DH</a></span> [<a href="#nt-idm46032766452112">4</a>] specifications wherever possible. ODR protocol messages are
referred to as envelopes in order to distinguish them from XMPP
&lt;message&gt;s.
</p>
<div class="indent"><dl>
<di>
<dt><strong>
identity-key
</strong></dt><dd>
Per-device public/private key pair used to authenticate communications
</dd>
</di>
<di>
<dt><strong>
pre-key
</strong></dt><dd>
A Diffie-Hellman public key, published in bulk and ahead of time
</dd>
</di>
<di>
<dt><strong>
signed-pre-key
</strong></dt><dd>
A Diffie-Hellman public key and a signature on this key (using the
identity-key), published ahead of time and regularly rotated
</dd>
</di>
<di>
<dt><strong>
omemo-envelope
</strong></dt><dd>
An ODR-encrypted envelope containing key material
</dd>
</di>
<di>
<dt><strong>
init-omemo-envelope
</strong></dt><dd>
An ODR-encrypted envelope containing key material. This envelope
includes the initial key exchange which is used to transparently build
sessions with the first exchanged envelope.
</dd>
</di>
<di>
<dt><strong>
pkid
</strong></dt><dd>
The ID of the counterpart's pre-key that was selected for an
init-omemo-envelope
</dd>
</di>
<di>
<dt><strong>
spkid
</strong></dt><dd>
The ID of the counterpart's signed-pre-key that was selected for an
init-omemo-envelope
</dd>
</di>
<di>
<dt><strong>
ek
</strong></dt><dd>
The own ephemeral key that was used for the init-omemo-envelope
</dd>
</di>
<di>
<dt><strong>
ik
</strong></dt><dd>
The own identity-key
</dd>
</di>
<di>
<dt><strong>
dhs
</strong></dt><dd>
The own sending ratchet DH public key
</dd>
</di>
<di>
<dt><strong>
pn
</strong></dt><dd>
The previous chain length for a (init-)omemo-envelope
</dd>
</di>
<di>
<dt><strong>
n
</strong></dt><dd>
The envelope number of a (init-)omemo-envelope
</dd>
</di>
</dl></div>
</div>
<h2>4.
<a name="odr" id="odr">OMEMO Double Ratchet</a></h2>
<p class="" style="">
The OMEMO Double Ratchet (ODR) uses the <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">Double Ratchet</a></span> [<a href="#nt-idm46032766461408">3</a>] algorithm (WITHOUT
header encryption) with <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/x3dh/x3dh.pdf">X3DH</a></span> [<a href="#nt-idm46032766452112">4</a>] key agreement. For details on these, see the
respective specifications.
</p>
<div class="indent"><h3>4.1 <a name="odr-parameters" id="odr-parameters">Parameters</a></h3>
<p class="" style="">
ODR uses <span class="ref" style=""><a href="http://cr.yp.to/ecdh/curve25519-20060209.pdf">Curve25519</a></span> [<a href="#nt-idm46032766368000">8</a>], SHA-256, HKDF, and AES-256-CBC-HMAC as suggested in
Section 5.2 of the <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">Double Ratchet</a></span> [<a href="#nt-idm46032766461408">3</a>] specification. The same primitives are
used for <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/x3dh/x3dh.pdf">X3DH</a></span> [<a href="#nt-idm46032766452112">4</a>] where applicable. The info string for the key agreement is
'OMEMO X3DH' and the info string for the ratchet is 'OMEMO Double
Ratchet'.
</p>
</div>
<div class="indent"><h3>4.2 <a name="odr-wire" id="odr-wire">Wire format</a></h3>
<p class="" style="">
ODR envelopes are serialized into an XML structure. These make up the
headers of OMEMO messages.
</p>
<p class="caption"><a name="example-1" id="example-1"></a>Example 1. An ODR element for an omemo-envelope</p><div class="indent"><pre class="prettyprint">
&lt;envelope rid='123' n='2' pn='1' dhs='BASE64ENCODED...'&gt;BASE64ENCODED&lt;/envelope&gt;
</pre></div>
<p class="" style="">
Init-omemo-envelopes include additional attributes for pkid, spkid, ek,
and ik.
</p>
<p class="caption"><a name="example-2" id="example-2"></a>Example 2. An ODR element for a init-omemo-envelope</p><div class="indent"><pre class="prettyprint">
&lt;init-envelope rid='123' pkid='1' spkid='1' ek='BASE64ENCODED...' ik='BASE64ENCODED' n='2' pn='0' dhs='BASE64ENCODED...'&gt;BASE64ENCODED&lt;/init-envelope&gt;
</pre></div>
</div>
<h2>5.
<a name="usecases" id="usecases">Use Cases</a></h2>
<div class="indent"><h3>5.1 <a name="usecases-setup" id="usecases-setup">Setup</a></h3>
<p class="" style="">
The first thing that needs to happen if a client wants to start using
OMEMO is they need to generate an IdentityKey and a Device ID. The
IdentityKey is a <span class="ref" style=""><a href="http://cr.yp.to/ecdh/curve25519-20060209.pdf">Curve25519</a></span> [<a href="#nt-idm46032766368000">8</a>] public/private Key pair. The Device ID is a
randomly generated integer between 1 and 2^31 - 1.
</p>
</div>
<div class="indent"><h3>5.2 <a name="usecases-discovering" id="usecases-discovering">Discovering peer support</a></h3>
<p class="" style="">
In order to determine whether a given contact has devices that support
OMEMO, the devicelist node in PEP is consulted. Devices MUST subscribe to
'urn:xmpp:omemo:1:devicelist' via PEP, so that they are informed whenever
their contacts add a new device. They MUST cache the most up-to-date
version of the devicelist.
</p>
<p class="caption"><a name="example-3" id="example-3"></a>Example 3. Devicelist update received by subscribed clients</p><div class="indent"><pre class="prettyprint">
&lt;message from='[email protected]'
to='[email protected]'
type='headline'
id='update_01'&gt;
&lt;event xmlns='http://jabber.org/protocol/pubsub#event'&gt;
&lt;items node='urn:xmpp:omemo:1:devicelist'&gt;
&lt;item&gt;
&lt;list xmlns='urn:xmpp:omemo:1'&gt;
&lt;device id='12345' /&gt;
&lt;device id='4223' /&gt;
&lt;/list&gt;
&lt;/item&gt;
&lt;/items&gt;
&lt;/event&gt;
&lt;/message&gt;</pre></div>
</div>
<div class="indent"><h3>5.3 <a name="usecases-announcing" id="usecases-announcing">Announcing support</a></h3>
<p class="" style="">
In order for other devices to be able to initiate a session with a given
device, it first has to announce itself by adding its device ID to the
devicelist PEP node.
</p>
<p class="caption"><a name="example-4" id="example-4"></a>Example 4. Adding the own device ID to the list</p><div class="indent"><pre class="prettyprint">
&lt;iq from='[email protected]' type='set' id='announce1'&gt;
&lt;pubsub xmlns='http://jabber.org/protocol/pubsub'&gt;
&lt;publish node='urn:xmpp:omemo:1:devicelist'&gt;
&lt;item&gt;
&lt;list xmlns='urn:xmpp:omemo:1'&gt;
&lt;device id='12345' /&gt;
&lt;device id='4223' /&gt;
&lt;device id='31415' /&gt;
&lt;/list&gt;
&lt;/item&gt;
&lt;/publish&gt;
&lt;/pubsub&gt;
&lt;/iq&gt;</pre></div>
<p class="" style="">
Furthermore, a device MUST announce it's identity-key, a signed-pre-key,
and a list of pre-keys in a separate, per-device PEP node.
</p>
<p class="caption"><a name="example-5" id="example-5"></a>Example 5. Announcing bundle information</p><div class="indent"><pre class="prettyprint">
&lt;iq from='[email protected]' type='set' id='announce2'&gt;
&lt;pubsub xmlns='http://jabber.org/protocol/pubsub'&gt;
&lt;publish node='urn:xmpp:omemo:1:bundles:31415'&gt;
&lt;item&gt;
&lt;bundle xmlns='urn:xmpp:omemo:1'&gt;
&lt;signed-pre-key-public spkid='1'&gt;
BASE64ENCODED...
&lt;/signed-pre-key-public&gt;
&lt;signed-pre-key-signature&gt;
BASE64ENCODED...
&lt;/signed-pre-key-signature&gt;
&lt;identity-key&gt;
BASE64ENCODED...
&lt;/identity-key&gt;
&lt;pre-keys&gt;
&lt;pre-key-public pkid='1'&gt;
BASE64ENCODED...
&lt;/pre-key-public&gt;
&lt;pre-key-public pkid='2'&gt;
BASE64ENCODED...
&lt;/pre-key-public&gt;
&lt;pre-key-public pkid='3'&gt;
BASE64ENCODED...
&lt;/pre-key-public&gt;
&lt;!-- ... --&gt;
&lt;/pre-keys&gt;
&lt;/bundle&gt;
&lt;/item&gt;
&lt;/publish&gt;
&lt;/pubsub&gt;
&lt;/iq&gt;</pre></div>
</div>
<div class="indent"><h3>5.4 <a name="usecases-building" id="usecases-building">Building a session</a></h3>
<p class="" style="">In order to build a session with a device, their bundle information is fetched.</p>
<p class="caption"><a name="example-6" id="example-6"></a>Example 6. Fetching a device's bundle information</p><div class="indent"><pre class="prettyprint">
&lt;iq type='get'
from='[email protected]'
to='[email protected]'
id='fetch1'&gt;
&lt;pubsub xmlns='http://jabber.org/protocol/pubsub'&gt;
&lt;items node='urn:xmpp:omemo:1:bundles:31415'/&gt;
&lt;/pubsub&gt;
&lt;/iq&gt;</pre></div>
<p class="" style="">
A random pre-key-public entry is selected, and used to build an ODR session.
</p>
</div>
<div class="indent"><h3>5.5 <a name="usecases-messagesend" id="usecases-messagesend">Sending a message</a></h3>
<p class="" style="">
In order to send a chat message, its &lt;body&gt; first has to be
encrypted. The client MUST generate a fresh 32-byte secret. This secret is
used in an AES-256-CBC and HMAC-SHA-256 based AEAD scheme identical to the
encryption in the ODR. The HKDF info string is 'OMEMO Payload'. For
details see Section 5.2 of the <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">Double Ratchet</a></span> [<a href="#nt-idm46032766461408">3</a>] specification. However the
HMAC output is NOT appended to the ciphertext. Rather, the HMAC output is
appended to the 32-byte secret. For each intended recipient device, i.e.
both own trusted devices as well as trusted devices associated with the
contact, this secret/HMAC combination is encrypted using the
corresponding long-standing ODR session. Each encrypted secret/HMAC
combination is tagged with the recipient device's ID. This is all
serialized into an OMEMO Message Element, which is transmitted in a
&lt;message&gt; as follows:
</p>
<p class="caption"><a name="example-7" id="example-7"></a>Example 7. Sending a message</p><div class="indent"><pre class="prettyprint">
&lt;message to='[email protected]' from='[email protected]' id='send1'&gt;
&lt;encrypted xmlns='urn:xmpp:omemo:1'&gt;
&lt;header sid='27183'&gt;`
&lt;envelope rid='31415' n='20' pn='5' dhs='BASE64ENCODED...'&gt;BASE64ENCODED&lt;/envelope&gt;
&lt;init-envelope rid='12321' pkid='1' spkid='1' ek='BASE64ENCODED...' ik='BASE64ENCODED' n='2' pn='0' dhs='BASE64ENCODED...'&gt;BASE64ENCODED&lt;/init-enveope&gt;
&lt;!-- ... --&gt;
&lt;iv&gt;BASE64ENCODED...&lt;/iv&gt;
&lt;/header&gt;
&lt;payload&gt;BASE64ENCODED&lt;/payload&gt;
&lt;/encrypted&gt;
&lt;store xmlns='urn:xmpp:hints'/&gt;
&lt;/message&gt;</pre></div>
</div>
<div class="indent"><h3>5.6 <a name="usecases-keysend" id="usecases-keysend">Sending a key</a></h3>
<p class="" style="">
The client may wish to transmit keying material to the contact for
external use (e.g. file transfer). This works analogously to sending a
regular message. A secret is generated and keys are derived (using the
info string 'OMEMO Payload') as before. The externally transmitted data
is encrypted and authenticated using the same CBC-HMAC AEAD scheme. The
HMAC is then appended to the secret, and they are separately encrypted
for each intended recipient device using the corresponding long-standing
ODR sessions and tagged with the respective rids. The resulting
collection of envelopes is serialized into a OMEMO Key Transport Element
which omits the &lt;payload&gt;.
</p>
<p class="caption"><a name="example-8" id="example-8"></a>Example 8. Sending a key</p><div class="indent"><pre class="prettyprint">
&lt;encrypted xmlns='urn:xmpp:omemo:1'&gt;
&lt;header sid='27183'&gt;
&lt;envelope rid='31415' n='21' pn='5' dhs='BASE64ENCODED...'&gt;BASE64ENCODED&lt;/envelope&gt;
&lt;init-envelope rid='12321' pkid='1' spkid='1' ek='BASE64ENCODED...' ik='BASE64ENCODED' n='3' pn='0' dhs='BASE64ENCODED...'&gt;BASE64ENCODED&lt;/init-envelope&gt;
&lt;!-- ... --&gt;
&lt;iv&gt;BASE64ENCODED...&lt;/iv&gt;
&lt;/header&gt;
&lt;/encrypted&gt;</pre></div>
<p class="" style="">This OMEMO Key Transport Element can then be sent over any applicable transport mechanism.</p>
</div>
<div class="indent"><h3>5.7 <a name="usecases-receiving" id="usecases-receiving">Receiving a message</a></h3>
<p class="" style="">
When an OMEMO element is received, the client first processes the
&lt;header&gt;. It MUST check whether there is at least one envelope with
an rid attribute matching its own device ID ("matching elements"). If
this is not the case, the element MUST be silently discarded. There might
also be more than one matching element, as device IDs are only unique on
a per-account basis, so the recipient MUST perform the following steps
for each matching element until one has been processed successfully.
</p>
<div class="indent"><h3>5.7.1 <a name="usecase-receiving-keys" id="usecase-receiving-keys">Processing the matching elements</a></h3>
<p class="" style="">
If the element is an init-omemo-envelope, a new session is built from
this received element. If this fails (e.g. because the pkid is not
valid), the client MUST try to continue with the next matching element.
If it succeeds, the client SHOULD then republish their bundle
information, replacing the used pre-key, such that it won't be used
again by a different client. The client MUST delete the private key
belonging to the pre-key after use. If the client already had an ODR
session with the sender's device, it MUST replace this session with the
newly built session.
</p>
<p class="" style="">
If the element is an omemo-envelope, and the client has a session
with the sender's device, it tries to decrypt the omemo-envelope using this
session. If the decryption fails, the client MUST try to continue with the
next matching element.
</p>
<p class="" style="">
If there are no more matching elements left to try, the OMEMO element
MUST be silently discarded.
</p>
</div>
<p class="" style="">
After having successfully processed one matching element, the client
extracts the secret and HMAC. It then derives 32-byte authentication and
encryption keys as well as the 16-byte IV from the secret using
HKDF-SHA-256 as before. It is now done processing the &lt;header&gt;, and
can continue with the rest of the OMEMO element.
</p>
<p class="" style="">
If the OMEMO element contains a &lt;payload&gt;, it is an OMEMO Message
Element. The client MUST first try to verify the HMAC on the base64 encoded
contents with HMAC-SHA-256 using the authentication key. If this is
successful, the client can then attempt to decrypt the contents with
AES-256-CBC using the IV and encryption key. If either authentication or
decryption fails, the client MUST silently discard the OMEMO Message
Element. If both succeed, the decrypted contents are treated as the
&lt;body&gt; of the received message.
</p>
<p class="" style="">
If the OMEMO element does not contain a &lt;payload&gt;, the client has
received a OMEMO Key Transport Element. The key material derived from the
matching element can then be used for other purposes (e.g. encrypted
file transfer). If the OMEMO Key Transport Element was received in an
otherwise empty &lt;message&gt;, i.e. this is an OMEMO Ratchet Update
Message, and therefore is of no use by itself, the client MUST ensure
that the ODR header is neverthelesss processed locally before the Omemo
element is silently discarded. This ensures that the ratchet is still
advanced (or, in the case of a init-omemo-envelope, the session
replaced entirely).
</p>
</div>
<div class="indent"><h3>5.8 <a name="uninstall" id="uninstall">Removing OMEMO support</a></h3>
<p class="" style="">
If a device wishes to remove OMEMO support, e.g. because the user is
removing the account from the client, it MUST remove itself from the
devicelist and SHOULD remove its bundle. This will turn it into an
inactive device, which implicitly notifies all counterparts not to address
messages to it any more.
</p>
</div>
<h2>6.
<a name="rules" id="rules">Business Rules</a></h2>
<p class="" style="">
Before publishing a freshly generated Device ID for the first time, a client
MUST check whether that Device ID already exists for this account by
consulting its own devicelist, and if so, generate a new one.
</p>
<p class="" style="">
A client MUST ensure that its bundle information is correct at least every time
it logs in. To this end, it SHOULD simply re-publish the entire bundle, as it would
otherwise have to query the node and then also verify all the information contained
within.
</p>
<p class="" style="">
The announcement step presents the risk of introducing a race condition: Two
devices might simultaneously try to announce themselves in the device list,
unaware of the other's existence. The second device would overwrite the
first one. To mitigate this, devices MUST check that their own device ID is
contained in the list whenever they receive a PEP update from their own
account. If they have been removed, they MUST reannounce themselves.
Furthermore, devices MAY also want to re-publish their own bundle at this
point in order to deal with cases where PEP was purged entirely (either
accidentally or maliciously). This part is OPTIONAL, however, as the
additional overhead in traffic caused by this mechanism might be undesirable
for constrained devices (e.g. mobile).
</p>
<p class="" style="">
If the device is repeatedly removed from the devicelist, or its bundle is
repeatedly removed or corrupted, the client SHOULD notify the user of this fact.
It MAY also stop attempting to correct the PEP records in order to conserve
resources on constrained devices.
</p>
<p class="" style="">
The size of the list of pre-keys in the bundle is a tradeoff between
preventing potential collisions and reducing overhead. If the list is very
small, multiple contacts have a higher chance of selecting the same pre-key
to initiate a session with this client (e.g. if they both build sessions
simultaneously, before the client has a chance to replace the used pre-keys,
or if the client is offline for a prolonged period of time). However, as the
bundle has to be re-published regularly, a large list of pre-keys would
increase the overhead, which might be disadvantageous for constrained
devices. The impact of pre-key collisions can further be reduced by
postponing removal of pre-key private keys during <span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0313.html">Message Archive Management (XEP-0313)</a></span> [<a href="#nt-idm46032766431856">6</a>] catch-up phases
as described further down. It is therefore RECOMMENDED to include 20
pre-keys in the list, but implementors should make their own determination
in light of the targeted use-case of their client.
</p>
<p class="" style="">
Clients MUST ensure that their signed-pre-key is replaced regularly, e.g. by
publishing a new one once a week. It is RECOMMENDED to (additionally)
replace it every time a bundle is published, i.e. after log-ins and having
received init-omemo-envelopes. The reason for this is that the client has
to transmit its signed-pre-key anyway, so it might as well push a new one.
</p>
<p class="" style="">
Clients SHOULD NOT immediately fetch the bundle and build a session as soon
as a new device is announced. Before the first message is exchanged, the
recipient does not know which pre-key has been used (or, in fact, that any
pre-key was used at all). As they have not had a chance to remove the used
pre-key from their bundle announcement, this could lead to collisions where
two (or more) different other devices pick the same pre-key to build a
session with a specific device. As each pre-key SHOULD only be used once,
the party that sends their initial init-omemo-envelope later loses this
race condition. This means that they think they have a valid session with
the contact, when in reality their messages MAY be ignored by the other
end. By postponing building sessions, the chance of such issues occurring
can be drastically reduced. It is RECOMMENDED to construct new sessions only
immediately before sending a message.
</p>
<p class="" style="">
As there are no explicit error messages in this protocol, if a client does
receive a init-omemo-envelope using an invalid pre-key, they SHOULD
respond with an OMEMO Ratchet Update Message using a
init-omemo-envelope. By building a new session with the original sender
this way, the invalid session of the original sender will be overwritten on
their end with this newly created, valid session.
</p>
<p class="" style="">
If a init-omemo-envelope is received as part of a <span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0313.html">Message Archive Management (XEP-0313)</a></span> [<a href="#nt-idm46032766431856">6</a>] catch-up and
used to establish a new session with the sender, the client SHOULD postpone
deletion of the private key corresponding to the used pre-key until after
MAM catch-up is completed. After completing catch-up, the client MUST then
also send an OMEMO Ratchet Update Message using a init-omemo-envelope
before sending any payloads using this session, to trigger re-keying. (as
above) This practice can mitigate the previously mentioned race condition
by preventing message loss.
</p>
<p class="" style="">
As the asynchronous nature of OMEMO enables currently offline devices to
decrypt received messages at a later time, clients MUST include a <span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0334.html">Message Processing Hints (XEP-0334)</a></span> [<a href="#nt-idm46032766280016">9</a>]
&lt;store /&gt; hint in their OMEMO messages. Otherwise, server
implementations of <span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0313.html">Message Archive Management (XEP-0313)</a></span> [<a href="#nt-idm46032766431856">6</a>] will generally not retain OMEMO messages,
since they do not contain a &lt;body /&gt;
</p>
<p class="" style="">
When sending messages, clients SHOULD only add envelopes for active
devices. They MAY also include devices that have only "recently" (e.g. the
past 24 hours or the past week) been marked as inactive in order to give
those devices a chance to reannounce themselves and not lose any history in
the meantime. Clients SHOULD retain ODR sessions for inactive devices, but
they SHOULD eventually delete them after a certain period of inactivity
(e.g. a month). Additionally, clients MAY regard devices from which they
have not received any envelopes, including OMEMO Ratchet Update Messages
("heartbeats"), in a long time as inactive.
</p>
<p class="" style="">
Clients MAY offer the functionality of removing other devices from the PEP
devicelist to the user. This could be used to clean up the devicelist
periodically, as all active devices would reannounce themselves, while stale
entries belonging to devices that are not in use anymore would not reappear.
However, clients MUST NOT interfere with other devices' bundles.
</p>
<h2>7.
<a name="impl" id="impl">Implementation Notes</a></h2>
<p class="" style="">
The OMEMO Double Ratchet deliberately uses mostly identical parameters for
its <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">Double Ratchet</a></span> [<a href="#nt-idm46032766461408">3</a>] and <span class="ref" style=""><a href="https://whispersystems.org/docs/specifications/x3dh/x3dh.pdf">X3DH</a></span> [<a href="#nt-idm46032766452112">4</a>] as the Signal protocol does so that Signal
protocol implementations can be reused with only minor modifications. Most
notably, the HKDF info strings are different for ODR. Additionally, as ODR
has its own, XML-based wire format, the protobuf serialization of the Signal
protocol can be removed. Thus, implementors will most likely want to fork an
implementation of the Signal protocol if one exists for their platform and
make the necessary changes. Reusing well-known code should reduce the
amount of work needed to implement OMEMO drastically, while also bolstering
security.
</p>
<p class="" style="">
The payload key derivation and encryption schemes employed by OMEMO are
identical to the ones employed by ODR, and therefore also identical to the
ones in the Signal protocol. Implementors that make use of existing Signal
protocol libraries SHOULD re-use the relevant library-internal code if at
all possible. In some cases this might necessitate some refactoring of the
code in order to expose an interface to these primitives, but it is worth
the effort, because it reduces the attack surface and limits the risk of
critical errors slipping in during re-implementation.
</p>
<p class="" style="">
The trust handling that is carried out internally by the Signal protocol
reference implementations (and presumably ports thereof to various other
platforms) doesn't mesh very well with the multi-end paradigm of OMEMO. For
this reason it may be desirable to have the library consider all keys
trusted, effectively disabling its internal trust management. This in turn
of course makes it necessary to implement trust handling oneself.
</p>
<p class="" style="">
If implementors using Signal protocol implementations for ODR choose to
implement the RECOMMENDED mechanism postponing deletion of pre-key private
keys until after <span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0313.html">Message Archive Management (XEP-0313)</a></span> [<a href="#nt-idm46032766431856">6</a>] catch-up, they need to be aware of the fact that
these libraries generally take care of removing pre-key private keys
themselves after they were used. Therefore, implementors may wish to suspend
this mechanism in their implementation of the backing PreKeyStore, create a
copy of the PreKeyStore contents to draw from during catch-up, or devise
their own scheme to preseve the pre-key private keys during this phase. In any
case, implementors MUST ensure that the pre-key private keys are nonetheless
deleted after catch-up is completed.
</p>
<h2>8.
<a name="security" id="security">Security Considerations</a></h2>
<p class="" style="">
Clients MUST NOT include themselves in the list of recipients for outgoing
OMEMO messages as this would result in an ODR session where only one of the
two chains would ever be used for sending, leading to a complete loss of
forward secrecy.
</p>
<p class="" style="">
Clients MUST NOT use a newly built session to transmit data without user
consent. If a client were to opportunistically start using new sessions for
sending without the user's knowledge, an attacker could publish a fake
device for this user, which would then silently receive copies of all
messages sent by/to this user. It is RECOMMENDED to apply Blind Trust
Before Verification (BTBV)
[<a href="#nt-idm46032766254384">10</a>], but more conservative clients may instead e.g. choose to
prompt the user for a trust decision on every new key.
</p>
<p class="" style="">
A client MAY use "not (yet) trusted" sessions for decryption of received
messages, but in that case it SHOULD indicate the untrusted nature of such
messages to the user.
</p>
<p class="" style="">
When prompting the user for a trust decision regarding a key, the client
SHOULD present the user with a fingerprint in the form of a hex string, QR
code, or other unique representation, such that it can be compared by the
user.
</p>
<p class="" style="">
While it is RECOMMENDED that clients postpone private key deletion until
after MAM catch-up and this standards mandates that clients MUST NOT use
duplicate-pre-key sessions for sending, clients MAY delete such keys
immediately for security reasons. For additional information on potential
security impacts of this decision, refer to
[<a href="#nt-idm46032766249680">11</a>].
</p>
<p class="" style="">
Clients SHOULD send OMEMO Ratchet Update Messages in regular intervals. These
act as "heartbeats", ensuring that the ratchet is advanced even during
prolonged periods of inactivity of the sending chain.
</p>
<p class="" style="">
Conversely, if a client has not received any (valid) ODR envelopes in a
session, the client MAY suspend sending on this specific session until an
envelope that advances this ratchet is received. This way clients can enforce a
certain bare minimum of forward secrecy. This is however NOT RECOMMENDED for
typical use, as it will cause very noticeable service degradation.
</p>
<p class="" style="">
In order to be able to handle out-of-order messages, the ODR stack has to
cache the keys belonging to "skipped" messages that have not been seen yet.
It is up to the implementor to decide how long and how many of such keys to
keep around.
</p>
<h2>9.
<a name="iana" id="iana">IANA Considerations</a></h2>
<p class="" style="">This document requires no interaction with the Internet Assigned Numbers Authority (IANA). </p>
<h2>10.
<a name="registrar" id="registrar">XMPP Registrar Considerations</a></h2>
<div class="indent"><h3>10.1 <a name="namespaces" id="namespaces">Protocol Namespaces</a></h3>
<p class="" style="">This specification defines the following XMPP namespaces:</p>
<ul class="" style="">
<li class="" style="">urn:xmpp:omemo:1</li>
</ul>
<p class="" style="">The <span class="ref" style=""><a href="https://xmpp.org/registrar/">XMPP Registrar</a></span> [<a href="#nt-idm46032766235760">12</a>] shall include the foregoing namespace in its registry at &lt;<a href="https://xmpp.org/registrar/namespaces.html">https://xmpp.org/registrar/namespaces.html</a>&gt;, as goverened by <span class="ref" style=""><a href="https://xmpp.org/extensions/xep-0053.html">XMPP Registrar Function (XEP-0053)</a></span> [<a href="#nt-idm46032766231120">13</a>].</p>
</div>
<div class="indent"><h3>10.2 <a name="versioning" id="versioning">Protocol Versioning</a></h3>
<p class="" style="">If the protocol defined in this specification undergoes a revision that is not fully backwards-compatible with an older version, the XMPP Registrar shall increment the protocol version number found at the end of the XML namespaces defined herein, as described in Section 4 of <span class="ref">XEP-0053</span>.</p>
</div>
<h2>11.
<a name="schema" id="schema">XML Schema</a></h2>
<p class="caption"></p><div class="indent"><pre class="prettyprint">
&lt;xml version="1.0" encoding="utf8"&gt;
&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:xmpp:omemo:1"
xmlns="urn:xmpp:omemo:1"&gt;
&lt;xs:element name="encrypted"&gt;
&lt;xs:complexType&gt;
&lt;xs:sequence&gt;
&lt;xs:element name="header"&gt;
&lt;xs:complexType&gt;
&lt;xs:sequence&gt;
&lt;xs:choice maxOccurs="unbounded"&gt;
&lt;xs:element name="envelope" type="xs:base64Binary"&gt;
&lt;xs:attribute name="rid" type="xs:integer" use="required"/&gt;
&lt;xs:attribute name="n" type="xs:integer" use="required"/&gt;
&lt;xs:attribute name="pn" type="xs:integer" use="required"/&gt;
&lt;xs:attribute name="dhs" type="xs:base64Binary" use="required"/&gt;
&lt;/xs:element&gt;
&lt;xs:element name="init-envelope" type="xs:base64Binary"&gt;
&lt;xs:attribute name="rid" type="xs:integer" use="required"/&gt;
&lt;xs:attribute name="n" type="xs:integer" use="required"/&gt;
&lt;xs:attribute name="pn" type="xs:integer" use="required"/&gt;
&lt;xs:attribute name="dhs" type="xs:base64Binary" use="required"/&gt;
&lt;xs:attribute name="pkid" type="xs:integer" use="required"/&gt;
&lt;xs:attribute name="spkid" type="xs:integer" use="required"/&gt;
&lt;xs:attribute name="ek" type="xs:base64Binary" use="required"/&gt;
&lt;xs:attribute name="ik" type="xs:base64Binary" use="required"/&gt;
&lt;/xs:element&gt;
&lt;/xs:choice&gt;
&lt;xs:element name="iv" type="xs:base64Binary" maxOccurs="1"/&gt;
&lt;/xs:sequence&gt;
&lt;xs:attribute name="sid" type="xs:integer"/&gt;
&lt;/xs:complexType&gt;
&lt;/xs:element&gt;
&lt;xs:element name="payload" type="xs:base64Binary" minOccurs="0"/&gt;
&lt;/xs:sequence&gt;
&lt;/xs:complexType&gt;
&lt;/xs:element&gt;
&lt;xs:element name="list"&gt;
&lt;xs:complexType&gt;
&lt;xs:sequence&gt;
&lt;xs:element name="device" maxOccurs="unbounded"&gt;
&lt;xs:attribute name="id" type="integer" use="required"/&gt;
&lt;/xs:element&gt;
&lt;/xs:sequence&gt;
&lt;/xs:complexType&gt;
&lt;/xs:element&gt;
&lt;xs:element name="bundle"&gt;
&lt;xs:complexType&gt;
&lt;xs:sequence&gt;
&lt;xs:element name="signed-pre-key-public" type="base64Binary"&gt;
&lt;xs:attribute name="spkid" type="integer" use="required"/&gt;
&lt;/xs:element&gt;
&lt;xs:element name="signed-pre-key-signature" type="base64Binary"/&gt;
&lt;xs:element name="identity-key" type="base64Binary"/&gt;
&lt;xs:element name="pre-keys"&gt;
&lt;xs:complexType&gt;
&lt;xs:sequence&gt;
&lt;xs:element name="pre-key-public" type="base64Binary" maxOccurs="unbounded"&gt;
&lt;xs:attribute name="pkid" type="integer" use="required"/&gt;
&lt;/xs:element&gt;
&lt;/xs:sequence&gt;
&lt;/xs:complexType&gt;
&lt;/xs:element&gt;
&lt;/xs:sequence&gt;
&lt;/xs:complexType&gt;
&lt;/xs:element&gt;
&lt;/xs:schema&gt;
</pre></div>
<h2>12.
<a name="ack" id="ack">Acknowledgements</a></h2>
<p class="" style="">
Big thanks to Daniel Gultsch for mentoring me during the development of this
protocol. Thanks to Thijs Alkemade and Cornelius Aschermann for talking
through some of the finer points of the protocol with me, and to Sebastian
Verschoor for auditing a previous version of the standard and giving valuable
recommendations towards improving it. Lastly I would also like to thank Sam
Whited, Holger Weiss, Florian Schmaus, René Calles, Germán Márquez Mejía,
Paul Schaub, and Richard Bayerle for their input on the standard.
</p>
<hr /><a name="appendices" id="appendices"></a><h2>Appendices</h2><hr /><a name="appendix-docinfo" id="appendix-docinfo"></a><h3>Appendix A: Document Information</h3><p class="indent">
Series: <a href="http://xmpp.org/extensions/">XEP</a><br />
Number: 0384<br />
Publisher: <a href="/xsf/">XMPP Standards Foundation</a><br />
Status:
<a href="http://xmpp.org/extensions/xep-0001.html#states-Experimental">Experimental</a><br />
Type:
<a href="http://xmpp.org/extensions/xep-0001.html#types-Standards Track">Standards Track</a><br />
Version: 0.2<br />
Last Updated: 2017-03-25<br />
Approving Body: <a href="http://xmpp.org/council/">XMPP Council</a><br />Dependencies: XMPP Core, XEP-0163<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: OMEMO<br />
Source Control:
<a class="standardsButton" href="https://github.com/xsf/xeps/blob/master/xep-0384.xml">HTML</a><br />
This document in other formats:
<a class="standardsButton" href="http://xmpp.org/extensions/xep-0384.xml">XML</a> 
<a class="standardsButton" href="http://xmpp.org/extensions/xep-0384.pdf">PDF</a></p><hr /><a name="appendix-authorinfo" id="appendix-authorinfo"></a><h3>Appendix B: Author Information</h3><div class="indent"><h3>Andreas Straub</h3><p class="indent">
Email:
<a href="mailto:[email protected]">[email protected]</a><br />
JabberID:
<a href="xmpp:[email protected]">[email protected]</a><br /></p></div><hr /><a name="appendix-legal" id="appendix-legal"></a><h3>Appendix C: Legal Notices</h3><div class="indent"><h4>Copyright</h4>This XMPP Extension Protocol is copyright © 1999 – 2017 by the <a href="https://xmpp.org/">XMPP Standards Foundation</a> (XSF).<h4>Permissions</h4>Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<h4>Disclaimer of Warranty</h4><span style="font-weight: bold">## NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##</span><h4>Limitation of Liability</h4>In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<h4>IPR Conformance</h4>This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at &lt;<a href="https://xmpp.org/about/xsf/ipr-policy">https://xmpp.org/about/xsf/ipr-policy</a>&gt; or obtained by writing to XMPP Standards Foundation, P.O. Box 787, Parker, CO 80134 USA).</div><hr /><a name="appendix-xmpp" id="appendix-xmpp"></a><h3>Appendix D: Relation to XMPP</h3><p class="indent">The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 6120) and XMPP IM (RFC 6121) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.</p><hr /><a name="appendix-discuss" id="appendix-discuss"></a><h3>Appendix E: Discussion Venue</h3><p class="indent">The primary venue for discussion of XMPP Extension Protocols is the &lt;<a href="http://mail.jabber.org/mailman/listinfo/standards">[email protected]</a>&gt; discussion list.</p><p class="indent">Discussion on other xmpp.org discussion lists might also be appropriate; see &lt;<a href="http://xmpp.org/about/discuss.shtml">http://xmpp.org/about/discuss.shtml</a>&gt; for a complete list.</p><p class="indent">Errata can be sent to &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;.</p><hr /><a name="appendix-conformance" id="appendix-conformance"></a><h3>Appendix F: Requirements Conformance</h3><p class="indent">The following requirements keywords as used in this document are to be interpreted as described in <a href="http://www.ietf.org/rfc/rfc2119.txt">RFC 2119</a>: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".</p><hr /><a name="appendix-notes" id="appendix-notes"></a><h3>Appendix G: Notes</h3><div class="indent"><p><a name="nt-idm46032767451904" id="nt-idm46032767451904">1</a>. XEP-0364: Current Off-the-Record Messaging Usage &lt;<a href="https://xmpp.org/extensions/xep-0364.html">https://xmpp.org/extensions/xep-0364.html</a>&gt;.</p><p><a name="nt-idm46032766467360" id="nt-idm46032766467360">2</a>. XEP-0027: Current Jabber OpenPGP Usage &lt;<a href="https://xmpp.org/extensions/xep-0027.html">https://xmpp.org/extensions/xep-0027.html</a>&gt;.</p><p><a name="nt-idm46032766461408" id="nt-idm46032766461408">3</a>. The Double Ratchet Algorithm &lt;<a href="https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf">https://whispersystems.org/docs/specifications/doubleratchet/doubleratchet.pdf</a>&gt;.</p><p><a name="nt-idm46032766452112" id="nt-idm46032766452112">4</a>. The X3DH Key Agreement Protocol &lt;<a href="https://whispersystems.org/docs/specifications/x3dh/x3dh.pdf">https://whispersystems.org/docs/specifications/x3dh/x3dh.pdf</a>&gt;.</p><p><a name="nt-idm46032766437136" id="nt-idm46032766437136">5</a>. XEP-0280: Message Carbons &lt;<a href="https://xmpp.org/extensions/xep-0280.html">https://xmpp.org/extensions/xep-0280.html</a>&gt;.</p><p><a name="nt-idm46032766431856" id="nt-idm46032766431856">6</a>. XEP-0313: Message Archive Management &lt;<a href="https://xmpp.org/extensions/xep-0313.html">https://xmpp.org/extensions/xep-0313.html</a>&gt;.</p><p><a name="nt-idm46032766425856" id="nt-idm46032766425856">7</a>. XEP-0163: Personal Eventing Protocol &lt;<a href="https://xmpp.org/extensions/xep-0163.html">https://xmpp.org/extensions/xep-0163.html</a>&gt;.</p><p><a name="nt-idm46032766368000" id="nt-idm46032766368000">8</a>. Curve25519: new Diffie-Hellman speed records &lt;<a href="http://cr.yp.to/ecdh/curve25519-20060209.pdf">http://cr.yp.to/ecdh/curve25519-20060209.pdf</a>&gt;.</p><p><a name="nt-idm46032766280016" id="nt-idm46032766280016">9</a>. XEP-0334: Message Processing Hints &lt;<a href="https://xmpp.org/extensions/xep-0334.html">https://xmpp.org/extensions/xep-0334.html</a>&gt;.</p><p><a name="nt-idm46032766254384" id="nt-idm46032766254384">10</a>. Blind Trust Before Verification
&lt;<a href="https://gultsch.de/trust.html">https://gultsch.de/trust.html</a>&gt;
</p><p><a name="nt-idm46032766249680" id="nt-idm46032766249680">11</a>. Menezes, Alfred, and Berkant Ustaoglu. "On reusing ephemeral
keys in Diffie-Hellman key agreement protocols." International Journal
of Applied Cryptography 2, no. 2 (2010): 154-158. </p><p><a name="nt-idm46032766235760" id="nt-idm46032766235760">12</a>. The XMPP Registrar maintains a list of reserved protocol namespaces as well as registries of parameters used in the context of XMPP extension protocols approved by the XMPP Standards Foundation. For further information, see &lt;<a href="https://xmpp.org/registrar/">https://xmpp.org/registrar/</a>&gt;.</p><p><a name="nt-idm46032766231120" id="nt-idm46032766231120">13</a>. XEP-0053: XMPP Registrar Function &lt;<a href="https://xmpp.org/extensions/xep-0053.html">https://xmpp.org/extensions/xep-0053.html</a>&gt;.</p></div><hr /><a name="appendix-revs" id="appendix-revs"></a><h3>Appendix H: Revision History</h3><p>Note: Older versions of this specification might be available at <a href="http://xmpp.org/extensions/attic/">http://xmpp.org/extensions/attic/</a></p><div class="indent"><h4>Version 0.2 (2017-03-25)</h4><div class="indent">
<p class="" style="">Use Double Ratchet and X3DH</p>
<p class="" style="">Describe use-cases more precisely</p>
<p class="" style="">Add clarifying business rules</p>
<p class="" style="">Use kebab-case throughout</p>
(as)
</div><h4>Version 0.1 (2016-12-07)</h4><div class="indent"><p class="" style="">Initial version approved by the council.</p> (XEP Editor: ssw)
</div><h4>Version 0.0.2 (2016-09-22)</h4><div class="indent"><p class="" style="">Depend on Olm instead of Axolotl.</p> (ssw, dg)
</div><h4>Version 0.0.1 (2015-10-25)</h4><div class="indent"><p class="" style="">First draft.</p> (as)
</div></div><hr /><p>END</p></body></html>
BODY {
background-color: #ffffff;
color: #000000;
font-family: Verdana, Arial, Helvetica, Geneva, sans-serif;
font-size: small;
line-height: 130%;
margin-left: 7%;
margin-right: 7%;
}
#left {
border: 0px;
border-color: #aaaaaa;
border-right: 1px;
border-style: solid;
float: left;
margin: 0% 0% 5% 0%;
padding: 4px 2% 10px 2%;
width: 12%;
}
#main {
border: 0px;
color: #000000;
font-weight: normal;
margin: 0% 0% 5% 17%;
padding: 4px 2% 10px 2%;
text-decoration: none;
}
#foot {
border-top: 0px solid;
clear: both;
color: #666666;
font-size: x-small;
font-weight: normal;
text-align: center;
text-decoration: none;
}
A:link {
color: #336699;
}
A.standardsButton {
background-color: #ff6600;
border: 1px solid;
border-color: #ffc8a4 #7d3302 #3f1a01 #ff9a57;
color: #ffffff;
padding: 0px 3px 0px 3px;
text-decoration: none;
margin: 0px;
}
A:visited {
color: #663399;
}
H1, H2, H3, H4, H5, H6 {
color: #336699;
line-height: 0.8;
}
pre {
font-family: Courier, monospace;
background-color: #e0e9f2;
padding: 0.4em;
border: 1px solid #369;
}
ul {
list-style: disc outside;
}
.body {
font-family: Verdana, Arial, Helvetica, Geneva, sans-serif;
font-size: small;
}
.bold {
font-weight: bold;
}
.box {
border: thin dotted;
padding-bottom: 1em;
padding-left: 2em;
padding-right: 2em;
padding-top: 1em;
}
.caption {
font-weight: bold;
}
.code {
font-family: "Courier New", Courier, monospace;
white-space: pre;
}
.def {
text-indent: -6.3em;
padding-bottom: 1em;
padding-left: 6.5em;
padding-right: 10em;
padding-top: 1em;
}
.em {
font-style: italic;
}
.example {
background-color: #f2ee6e;
margin: 0.4em 5%;
border: 1px solid #999633;
padding: 0 0.4em;
}
.indent {
padding-left: 5%;
padding-right: 5%;
}
.head {
color: #336699;
font-weight: bold;
}
.highlight {
color: #336699;
}
.nav {
font-size: small;
line-height: 45%;
text-decoration: none;
white-space: nowrap;
}
.navhead {
color: #336699;
font-size: medium;
line-height: 90%;
padding-left: 0px;
text-decoration: none;
}
.pagehead {
color: #336699;
text-decoration: none;
}
A:visited.pagehead {
color: #336699;
text-decoration: none;
}
.ref {
font-weight: bold;
}
.strong {
font-weight: bold;
}
.subhead {
font-style: italic;
}
.sub {
font-size: xx-small;
vertical-align: sub;
}
.super {
font-size: xx-small;
vertical-align: super;
}
.tablebody {
font-family: Verdana, Arial, Helvetica, Geneva, sans-serif;
font-size: small;
white-space: nowrap;
}
.event {
color: #336699;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment