<!--
{
  "documentType" : "article",
  "framework" : "DeviceManagement",
  "identifier" : "/documentation/DeviceManagement/creating-and-using-bypass-codes",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Creating and Using Bypass Codes"
}
-->

# Creating and Using Bypass Codes

Maintain the bypass code parameters for disabling Activation Lock.

## Discussion

To manage Activation Lock, your mobile device management (MDM) server implementation needs to store two bypass codes:

- The device-generated bypass code. The server retains this code until it receives a different, nonempty code from the device. For more information, see the ``doc://com.apple.devicemanagement/documentation/DeviceManagement/Activation-Lock-Bypass-Code-Command`` query.
- The bypass code the server creates when initiating Activation Lock through MDM.

The server attempts to unlock the device by passing in an escrow key with one of the bypass codes as its value. Try the other code if the first one fails. It’s impossible for the server to determine which code is active at a given time, or even to determine if the device is in a locked state, because the user can erase the device and remove Activation Lock manually by entering the correct Apple Account or password. The deviceʼs `IsActivationLockEnabled` value isn’t a reflection of its Activation Lock state because the device can report either a false-positive or a false-negative.

> Note:
> The MDM server must request the activation lock bypass code before the device enables Activation Lock. If this sequence isn’t followed, the user may lock the device before MDM installs the bypass, in which case the bypass code won’t work.

### Create a Bypass Code

When initiating Activation Lock for a device, your MDM implementation needs to generate the bypass code necessary to disable Activation Lock at a later time.

The following code sample shows how to generate a bypass code:

```other
#define MCBYPASS_CODE_LENGTH 31 // Excluding terminating null.
#define MCBYPASS_CODE_BUFFER_LENGTH 32 // Including terminating null.
#define MCBYPASS_RAW_BYTES_LENGTH 16
#define MCBYPASS_HASH_LENGTH CC_SHA256_DIGEST_LENGTH

- (NSString*) _createNewActivationLockBypassCodeOutHash:(NSString**)outHash
{
#define RANDOM_BYTES_LENGTH 16
#define SALT_LENGTH 4
    // Encode raw bytes.
    static const char kSymbols[] = "0123456789ACDEFGHJKLMNPQRTUVWXYZ";
                                //  00000000000000001111111111111111
                                //  0123456789abcdef0123456789abcdef

    // Insert dashes after outputting characters at these positions.
    static const int kDashPositions[] = { 5, 10, 14, 18, 22 };

    char    rawBytes[MCBYPASS_RAW_BYTES_LENGTH];
    char    code[MCBYPASS_CODE_BUFFER_LENGTH];
    uint8_t hash[MCBYPASS_HASH_LENGTH];
    uint8_t salt[SALT_LENGTH] = {0, 0, 0, 0};

    arc4random_buf(rawBytes, RANDOM_BYTES_LENGTH);
    CCKeyDerivationPBKDF(kCCPBKDF2, rawBytes, RANDOM_BYTES_LENGTH, salt, SALT_LENGTH, 
        kCCPRFHmacAlgSHA256, 50000, hash, CC_SHA256_DIGEST_LENGTH);

    if (outHash) {
        int                 len = MCBYPASS_HASH_LENGTH;
        NSMutableString*    str = [NSMutableString stringWithCapacity:MCBYPASS_HASH_LENGTH * 2 + 1];
        const uint8_t*      p   = (const uint8_t*)hash;
        while (len-- > 0) [str appendFormat:@"%02X", *p++];
        *outHash = [NSString stringWithString:str];
    }

    int         outputCharacterCount = 0;
    const int*  nextDashPosition     = kDashPositions;
    char*       outputCursor         = code;
    uint8_t*    inputCursor          = (uint8_t*)rawBytes;

    // Generate output one symbol at a time.
#define INPUT_BITS      128
#define BITS_PER_BYTE   8
#define BITS_PER_SYMBOL 5

    int bitsProcessed     = 0;
    int bitOffsetIntoByte = 0;
    while (bitsProcessed <= (INPUT_BITS - BITS_PER_SYMBOL)) {
        int bitsThisByte = (bitOffsetIntoByte < BITS_PER_BYTE - BITS_PER_SYMBOL 
            ? BITS_PER_SYMBOL : BITS_PER_BYTE - bitOffsetIntoByte);
        int bitsNextByte = (bitsThisByte < BITS_PER_SYMBOL ? BITS_PER_SYMBOL 
            - bitsThisByte : 0);

        uint8_t value = (((*inputCursor << bitOffsetIntoByte) & 0xff) 
        >> (BITS_PER_BYTE - bitsThisByte));

        bitOffsetIntoByte += BITS_PER_SYMBOL;
        if (bitOffsetIntoByte >= BITS_PER_BYTE) {
            bitOffsetIntoByte -= BITS_PER_BYTE;
            inputCursor++;
        }

        if (bitsNextByte) {
            value <<= bitsNextByte;
            value |= (*inputCursor >> (BITS_PER_BYTE - bitsNextByte));
        }

       *outputCursor++ = kSymbols[value];
        if (++outputCharacterCount == *nextDashPosition) {
            ++nextDashPosition;
            *outputCursor++ = '-';
        }

        bitsProcessed += BITS_PER_SYMBOL;
    }

    // Process remaining bits.
    int bitsRemaining = INPUT_BITS - bitsProcessed;
    if (bitsRemaining) {
        uint8_t value = (((*inputCursor << bitOffsetIntoByte) & 0xff) 
            >> (BITS_PER_BYTE - bitsRemaining));
       *outputCursor++ = kSymbols[value];
    }
    *outputCursor = '\0';
    return [NSString stringWithUTF8String:code];
} // -_createNewActivationLockBypassCodeOutHash:
```

### Use a Bypass Code to Disable Activation Lock

To remove Activation Lock, provide the deviceʼs bypass code to the web service as its `escrowKey`. The request needs to be a standard HTTPS POST on port 443 to `https://deviceservices-external.apple.com/deviceservicesworkers/escrowKeyUnlock`, and your MDM server must provide its APNs certificate when establishing the SSL connection with the web service. The request must also have `application/x-www-form-urlencoded` as its `contentType` header.

You must provide the following arguments as part of the URL request string:

- term `serial`: The deviceʼs serial number (required).
- term `imei`: The device’s IMEI (omit for non-cellular devices).
- term `imei2`: The device’s secondary IMEI (omit for non-cellular and single-SIM devices).
- term `meid`: The device’s MEID (omit for non-cellular devices).
- term `productType`: Example: iPad4,1 (required).

You can obtain the IMEI values from the results of a [`DeviceInformationCommand`](/documentation/DeviceManagement/DeviceInformationCommand) with a `ServiceSubscriptions` query. Use the IMEI and MEID values for a `Slot` value of `CTSubscriptionSlotOne` for the `imei` and `meid` arguments, respectively. For the `imei2` value, use the IMEI value (if any) for a `Slot` value of `CTSubscriptionSlotTwo`. Note that the server might ignore any MEID value that `CTSubscriptionSlotTwo` reports—this request only requires the first MEID, even for devices that have two IMEIs.

Include the following arguments in the message body:

- term `orgName`: The client-supplied value for auditing purposes: a string that identifies the name of the organization.
- term `guid`: The client-supplied value for auditing purposes: a string that identifies the user requesting the removal (such as email, LDAP ID, or name).
- term `escrowKey`: The device’s bypass code.

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)
