9. Security

9.1. Introduction

NEX includes a check to detect packet tampering using MD5, and an encryption feature based on the 256-bit ArcFour common key algorithm.

The check to detect packet tampering is enabled for all communication modes. By default, encryption is enabled only when communicating with the game server. The packet tampering is checked for when packets are received. Invalid packets are destroyed and never reach the application.

When using the Internet, applications must specify the signature key distributed by the game server during matchmaking to NetZ, to enhance the securing of the packet tampering check for peer-to-peer communications.

9.2. Packet Tampering Check for Peer-to-Peer Communication

An application must specify a signature key to use NetZ's packet tampering check for peer-to-peer communications.

For local communication, the application's shared key is set using Network::SetP2PDataPacketDefaultSignatureKey(). If the application's shared key is not set, the default key within NEX is used for the signature.

The game server sends a 256-bit shared key used with matchmaking sessions during matchmaking when using the Internet. You must set this key before executing Session::CreateSession or Session::JoinSession. The value set using Network::SetP2PDataPacketDefaultSignatureKey() is ignored at this time.

Use MatchmakeSession::GetSessionKey(), MatchmakeExtensionClient::CreateMatchmakeSession(), and MatchmakeExtensionClient::JoinMatchmakeSession() to get the session shared key. Use Network::SetP2PDataPacketSessionSignatureKey() to set this shared key.

Warning

For Internet communication, if you call the Session::CreateSession or Session::JoinSession function without specifying a shared session key, execution halts with an assertion error.

9.2.1. Sample Implementation in an Application

Code 9.1 Setting the Shared Signature Key for a Peer-to-Peer Application

// Initialization processing.
nn::nex::GlobalVariables::AcquireInstance();

//The signature key used for the P2P section of code. This key must be changed for every application.
static qByte SIGNATURE_KEY[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};

// Set the signature key for the P2P section of code.
nn::nex::Network::GetInstance()->SetP2PDataPacketDefaultSignatureKey
        (SIGNATURE_KEY, sizeof(SIGNATURE_KEY));

Code 9.2 Setting the Shared Signature Key for a Peer-to-Peer Session

nn::nex::MatchmakeSession* matchmakeSession = qNew nn::nex::MatchmakeSession();

//Omitted.

nn::nex::GatheringHolder oInGatheringHolder = matchmakeSession;
nn::nex::GatheringHolder oOutGatheringHolder;   // The gathering the local system is joined in.

// Search for or create a matchmaking session.
nn::nex::ProtocolCallContext oContext;
if (pMatchMakingClient->AutoMatchmake(&oContext, criteriaList, oInGatheringHolder, &oOutGatheringHolder, _T("auto matchmake session")))
{
    //Omitted.

    //By setting a key sent from the game server as the P2P session signature key,
    // generate a different signature for each session.
    nn::nex::Network::GetInstance()->SetP2PDataPacketSessionSignatureKey(
            reinterpret_cast<nn::nex::MatchmakeSession*>(oOutGatheringHolder.Get())
            ->GetSessionKey());

Note

You cannot get a shared session key from MatchmakeSession set in the matchmakingSession argument of MatchmakeExtensionClient::AutoMatchmake(). Get the shared session key by executing a get method for joinedMatchmakingSession, as in the sample implementation, or from MatchmakeSession obtained by casting to MatchmakeSession*.

9.3. Encrypting a Peer-to-Peer Session

NetZ does not encrypt peer-to-peer sessions by default. Encrypt sessions by using StreamSettings::SetIsEncryptionRequired() to enable encryption for an application, and then using StreamSettings::SetEncryptionKey to set an encryption key.

When using the Internet, the game server notifies a shared matchmaking session key during matchmaking. Use this key for the encryption key.

Warning

Encryption must be enabled by setting the key before executing the Session::CreateSession or Session::JoinSession function. If necessary, you can disable encryption after the NetZ::Terminate function completes. If you attempt operations after calling the Session::CreateSession or Session::JoinSession function, but before calling the NetZ::Terminate function, execution is either forcibly stopped on by an assertion or update fails.

9.3.1. Internal Implementation Specifications

Implementation of encryption differs between reliable and unreliable communication.

Streaming encryption is used for reliable communication by adding a different ID for each session to a user-defined key of up to 256 bits. The encryption sequence differs for each session.

Unreliable communications are encrypted at the payload level by concatenating a 16-bit sequence number as an initial vector with a 240-bit key. When the sequence number has completed a full cycle (after sending 65536 times) the same encryption sequence is used again. Use reliable communication when sending permanent in-game data, because it a uses stronger encryption type than reliable communication. A 240-bit key that differs from the key used with reliable communication is generated internally, and the session ID is added to it to form the key that is used.

9.3.2. Sample Implementation in an Application

Code 9.3 Setting the Encryption Key for a Peer-to-Peer Session

nn::nex::MatchmakeSession* matchmakeSession = qNew nn::nex::MatchmakeSession();

//Omitted.

nn::nex::GatheringHolder oInGatheringHolder = matchmakeSession;
nn::nex::GatheringHolder oOutGatheringHolder;   // The gathering the local system is joined in.

// Search for or create a matchmaking session.
nn::nex::ProtocolCallContext oContext;
if (pMatchMakingClient->AutoMatchmake(&oContext, criteriaList, oInGatheringHolder, &oOutGatheringHolder, _T("auto matchmake session")))
{
    //Omitted.

    // Encrypt the P2P session.
    nn::nex::Stream::GetSettings().SetIsEncryptionRequired(true); //Enable encryption.
    nn::nex::Stream::GetSettings().SetEncryptionKey(
            reinterpret_cast<nn::nex::MatchmakeSession*>(oOutGatheringHolder.Get())
            ->GetSessionKey()); //Set the encryption key.

Note

You cannot get a shared session key from MatchmakeSession set in the matchmakingSession argument of the MatchmakeExtensionClient::AutoMatchmake function. Get the shared session key by executing a get method for joinedMatchmakingSession, as in the sample implementation, or from MatchmakeSession obtained by casting to MatchmakeSession*.


CONFIDENTIAL