{"_id":"56d1fb3d93f76e0b00bbc5e2","version":{"_id":"552829408962f339009a6790","project":"552829408962f339009a678d","__v":26,"createdAt":"2015-04-10T19:49:20.516Z","releaseDate":"2015-04-10T19:49:20.516Z","categories":["552829418962f339009a6791","55284ed68962f339009a67e1","55286c73391a362500d9b3f4","552918f6b316811900149f59","5529b255d739240d00a3483e","553287590a578a0d008d4ff5","55329385e7d1fa0d003fc946","5550b55200420e0d00d1312f","55525fca953c9c0d00f507d7","559199695631432f002d358a","559d8d96980b801700d5ec7e","55c5e833cccdeb2d004e24b9","55d76504f662951900fc0e7d","55ea213cc62aa02f008229cd","56157b750f5ed00d00483dd8","561981fbac0924170069f4e8","561b8b1ea430930d0037ea67","563417428b86331700b488ca","56cd785bface161300dae0ec","56cdcc6e70db8a15006395f4","56cdf1b749abf10b0036a34a","56cedc8ce50c9c1b00830423","56e97ba8d825061900d1ac83","570d505228e6900e00477229","573614ca2ab52e1700c8e851","57d556a2496a3117004d70cf"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"category":{"_id":"55284ed68962f339009a67e1","__v":6,"pages":["552854af60c60f230003fb96","5528553ad9e1db2d00cd9292","55286c7d391a362500d9b3f5","55290f5bceedaa0d00bc5c5b","56d1fb3d93f76e0b00bbc5e2","56d1fb6293f76e0b00bbc5e4"],"project":"552829408962f339009a678d","version":"552829408962f339009a6790","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-04-10T22:29:42.627Z","from_sync":false,"order":9,"slug":"protocol","title":"MTProto v2"},"parentDoc":null,"project":"552829408962f339009a678d","user":"55282916d9e1db2d00cd923c","__v":0,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-02-27T19:38:37.350Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":5,"body":"# Authentication Key\n\nIn rev3 of protocol MTProto v2 introduces a better way of authentication of requests. In previous versions server tell authKey explictly and client apps need to pass it to every request for authentication. This is not a problem as TLS is required and everything is encrypted by default already.\nBut we think that can be a problem in some cases on the server side as this key flaws around the server and can occasionaly appear in server's logs. On the other side application might need to have some shared secret for performing various security related tasks, for example, sigining voice call requests.\n\nEventually, in rev4 of MTProto we will eliminate using of TLS for better speed and security.\n\nMTProtoV2 uses Curve25519 for performing DH for calculating AuthKey.\n\nThis technique use [TLS 1.2 RFC](https://tools.ietf.org/html/rfc5246) for it's basis and doesn't try to invent wheel, but improves performance of TLS:\n\n* Not sending server certificates if not needed on every connection.\n* One DiffieHellman to build one shared secret without repeating on almost every reconnect. (we will implement PFS in next revision of MTProto v2)\n* Using only Curve25519, AES-CBC, Kuznechik-CBC and Streebog\n* Extending master_secret to make it 256 bytes long with two different algorithms based on TLS's PRF function with SHA256 and Streebog hashes.\n* Added Signing of response just to check that everything is ok and add one more protection level\n* **Protocol uses 256 bits of block length in HMAC instead of standart one**. This was caused by bug in initial implementation of HMAC, but doesn't affect security parameters.\n\n# Primitives\n\nSHA256-based pseudo-random function (https://tools.ietf.org/html/rfc5246#section-5):\n\n```\nPRF(secret: bytes, label: string, seed: bytes) = P_SHA256(secret, bytes(label) + seed);\nP_SHA256(secret, seed) = SHA256(secret, A(1) + seed) + SHA256(secret, A(2) + seed) + SHA256(secret, A(3) + seed) + ...\n  where A():\n    A(0) = seed\n    A(i) = HMAC_hash(secret, A(i-1))\n```\n\nOriginal key is too short - only 32 bytes and we need to extend key to more bytes in a secure way. Pseudo-code above is taken from TLS 1.2 RFC. Basic idea is to take some plain-text seed from client and server, add some fixed seed to avoid getting same hashes in different parts of a program. We use client and server seed for protecting from not that good random generators. Using text as fixed seed value is for cleaner code and specifications. In our Implementation we are performing **8** SHA256 calculations.\n\n# New Requesting Authentication Key\nOld method of AuthId creation will continue to work, but rev3 introduces new way of more secure way to get AuthId and AuthKey.\n\n#### Server's Key Loading\n\nBefore begin you need to securely generate random long value - randomId. This is temprorary unique id used by server to identify authentication session. Server doesn't try to scope authentication procedure to single connection and even to single server and this value helps it to identify state of DH. If collision will take place it will only lead to DH failure and nothing more.\n\n\nBefore start Client MUST send ```RequestStartAuth``` message: \n```\nRequestStartAuth {\n  HEADER = 0xE0\n  randomId: long\n}\n```\n\nServer MUST return list of truncated to 8 bytes of SHA-256 of available keys\n```\nResponseStartAuth {\n  HEADER = 0xE1\n  randomId: long\n  availableKeys: longs\n  serverNonce: bytes\n}\n```\n\nClient downloads required key. Client can skip downloading keys if it have built-in keys installed.\n```\nRequestGetServerKey {\n  HEADER = 0xE2\n  keyId: long\n}\n```\n\nServer return raw key data. Client MUST to check received key by comparing FULL hash that is hardcoded inside application. Again, DON'T compare truncated hashes - this is insecure. \n```\nResponseGetServerKey {\n  HEADER = 0xE3\n  keyId: long\n  key: bytes\n}\n```\n\n#### Performing Diffie Hellman\n\n```\nRequestDH {\n  HEADER = 0xE6\n  randomId: long\n  // Used keyId\n  keyId: long\n  // Client's 32 securely generated bytes\n  clientNonce: bytes\n  // Client's key used for encryption\n  clientKey: bytes\n}\n```\n\nCalculations\n```\npre_master_secret := <result_of_dh>\nmaster_secret := PRF_COMBINED(pre_master_secret, \"master secret\", clientNonce + ServerNonce, 128)\nverify := PRF_COMBINED(master_secret, \"client finished\", clientNonce + ServerNonce, 256)\nverify_sign := Ed25519(verification, server_private_signing_key)\n\nwhere PRF_COMBINED:\n  PRF(COMBINE(SHA256, STREEBOG256)), where:\n    COMBINE(str, HASH1, HASH2) = HASH1(str + HASH2(str))\n```\n\nmaster_secret is result encryption key. First 128 bytes is US encryption keys and last 128 bytes is Russian encryption keys.\n\n```\nResponseDoDH {\n  HEADER = 0xE7\n  randomId: long\n  verify: bytes\n  verifySign: bytes\n}\n```","excerpt":"Calculating encryption keys for MTProto v2","slug":"encryption-key-negotiation","type":"basic","title":"Encryption: Key Negotiation"}

Encryption: Key Negotiation

Calculating encryption keys for MTProto v2

# Authentication Key In rev3 of protocol MTProto v2 introduces a better way of authentication of requests. In previous versions server tell authKey explictly and client apps need to pass it to every request for authentication. This is not a problem as TLS is required and everything is encrypted by default already. But we think that can be a problem in some cases on the server side as this key flaws around the server and can occasionaly appear in server's logs. On the other side application might need to have some shared secret for performing various security related tasks, for example, sigining voice call requests. Eventually, in rev4 of MTProto we will eliminate using of TLS for better speed and security. MTProtoV2 uses Curve25519 for performing DH for calculating AuthKey. This technique use [TLS 1.2 RFC](https://tools.ietf.org/html/rfc5246) for it's basis and doesn't try to invent wheel, but improves performance of TLS: * Not sending server certificates if not needed on every connection. * One DiffieHellman to build one shared secret without repeating on almost every reconnect. (we will implement PFS in next revision of MTProto v2) * Using only Curve25519, AES-CBC, Kuznechik-CBC and Streebog * Extending master_secret to make it 256 bytes long with two different algorithms based on TLS's PRF function with SHA256 and Streebog hashes. * Added Signing of response just to check that everything is ok and add one more protection level * **Protocol uses 256 bits of block length in HMAC instead of standart one**. This was caused by bug in initial implementation of HMAC, but doesn't affect security parameters. # Primitives SHA256-based pseudo-random function (https://tools.ietf.org/html/rfc5246#section-5): ``` PRF(secret: bytes, label: string, seed: bytes) = P_SHA256(secret, bytes(label) + seed); P_SHA256(secret, seed) = SHA256(secret, A(1) + seed) + SHA256(secret, A(2) + seed) + SHA256(secret, A(3) + seed) + ... where A(): A(0) = seed A(i) = HMAC_hash(secret, A(i-1)) ``` Original key is too short - only 32 bytes and we need to extend key to more bytes in a secure way. Pseudo-code above is taken from TLS 1.2 RFC. Basic idea is to take some plain-text seed from client and server, add some fixed seed to avoid getting same hashes in different parts of a program. We use client and server seed for protecting from not that good random generators. Using text as fixed seed value is for cleaner code and specifications. In our Implementation we are performing **8** SHA256 calculations. # New Requesting Authentication Key Old method of AuthId creation will continue to work, but rev3 introduces new way of more secure way to get AuthId and AuthKey. #### Server's Key Loading Before begin you need to securely generate random long value - randomId. This is temprorary unique id used by server to identify authentication session. Server doesn't try to scope authentication procedure to single connection and even to single server and this value helps it to identify state of DH. If collision will take place it will only lead to DH failure and nothing more. Before start Client MUST send ```RequestStartAuth``` message: ``` RequestStartAuth { HEADER = 0xE0 randomId: long } ``` Server MUST return list of truncated to 8 bytes of SHA-256 of available keys ``` ResponseStartAuth { HEADER = 0xE1 randomId: long availableKeys: longs serverNonce: bytes } ``` Client downloads required key. Client can skip downloading keys if it have built-in keys installed. ``` RequestGetServerKey { HEADER = 0xE2 keyId: long } ``` Server return raw key data. Client MUST to check received key by comparing FULL hash that is hardcoded inside application. Again, DON'T compare truncated hashes - this is insecure. ``` ResponseGetServerKey { HEADER = 0xE3 keyId: long key: bytes } ``` #### Performing Diffie Hellman ``` RequestDH { HEADER = 0xE6 randomId: long // Used keyId keyId: long // Client's 32 securely generated bytes clientNonce: bytes // Client's key used for encryption clientKey: bytes } ``` Calculations ``` pre_master_secret := <result_of_dh> master_secret := PRF_COMBINED(pre_master_secret, "master secret", clientNonce + ServerNonce, 128) verify := PRF_COMBINED(master_secret, "client finished", clientNonce + ServerNonce, 256) verify_sign := Ed25519(verification, server_private_signing_key) where PRF_COMBINED: PRF(COMBINE(SHA256, STREEBOG256)), where: COMBINE(str, HASH1, HASH2) = HASH1(str + HASH2(str)) ``` master_secret is result encryption key. First 128 bytes is US encryption keys and last 128 bytes is Russian encryption keys. ``` ResponseDoDH { HEADER = 0xE7 randomId: long verify: bytes verifySign: bytes } ```