Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.11'

Expand All @@ -38,7 +38,7 @@ jobs:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.11'

Expand Down Expand Up @@ -113,7 +113,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-')
environment:
name: pypi
url: https://pypi.org/p/git-safe
url: https://pypi.org/p/gitsafe-cli
permissions:
id-token: write
steps:
Expand All @@ -125,16 +125,14 @@ jobs:

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}

publish-test-pypi:
needs: [test, build]
runs-on: ubuntu-latest
if: contains(github.ref, '-') || github.event_name == 'workflow_dispatch'
environment:
name: testpypi
url: https://test.pypi.org/p/git-safe
url: https://test.pypi.org/p/gitsafe-cli
permissions:
id-token: write
steps:
Expand All @@ -147,7 +145,6 @@ jobs:
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository-url: https://test.pypi.org/legacy/

docker:
Expand Down Expand Up @@ -183,4 +180,14 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64
platforms: linux/amd64,linux/arm64

- name: Update Docker Hub Description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: ${{ secrets.DOCKER_USERNAME }}/git-safe
short-description: "Effortless file encryption for your git repos—pattern-matched, secure, and keyfile-flexible."
readme-filepath: ./README.md
enable-url-completion: true
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
[![CI](https://github.com/hemonserrat/git-safe/workflows/CI/badge.svg)](https://github.com/hemonserrat/git-safe/actions/workflows/ci.yml)
[![Security Scan](https://github.com/hemonserrat/git-safe/workflows/Security%20Scan/badge.svg)](https://github.com/hemonserrat/git-safe/actions/workflows/security.yml)
[![codecov](https://codecov.io/gh/hemonserrat/git-safe/branch/main/graph/badge.svg)](https://codecov.io/gh/hemonserrat/git-safe)
[![PyPI version](https://badge.fury.io/py/git-safe.svg)](https://badge.fury.io/py/git-safe)
[![Python versions](https://img.shields.io/pypi/pyversions/git-safe.svg)](https://pypi.org/project/git-safe/)
[![PyPI version](https://badge.fury.io/py/gitsafe-cli.svg)](https://badge.fury.io/py/gitsafe-cli)
[![Python versions](https://img.shields.io/pypi/pyversions/gitsafe-cli.svg)](https://pypi.org/project/gitsafe-cli/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
Expand Down Expand Up @@ -33,7 +33,7 @@ Effortless file encryption for your git repos—pattern-matched, secure, and key

```bash
# Install from PyPI
pip install git-safe
pip install gitsafe-cli

# Or install from source
git clone https://github.com/hemonserrat/git-safe.git
Expand Down Expand Up @@ -67,7 +67,7 @@ git commit -m "Add secret config"
### From PyPI (Recommended)

```bash
pip install git-safe
pip install gitsafe-cli
```

### From Source
Expand Down Expand Up @@ -360,8 +360,8 @@ gpg --version # Should show GPG version

**Import errors**: If you encounter import errors, try reinstalling:
```bash
pip uninstall git-safe
pip install git-safe
pip uninstall gitsafe-cli
pip install gitsafe-cli
```

### Keyfile Issues
Expand Down
49 changes: 24 additions & 25 deletions git_safe/crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,30 @@ def ctr_decrypt(aes_key: bytes, nonce: bytes, data: bytes) -> bytes:
Returns:
Decrypted data
"""
# Create cipher in ECB mode for manual CTR implementation
cipher = Cipher(algorithms.AES(aes_key), modes.ECB(), backend=default_backend()) # nosec B305
encryptor = cipher.encryptor()

out = bytearray()

for off in range(0, len(data), BLOCK_SIZE):
block = data[off : off + BLOCK_SIZE]
# Create counter by combining nonce and block counter
counter_bytes = nonce + struct.pack(">I", off // BLOCK_SIZE)

# Pad or truncate to exactly BLOCK_SIZE (16 bytes) for ECB mode
if len(counter_bytes) < BLOCK_SIZE:
# Pad with zeros
ctr = counter_bytes + b"\x00" * (BLOCK_SIZE - len(counter_bytes))
else:
# Truncate to block size
ctr = counter_bytes[:BLOCK_SIZE]

stream = encryptor.update(ctr)
out.extend(b ^ s for b, s in zip(block, stream, strict=False))

# Finalize the encryptor (required by cryptography library)
encryptor.finalize()
return bytes(out)
if not data:
return b""

# Prepare the initial counter value by combining nonce with counter
# Pad or truncate nonce to fit in the counter space
if len(nonce) < BLOCK_SIZE:
# Pad with zeros, leaving space for counter at the end
counter_prefix = nonce + b"\x00" * (BLOCK_SIZE - 4 - len(nonce))
initial_counter = counter_prefix + b"\x00\x00\x00\x00" # 32-bit counter starts at 0
else:
# Truncate nonce and reserve last 4 bytes for counter
counter_prefix = nonce[:BLOCK_SIZE - 4]
initial_counter = counter_prefix + b"\x00\x00\x00\x00"

# Use proper CTR mode from cryptography library
cipher = Cipher(
algorithms.AES(aes_key),
modes.CTR(initial_counter),
backend=default_backend()
)
decryptor = cipher.decryptor()

result = decryptor.update(data) + decryptor.finalize()
return result


def ctr_encrypt(aes_key: bytes, nonce: bytes, data: bytes) -> bytes:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "git-safe"
name = "gitsafe-cli"
version = "1.0.0"
authors = [
{name = "Hernan Monserrat"},
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
]

setup(
name="git-safe",
name="gitsafe-cli",
version="1.0.0",
author="Hernan Monserrat",
author_email="",
Expand Down