I'm building an authentication server in python, and was wondering about how I could secure a connection totally between two peers totally? I cannot see how in any way a malicious user wouldn't be able to copy packets and simply analyze them if he understands what comes in which order.

Admitting a client server schema. Client asks for an Account. Even though SRP, packets can be copied and sent later on to allow login.

Then now, if I add public - private key encryption, how do I send the public key to each other without passing them in an un-encrypted channel?

Sorry if my questions remains noobish or looks like I haven't minded about the question, but I really have a hard time figuring out, how I can build up an authentication process without having several security holes.

  • Perhaps some clarification is needed. It sounds like you want two nodes to be able to communicate securely from the first byte, without a third party being able to decipher anything sent between them, nor being able to impersonate either of them. Is this true? – KeithS Aug 5 '13 at 19:08
  • 1
    @apsillers public keys are meant to be public... :P – enigma Aug 5 '13 at 19:13
  • Yep that's my question KeithS :) – cp151 Aug 5 '13 at 19:17
  • 1
    there is no total security! the only thing you can do is minimizing the attack vector :) i think you should go with asymmertic crypto – enigma Aug 5 '13 at 19:20
  • How is the application deployed? After deployment, use SSL. During deployment, ensure that the parties have each others' certificate, or a means to obtain it reliably. So, how does deployment work? – Gilles 'SO- stop being evil' Aug 5 '13 at 20:23

Basically, the solution you're looking for is going to involve some sort of offline transfer. The two computers that are the endpoint nodes of your secure tunnel must be "introduced" to each other, exchanging some secret that will allow one side to initiate a connection in such a way that only the other node could understand it.

While this shared secret could be the symmetric key in itself, this can be problematic; symmetric algorithms are most secure when nothing about the key is known, even the fact that it's the same key as was used for another communication. An attacker could watch multiple "conversations" between the nodes, and if he knows the conversations use the same key and IV, and if he can guess the plain text (which he is likely to do as the information sent in the initial stages of communication is fairly boilerplate), he can use the ciphertext to reverse-engineer the key. For this reason, the symmetric key must be renegotiated often, even on the same secure channel, depending on how much data is sent across.

The go-to solution is asymmetric or public-key cryptography. Understand one thing; public keys are meant to be public. You could spray-paint your public key on the side of your car and drive it through Black Hat or DEF CON, and all anyone could do is attempt to connect to your endpoint securely (which is no more than they could do to any other TLS-secured endpoint, and they wouldn't get far here; keep reading). The private key is needed in any public-key scheme in order for data to be decrypted efficiently (and thus for information to be at risk).

Now, you may not publicly distribute this certificate; you could, quite plausibly, implement a simple variant of the basic TLS scheme where the normal first step, the client's request for the server's certificate, would be ignored by the server. Instead, the client must already have a certificate for the server "pinned" in the OS certificate store, and would not (could not) verify it had the latest version. It would then be able to negotiate a secure connection without a single bit of actual data being sent plainly (the packet data would still be in a well-formed IP packet).

Conceptually, it would work as follows; the client would have the public key of the server, which it was given offline (here, the only difference between "client" and "server" that we care about is that the client is the one initiating communication; both computers can be "servers" in other senses of the word, such as file servers in the cloud). The server would have the public key of the client, which it received offline. The client encrypts a request using the server's public key, which will contain the client's certificate. That request goes to the server IP, and only the server can decrypt it, even if someone else were sniffing or spoofing traffic on that same IP address. The request can contain a nonce, such as a simple counter value, preventing replay attacks (the server can ignore multiple requests from the same client with the same nonce, though it must decrypt each request it receives to determine this, which could make it vulnerable to DDoS).

The server would then use the client certificate, which it can independently verify as an authorized client because an exact copy of the client cert lives in the server's OS store, to send a symmetric key negotiation. From this point the scheme is virtually identical to two-certificate TLS negotiation; the server sends the client the key negotiation request, the client receives, sets up its cipher, and returns either a symmetrically-encrypted acknowledgement or the other half of the key-exchange protocol so the server now knows they're talking the same language. From then on, client and server can communicate using the symmetric channel. All this, without a third-party observer seeing any packet data in plain text.

Now, this is just to create a secure channel. Even if the client node has a static IP, it's always good to subsequently verify, after negotiating the secure tunnel, that the human controlling the computer on the other end is someone authorized to use the system. Credential exchange like username/password, or the entry of a time-limited key value generated by a fob, are common and perfectly feasible means to authenticate the user of the authenticated computer(s).


If a symmetric key is pre-shared, then a simple counter can be used to prevent replay. Only messages that make sense and have a valid count should be honored and an attacker may be able to get in-between, but wouldn't be able to make sense of the traffic or add any instructions to the series.

Similarly, for asymmetric encryption, the public keys are public and can simply be shared in the open. These can then be used to exchange a symmetric key for actual communication and challenge response can be used to prevent replay of the asymmetric authentication. The main key is that trust in the public key has to be established, this is either done by verifying the thumbprint of the public key via a secure channel (such as making a phone call) or done by signing the public key in a certificate (such as is done with SSL certificates from a Certificate Authority). Alternately, a web of trust can be used to give confidence that a public key's corresponding private key is held by the individual that the public clean claims to be for.

  • I'm looking for something that wouldn't rely on external services. I was thinking about sending the publics keys over an already secured channel, but still cannot figure how to build that first secured channel. What if someone copies only one part of a core data used to decrypt the following messages ? To simplify my question, what is the real bottom level of what I can send over socket communication, and how can I level up the security level after-on ? – cp151 Aug 5 '13 at 19:34
  • To create a channel over a public network, you must have already exchanged some data offline that can be used to validate trust in an online identity. You cannot build a secure tunnel from whole cloth; both sides have to be able to prove they are who they say they are. As for "external services", a web of trust doesn't require paying money for a third-party certificate, but it does require at least two people to meet offline and digitally sign each others' keys before taking them back to install in their cert stores. – KeithS Aug 5 '13 at 19:55
  • @cp151 - a secure channel can be as simple as a phone call or some form of identity verification, but ultimately, it is not possible to communicate with anything securely without first establishing trust through some mechanism. Trust can only be achieved through verification which requires some type of trusted interaction between nodes. – AJ Henderson Aug 5 '13 at 20:14
  • As @AJHenderson says, verification requires trust which requires verification which requires trust. At some point, the scope of this cycle must extend beyond the digital realm; the two parties to the communication must be given or specify some piece of information that only they can know, but which the other party in the system can easily verify. – KeithS Aug 5 '13 at 20:24

Don't re-invent the wheel and don't overcomplicate things.

Just setup an IPSec VPN between the two nodes and pass traffic over that.

Leave the security stuff to the people who know how to code security, and focus your efforts on the bits of your Python code that are required for the actual business rather than wasting time on coding up, testing and debugging TLS channels or whatever.


An absolute minimum of unsecured traffic would be a (maybe self-signed, maybe one-time or unique-per-user cretificate). All ongoing traffic can be sent through an SSL-encrypted channel. Additional security can be provided by Session and/ or One-time keys for an additional encryption layer above the SSL-Tunnel. Authentication with challenge/response and Diffie-Hellmann for Session key agreement should lock out most attackers without physical access to either side of the communication link.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.