/// <summary>Decrypt the key and iv of the negotiated cipher option.</summary> /// <param name="option">negotiated cipher option</param> /// <param name="sasl">SASL participant representing client</param> /// <returns> /// CipherOption negotiated cipher option which contains the /// decrypted key and iv /// </returns> /// <exception cref="System.IO.IOException">for any error</exception> public static CipherOption Unwrap(CipherOption option, SaslParticipant sasl) { if (option != null) { byte[] inKey = option.GetInKey(); if (inKey != null) { inKey = sasl.Unwrap(inKey, 0, inKey.Length); } byte[] outKey = option.GetOutKey(); if (outKey != null) { outKey = sasl.Unwrap(outKey, 0, outKey.Length); } return(new CipherOption(option.GetCipherSuite(), inKey, option.GetInIv(), outKey, option.GetOutIv())); } return(null); }
/// <summary> /// Create IOStreamPair of /// <see cref="Org.Apache.Hadoop.Crypto.CryptoInputStream"/> /// and /// <see cref="Org.Apache.Hadoop.Crypto.CryptoOutputStream"/> /// </summary> /// <param name="conf">the configuration</param> /// <param name="cipherOption">negotiated cipher option</param> /// <param name="out">underlying output stream</param> /// <param name="in">underlying input stream</param> /// <param name="isServer">is server side</param> /// <returns>IOStreamPair the stream pair</returns> /// <exception cref="System.IO.IOException">for any error</exception> public static IOStreamPair CreateStreamPair(Configuration conf, CipherOption cipherOption , OutputStream @out, InputStream @in, bool isServer) { if (Log.IsDebugEnabled()) { Log.Debug("Creating IOStreamPair of CryptoInputStream and " + "CryptoOutputStream." ); } CryptoCodec codec = CryptoCodec.GetInstance(conf, cipherOption.GetCipherSuite()); byte[] inKey = cipherOption.GetInKey(); byte[] inIv = cipherOption.GetInIv(); byte[] outKey = cipherOption.GetOutKey(); byte[] outIv = cipherOption.GetOutIv(); InputStream cIn = new CryptoInputStream(@in, codec, isServer ? inKey : outKey, isServer ? inIv : outIv); OutputStream cOut = new CryptoOutputStream(@out, codec, isServer ? outKey : inKey , isServer ? outIv : inIv); return(new IOStreamPair(cIn, cOut)); }
/// <summary>This method actually executes the server-side SASL handshake.</summary> /// <param name="underlyingOut">connection output stream</param> /// <param name="underlyingIn">connection input stream</param> /// <param name="saslProps">properties of SASL negotiation</param> /// <param name="callbackHandler">for responding to SASL callbacks</param> /// <returns>new pair of streams, wrapped after SASL negotiation</returns> /// <exception cref="System.IO.IOException">for any error</exception> private IOStreamPair DoSaslHandshake(OutputStream underlyingOut, InputStream underlyingIn , IDictionary <string, string> saslProps, CallbackHandler callbackHandler) { DataInputStream @in = new DataInputStream(underlyingIn); DataOutputStream @out = new DataOutputStream(underlyingOut); SaslParticipant sasl = SaslParticipant.CreateServerSaslParticipant(saslProps, callbackHandler ); int magicNumber = @in.ReadInt(); if (magicNumber != SaslTransferMagicNumber) { throw new InvalidMagicNumberException(magicNumber, dnConf.GetEncryptDataTransfer( )); } try { // step 1 byte[] remoteResponse = DataTransferSaslUtil.ReadSaslMessage(@in); byte[] localResponse = sasl.EvaluateChallengeOrResponse(remoteResponse); DataTransferSaslUtil.SendSaslMessage(@out, localResponse); // step 2 (server-side only) IList <CipherOption> cipherOptions = Lists.NewArrayList(); remoteResponse = DataTransferSaslUtil.ReadSaslMessageAndNegotiationCipherOptions( @in, cipherOptions); localResponse = sasl.EvaluateChallengeOrResponse(remoteResponse); // SASL handshake is complete DataTransferSaslUtil.CheckSaslComplete(sasl, saslProps); CipherOption cipherOption = null; if (sasl.IsNegotiatedQopPrivacy()) { // Negotiate a cipher option cipherOption = DataTransferSaslUtil.NegotiateCipherOption(dnConf.GetConf(), cipherOptions ); if (cipherOption != null) { if (Log.IsDebugEnabled()) { Log.Debug("Server using cipher suite " + cipherOption.GetCipherSuite().GetName()); } } } // If negotiated cipher option is not null, wrap it before sending. DataTransferSaslUtil.SendSaslMessageAndNegotiatedCipherOption(@out, localResponse , DataTransferSaslUtil.Wrap(cipherOption, sasl)); // If negotiated cipher option is not null, we will use it to create // stream pair. return(cipherOption != null?DataTransferSaslUtil.CreateStreamPair(dnConf.GetConf (), cipherOption, underlyingOut, underlyingIn, true) : sasl.CreateStreamPair(@out , @in)); } catch (IOException ioe) { if (ioe is SaslException && ioe.InnerException != null && ioe.InnerException is InvalidEncryptionKeyException) { // This could just be because the client is long-lived and hasn't gotten // a new encryption key from the NN in a while. Upon receiving this // error, the client will get a new encryption key from the NN and retry // connecting to this DN. SendInvalidKeySaslErrorMessage(@out, ioe.InnerException.Message); } else { DataTransferSaslUtil.SendGenericSaslErrorMessage(@out, ioe.Message); } throw; } }