shadow1ng/fscan · error

oracle session key should be either 64 or 96 bytes long

Error message

oracle session key should be either 64 or 96 bytes long

What it means

finish() derives client-side session keys from the server's encrypted session key (eServerSessKey). The Oracle auth protocol defines this as either 64 bytes (AES-192) or 96 bytes (AES-256); any other length means key derivation cannot proceed, so the library rejects the authentication data before attempting decryption.

Source

Thrown at plugins/services/oracle_raw.go:1339

			}
		default:
			err := s.readMsg(msg)
			if err != nil {
				return nil, err
			}
			if msg == 4 {
				if s.hasError() {
					return nil, s.oracleError()
				}
				return auth.finish(username, password, nego)
			}
		}
	}
}

func (auth *oracleAuthObject) finish(username, password string, nego *oracleTCPNego) (*oracleAuthObject, error) {
	if len(auth.eServerSessKey) != 64 && len(auth.eServerSessKey) != 96 {
		return nil, errors.New("oracle session key should be either 64 or 96 bytes long")
	}
	var key []byte
	var speedyKey []byte
	padding := false
	var err error
	switch auth.verifierType {
	case 2361:
		key, err = oracleKeyFromUserPass(username, password)
	case 6949:
		if len(nego.serverCompileTimeCaps) > 4 && nego.serverCompileTimeCaps[4]&2 == 0 {
			padding = true
		}
		salt, err := hex.DecodeString(auth.salt)
		if err != nil {
			return nil, err
		}
		h := sha1.New()
		_, _ = h.Write(append([]byte(password), salt...))

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Check Oracle server crypto/NNE configuration and version against plugin-supported combinations (64 vs 96 byte keys)
  2. Retry and inspect whether the auth response was truncated by the network/proxy — a full 64/96-byte key may simply be missing tail bytes
  3. Align AUTH_PBKDF2_* parameters and verifier type between client and server (e.g. avoid forcing key size via sqlnet crypto settings)
  4. Log the actual session-key length and file an upstream issue if your server version legitimately uses a different size

Example fix

// before
if len(auth.eServerSessKey) != 64 && len(auth.eServerSessKey) != 96 {
	return nil, errors.New("oracle session key should be either 64 or 96 bytes long")
}
// after
if len(auth.eServerSessKey) != 64 && len(auth.eServerSessKey) != 96 {
	return nil, fmt.Errorf("oracle session key should be either 64 or 96 bytes long: got %d", len(auth.eServerSessKey))
}
Defensive patterns

Strategy: validation

Validate before calling

// validate session-key length before deriving keys
if len(auth.eServerSessKey) != 64 && len(auth.eServerSessKey) != 96 {
	return fmt.Errorf("bad server session key length: %d", len(auth.eServerSessKey))
}

Type guard

func validServerSessKey(k []byte) bool { return len(k) == 64 || len(k) == 96 }

Try / catch

auth, err := authObj.finish(user, pass, nego)
if err != nil && strings.Contains(err.Error(), "session key should be either 64 or 96 bytes") {
	return fmt.Errorf("server sent %d-byte session key; check server crypto config and version support: %w", len(auth.eServerSessKey), err)
}

Prevention

When it happens

Trigger: auth.finish(username, password, nego) is called after parsing the auth response and len(auth.eServerSessKey) is neither 64 nor 96 — typically when verifierType indicates PBKDF2/AES but the server sent a legacy or malformed session key.

Common situations: Server configured for a crypto strength the plugin's length check doesn't cover; mixed-version behavior where an older verifier type is answered with a different key size; a truncated auth response from the network.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/c5cb0744f02c542e. Report an issue: GitHub.